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.
24 \brief Main packet interface
26 \todo Implement assign() method akin to reinterpret(). However,
27 instead of using the data already present, assign() will replace
28 the date of the current packet with the given Packet.
30 \todo Implement wrapping-constructor. Somehow we want to have a
31 constructor, which allows creating a chain of packet interpreters
32 with as little overhead as possible.
34 \todo Document the additional concrete Packet facade requirements
35 explicitly and not only within the Parser requirements (check(),
36 bytes() and min_bytes() members ...)
38 \todo Implement special container replacing vector which manages
39 some headroom to allow efficient insertion of elements at the
40 beginning. This really is just another type of dequeue
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 controls 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 classes 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 common
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 is the container class used to hold the raw
228 data. This currently is an \a std::vector. This could be
229 improved 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 requested 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 externally 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 truncated 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, whether the packet is of the given type
383 \return true, if packet 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. You must ensure, not to use the Packet instance any
399 further after this call
401 \return smart pointer to a \e new packet facade
402 \throws TruncatedPacketException there is not enough data
403 to safely 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 iterator 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 typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence;
444 /** \brief insert single byte \a v before pos
446 \attention The change will \e not be validated by the
447 derived packet instance. This method is mostly to be used
448 by the derived class implementation and their helper
450 void insert(iterator pos, byte v, Whence whence = AUTO);
451 /** \brief insert \a n copies of byte \a v before pos
453 \attention The change will \e not be validated by the
454 derived packet instance. This method is mostly to be used
455 by the derived class implementation and their helper
457 void insert(iterator pos, size_type n, byte v, Whence whence = AUTO);
458 /** \brief insert a copy of the given range before pos
460 \attention The change will \e not be validated by the
461 derived packet instance. This method is mostly to be used
462 by the derived class implementation and their helper
464 template <class InputIterator>
465 void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO);
467 /** \brief erase single byte
469 \attention The change will \e not be validated by the
470 derived packet instance. This method is mostly to be used
471 by the derived class implementation and their helper
473 void erase(iterator pos);
474 /** \brief erase range
476 \attention The change will \e not be validated by the
477 derived packet instance. This method is mostly to be used
478 by the derived class implementation and their helper
480 void erase(iterator first, iterator last);
484 void dump(std::ostream & os) const;
487 ///\name Derived class interface
490 /** \brief create new interpreter facade for an existing packet
492 This constructor is called, when a new interpreter is to
493 be added to the interpreter chain. The constructor is
494 called indirectly from registerInterpreter() or
495 reinterpret() via the derived classes template
498 template <class Operation>
499 Packet(Operation const & arg);
503 /** \brief create next packet interpreter
505 This method is called by next(), last() or find_next() to
506 create any missing interpreters in the interpreter
507 chain. This method must be overridden in the derived class
508 to register the next packet interpreter in the interpreter
509 chain with the packet framework.
511 To register the new interpreter, use
512 registerInterpreter() to create the new Packet
513 instance. The new instance is automatically added to the
514 interpreter chain after the current interpreter.
516 See also senf::PacketRegistryMixin on how to
517 use a Registry to find the next interpreters implementing
520 virtual void v_nextInterpreter() const = 0;
522 /** \brief finalize packet for sending
524 This method is called by the packet framework to let the
525 interpreter facade do some final calculations/packet
526 cleanup before the packet is sent out or digested in some
527 other way. This is the place to calculate checksums and
530 This method is automatically called for all interpreters on
531 the interpreter chain.
533 virtual void v_finalize() = 0;
535 virtual void v_dump(std::ostream & os) const = 0;
538 /** \brief add interpreter to interpreter chain
540 This method is used by v_nextInterpreter() in the derived
541 classes to add a new interpreter to the interpreter
542 chain. This method will call \c OtherPacket's constructor
543 with the correct arguments and insert the new interpreter
544 into the interpreter list. This method is used, if no
545 further arguments are to be passed to the \c OtherPacket
546 constructor. If additional arguments are necessary, just
547 add them after \c end. The compiler will then choose the
548 correct overload to use.
550 template <class OtherPacket>
551 typename ptr_t<OtherPacket>::ptr registerInterpreter(
552 raw_container::iterator begin, raw_container::iterator end) const;
553 template <class OtherPacket, class A0>
554 typename ptr_t<OtherPacket>::ptr registerInterpreter(
555 raw_container::iterator begin, raw_container::iterator end,
556 A0 const & a0) const;
558 # define BOOST_PP_ITERATION_PARAMS_1 (4, (2, 9, "Packets/Packet.mpp", 3))
559 # include BOOST_PP_ITERATE()
565 ///\name Implementation
568 void add_ref() const;
572 struct PacketOp_register;
573 friend class PacketOp_register;
574 void i_registerInterpreter(Packet * p) const;
576 struct PacketOp_replace;
577 friend class PacketOp_replace;
578 void i_replaceInterpreter(Packet * p);
581 friend class PacketOp_set;
582 void i_setInterpreter(impl::PacketImpl * i);
585 friend class impl::PacketImpl;
586 template <class OtherPacket> friend class impl::PkReg_EntryImpl;
588 impl::PacketImpl* impl_;
591 interpreter_list::iterator self_;
592 mutable bool parsed_;
593 mutable refcount_t refcount_;
598 /** \brief dump packet to stream
600 // std::ostream & operator<<(std::ostream & os, Packet const & packet);
602 /** \brief smart pointer handling
604 void intrusive_ptr_add_ref(Packet const *);
605 /** \brief smart pointer handling
607 void intrusive_ptr_release(Packet *);
609 struct TruncatedPacketException : public std::exception
610 { virtual char const * what() const throw() { return "truncated packet"; } };
614 // ////////////////////////////hh.e////////////////////////////////////////
615 #include "Packet.cci"
617 #include "Packet.cti"
619 #include "Packet.mpp"
626 // c-file-style: "senf"
627 // indent-tabs-mode: nil
628 // ispell-local-dictionary: "american"