4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 // Stefan Bund <stefan.bund@fokus.fraunhofer.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // TODO: Implement assign() method akin to reinterpret(). However,
24 // instead of using the data already present, assign() will replace
25 // the date of the current packet with the given Packet.
27 // TODO: Implement wrapping-constructor. Somehow we want to have a
28 // constructor, which allows creating a chain of packet interpreters
29 // with as little overhead as possible.
31 // TODO: Document the additional concrete Packet facade requirements
32 // explicitly and not only within the Parser requirements (check(),
33 // bytes() and min_bytes() members ...)
35 // TODO: Implement special container replacing vector which manages
36 // some headroom to allow efficient insertion of elements at the
37 // beginning. This really is just another type of deque
41 \brief Main packet interface
48 #include <boost/utility.hpp> // for boost::noncopyable
49 #include <boost/cstdint.hpp>
50 #include <boost/shared_ptr.hpp>
51 #include <boost/intrusive_ptr.hpp>
57 // ////////////////////////////hh.p////////////////////////////////////////
61 namespace impl { template <class OtherPacket> class PkReg_EntryImpl; }
62 namespace impl { class PacketImpl; }
64 /** \brief Basic interface to all packet facades
66 \section packet_overview Overview
68 This class is the base class of all Packets. It implements the
69 generic Packet interface and provides the packet management
70 framework. senf::Packet manages the necessary memory
71 resources and controlls the chain of packet interpreters.
73 The Packet user always interfaces with the pkf via a Packet
74 derived class. This is the only external entity ever held by a
75 library user. The interface is implemented using a reference
76 counted smart pointer, so resource management is quasi
79 \image html "../../structure.png" Overview
81 Internally, every Packet references a PacketImpl instance which
82 manages the raw packet data and the interpreter list. This raw
83 data is interpreted by the concrete Packet derived class
84 according to the definition of that derived class's packet
85 type (i.e. EthernetPacket or UDPPacket).
87 Packet provides several interfaces:
89 - Creation of Packet instances: create()
91 - Access to the chain of interpreters: next(), prev(), head(),
92 last(), find_next(), find_prev(), get_next(), get_prev(),
93 is(), as() and reinterpret()
95 - Access to the raw packet data: begin(), end(), size(),
98 - An interface to the derived class: v_nextInterpreter(),
99 v_finalize(), registerInterpreter()
102 \section packet_der Implementing new Packet facades
104 To implement a new Packet facade, publically derive from
105 Packet. You need to implement the following minimal interface:
107 - You need to provide a new #ptr typedef
109 - You have to implement v_nextInterpreter() and v_finalize()
111 - The constructor should be private
113 - You must make Packet a \c friend of the new Packet facade
115 - You must implement a static check() method which validates
116 a byte region as your new Packet
120 : public senf::Packet
123 typedef ptr_t<ExamplePacket>::ptr ptr;
125 static bool check(Packet::iterator begin, Packet::iterator end)
127 // Validate, that the region [begin,end) can be
128 // interpreted as an ExamplePacket without risking
129 // memory access violations.
134 ExamplePacket(Arg arg [, other args ... ])
138 virtual void v_nextInterpreter() const
140 // NextPacketType and header_length of course
141 // depend on the packet type
142 registerInterpreter<NextPacketType>(begin()+header_length, end());
145 virtual void v_finalize()
147 // calculate checksum etc
150 friend class senf::Packet;
154 Please do not implement the methods inline to not clutter up
155 the header file. This is done here in the example to simplify
156 it. If a class is to be registered in some
157 senf:PacketRegistry, it must not take any additional
158 constructor parameters.
160 After having implemented the bare framework, the most comman
161 way to implement access to the packets specific data is to use
162 the parser framework by additionally inheriting a
163 corresponding parser. This also automatically implements the
164 check() method, which is provided by the Parser.
166 In the following example we only show the differences from the
171 : public senf::Packet,
172 public Parse_Example<senf::Packet::iterator,
176 // check does not need to be implemented here, it is
177 // inherited from the parser
180 template <class InputIterator>
181 ExamplePacket(InputIterator begin, InputIterator end)
182 : senf::Packet(begin,end)
187 See the senf::ParserBase Documentation for how to
188 implement Parse_Example.
190 The implementation of v_nextInterpreter most of the time
191 relies on some packet registry. This is simplified using the
192 senf::PacketRegistryMixin class as follows. Again, we
193 only show the differences from the preceding Example:
196 struct ExampleRegistry {
197 type boost::uint16_t key_t;
201 : public senf::Packet,
202 public Parse_Example<senf::Packet::iterator,
204 public senf::PacketRegistryMixin<ExampleRegistry,
207 using senf::Packet::registerInterpreter;
208 using senf::PacketRegsitryMixin<ExampleRegistry,ExamplePacket>::registerInterpreter;
210 virtual void v_nextInterpreter() const
212 // nextType() is defined in Parse_Example and
213 // returns the key in the ExampleRegistry of the
215 registerInterpreter(nextType(),begin()+header_length, end());
220 For further details on the packet registry, see
221 senf::PacketRegistry.
223 \section packet_impl Implementation details
225 The Packet interface is implemented to minimize overhead as
226 far as possible without getting to complex. One area for
227 improvement ist the container class used to hold the raw
228 data. This currently is an \a std::vector. This could be
229 imporved by either allocating some headroom/tailroom in the
230 vector and using this when inserting data at the beginning or
231 end. Alternatively, a new container class (like the
232 senf::deque_list) could be used to support zero-copy
235 At the moment, we leave the implementation at
236 std::vector. This container is very simple and especially it
237 can directly be sent out using the operating system since a \a
238 vector stores data at contiguous memory locations. An \a
239 std::deque could be used with \a writev(), however since we
240 have no access to the implementation details of the \a deque,
241 we cannot construct the \a writev() data structures.
243 The interpreter list managed by Packet is lazy, meaning packet
244 interpreter facades are added only when requestd by next(),
245 last() or find_next(). v_nextInterpreter() is called if
246 necessary by these methods to complete the interpreter chain.
248 To implement the automatic memory management, every Packet
249 facade is reference counted. Additionally, the number of
250 (indirect) references to PacketImpl is counted. This allows to
251 manage the PacketImpl instance automatically. To make this
252 work, it is necessary to ensure throughout the Packet code,
253 that the reference count of a Packet is not accidentally
254 decremented to zero. Also, the internal pointers from the
255 interpreter list to the Packet facades must not be
256 counted. They are therefore implemented differently (
257 boost::shared_ptr vs. boost::intrusive_ptr). The choice of
258 boost::intrusive_ptr for the externaly visible smart pointer
259 for all Packet facades is taken to reduce the overhead (an
260 intrusive_ptr is only the size of an ordinary pointer, a
261 smart_ptr has the size of two pointers).
265 class Packet : boost::noncopyable
270 typedef boost::uint8_t byte; //!< single byte datatype
274 ///\name Implementation
276 // These types are implementation details. They are however
277 // needed to provide the correct typedefs for the user
278 // interface. Hiding these classes would incur a huge
279 // additional indirection overhead.
281 typedef std::vector<byte> raw_container;
282 typedef boost::shared_ptr<Packet> interpreter_list_ptr;
283 typedef std::list<senf::Packet::interpreter_list_ptr> interpreter_list;
284 typedef unsigned refcount_t;
290 ///////////////////////////////////////////////////////////////////////////
294 /** \brief smart pointer template for all Packet classes
296 This struct is just a template typedef. It defines the
297 smart pointer used for all Packet classes.
299 template <class T> struct ptr_t { typedef boost::intrusive_ptr<T> ptr; };
301 /** \brief smart pointer to the Packet facades
303 Every derived class \e must redeclare this member for it's
306 typedef ptr_t<DerivedClass>::ptr ptr
309 typedef ptr_t<Packet>::ptr ptr;
310 typedef raw_container::iterator iterator; //!< raw data iterator
311 typedef raw_container::size_type size_type;
312 typedef raw_container::difference_type difference_type;
316 // ////////////////////////////////////////////////////////////////////////
318 ///\name Creating packets
321 /** \brief create new Packet
323 This method is used to create a new Packet. All Packet
324 instances are created via this method, they are \e never
325 created directly from the Packet derived class.
327 \param OtherPacket Type of Packet to create, a Packet
329 \param b begin iterator of byte range to create the Packet
331 \param e corresponding end iterator
332 \return smart pointer to new packet
333 \throws TruncatedPacketException The data cannot be parsed
334 securely (the data might be trunctated or just
337 template <class OtherPacket, class InputIterator>
338 static typename ptr_t<OtherPacket>::ptr create(InputIterator b, InputIterator e);
340 template <class OtherPacket>
341 static typename ptr_t<OtherPacket>::ptr create();
343 template <class OuterPacket>
344 static typename ptr_t<OuterPacket>::ptr create(Packet::ptr payload);
348 ///\name Interpreter chain
351 /** \brief get next packet from the interpreter chain
352 \return smart pointer to next packet or 0 if last packet */
354 /** \brief get previous packet from the interpreter chain
355 \return smart pointer to previous packet or 0 if last packet */
357 /** \brief first packet of the interpreter chain
358 \return smart pointer to first packet */
360 /** \brief get last packet of the interpreter chain
361 \return smart pointer to last packet */
364 /** \brief first packet of given type after the current packet
365 \return smart pointer to first following packet of type \a
366 OtherPacket or 0, if no such packet exists */
367 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_next() const;
368 /** \brief first packet of given type before the current packet
369 \return smart pointer to first preceding packet of type \a
370 OtherPacket or 0, if no such packet exists */
371 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_prev() const;
373 /** \brief first packet of given type after the current packet
374 \return smart pointer to first following packet of type \a
375 OtherPacket. \e Assert's, that a packet of this type exists */
376 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_next() const;
377 /** \brief first packet of given type before the current packet
378 \return smart pointer to first preceding packet of type \a
379 OtherPacket. \e Assert's, that a packet of this type exists */
380 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_prev() const;
382 /** \brief check, wether the packet is of the given type
383 \return true, if packt is of type \a OtherPacket, false
385 template <class OtherPacket> bool is() const;
386 /** \brief cast packet pointer to the given type
387 \return a properly cast smart pointer if packet is of type
388 \a OtherPacket. Otherwise return 0 */
389 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr as();
391 /** \brief replace current packet interpreter
393 This method will \e replace the current packet facade in
394 the interpreter list with a new interpreter given by \a
397 \attention This invalidates the packet instance \e
398 this</b>. You must ensure, not to use the Packet instance
399 any further after this call
401 \return smart pointer to a \e new packet facade
402 \throws TruncatedPacketException there is not enough data
403 to savely interpret the packet as the given type. The
404 original packet is \e not invalidated
406 template <class OtherPacket>
407 typename ptr_t<OtherPacket>::ptr reinterpret();
411 ///\name Raw packet data
414 /** \brief begin interator of raw packet data
416 This iterator allows access to the raw data interpreted by
417 the packet facade. This \e includes any header possibly
418 interpreted by the derived packet instance. To access the
419 payload of the packet, use next()->begin().
421 \return random access iterator to the begin of the raw
423 iterator begin() const;
424 /** \brief past-the-end iterator of raw packet data
426 This iterator allows access to the raw data interpreted by
427 the packet facade. This \e includes any header possibly
428 interpreted by the derived packet instance. To access the
429 payload of the packet, use next()->end().
431 \return random access past-the-end iterator of the raw
433 iterator end() const;
434 /** \brief raw data size of packet
435 \return size of the raw data interpreted by this
436 packet in bytes. This is \e not necessarily the size of
437 the complete packet, use head()->size() for this. */
440 // Modifying the raw packet data
442 // FIXME: Make all data mutators protected
444 typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence;
446 /** \brief insert single byte \a v before pos
448 \attention The change will \e not be validated by the
449 derived packet instance. This method is mostly to be used
450 by the derived class implementation and their helper
452 void insert(iterator pos, byte v, Whence whence = AUTO);
453 /** \brief insert \a n copies of byte \a v before pos
455 \attention The change will \e not be validated by the
456 derived packet instance. This method is mostly to be used
457 by the derived class implementation and their helper
459 void insert(iterator pos, size_type n, byte v, Whence whence = AUTO);
460 /** \brief insert a copy of the given range before pos
462 \attention The change will \e not be validated by the
463 derived packet instance. This method is mostly to be used
464 by the derived class implementation and their helper
466 template <class InputIterator>
467 void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO);
469 /** \brief erase single byte
471 \attention The change will \e not be validated by the
472 derived packet instance. This method is mostly to be used
473 by the derived class implementation and their helper
475 void erase(iterator pos);
476 /** \brief erase range
478 \attention The change will \e not be validated by the
479 derived packet instance. This method is mostly to be used
480 by the derived class implementation and their helper
482 void erase(iterator first, iterator last);
486 void dump(std::ostream & os) const;
489 ///\name Derived class interface
492 /** \brief create new interpreter facade for an existing packet
494 This constructor is called, when a new interpreter is to
495 be added to the interpreter chain. The constructor is
496 called indirectly from registerInterpreter() or
497 reinterpret() via the derived classes template
500 template <class Operation>
501 Packet(Operation const & arg);
505 /** \brief create next packet interpreter
507 This method is called by next(), last() or find_next() to
508 create any missing interpreters in the interpreter
509 chain. This method must be overridden in the derived class
510 to register the next packet interpreter in the interpreter
511 chain with the packet framework.
513 To register the new interpreter, use
514 registerInterpreter() to create the new Packet
515 instance. The new instance is automatically added to the
516 interpreter chain after the current interpreter.
518 See also senf::PacketRegistryMixin on how to
519 use a Registry to find the next interpreters implementing
522 virtual void v_nextInterpreter() const = 0;
524 /** \brief finalize packet for sending
526 This method is called by the packet framework to let the
527 interpreter facade do some final calculations/packet
528 cleanup before the packet is sent out or digested in some
529 other way. This is the place to calcaulate checksums and
532 This method is autmatically called for all interpreters on
533 the interpreter chain.
535 virtual void v_finalize() = 0;
537 virtual void v_dump(std::ostream & os) const = 0;
540 /** \brief add interpreter to interpreter chain
542 This method is used by v_nextInterpreter() in the derived
543 classes to add a new interpreter to the interpreter
544 chain. This method will call \c OtherPacket's constructor
545 with the correct arguments and insert the new interpreter
546 into the interpreter list. This method is used, if no
547 further arguments are to be passed to the \c OtherPacket
548 constructor. If additional arguments are necessary, just
549 add them after \c end. The compiler will then choose the
550 correct overload to use.
552 template <class OtherPacket>
553 typename ptr_t<OtherPacket>::ptr registerInterpreter(
554 raw_container::iterator begin, raw_container::iterator end) const;
555 template <class OtherPacket, class A0>
556 typename ptr_t<OtherPacket>::ptr registerInterpreter(
557 raw_container::iterator begin, raw_container::iterator end,
558 A0 const & a0) const;
560 # define BOOST_PP_ITERATION_PARAMS_1 (4, (2, 9, "Packets/Packet.mpp", 3))
561 # include BOOST_PP_ITERATE()
567 ///\name Implementation
570 void add_ref() const;
574 struct PacketOp_register;
575 friend class PacketOp_register;
576 void i_registerInterpreter(Packet * p) const;
578 struct PacketOp_replace;
579 friend class PacketOp_replace;
580 void i_replaceInterpreter(Packet * p);
583 friend class PacketOp_set;
584 void i_setInterpreter(impl::PacketImpl * i);
587 friend class impl::PacketImpl;
588 template <class OtherPacket> friend class impl::PkReg_EntryImpl;
590 impl::PacketImpl* impl_;
593 interpreter_list::iterator self_;
594 mutable bool parsed_;
595 mutable refcount_t refcount_;
600 /** \brief dump packet to stream
602 // std::ostream & operator<<(std::ostream & os, Packet const & packet);
604 /** \brief smart pointer handling
606 void intrusive_ptr_add_ref(Packet const *);
607 /** \brief smart pointer handling
609 void intrusive_ptr_release(Packet *);
611 struct TruncatedPacketException : public std::exception
612 { virtual char const * what() const throw() { return "truncated packet"; } };
616 // ////////////////////////////hh.e////////////////////////////////////////
617 #include "Packet.cci"
619 #include "Packet.cti"
621 #include "Packet.mpp"
627 // c-file-style: "senf"