From: g0dil Date: Wed, 23 Jan 2008 14:36:55 +0000 (+0000) Subject: HowTos/NewPacket: Some updates X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=409385419f05893d7d226931796124a70c2f6c63;p=senf.git HowTos/NewPacket: Some updates doclib: Find optimal graph rotation for large dot graphs doclib: Break long pathnames in dot graphs doclib: Use new DOT_GRAPH_MAX_NODES parameter in Doxyfile.global doclib: Break lines in (textual) class inheritance lists git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@634 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/HowTos/NewPacket/Mainpage.dox b/HowTos/NewPacket/Mainpage.dox index 482c84e..77c649b 100644 --- a/HowTos/NewPacket/Mainpage.dox +++ b/HowTos/NewPacket/Mainpage.dox @@ -46,7 +46,7 @@ both be omitted. Another information we take from the RFC is, that the \a Protocol \a Type is used to define the - type of payload which directly follows the GRE header. This value is the ETHERTYPE value. To allow the packet library to automatically parse the GRE payload data, we need to tell the packet library which ETHERTYPE represents which packet type. This association already exists in form of the @@ -57,7 +57,7 @@ \li The GRE packet header is a dynamically sized header. \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection - \section howto_newpacket_impl Implementing the GRE Parser + \section howto_newpacket_parser Implementing the GRE Parser The next step in creating a new packet type is to implement the parser. The parser is responsible for turning a bunch of bytes into an interpreted header with specific fields. The @@ -97,9 +97,13 @@ SENF_PARSER_BITFIELD ( protocolType, 16, unsigned ); \endcode - This is a direct transcript of the field definition above. However, we can optimize this a - little bit: Since the \a protocolType field is aligned on a byte boundary, instead of defining - it as a bitfield, we can define it as a UInt16 field: + This is a direct transcript of the field definition above. There are quite a number of macros + which may be used to define fields. All these macros are documented in '\ref + packetparsermacros'. + + This is a correct \c GREPacket header definition but we can optimize a little bit: Since the \a + protocolType field is aligned on a byte boundary, instead of defining it as a bitfield, we can + define it as a UInt16 field: \code SENF_PARSER_BITFIELD ( checksumPresent, 1, bool ); @@ -109,27 +113,28 @@ SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser ); \endcode - There are quite a number of such \c SENF_PARSER_ macros. They are all listed in \ref - packetparsermacros. The basic field types (like senf::UInt16Parser) are listed in \ref parseint. - - What happens in the above macros? Most of the macros define an accessor for a specific field: \a - checksumPresent() or \a protocolType(). They also manage a current Offset. This value - is advanced according to the field size whenever a new field is defined (and since this parser - is defined as a dynamically sized parser, this offset is not a constant, it is an expression - which calculates the offset of a field depending on the preceding data). + Whereas \ref SENF_PARSER_BITFIELD can define only bit-fields, \ref SENF_PARSER_FIELD can define + almost arbitrary field types. The type is specified by passing the name of another parser to + \ref SENF_PARSER_FIELD. It is important to understand, that the accessors do \e not return the parsed field value. They return another \e parser which is used to further interpret the value. This is the inherent recursive nature of the SENF packet parsers. This allows to define wildly complex header formats if needed. Of course, at some point we need the real value. This is, what the so called value parsers do: They interpret some bytes or bits and return the value of that field - (not a parser). Examples are the bitfield parsers returnd by the accessors generated by + (not a parser). Examples are the bitfield parsers returned by the accessors generated by SENF_PARSER_BITFIELD (like senf::UIntFieldParser) or the senf::UInt16Parser. + What happens in the above macros? Most of the macros define an accessor for a specific field: \a + checksumPresent() or \a protocolType(). They also manage a current Offset. This value + is advanced according to the field size whenever a new field is defined (and since this parser + is defined as a dynamically sized parser, this offset is not a constant, it is an expression + which calculates the offset of a field depending on the preceding data). + We now come to the optional fields. Since there are two fields which need to be disabled/enabled - together, we first need to define an additional sub-parser which parses those two fields. After - this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser as an optional - parser to the GRE header. + together, we first need to define an additional sub-parser which combines those two + fields. After this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser + as an optional parser to the GRE header. \code struct GREParser_OptFields : public senf::PacketParser @@ -159,32 +164,35 @@ (GREParser_OptFields) ); \endcode - How does this work? For a variant parser, two things need to be specified: A selector and a list - of variant parsers. The selector is another parser field which is used to decide, which variant - to choose. In this simple case, the field must be an unsigned integer (more precisely a value + For a variant parser, two things need to be specified: A selector and a list of variant + parsers. The selector is another parser field which is used to decide, which variant to + choose. In this simple case, the field must be an unsigned integer (more precisely a value parser which returns a value which is implicitly convertible to \c unsigned). This value is used as index into the list of variant types. So in our case, 0 is associated with - senf::VoidPacketParser whereas 1 is associated with \c GREParser_OptFields. + senf::VoidPacketParser whereas 1 is associated with \c + GREParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a + Variant to denote cases in which the variant parser should not parse anything) This parser will work, it is however not very safe and not very usable. If \a p is a GREParser instance, than we access the fields via: \code - p.checksumPresent() - p.version() - p.protocolType() - p.optionalFields().get<1>().checksum() + p.checksumPresent() = true; + p.version() = 4u; + p.protocolType() = 0x86dd; + p.optionalFields().get<1>().checksum() = 12345u; \endcode There are two problems here: - \li accessing the checksum field is not straight forward + \li accessing the checksum field is quite unwieldy \li changing the checksumPresent() value will break the parser The reason for the second problem lies in the fact, that the variant parser needs to be informed whenever the selector (here \a checksumPresent) is changed since the variant parser must ensure, that the header data stays consistent. In this example, whenever the checksumPresent field is enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes, - when the checksumPresent field is disabled. We therefore make the checksumPresent field - read-only: + when the checksumPresent field is disabled. + + To fix this, we make the checksumPresent field read-only: \code SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool ); @@ -199,18 +207,21 @@ The first statements switches to the first variant and therefore in this case disables the checksum field. The second statement will switch to the second variant and enable the checksum - field. This again is not very usable. So we complete the parser by providing simple additional - members which access the fields in a more readable way. While doing this, we also mark the - variant as a private field so it is not directly accessible any more. Here the final \c - GREParser + field. + + This again is not very usable. So we complete the parser by providing simple additional members + which wrap these complicated calls. While doing this, we also mark the variant as a private + field so it is not directly accessible any more (since we now have the additional helpers which + are used to access the variant, we don't want anyone to mess around with it directly). Here the + final \c GREParser \code struct GREParser_OptFields : public senf::PacketParser { # include SENF_FIXED_PARSER() - SENF_PARSER_FIELD ( checksum, senf::UInt16Parser ); - SENF_PARSER_SKIP ( 2 ); + SENF_PARSER_FIELD ( checksum, senf::UInt16Parser ); + SENF_PARSER_SKIP ( 2 ); SENF_PARSER_FINALIZE(GREParser_OptFields); }; @@ -239,6 +250,20 @@ SENF_PARSER_FINALIZE(GREParser); }; \endcode + + Above code has one other twist we need to discuss: the \a checksum_t typedef. This is added as a + convenience to the user of this parser. The \c SENF_PARSER_* macros which define a field all + define some additional symbols providing further information about the field. Of these + additional symbols, the most important is field_t, which is the (parser) + type returned by the field. This helps to work with a parser in more complex situations + (e.g. when using collection parsers) since it allows to access the parser type without exact + knowledge of this type (which may become quite complex if templates are involved) as long as the + field name is known. Since we provide an accessor for the \a checksum field, we also provide the + \a checksum_t typedef for this accessor. + + The \c GREParser is now simple and safe to use. The only responsibility of the user now is to + only access \a checksum() if the \a checksumPresent() field is set. Otherwise, the behavior is + undefined (in debug builds, the parser will terminate the application with an assert). */ diff --git a/doclib/Doxyfile.global b/doclib/Doxyfile.global index 3184f92..2674a00 100644 --- a/doclib/Doxyfile.global +++ b/doclib/Doxyfile.global @@ -73,9 +73,8 @@ TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES GROUP_GRAPHS = NO -MAX_DOT_GRAPH_WIDTH = 800 -MAX_DOT_GRAPH_HEIGHT = 1600 MAX_DOT_GRAPH_DEPTH = 3 +DOT_GRAPH_MAX_NODES = 10 DOT_MULTI_TARGETS = YES DOT_CLEANUP = NO DOT_PATH = "$(TOPDIR)/doclib" @@ -85,4 +84,4 @@ DOT_PATH = "$(TOPDIR)/doclib" # Local Variables: # mode: indented-text # indent-tabs-mode: nil -# End: \ No newline at end of file +# End: diff --git a/doclib/dot b/doclib/dot index fca62c8..a0efac5 100755 --- a/doclib/dot +++ b/doclib/dot @@ -2,4 +2,37 @@ topdir="`dirname "$0"`"; topdir="`cd "$topdir/.."; pwd`" "$topdir/doclib/dot-munge.pl" "$1" -exec dot "$@" + +case "$2" in + -Tpng:gd) + first="$1"; shift; shift + set -- "$first" "-Tpng" "$@" + ;; + *) +esac + +set -e + +dot "$@" +if [ -r "$4" ]; then + size="`pngtopnm "$4" | sed -n -e '2p'`" + width_a="${size% *}" + height_a="${size#* }" + if [ $width_a -gt 800 ]; then + for file in "${1%.dot}".*; do + cp "$file" "$file.a" + done + sed -e 's/rankdir=LR/rankdir=TB/' -e t -e 's/rankdir=TB/rankdir=LR/' "$1.a" > "$1" + dot "$@" + size="`pngtopnm "$4" | sed -n -e '2p'`" + width_b="${size% *}" + height_b="${size#* }" + if [ $width_a -lt $width_b ]; then + for file in "${1%.dot}".*.a; do + mv "$file" "${file%.a}" + done + else + rm "${1%.dot}".*.a + fi + fi +fi diff --git a/doclib/dot-munge.pl b/doclib/dot-munge.pl index 7cc72ca..dd0d8f9 100755 --- a/doclib/dot-munge.pl +++ b/doclib/dot-munge.pl @@ -1,19 +1,17 @@ #!/usr/bin/perl -i -n -# Reduce font size +# Reduce fontsize and change font s/fontsize=10/fontsize=8/g; -##s/fontname="FreeSans.ttf"/fontname="Bitstream Vera Sans Mono"/g; s/fontname="FreeSans.ttf"/fontname="Verdana"/g; -##s/fontname="FreeSans.ttf"/fontname="Lucida Sans Typewriter"/g; -# Wrap long labels (templates) +# Wrap long labels (templates and pathnames) if (/label=\"([^"]*)\"/) { #"])){ # To make emacs happy ... $pre=$`; $post=$'; #'; # To make emacs happy ... $label=$1; - # Break at each komma - $label=~s/,/,\\r\\ \\ \\ \\ \\ \\ \\ \\ /g; + # Break at each komma or / + $label=~s{[,/]}{$&\\r\\ \\ \\ \\ \\ \\ \\ \\ }g; # If more than one '<' is in the label, break after each '<' if (($label=~tr/1) { @@ -22,10 +20,17 @@ if (/label=\"([^"]*)\"/) { #"])){ # To make ema # If at least one break is in there ... if ($label=~/\\r/) { + # If it's a pathname, make all but the last line flush left + # Otherwise only make first line flush left + if ($label=~m{/}) { + $label=~s/\\r(\\ )*/\\ \\ \\ \\ \\ \\ \\ \\ \\l/g; + # Re-add blanks before last line + $label=~s/^.*\\l/$&\\ \\ \\ \\ \\ \\ \\ \\ /; + } else { + $label=~s/\\r/\\ \\ \\ \\ \\ \\ \\ \\ \\l/; + } # Make last line flush right $label.="\\r"; - # and first line flush left - $label=~s/\\r/\\ \\ \\ \\ \\ \\ \\ \\ \\l/; } print "${pre}label=\"${label}\"${post}"; } else { diff --git a/doclib/html-munge.xsl b/doclib/html-munge.xsl index 6bc7038..3229bf7 100644 --- a/doclib/html-munge.xsl +++ b/doclib/html-munge.xsl @@ -9,7 +9,7 @@ - + @@ -33,15 +33,12 @@ - - - - - + + - + - + @@ -55,6 +52,43 @@ + + + + + + + commalist + + + + + +
+
+ + + + + + + +
+ +
+ + + + ,
+ +
+ + + + + + + xref-bug @@ -157,6 +191,14 @@ + + + + + + + + diff --git a/doclib/senf.css b/doclib/senf.css index ba3e05f..368d233 100644 --- a/doclib/senf.css +++ b/doclib/senf.css @@ -480,7 +480,13 @@ div.toc li { div.toc div { margin: 10px 0px; font-weight: bold; - font-size: 120% + font-size: 120%; +} + +p.commalist { + white-space: nowrap; + margin-left: 4em; + text-indent: -4em; } /* diff --git a/senf.dict b/senf.dict index 181aec0..acecafb 100644 --- a/senf.dict +++ b/senf.dict @@ -34,6 +34,7 @@ cc cd cerr cfi +checksumPresent CIDR ClientSocketHandle CloneSource @@ -58,12 +59,15 @@ defaultInit defgroup deque dil +disableChecksum dl DNS dontinclude +dox DSMCCSection dt ElementParser +enableChecksum endcode enum eof @@ -109,6 +113,7 @@ FroblizerArea GlobalScope GRE GREPacket +GREParser hangup HangupException hh @@ -121,7 +126,7 @@ href htm html http -IANA +iana IdleEvent ietf ih @@ -186,6 +191,8 @@ onRequest onThrottle onUnthrottle Ooops +OptFields +optionalFields org os ostream @@ -242,6 +249,7 @@ prev PriorityJoin protocolbundle protocolbundles +protocolType QueueingDiscipline queueSize RateFilter @@ -317,6 +325,7 @@ udpReader udpWriter UInt UIntField +UIntFieldParser Unhandled unicast unthrottle