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).
263 \fixme Make all data mutators protected
267 class Packet : boost::noncopyable
272 typedef boost::uint8_t byte; //!< single byte datatype
276 ///\name Implementation
278 // These types are implementation details. They are however
279 // needed to provide the correct typedefs for the user
280 // interface. Hiding these classes would incur a huge
281 // additional indirection overhead.
283 typedef std::vector<byte> raw_container;
284 typedef boost::shared_ptr<Packet> interpreter_list_ptr;
285 typedef std::list<senf::Packet::interpreter_list_ptr> interpreter_list;
286 typedef unsigned refcount_t;
292 ///////////////////////////////////////////////////////////////////////////
296 /** \brief smart pointer template for all Packet classes
298 This struct is just a template typedef. It defines the
299 smart pointer used for all Packet classes.
301 template <class T> struct ptr_t { typedef boost::intrusive_ptr<T> ptr; };
303 /** \brief smart pointer to the Packet facades
305 Every derived class \e must redeclare this member for it's
308 typedef ptr_t<DerivedClass>::ptr ptr
311 typedef ptr_t<Packet>::ptr ptr;
312 typedef raw_container::iterator iterator; //!< raw data iterator
313 typedef raw_container::size_type size_type;
314 typedef raw_container::difference_type difference_type;
318 // ////////////////////////////////////////////////////////////////////////
320 ///\name Creating packets
323 /** \brief create new Packet
325 This method is used to create a new Packet. All Packet
326 instances are created via this method, they are \e never
327 created directly from the Packet derived class.
329 \param OtherPacket Type of Packet to create, a Packet
331 \param b begin iterator of byte range to create the Packet
333 \param e corresponding end iterator
334 \return smart pointer to new packet
335 \throws TruncatedPacketException The data cannot be parsed
336 securely (the data might be truncated or just
339 template <class OtherPacket, class InputIterator>
340 static typename ptr_t<OtherPacket>::ptr create(InputIterator b, InputIterator e);
342 template <class OtherPacket>
343 static typename ptr_t<OtherPacket>::ptr create();
345 template <class OuterPacket>
346 static typename ptr_t<OuterPacket>::ptr create(Packet::ptr payload);
350 ///\name Interpreter chain
353 /** \brief get next packet from the interpreter chain
354 \return smart pointer to next packet or 0 if last packet */
356 /** \brief get previous packet from the interpreter chain
357 \return smart pointer to previous packet or 0 if last packet */
359 /** \brief first packet of the interpreter chain
360 \return smart pointer to first packet */
362 /** \brief get last packet of the interpreter chain
363 \return smart pointer to last packet */
366 /** \brief first packet of given type after the current packet
367 \return smart pointer to first following packet of type \a
368 OtherPacket or 0, if no such packet exists */
369 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_next() const;
370 /** \brief first packet of given type before the current packet
371 \return smart pointer to first preceding packet of type \a
372 OtherPacket or 0, if no such packet exists */
373 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_prev() const;
375 /** \brief first packet of given type after the current packet
376 \return smart pointer to first following packet of type \a
377 OtherPacket. \e Assert's, that a packet of this type exists */
378 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_next() const;
379 /** \brief first packet of given type before the current packet
380 \return smart pointer to first preceding packet of type \a
381 OtherPacket. \e Assert's, that a packet of this type exists */
382 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_prev() const;
384 /** \brief check, whether the packet is of the given type
385 \return true, if packet is of type \a OtherPacket, false
387 template <class OtherPacket> bool is() const;
388 /** \brief cast packet pointer to the given type
389 \return a properly cast smart pointer if packet is of type
390 \a OtherPacket. Otherwise return 0 */
391 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr as();
393 /** \brief replace current packet interpreter
395 This method will \e replace the current packet facade in
396 the interpreter list with a new interpreter given by \a
399 \attention This invalidates the packet instance \e
400 this. You must ensure, not to use the Packet instance any
401 further after this call
403 \return smart pointer to a \e new packet facade
404 \throws TruncatedPacketException there is not enough data
405 to safely interpret the packet as the given type. The
406 original packet is \e not invalidated
408 template <class OtherPacket>
409 typename ptr_t<OtherPacket>::ptr reinterpret();
413 ///\name Raw packet data
416 /** \brief begin iterator of raw packet data
418 This iterator allows access to the raw data interpreted by
419 the packet facade. This \e includes any header possibly
420 interpreted by the derived packet instance. To access the
421 payload of the packet, use next()->begin().
423 \return random access iterator to the begin of the raw
425 iterator begin() const;
426 /** \brief past-the-end iterator of raw packet data
428 This iterator allows access to the raw data interpreted by
429 the packet facade. This \e includes any header possibly
430 interpreted by the derived packet instance. To access the
431 payload of the packet, use next()->end().
433 \return random access past-the-end iterator of the raw
435 iterator end() const;
436 /** \brief raw data size of packet
437 \return size of the raw data interpreted by this
438 packet in bytes. This is \e not necessarily the size of
439 the complete packet, use head()->size() for this. */
442 // Modifying the raw packet data
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 calculate checksums and
532 This method is automatically 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"
628 // c-file-style: "senf"
629 // indent-tabs-mode: nil
630 // ispell-local-dictionary: "american"