ipv4.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 305 行
CPP
305 行
/*============================================================================= Copyright (c) 2002-2003 Joel de Guzman http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)=============================================================================*/#include <boost/spirit/include/classic_core.hpp>#include <boost/spirit/include/classic_push_back_actor.hpp>#include <boost/spirit/include/classic_if.hpp>#include <boost/spirit/include/classic_for.hpp>#include <boost/spirit/include/phoenix1.hpp>#include <iostream>#include <string>#include <vector>#include <algorithm>/////////////////////////////////////////////////////////////////////////////////// Sample parser for binary data. This sample highlights the use of dynamic// parsing where the result of actions direct the actual parsing behavior.// We shall demonstrate 1) the use of phoenix to implement lambda (unnamed)// functions, 2) dynamic looping using for_p, 3) the push_back_a actor for// stuffing data into a vector, and 4) the if_p parser for choosing parser// branches based on semantic conditions.//// << Sample idea by Florian Weimer >>//// For simplicity, we shall use bytes as atoms (and not 16-bit quantities// in big-endian format or something similar, which would be more realistic)// and PASCAL strings.//// A packet is the literal octet with value 255, followed by a variable// octet N (denoting the total length of the packet), followed by N-2 octets// (the payload). The payload contains a variable-length header, followed// by zero or more elements.//// The header contains a single PASCAL string.//// An element is a PASCAL string (alternative: an element is an octet M,// followed by [M/8] bytes, i.e. the necessary number of bytes to store M// bits).//// (This data structure is inspired by the format of a BGP UPDATE message.)//// Packet layout://// .-------------------.// | 0xff | ^// +-------------------+ |// | packet length | |// +-------------------+ | number of bytes indicated by packet length// : : |// : payload : |// | | v// `-------------------'//// Payload layout://// .-------------------.// | header length |// +-------------------+// | header octets | ^// : : | number of octets given by header length// : : |// : : v// +-------------------+// | IPv4 prefix | ^// : : | IPv4 prefixes have variable length (see// +-------------------+ | below). The number of prefixes is// | IPv4 prefix | | determined by the packet length.// : : |// +-------------------+ |// : : |// : : v////// IPv4 prefix layout comes in five variants, depending on the first// octet://// .-------------------.// | 0x00 | single octet, corresponds to 0.0.0.0/0// `-------------------'//// .-------------------.// | 0x01 to 0x08 | two octets, prefix lengths up to /8.// +-------------------+// | MSB of network |// `-------------------'//// .-------------------.// | 0x09 to 0x10 | three octets, prefix lengths up to /16.// +-------------------+// | MSB of network |// +-------------------+// | next octet |// `-------------------'//// .-------------------.// | 0x11 to 0x18 | four octets, prefix lengths up to /24.// +-------------------+// | MSB of network |// +-------------------+// | next octet |// +-------------------+// | next octet |// `-------------------'//// .-------------------.// | 0x19 to 0x20 | five octets, prefix lengths up to /32.// +-------------------+// | MSB of network |// +-------------------+// | next octet |// +-------------------+// | next octet |// +-------------------+// | LSB of network |// `-------------------'/////////////////////////////////////////////////////////////////////////////////using namespace std;using namespace BOOST_SPIRIT_CLASSIC_NS;using namespace phoenix;struct ipv4_prefix_data{ char prefix_len, n0, n1, n2, n3; ipv4_prefix_data() : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}};struct ipv4_data{ char packet_len, header_len; std::string header; std::vector<ipv4_prefix_data> prefixes; ipv4_data() : packet_len(0),header_len(0){}};struct ipv4 : public grammar<ipv4>{ template <typename ScannerT> struct definition { definition(ipv4 const& self) { packet = '\xff' >> anychar_p[var(self.data.packet_len) = arg1] >> payload ; payload = anychar_p[var(self.data.header_len) = arg1] >> for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i)) [ anychar_p[var(self.data.header) += arg1] ] >> *ipv4_prefix ; ipv4_prefix = anychar_p [ var(temp.prefix_len) = arg1, var(temp.n0) = 0, var(temp.n1) = 0, var(temp.n2) = 0, var(temp.n3) = 0 ] >> if_p(var(temp.prefix_len) > 0x00) [ anychar_p[var(temp.n0) = arg1] >> if_p(var(temp.prefix_len) > 0x08) [ anychar_p[var(temp.n1) = arg1] >> if_p(var(temp.prefix_len) > 0x10) [ anychar_p[var(temp.n2) = arg1] >> if_p(var(temp.prefix_len) > 0x18) [ anychar_p[var(temp.n3) = arg1] ] ] ] ] [ push_back_a(self.data.prefixes, temp) ] ; } int i; ipv4_prefix_data temp; rule<ScannerT> packet, payload, ipv4_prefix; rule<ScannerT> const& start() const { return packet; } }; ipv4(ipv4_data& data) : data(data) {} ipv4_data& data;};//////////////////////////////////////////////////////////////////////////////// Main program//////////////////////////////////////////////////////////////////////////////intas_byte(char n){ if (n < 0) return n + 256; return n;}voidprint_prefix(ipv4_prefix_data const& prefix){ cout << "prefix length = " << as_byte(prefix.prefix_len) << endl; cout << "n0 = " << as_byte(prefix.n0) << endl; cout << "n1 = " << as_byte(prefix.n1) << endl; cout << "n2 = " << as_byte(prefix.n2) << endl; cout << "n3 = " << as_byte(prefix.n3) << endl;}voidparse_ipv4(char const* str, unsigned len){ ipv4_data data; ipv4 g(data); parse_info<> info = parse(str, str+len, g); if (info.full) { cout << "-------------------------\n"; cout << "Parsing succeeded\n"; cout << "packet length = " << as_byte(data.packet_len) << endl; cout << "header length = " << as_byte(data.header_len) << endl; cout << "header = " << data.header << endl; for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix); cout << "-------------------------\n"; } else { cout << "Parsing failed\n"; cout << "stopped at:"; for (char const* s = info.stop; s != str+len; ++s) cout << static_cast<int>(*s) << endl; }}// Test inputs:// The string in the header is "empty", the prefix list is empty.char const i1[8] ={ 0xff,0x08,0x05, 'e','m','p','t','y'};// The string in the header is "default route", the prefix list// has just one element, 0.0.0.0/0.char const i2[17] ={ 0xff,0x11,0x0d, 'd','e','f','a','u','l','t',' ', 'r','o','u','t','e', 0x00};// The string in the header is "private address space", the prefix list// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.char const i3[32] ={ 0xff,0x20,0x15, 'p','r','i','v','a','t','e',' ', 'a','d','d','r','e','s','s',' ', 's','p','a','c','e', 0x08,0x0a, 0x0c,0xac,0x10, 0x10,0xc0,0xa8};intmain(){ parse_ipv4(i1, sizeof(i1)); parse_ipv4(i2, sizeof(i2)); parse_ipv4(i3, sizeof(i3)); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?