Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/spirit/example/intermediate/ipv4.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 9.0 KB
Line 
1/*=============================================================================
2    Copyright (c) 2002-2003 Joel de Guzman
3    http://spirit.sourceforge.net/
4
5    Use, modification and distribution is subject to the Boost Software
6    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7    http://www.boost.org/LICENSE_1_0.txt)
8=============================================================================*/
9#include <boost/spirit/core.hpp>
10#include <boost/spirit/actor/push_back_actor.hpp>
11#include <boost/spirit/dynamic/if.hpp>
12#include <boost/spirit/dynamic/for.hpp>
13#include <boost/spirit/phoenix.hpp>
14#include <iostream>
15#include <string>
16#include <vector>
17#include <algorithm>
18
19///////////////////////////////////////////////////////////////////////////////
20//
21//  Sample parser for binary data. This sample highlights the use of dynamic
22//  parsing where the result of actions direct the actual parsing behavior.
23//  We shall demonstrate 1) the use of phoenix to implement lambda (unnamed)
24//  functions, 2) dynamic looping using for_p, 3) the push_back_a actor for
25//  stuffing data into a vector, and 4) the if_p parser for choosing parser
26//  branches based on semantic conditions.
27//
28//  << Sample idea by Florian Weimer >>
29//
30//  For simplicity, we shall use bytes as atoms (and not 16-bit quantities
31//  in big-endian format or something similar, which would be more realistic)
32//  and PASCAL strings.
33//
34//  A packet is the literal octet with value 255, followed by a variable
35//  octet N (denoting the total length of the packet), followed by N-2 octets
36//  (the payload). The payload contains a variable-length header, followed
37//  by zero or more elements.
38//
39//  The header contains a single PASCAL string.
40//
41//  An element is a PASCAL string (alternative: an element is an octet M,
42//  followed by [M/8] bytes, i.e. the necessary number of bytes to store M
43//  bits).
44//
45//  (This data structure is inspired by the format of a BGP UPDATE message.)
46//
47//  Packet layout:
48//
49//       .-------------------.
50//       |       0xff        |  ^
51//       +-------------------+  |
52//       |   packet length   |  |
53//       +-------------------+  | number of bytes indicated by packet length
54//       :                   :  |
55//       :      payload      :  |
56//       |                   |  v
57//       `-------------------'
58//
59//  Payload layout:
60//
61//       .-------------------.
62//       |   header length   |
63//       +-------------------+
64//       |   header octets   |  ^
65//       :                   :  |  number of octets given by header length
66//       :                   :  |
67//       :                   :  v
68//       +-------------------+
69//       |   IPv4 prefix     |  ^
70//       :                   :  |  IPv4 prefixes have variable length (see
71//       +-------------------+  |  below).  The number of prefixes is
72//       |   IPv4 prefix     |  |  determined by the packet length.
73//       :                   :  |
74//       +-------------------+  |
75//       :                   :  |
76//       :                   :  v
77//
78//
79//  IPv4 prefix layout comes in five variants, depending on the first
80//  octet:
81//
82//       .-------------------.
83//       |       0x00        |     single octet, corresponds to 0.0.0.0/0
84//       `-------------------'
85//
86//       .-------------------.
87//       |    0x01 to 0x08   |     two octets, prefix lengths up to /8.
88//       +-------------------+
89//       |   MSB of network  |
90//       `-------------------'
91//
92//       .-------------------.
93//       |    0x09 to 0x10   |     three octets, prefix lengths up to /16.
94//       +-------------------+
95//       |   MSB of network  |
96//       +-------------------+
97//       |   next octet      |
98//       `-------------------'
99//
100//       .-------------------.
101//       |    0x11 to 0x18   |     four octets, prefix lengths up to /24.
102//       +-------------------+
103//       |   MSB of network  |
104//       +-------------------+
105//       |   next octet      |
106//       +-------------------+
107//       |   next octet      |
108//       `-------------------'
109//
110//       .-------------------.
111//       |    0x19 to 0x20   |     five octets, prefix lengths up to /32.
112//       +-------------------+
113//       |   MSB of network  |
114//       +-------------------+
115//       |   next octet      |
116//       +-------------------+
117//       |   next octet      |
118//       +-------------------+
119//       |   LSB of network  |
120//       `-------------------'
121//
122///////////////////////////////////////////////////////////////////////////////
123using namespace std;
124using namespace boost::spirit;
125using namespace phoenix;
126
127struct ipv4_prefix_data
128{
129    char prefix_len, n0, n1, n2, n3;
130
131    ipv4_prefix_data()
132        : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}
133};
134
135struct ipv4_data
136{
137    char packet_len, header_len;
138    std::string header;
139    std::vector<ipv4_prefix_data> prefixes;
140
141    ipv4_data()
142        : packet_len(0),header_len(0){}
143
144};
145
146struct ipv4 : public grammar<ipv4>
147{
148    template <typename ScannerT>
149    struct definition
150    {
151        definition(ipv4 const& self)
152        {
153            packet =
154                '\xff'
155                >> anychar_p[var(self.data.packet_len) = arg1]
156                >> payload
157            ;
158
159            payload =
160                anychar_p[var(self.data.header_len) = arg1]
161                >>  for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i))
162                    [
163                        anychar_p[var(self.data.header) += arg1]
164                    ]
165                >> *ipv4_prefix
166             ;
167
168            ipv4_prefix =
169                anychar_p
170                [
171                    var(temp.prefix_len) = arg1,
172                    var(temp.n0) = 0,
173                    var(temp.n1) = 0,
174                    var(temp.n2) = 0,
175                    var(temp.n3) = 0
176                ]
177
178                >>  if_p(var(temp.prefix_len) > 0x00)
179                    [
180                        anychar_p[var(temp.n0) = arg1]
181                        >>  if_p(var(temp.prefix_len) > 0x08)
182                            [
183                                anychar_p[var(temp.n1) = arg1]
184                                >>  if_p(var(temp.prefix_len) > 0x10)
185                                    [
186                                        anychar_p[var(temp.n2) = arg1]
187                                        >>  if_p(var(temp.prefix_len) > 0x18)
188                                            [
189                                                anychar_p[var(temp.n3) = arg1]
190                                            ]
191                                    ]
192                            ]
193                    ]
194                    [
195                        push_back_a(self.data.prefixes, temp)
196                    ]
197            ;
198        }
199
200        int i;
201        ipv4_prefix_data temp;
202        rule<ScannerT> packet, payload, ipv4_prefix;
203        rule<ScannerT> const&
204        start() const { return packet; }
205    };
206
207    ipv4(ipv4_data& data)
208        : data(data) {}
209
210    ipv4_data& data;
211};
212
213////////////////////////////////////////////////////////////////////////////
214//
215//  Main program
216//
217////////////////////////////////////////////////////////////////////////////
218int
219as_byte(char n)
220{
221    if (n < 0)
222        return n + 256;
223    return n;
224}
225
226void
227print_prefix(ipv4_prefix_data const& prefix)
228{
229    cout << "prefix length = " << as_byte(prefix.prefix_len) << endl;
230    cout << "n0 = " << as_byte(prefix.n0) << endl;
231    cout << "n1 = " << as_byte(prefix.n1) << endl;
232    cout << "n2 = " << as_byte(prefix.n2) << endl;
233    cout << "n3 = " << as_byte(prefix.n3) << endl;
234}
235
236void
237parse_ipv4(char const* str, unsigned len)
238{
239    ipv4_data data;
240    ipv4 g(data);
241    parse_info<> info = parse(str, str+len, g);
242
243    if (info.full)
244    {
245        cout << "-------------------------\n";
246        cout << "Parsing succeeded\n";
247
248        cout << "packet length = " << as_byte(data.packet_len) << endl;
249        cout << "header length = " << as_byte(data.header_len) << endl;
250        cout << "header = " << data.header << endl;
251
252        for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix);
253        cout << "-------------------------\n";
254    }
255    else
256    {
257        cout << "Parsing failed\n";
258        cout << "stopped at:";
259        for (char const* s = info.stop; s != str+len; ++s)
260            cout << static_cast<int>(*s) << endl;
261    }
262}
263
264// Test inputs:
265
266// The string in the header is "empty", the prefix list is empty.
267char const i1[8] =
268{
269    0xff,0x08,0x05,
270    'e','m','p','t','y'
271};
272
273// The string in the header is "default route", the prefix list
274// has just one element, 0.0.0.0/0.
275char const i2[17] =
276{
277    0xff,0x11,0x0d,
278    'd','e','f','a','u','l','t',' ',
279    'r','o','u','t','e',
280    0x00
281};
282
283// The string in the header is "private address space", the prefix list
284// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
285char const i3[32] =
286{
287    0xff,0x20,0x15,
288    'p','r','i','v','a','t','e',' ',
289    'a','d','d','r','e','s','s',' ',
290    's','p','a','c','e',
291    0x08,0x0a,
292    0x0c,0xac,0x10,
293    0x10,0xc0,0xa8
294};
295
296int
297main()
298{
299    parse_ipv4(i1, sizeof(i1));
300    parse_ipv4(i2, sizeof(i2));
301    parse_ipv4(i3, sizeof(i3));
302    return 0;
303}
304
Note: See TracBrowser for help on using the repository browser.