summaryrefslogtreecommitdiffstats
path: root/doc/README.developer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /doc/README.developer
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/README.developer')
-rw-r--r--doc/README.developer995
1 files changed, 995 insertions, 0 deletions
diff --git a/doc/README.developer b/doc/README.developer
new file mode 100644
index 0000000..6d6ede9
--- /dev/null
+++ b/doc/README.developer
@@ -0,0 +1,995 @@
+This file is a HOWTO for Wireshark developers. It describes general development
+and coding practices for contributing to Wireshark no matter which part of
+Wireshark you want to work on.
+
+To learn how to write a dissector, read this first, then read the file
+README.dissector.
+
+This file is compiled to give in depth information on Wireshark.
+It is by no means all inclusive and complete. Please feel free to discuss on
+the developer mailing list or upload merge requests to gitlab.
+
+0. Prerequisites.
+
+Before starting to develop a new dissector, a "running" Wireshark build
+environment is required - there's no such thing as a standalone "dissector
+build toolkit".
+
+How to setup such an environment is platform dependent; detailed
+information about these steps can be found in the "Developer's Guide"
+(available from: https://www.wireshark.org) and in the INSTALL and
+README.md files of the sources root dir.
+
+0.1. General README files.
+
+You'll find additional information in the following README files:
+
+- doc/README.capture - the capture engine internals
+- doc/README.design - Wireshark software design - incomplete
+- doc/README.developer - this file
+- doc/README.dissector - How to dissect a packet
+- doc/README.display_filter - Display Filter Engine
+- doc/README.idl2wrs - CORBA IDL converter
+- doc/README.regression - regression testing of WS and TS
+- doc/README.stats_tree - a tree statistics counting specific packets
+- doc/README.tapping - "tap" a dissector to get protocol specific events
+- doc/README.vagrant - how to create a development VM using vagrant
+- doc/README.wslua - working with LUA
+- doc/README.xml-output - how to work with the PDML exported output
+- wiretap/README.developer - how to add additional capture file types to
+ Wiretap
+
+0.2. Dissector related README files.
+
+You'll find additional dissector related information in the file
+README.dissector as well as the following README files:
+
+- doc/README.heuristic - what are heuristic dissectors and how to write
+ them
+- doc/README.plugins - how to "pluginize" a dissector
+- doc/README.request_response_tracking - how to track req./resp. times and such
+- doc/README.wmem - how to obtain "memory leak free" memory
+
+0.3 Contributors
+
+James Coe <jammer[AT]cin.net>
+Gilbert Ramirez <gram[AT]alumni.rice.edu>
+Jeff Foster <jfoste[AT]woodward.com>
+Olivier Abad <oabad[AT]cybercable.fr>
+Laurent Deniel <laurent.deniel[AT]free.fr>
+Gerald Combs <gerald[AT]wireshark.org>
+Guy Harris <guy[AT]alum.mit.edu>
+Ulf Lamping <ulf.lamping[AT]web.de>
+
+1. Portability.
+
+Wireshark runs on many platforms, and can be compiled with a number of
+different compilers; here are some rules for writing code that will work
+on multiple platforms.
+
+Building Wireshark requires a compiler that supports C11. This includes
+reasonably recent versions of GCC and clang. Microsoft Visual Studio supports
+C11 from Visual Studio 2019 version 16.8 and later. Support requires an updated
+Universal C Runtime (UCRT) and Windows SDK version to work properly with the
+conforming preprocessor. The minimum SDK version is 10.0.20348.0 (version 2104).
+
+The C11 has some optional parts that are not a requirement to build Wireshark.
+In particular the following optional C11 features must NOT be used:
+ - Variable length arrays
+ - Bounds-checking interfaces (Annex K)
+
+We don't allow them because their value is questionable and requiring them
+would exclude a lot of compilers and runtimes that we wish to support.
+
+Don't initialize global or static variables (variables with static
+storage duration) in their declaration with non-constant values. This is not
+permitted in C. E.g., if "i" is a static or global
+variable, don't declare "i" as
+
+ uint32_t i = somearray[2];
+
+outside a function, or as
+
+ static uint32_t i = somearray[2];
+
+inside or outside a function, declare it as just
+
+ uint32_t i;
+
+or
+
+ static uint32_t i;
+
+and later, in code, initialize it with
+
+ i = somearray[2];
+
+instead. Initializations of variables with automatic storage duration -
+i.e., local variables - with non-constant values is permitted, so,
+within a function
+
+ uint32_t i = somearray[2];
+
+is allowed.
+
+Don't use zero-length arrays as structure members, use flexible array members
+instead.
+
+Don't use "uchar", "u_char", "ushort", "u_short", "uint", "u_int",
+"ulong", "u_long" or "boolean"; they aren't defined on all platforms.
+
+GLib typedefs have historically been used extensively throughout the
+codebase (gchar, guint8, gint16, etc). We are moving towards the fixed
+width integers provided in C since C99. These are defined in <stdint.h>,
+which is included in <wireshark.h>. You should choose stdint types when
+possible, but realise that until we can fully migrate our APIs, in many
+situations the GLib types still make sense.
+
+If you want an 8-bit unsigned quantity, use "uint8_t"; if you want an
+8-bit character value with the 8th bit not interpreted as a sign bit,
+use "unsigned char"; if you want a 16-bit unsigned quantity, use "uint16_t";
+if you want a 32-bit unsigned quantity, use "uint32_t"; and if you want
+an "int-sized" unsigned quantity, use "unsigned"; if you want a boolean,
+use "bool" (defined in <stdbool.h>). You don't need to explicitly include
+these headers; they are included in <wireshark.h>. Use that instead.
+
+To print fixed width integers you must use the macros provided in <inttypes.h>.
+
+ uint32_t var;
+ printf("var = " PRIu32 "\n", var);
+
+Don't use "long" to mean "signed 32-bit integer", and don't use
+"unsigned long" to mean "unsigned 32-bit integer"; "long"s are 64 bits
+long on many platforms. Use "int32_t" for signed 32-bit integers and use
+"uint32_t" for unsigned 32-bit integers.
+
+Don't use "long" to mean "signed 64-bit integer" and don't use "unsigned
+long" to mean "unsigned 64-bit integer"; "long"s are 32 bits long on
+many other platforms. Don't use "long long" or "unsigned long long",
+either, as not all platforms support them; use "int64_t" or "uint64_t",
+which will be defined as the appropriate types for 64-bit signed and
+unsigned integers.
+
+On LLP64 data model systems (notably 64-bit Windows), "int" and "long"
+are 32 bits while "size_t" and "ptrdiff_t" are 64 bits. This means that
+the following will generate a compiler warning:
+
+ int i;
+ i = strlen("hello, sailor"); /* Compiler warning */
+
+Normally, you'd just make "i" a size_t. However, many GLib and Wireshark
+functions won't accept a size_t on LLP64:
+
+ size_t i;
+ char greeting[] = "hello, sailor";
+ unsigned byte_after_greet;
+
+ i = strlen(greeting);
+ byte_after_greet = tvb_get_guint8(tvb, i); /* Compiler warning */
+
+Try to use the appropriate data type when you can. When you can't, you
+will have to cast to a compatible data type, e.g.
+
+ size_t i;
+ char greeting[] = "hello, sailor";
+ uint8_t byte_after_greet;
+
+ i = strlen(greeting);
+ byte_after_greet = tvb_get_guint8(tvb, (int) i); /* OK */
+
+or
+
+ int i;
+ char greeting[] = "hello, sailor";
+ uint8_t byte_after_greet;
+
+ i = (int) strlen(greeting);
+ byte_after_greet = tvb_get_guint8(tvb, i); /* OK */
+
+See http://www.unix.org/version2/whatsnew/lp64_wp.html for more
+information on the sizes of common types in different data models.
+
+A lot of legacy code still uses GLib types and I/O replacement API. These
+should be gradually transitioned to use the standard interfaces provided in
+C11. Sometimes it may be necessary to use an unsavory cast or two or abuse
+a macro to bridge the two codebases during the transition. Such is life,
+use your judgement and do the best possible under the circumstances.
+
+Avoid GLib synonyms like gchar and gint and especially don't
+use gpointer and gconstpointer, unless you are writing GLib callbacks
+and trying to match their signature exactly. These just obscure the
+code and gconstpointer in particular is just semantically weird and poor style.
+
+When printing or displaying the values of 64-bit integral data types,
+don't use "%lld", "%llu", "%llx", or "%llo" - not all platforms
+support "%ll" for printing 64-bit integral data types. Instead use
+the macros in <inttypes.h>, for example:
+
+ proto_tree_add_uint64_format_value(tree, hf_uint64, tvb, offset, len,
+ val, "%" PRIu64, val);
+
+For GLib routines, and only those, you can choose whichever format style
+you prefer:
+
+ uint64_t val = UINT64_C(1);
+ char *str1 = g_string_printf("%" G_GUINT64_FORMAT, val);
+ char *str2 = g_string_printf("%" PRIu64, val);
+
+These format macros will be the same modulo any GLib bugs.
+
+When specifying an integral constant that doesn't fit in 32 bits, don't
+use "LL" at the end of the constant - not all compilers use "LL" for
+that. Instead, put the constant in a call to the "INT64_C()" or "UINT64_C()"
+macro, e.g.
+
+ INT64_C(-11644473600), UINT64_C(11644473600)
+
+rather than
+
+ -11644473600LL, 11644473600ULL
+
+Don't assume that you can scan through a va_list initialized by va_start
+more than once without closing it with va_end and re-initializing it with
+va_start. This applies even if you're not scanning through it yourself,
+but are calling a routine that scans through it, such as vfprintf() or
+one of the routines in Wireshark that takes a format and a va_list as an
+argument. You must do
+
+ va_start(ap, format);
+ call_routine1(xxx, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+ call_routine2(xxx, format, ap);
+ va_end(ap);
+
+rather than
+
+ va_start(ap, format);
+ call_routine1(xxx, format, ap);
+ call_routine2(xxx, format, ap);
+ va_end(ap);
+
+Don't use a label without a statement following it. For example,
+something such as
+
+ if (...) {
+
+ ...
+
+ done:
+ }
+
+will not work with all compilers - you have to do
+
+ if (...) {
+
+ ...
+
+ done:
+ ;
+ }
+
+with some statement, even if it's a null statement, after the label.
+Preferably don't do it at all.
+
+Don't use "bzero()", "bcopy()", or "bcmp()"; instead, use the ANSI C
+routines
+
+ "memset()" (with zero as the second argument, so that it sets
+ all the bytes to zero);
+
+ "memcpy()" or "memmove()" (note that the first and second
+ arguments to "memcpy()" are in the reverse order to the
+ arguments to "bcopy()"; note also that "bcopy()" is typically
+ guaranteed to work on overlapping memory regions, while
+ "memcpy()" isn't, so if you may be copying from one region to a
+ region that overlaps it, use "memmove()", not "memcpy()" - but
+ "memcpy()" might be faster as a result of not guaranteeing
+ correct operation on overlapping memory regions);
+
+ and "memcmp()" (note that "memcmp()" returns 0, 1, or -1, doing
+ an ordered comparison, rather than just returning 0 for "equal"
+ and 1 for "not equal", as "bcmp()" does).
+
+Not all platforms necessarily have "bzero()"/"bcopy()"/"bcmp()", and
+those that do might not declare them in the header file on which they're
+declared on your platform.
+
+Don't use "index()" or "rindex()"; instead, use the ANSI C equivalents,
+"strchr()" and "strrchr()". Not all platforms necessarily have
+"index()" or "rindex()", and those that do might not declare them in the
+header file on which they're declared on your platform.
+
+Don't use "tvb_get_ptr()". If you must use it, keep in mind that the pointer
+returned by a call to "tvb_get_ptr()" is not guaranteed to be aligned on any
+particular byte boundary; this means that you cannot safely cast it to any
+data type other than a pointer to "char", "unsigned char", "guint8", or other
+one-byte data types. Casting a pointer returned by tvb_get_ptr() into any
+multi-byte data type or structure may cause crashes on some platforms (even
+if it does not crash on x86-based PCs). Even if such mis-aligned accesses
+don't crash on your platform they will be slower than properly aligned
+accesses would be. Furthermore, the data in a packet is not necessarily in
+the byte order of the machine on which Wireshark is running. Use the tvbuff
+routines to extract individual items from the packet, or, better yet, use
+"proto_tree_add_item()" and let it extract the items for you.
+
+Don't use structures that overlay packet data, or into which you copy
+packet data; the C programming language does not guarantee any
+particular alignment of fields within a structure, and even the
+extensions that try to guarantee that are compiler-specific and not
+necessarily supported by all compilers used to build Wireshark. Using
+bitfields in those structures is even worse; the order of bitfields
+is not guaranteed.
+
+Don't use "ntohs()", "ntohl()", "htons()", or "htonl()"; the header
+files required to define or declare them differ between platforms, and
+you might be able to get away with not including the appropriate header
+file on your platform but that might not work on other platforms.
+Instead, use "g_ntohs()", "g_ntohl()", "g_htons()", and "g_htonl()";
+those are declared by <glib.h>, and you'll need to include that anyway,
+as Wireshark header files that all dissectors must include use stuff from
+<glib.h>.
+
+Don't fetch a little-endian value using "tvb_get_ntohs() or
+"tvb_get_ntohl()" and then using "g_ntohs()", "g_htons()", "g_ntohl()",
+or "g_htonl()" on the resulting value - the g_ routines in question
+convert between network byte order (big-endian) and *host* byte order,
+not *little-endian* byte order; not all machines on which Wireshark runs
+are little-endian, even though PCs are. Fetch those values using
+"tvb_get_letohs()" and "tvb_get_letohl()".
+
+Do not use "open()", "rename()", "mkdir()", "stat()", "unlink()", "remove()",
+"fopen()", "freopen()" directly. Instead use "ws_open()", "ws_rename()",
+"ws_mkdir()", "ws_stat()", "ws_unlink()", "ws_remove()", "ws_fopen()",
+"ws_freopen()": these wrapper functions change the path and file name from
+UTF-8 to UTF-16 on Windows allowing the functions to work correctly when the
+path or file name contain non-ASCII characters.
+
+Also, use ws_read(), ws_write(), ws_lseek(), ws_dup(), ws_fstat(), and
+ws_fdopen(), rather than read(), write(), lseek(), dup(), fstat(), and
+fdopen() on descriptors returned by ws_open().
+
+Those functions are declared in <wsutil/file_util.h>; include that
+header in any code that uses any of those routines.
+
+When opening a file with "ws_fopen()", "ws_freopen()", or "ws_fdopen()", if
+the file contains ASCII text, use "r", "w", "a", and so on as the open mode
+- but if it contains binary data, use "rb", "wb", and so on. On
+Windows, if a file is opened in a text mode, writing a byte with the
+value of octal 12 (newline) to the file causes two bytes, one with the
+value octal 15 (carriage return) and one with the value octal 12, to be
+written to the file, and causes bytes with the value octal 15 to be
+discarded when reading the file (to translate between C's UNIX-style
+lines that end with newline and Windows' DEC-style lines that end with
+carriage return/line feed).
+
+In addition, that also means that when opening or creating a binary
+file, you must use "ws_open()" (with O_CREAT and possibly O_TRUNC if the
+file is to be created if it doesn't exist), and OR in the O_BINARY flag,
+even on UN*X - O_BINARY is defined by <wsutil/file_util.h> as 0 on UN*X.
+
+Do not include <unistd.h>, <fcntl.h>, or <io.h> to declare any of the
+routines listed as replaced by routines in <wsutil/file_util.h>;
+instead, just include <wsutil/file_util.h>.
+
+If you need the declarations of other functions defined by <unistd.h>,
+don't include it without protecting it with
+
+ #ifdef HAVE_UNISTD_H
+
+ ...
+
+ #endif
+
+Don't use forward declarations of static arrays without a specified size
+in a fashion such as this:
+
+ static const value_string foo_vals[];
+
+ ...
+
+ static const value_string foo_vals[] = {
+ { 0, "Red" },
+ { 1, "Green" },
+ { 2, "Blue" },
+ { 0, NULL }
+ };
+
+as some compilers will reject the first of those statements. Instead,
+initialize the array at the point at which it's first declared, so that
+the size is known.
+
+For #define names and enum member names, prefix the names with a tag so
+as to avoid collisions with other names - this might be more of an issue
+on Windows, as it appears to #define names such as DELETE and
+OPTIONAL.
+
+Don't use the "positional parameters" extension that many UNIX printf's
+implement, e.g.:
+
+ snprintf(add_string, 30, " - (%1$d) (0x%1$04x)", value);
+
+as not all UNIX printf's implement it, and Windows printf doesn't appear
+to implement it. Use something like
+
+ snprintf(add_string, 30, " - (%d) (0x%04x)", value, value);
+
+instead.
+
+Don't use
+
+ case N ... M:
+
+as that's not supported by all compilers.
+
+Prefer the C99 output functions from <stdio.h> instead of their GLib
+replacements (note that positional format parameters are not part of C99).
+In the past we used to recommend using g_snprintf() and g_vsnprintf()
+instead but since Visual Studio 2015 native C99 implementations are
+available on all platforms we support. These are optimized better than
+the gnulib (GLib) implementation and on hot codepaths that can be a
+noticeable difference in execution speed.
+
+tmpnam() -> mkstemp()
+tmpnam is insecure and should not be used any more. Wireshark brings its
+own mkstemp implementation for use on platforms that lack mkstemp.
+Note: mkstemp does not accept NULL as a parameter.
+
+Wireshark requires minimum versions of each of the libraries it uses, in
+particular GLib 2.54.0 and Qt 5.12.0 or newer. If you require a mechanism
+that is available only in a newer version of a library then use its
+version detection macros, e.g. "#if GLIB_CHECK_VERSION(...)" and "#if
+QT_VERSION_CHECK(...)" to conditionally compile code using that
+mechanism.
+
+When different code must be used on UN*X and Win32, use a #if or #ifdef
+that tests _WIN32, not WIN32. Try to write code portably whenever
+possible, however; note that there are some routines in Wireshark with
+platform-dependent implementations and platform-independent APIs, such
+as the routines in epan/filesystem.c, allowing the code that calls it to
+be written portably without #ifdefs.
+
+We support building on Windows using MinGW-w64 (experimental) so be mindful
+of the difference between an #ifdef on _WIN32 and _MSC_VER. The first tests
+if the platform is some version of Windows and also applies to MinGW. The
+latter tests if the toolchain is Microsoft Visual Studio. Sometimes you need
+one or the other, depending on whether the condition applies to all Windows
+compilers or only Microsoft's compiler. Use #ifdef __MINGW32__ to test for
+a MinGW toolchain, including MinGW-w64. The same concern applies to CMake
+code. Depending on the particular situation you may need to use if(WIN32) or
+if(MSVC) or if(MINGW).
+
+Wireshark uses Libgcrypt as general-purpose crypto library. Some Wireshark
+specific extensions are defined in wsutil/wsgcrypt.h. You might want to
+include that file instead.
+
+2. String handling
+
+Do not use functions such as strcat() or strcpy().
+A lot of work has been done to remove the existing calls to these functions and
+we do not want any new callers of these functions.
+
+Instead use snprintf() since that function will if used correctly prevent
+buffer overflows for large strings.
+
+Be sure that all pointers passed to %s specifiers in format strings are non-
+NULL. Some implementations will automatically replace NULL pointers with the
+string "(NULL)", but most will not.
+
+When using a buffer to create a string, do not use a buffer stored on the stack.
+I.e. do not use a buffer declared as
+
+ char buffer[1024];
+
+instead allocate a buffer dynamically using the string-specific or plain wmem
+routines (see README.wmem) such as
+
+ wmem_strbuf_t *strbuf;
+ strbuf = wmem_strbuf_new(pinfo->pool, "");
+ wmem_strbuf_append_printf(strbuf, ...
+
+or
+
+ char *buffer=NULL;
+ ...
+ #define MAX_BUFFER 1024
+ buffer=wmem_alloc(pinfo->pool, MAX_BUFFER);
+ buffer[0]='\0';
+ ...
+ snprintf(buffer, MAX_BUFFER, ...
+
+This avoids the stack from being corrupted in case there is a bug in your code
+that accidentally writes beyond the end of the buffer.
+
+
+If you write a routine that will create and return a pointer to a filled in
+string and if that buffer will not be further processed or appended to after
+the routine returns (except being added to the proto tree),
+do not preallocate the buffer to fill in and pass as a parameter instead
+pass a pointer to a pointer to the function and return a pointer to a
+wmem-allocated buffer that will be automatically freed. (see README.wmem)
+
+I.e. do not write code such as
+ static void
+ foo_to_str(char *string, ... ){
+ <fill in string>
+ }
+ ...
+ char buffer[1024];
+ ...
+ foo_to_str(buffer, ...
+ proto_tree_add_string(... buffer ...
+
+instead write the code as
+ static void
+ foo_to_str(char **buffer, ...
+ #define MAX_BUFFER x
+ *buffer=wmem_alloc(pinfo->pool, MAX_BUFFER);
+ <fill in *buffer>
+ }
+ ...
+ char *buffer;
+ ...
+ foo_to_str(&buffer, ...
+ proto_tree_add_string(... *buffer ...
+
+Use wmem_ allocated buffers. They are very fast and nice. These buffers are all
+automatically free()d when the dissection of the current packet ends so you
+don't have to worry about free()ing them explicitly in order to not leak memory.
+Please read README.wmem.
+
+Source files can use UTF-8 encoding, but characters outside the ASCII
+range should be used sparingly. It should be safe to use non-ASCII
+characters in comments and strings, but some compilers (such as GCC
+versions prior to 10) may not support extended identifiers very well.
+There is also no guarantee that a developer's text editor will interpret
+the characters the way you intend them to be interpreted.
+
+The majority of Wireshark encodes strings as UTF-8. The main exception
+is the code that uses the Qt API, which uses UTF-16. Console output is
+UTF-8, but as with the source code extended characters should be used
+sparingly since some consoles (most notably Windows' cmd.exe) have
+limited support for UTF-8.
+
+3. Robustness.
+
+Wireshark is not guaranteed to read only network traces that contain correctly-
+formed packets. Wireshark is commonly used to track down networking
+problems, and the problems might be due to a buggy protocol implementation
+sending out bad packets.
+
+Therefore, code does not only have to be able to handle
+correctly-formed packets without, for example, crashing or looping
+infinitely, they also have to be able to handle *incorrectly*-formed
+packets without crashing or looping infinitely.
+
+Here are some suggestions for making code more robust in the face
+of incorrectly-formed packets:
+
+Do *NOT* use "ws_assert()" or "ws_assert_not_reached()" with input data in dissectors.
+*NO* value in a packet's data should be considered "wrong" in the sense
+that it's a problem with the dissector if found; if it cannot do
+anything else with a particular value from a packet's data, the
+dissector should put into the protocol tree an indication that the
+value is invalid, and should return. The "expert" mechanism should be
+used for that purpose.
+
+Use assertions to catch logic errors in your program. A failed assertion
+indicates a bug in the code. Use ws_assert() instead of g_assert() to
+test a logic condition. Note that ws_assert() can be removed at compile
+time. Therefore assertions should not have any side-effects,
+otherwise the program may behave inconsistently.
+
+Use ws_assert_not_reached() instead of g_assert_not_reached() for
+unreachable error conditions. For example if (and only if) you know
+'myvar' can only have the values 1 and 2 do:
+ switch(myvar) {
+ case 1:
+ (...)
+ break;
+ case 2:
+ (...)
+ break;
+ default:
+ ws_assert_not_reached();
+ break;
+ }
+
+For dissectors use DISSECTOR_ASSERT() and DISSECTOR_ASSERT_NOT_REACHED()
+instead, with the same caveats as above.
+
+You should continue to use g_assert_true(), g_assert_cmpstr(), etc for
+"test code", such as unit testing. These assertions are always active.
+See the GLib Testing API documentation for the details on each of those
+functions.
+
+If there is a case where you are checking not for an invalid data item
+in the packet, but for a bug in the dissector (for example, an
+assumption being made at a particular point in the code about the
+internal state of the dissector), use the DISSECTOR_ASSERT macro for
+that purpose; this will put into the protocol tree an indication that
+the dissector has a bug in it, and will not crash the application.
+
+If you are allocating a chunk of memory to contain data from a packet,
+or to contain information derived from data in a packet, and the size of
+the chunk of memory is derived from a size field in the packet, make
+sure all the data is present in the packet before allocating the buffer.
+Doing so means that:
+
+ 1) Wireshark won't leak that chunk of memory if an attempt to
+ fetch data not present in the packet throws an exception.
+
+and
+
+ 2) it won't crash trying to allocate an absurdly-large chunk of
+ memory if the size field has a bogus large value.
+
+If you're fetching into such a chunk of memory a sequence of bytes from
+the buffer, and the sequence has a specified size, you can use
+"tvb_memdup()", which will check whether the entire sequence is present
+before allocating a buffer for it.
+
+Otherwise, you can check whether the data is present by using
+"tvb_ensure_bytes_exist()" although this frequently is not needed: the
+TVB-accessor routines can handle requests to read data beyond the end of
+the TVB (by throwing an exception which will either mark the frame as
+truncated--not all the data was captured--or as malformed).
+
+If you're fetching a string only to add it to the tree, you should
+generally be using "proto_tree_add_item()" instead. If you also need
+the string, you can use the variant "proto_tree_add_item_ret_string()"
+or "proto_tree_add_item_ret_string_and_length()" forms.
+
+If you must fetch it from the tvbuff, and the string has a specified
+size and known encoding, you can use "tvb_get_string_enc()" for most
+encodings, which will check whether the entire string is present before
+allocating a buffer for the string, will put a trailing '\0' at the end
+of the buffer, and will also check for invalid characters in the supplied
+encoding and convert the string to UTF-8. The "tvb_get_*_string()" set of
+functions is available as well, and must be used for some encodings,
+primarily non byte aligned ones. If the string has a known encoding and
+is null terminated, the "stringz" variants can be used. (Note that these
+functions are called with memory allocators, and if called with a NULL
+allocator you are required to free the string when finished with it.)
+
+If the string has a known encoding but requires token parsing or other
+text manipulation to determine the offset and size, do so by calling
+tvb_*() functions on the tvbuff that perform bounds checking if possible.
+Only extract the bytes into a newly allocated buffer to extract a string
+if absolutely necessary. If you do so, then you *must* ensure that the
+string is valid UTF-8 when passing it to a libwireshark API function
+such as proto_tree_add_string(). (Cf. 7.5: Unicode and string encoding
+best practices.)
+
+Conversion to UTF-8 can produce a string with a length longer than
+that of the string in the original packet data; this includes strings
+encoded in ASCII or UTF-8 itself if they have invalid character sequences
+that are replaced with the 3 byte UTF-8 REPLACEMENT CHARACTER. Truncating
+a valid UTF-8 string to an arbitrary number of bytes does not guarantee
+that the result is a valid UTF-8 string, because a multibyte character
+might span the boundary.
+
+Note also that you should only fetch string data into a fixed-length
+buffer if the code ensures that no more bytes than will fit into the
+buffer are fetched ("the protocol ensures" isn't good enough, as
+protocol specifications can't ensure only packets that conform to the
+specification will be transmitted or that only packets for the protocol
+in question will be interpreted as packets for that protocol by
+Wireshark).
+
+If you have gotten a pointer using "tvb_get_ptr()" (which you should not
+have: you should seriously consider a better alternative to this function),
+you must make sure that you do not refer to any data past the length passed
+as the last argument to "tvb_get_ptr()"; while the various "tvb_get"
+routines perform bounds checking and throw an exception if you refer to data
+not available in the tvbuff, direct references through a pointer gotten from
+"tvb_get_ptr()" do not do any bounds checking.
+
+If you have a loop that dissects a sequence of items, each of which has
+a length field, with the offset in the tvbuff advanced by the length of
+the item, then, if the length field is the total length of the item, and
+thus can be zero, you *MUST* check for a zero-length item and abort the
+loop if you see one. Otherwise, a zero-length item could cause the
+dissector to loop infinitely. You should also check that the offset,
+after having the length added to it, is greater than the offset before
+the length was added to it, if the length field is greater than 24 bits
+long, so that, if the length value is *very* large and adding it to the
+offset causes an overflow, that overflow is detected.
+
+If you have a
+
+ for (i = {start}; i < {end}; i++)
+
+loop, make sure that the type of the loop index variable is large enough
+to hold the maximum {end} value plus 1; otherwise, the loop index
+variable can overflow before it ever reaches its maximum value. In
+particular, be very careful when using int8_t, uint8_t, int16_t, or uint16_t
+(or the deprecated Glib synonyms gint8, guint8, gint16, or guint16)
+variables as loop indices; you almost always want to use an "int"/"gint"
+or "unsigned"/"guint" as the loop index rather than a shorter type.
+
+If you are fetching a length field from the buffer, corresponding to the
+length of a portion of the packet, and subtracting from that length a
+value corresponding to the length of, for example, a header in the
+packet portion in question, *ALWAYS* check that the value of the length
+field is greater than or equal to the length you're subtracting from it,
+and report an error in the packet and stop dissecting the packet if it's
+less than the length you're subtracting from it. Otherwise, the
+resulting length value will be negative, which will either cause errors
+in the dissector or routines called by the dissector, or, if the value
+is interpreted as an unsigned integer, will cause the value to be
+interpreted as a very large positive value.
+
+Any tvbuff offset that is added to as processing is done on a packet
+should be stored in a 32-bit variable, such as an "int"; if you store it
+in an 8-bit or 16-bit variable, you run the risk of the variable
+overflowing.
+
+sprintf() -> snprintf()
+Prevent yourself from using the sprintf() function, as it does not test the
+length of the given output buffer and might be writing into unintended memory
+areas. This function is one of the main causes of security problems like buffer
+exploits and many other bugs that are very hard to find. It's much better to
+use the snprintf() function declared by <stdio.h> instead.
+
+You should test your dissector against incorrectly-formed packets. This
+can be done using the randpkt and editcap utilities that come with the
+Wireshark distribution. Testing using randpkt can be done by generating
+output at the same layer as your protocol, and forcing Wireshark/TShark
+to decode it as your protocol, e.g. if your protocol sits on top of UDP:
+
+ randpkt -c 50000 -t dns randpkt.pcap
+ tshark -nVr randpkt.pcap -d udp.port==53,<myproto>
+
+Testing using editcap can be done using preexisting capture files and the
+"-E" flag, which introduces errors in a capture file. E.g.:
+
+ editcap -E 0.03 infile.pcap outfile.pcap
+ tshark -nVr outfile.pcap
+
+tools/fuzz-test.sh is available to help automate these tests.
+
+4. Name convention.
+
+Wireshark uses the underscore_convention rather than the InterCapConvention for
+function names, so new code should probably use underscores rather than
+intercaps for functions and variable names. This is especially important if you
+are writing code that will be called from outside your code. We are just
+trying to keep things consistent for other developers.
+
+C symbols exported from libraries shipped with Wireshark should start with a
+prefix that helps avoiding name collision with public symbols from other shared
+libraries. The current suggested prefixes for newly added symbols are
+ws_, wslua_, wmem_ and wtap_.
+
+5. White space convention.
+
+Most of the C and C++ files in Wireshark use 4-space or 2-space indentation.
+When creating new files you are you are strongly encouraged to use 4-space
+indentation for source code in order to ensure consistency between files.
+
+Please avoid using tab expansions different from 8 column widths, as not all
+text editors in use by the developers support this. For a detailed discussion
+of tabs, spaces, and indentation, see
+
+ http://www.jwz.org/doc/tabs-vs-spaces.html
+
+We use EditorConfig (http://editorconfig.org) files to provide formatting
+hints. Most editors and IDEs support EditorConfig, either directly or via
+a plugin. If yours requires a plugin we encourage you to install it. Our
+default EditorConfig indentation style for C and C++ files is 4 spaces.
+
+Many files also have a short comment (modelines) on the indentation logic at
+the end of the file. This was required in the past but has been superseded by
+EditorConfig. See
+
+ https://www.wireshark.org/tools/modelines.html
+
+for more information.
+
+Please do not leave trailing whitespace (spaces/tabs) on lines.
+
+Quite a bit of our source code has varying indentation styles. When editing an
+existing file, try following the existing indentation logic. If you wish to
+convert a file to 4 space indentation, please do so in its own commit and be
+sure to remove its .editorconfig entry so that the default setting takes
+effect.
+
+6. Compiler warnings
+
+You should write code that is free of compiler warnings. Such warnings will
+often indicate questionable code and sometimes even real bugs, so it's best
+to avoid warnings at all.
+
+The compiler flags in the Makefiles are set to "treat warnings as errors",
+so your code won't even compile when warnings occur.
+
+7. General observations about architecture
+
+7.1 The global header "wireshark.h"
+
+You should include the global header <wireshark.h> in your code. However
+there are some things to keep in mind when using it and especially
+if you are considering modifying it.
+
+** wireshark.h needs to be minimal: for efficiency reasons, to reduce the
+error surface and because every time this header changes everything must be
+rebuilt. Consider carefully if another header/module should be included
+globally with every project file and exported as public header.
+
+** No configuration: configuration is specific to the build environment
+and target machine. wireshark.h must not depend on that.
+
+** Only wireshark system headers allowed: plugins use this header and
+cannot depend on any header (even indirectly) that is not installed on the
+target system.
+
+** Only global definitions allowed: for example it is acceptable to include
+'wsutil' headers in wireshark.h because every component of Wireshark is allowed
+to depend on wsutil. wiretap is not acceptable because we cannot introduce
+dependencies on wiretap globally (and wireshark.h must be usable everywhere).
+
+7.2 Best practices using headers
+
+C files can be categorized in three types: source files, private headers and
+public headers.
+
+A module "foobar" can have only a private header, only a public header, or
+both. If it's only one it is named "foobar.h" in both cases. If it is both they
+are named "foobar-int.h" and "foobar.h" respectively.
+
+In general the order of #include's for a C module source files (foobar.c),
+assuming foobar implements any kind of interface should be:
+
+ #include "config.h"
+ #define WS_LOG_DOMAIN "mydomain"
+ #include "foobar-int.h"
+
+ followed by <system headers>
+ followed by <wireshark public headers>
+ followed by <wireshark private headers>
+
+For header files (private and public) config.h must NOT be included. A public
+header file (foobar.h) looks like this:
+
+ #ifndef __FOOBAR_H__
+ #define __FOOBAR_H__
+ #include <wireshark.h>
+ followed by <system headers>
+ followed by <wireshark public headers>
+
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ (declarations)
+ #ifdef __cplusplus
+ }
+ #endif
+ #endif /* FOOBAR_H */
+
+A private header (foobar-int.h) is the public header plus the declarations
+with private scope:
+
+ #ifndef __FOOBAR_INT_H__
+ #define __FOOBAR_INT_H__
+ #include "foobar.h"
+ followed by <system headers>
+ followed by <wireshark public headers>
+ followed by <wireshark private headers>
+ (etc.)
+
+Again if there are only public or private declarations the name foobar-int.h
+is not used. The macro symbol WS_LOG_DOMAIN can be defined in source files or
+private headers as long as it comes before wireshark.h.
+
+7.3 Wireshark internal and external API policy
+
+Wireshark has several APIs. We need to distinguish between internal
+Wireshark library APIs and external Wireshark APIs. Wireshark the project is
+composed of many different programs and these executable binaries use a number
+of internal libraries to share code efficiently. These internal shared
+libraries need to be installed on the system to run the programs (wireshark,
+tshark, etc).
+
+A library's public API includes the symbols exported by the DSO (wsutil,
+libwireshark, etc). The internal API is made available in the shared libraries
+and exists to support the goals of the project. It is public from the point
+of view of Wireshark programs (client users of the internal API). The
+external API exists to support plugins (client users of the external API)
+and is a loosely defined subset of the internal API plus any infrastructure
+required to support a plugin system. Note that these two uses of shared
+libraries coexist with a lot of overlap, but are nevertheless distinct.
+
+The internal (public) API is not considered to be stable and will regularly
+change as a normal part of development to support new features, remove cruft,
+and whatever else is necessary to make the project sustainable and ease the
+burden on developers. There is less freedom to change something that could
+break a lot of plugins but this is also acceptable (with cause).
+
+The plugin ABI policy is to be compatible only between micro releases (also
+called patch releases). That means we try to make it unnecessary to recompile
+plugins with each micro release (on a best-effort basis). For major.minor
+releases it is explicitly required to recompile plugins. There is no stable
+ABI contract of any kind in that case.
+
+Keep in mind that APIs can exist in different scopes and levels of abstraction.
+Don't get stuck thinking the words public/private have a very specific
+meaning, like being decorated or not with WS_DLL_PUBLIC, although that is a
+big part of it usually.
+
+Also the Wireshark developers have historically tried to keep the Lua API
+very stable and provide strong backward-compatibility guarantees. Under this
+policy moving from Lua 5.2 is unlikely to happen in the foreseeable future.
+
+7.4 libwireshark is not a single monolithic entity
+
+One day we might conceivably wish to load dissectors on demand and do other
+more sophisticated kinds of unit test. Plus other scenarios not immediately
+obvious. For this to be possible it is important that the code in epan/ does
+not depend on code in epan/dissectors, i.e it is possible to compile epan
+without linking with dissector code. It helps to view dissectors as clients
+of an API provided by epan (libwireshark being constituted by two distinct
+components "epan" and "dissectors" bundled together, plus other bits and
+pieces). The reverse is not* true; epan should not be the client of an API
+provided by dissectors.
+
+The main way this separation of concerns is achieved is by using runtime
+registration interfaces in epan for dissectors, preferences, etc. that are
+dynamic and do not have any dissector routines hard coded. Naturally this
+is also an essential component of a plugin system (libwireshark has plugins
+for taps, dissectors and an experimental interface to augment dissection with
+new extension languages).
+
+7.5 Unicode and string encoding best practices
+
+Wireshark strings are always encoded in UTF-8 internally, regardless of the
+platform where it is running. The C datatype used is "pointer to char" and this
+is assumed to point to a valid UTF-8 string. Sometimes older code uses char to
+point to opaque byte strings but this archaic usage should be avoided. A better
+data type for that is uint8_t.
+
+Every untrusted string needs to be validated for correct and error-free UTF-8
+encoding, or converted from the source encoding to UTF-8. This should be done
+at the periphery of the code. This means converting input during dissection or
+when reading input generally. To reiterate: all the Wireshark APIs expect to
+receive valid UTF-8 strings. These include proto_tree_add_string(),
+proto_item_append_text() and col_append_fstr() just to name a few.
+
+If a dissector uses standard API functions to handle strings, such as
+proto_tree_add_item() with an FT_STRING header field type, the API will
+transparently handle the conversion from the source encoding to UTF-8 and
+nothing else needs to be done to ensure valid string input.
+
+If your dissector does text manipulation, token parsing and such and generally
+extracts text strings from the TVBuff or tries to do line oriented input from
+TVBuffs it *must* make sure it passes only valid UTF-8 to libwireshark APIs.
+This should be done using tvb_get_string_enc() to extract a string from a TVbuff
+or get_utf_8_string() to validate a string after it has been constructed.
+
+The Qt API uses UTF-16 for its QString class; when converting between a
+QString and a pointer to char, functions that convert to or from UTF-8
+encoded pointers to char (or QByteArrays) such as toUtf8() should be used,
+not toLocal8Bit() or toLatin1().
+
+8. Miscellaneous notes
+
+Each commit in your branch corresponds to a different VCSVERSION string
+automatically defined in the header 'vcs_version.h' during the build. If you happen
+to find it convenient to disable this feature it can be done using:
+
+ touch .git/wireshark-disable-versioning
+
+i.e., the file 'wireshark-disable-versioning' must exist in the git repo dir.
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */