diff --git a/VERSION.TXT b/VERSION.TXT index 72fe61b3..ba5632ab 100644 --- a/VERSION.TXT +++ b/VERSION.TXT @@ -1,3 +1,16 @@ +Version 5.02b +============= + - Contains bug fix to correctly set mgen TCP send and recv'd + message tx times under heavy load. + - Contains bug fix to correctly set binary time in mgen send + messages. + +Version 5.02 +============ + - Contains bug fix to close open UDP sockets + - Contains bug fix to handle incoming tcp connections on windows + correctly + Version 5.01c ============= - Contains bug fixes for compilation under Visual Studio 6.0 diff --git a/doc/example.mgn b/doc/example.mgn index 283eec16..87b6e733 100644 --- a/doc/example.mgn +++ b/doc/example.mgn @@ -36,6 +36,9 @@ BURST [REGULAR 10.0 PERIODIC [10.0 256] FIXED 5.0] # This JOIN is for UNIX 0.0 JOIN 224.225.1.2 +# This SSM JOIN is for UNIX (Currently SSM is supported only in UNIX) +#0.0 JOIN 224.225.1.2 SRC 25.25.25.1 + # For WIN32, the PORT option is needed for JOINs #0.0 JOIN 224.225.1.2 PORT 5001 @@ -45,6 +48,9 @@ BURST [REGULAR 10.0 PERIODIC [10.0 256] FIXED 5.0] 5.0 LEAVE 224.225.1.2 +# This SSM LEAVE is for UNIX (Currently SSM is supported only in UNIX) +#5.0 LEAVE 224.224.1.2 SRC 25.25.25.1 INTERFACE eth0 + # If an interface was dictated on the JOIN, # it is also required for the LEAVE #5.0 LEAVE 224.224.1.2 INTERFACE eth0 diff --git a/doc/html.css b/doc/html.css index 2158da3a..901b1edd 100644 --- a/doc/html.css +++ b/doc/html.css @@ -1,27 +1,325 @@ -body { - background-color: #FFFFFF; +body { + font-family: sans-serif; + font-size: 10pt; + color: black; + background-color: white; } -h1, h2, h3, h4, h5 { - color: #800000; - font-family: sans-serif; +h1, +h2, +h3, +h4, +h5, +h6 { + color: #394986; + font-height: bold; + margin-top: 1.33ex; + margin-bottom: 1.33ex; } -span.term { - font-weight: bold; +h1 { + font-size: 1.8em; } -div.sidebar { - background-color: #F0F0F0; - border: 1px solid gray; - padding: 5px; - margin: 20px; +h2 { + font-size: 1.6em; } -pre.programlisting { - background-color: #F0F0F0; - border: 1px solid gray; - padding: 2px; - font-size: 10pt; +h3 { + font-size: 1.4em; +} + +h4 { + font-size: 1.2em; +} + +h5, +h6 { + font-size: 1em; +} + +table { + border-spacing: 0; + font-size: 1em; +} + +thead, +tfoot { + background-color: #EEEEEE; +} + +th, +td { + padding: 0 0.5ex; +} + +blockquote { + margin-top: 1.33ex 4ex; +} + +p, +th, +td, +li, +dt, +dd { + font-size: 1em; +} + +p, +pre, +ol, +dl, +ul, +table { + margin-top: 1.33ex; + margin-bottom: 1.33ex; +} + +code, +kbd, +tt, +pre { + font-family: monospace; + font-size: 90%; +} + +pre { white-space: pre; + background-color: #EEEEEE; + border: 1px solid #C0C0C0; + padding: 1ex; +} + +li { + margin-top: 1.33ex; + margin-bottom: 1.33ex; +} + +*[compact] > li { + margin-top: 0; + margin-bottom: 0; +} + +dt { + margin-top: 1.33ex; + margin-bottom: 0; +} + +dd { + margin-top: 0; + margin-bottom: 1.33ex; +} + +*[compact] > dt { + margin-top: 0; +} + +*[compact] > dd { + margin-bottom: 0; +} + +div.toc, +div.index, +div.list-of-figures, +div.list-of-tables, +div.list-of-examples, +div.list-of-equations, +div.list-of-procedures { + margin-top: 1.33ex; + margin-bottom: 1.33ex; +} + +div.toc dl, +div.index dl, +div.list-of-figures dl, +div.list-of-tables dl, +div.list-of-examples dl, +div.list-of-equations dl, +div.list-of-procedures dl { + margin-top: 0; + margin-bottom: 0; +} + +div.toc dt, +div.index dt, +div.list-of-figures dt, +div.list-of-tables dt, +div.list-of-examples dt, +div.list-of-equations dt, +div.list-of-procedures dt { + margin-top: 0.25ex; + margin-bottom: 0.25ex; +} + +div.toc dd, +div.index dd, +div.list-of-figures dd, +div.list-of-tables dd, +div.list-of-examples dd, +div.list-of-equations dd, +div.list-of-procedures dd { + margin-top: 0; + margin-bottom: 0; +} + +div.toc span.part, +div.toc span.chapter, +div.toc span.appendix { + font-weight: bold; +} + +div.attribution { + text-align: right; +} + +div.sidebar { + background-color: #EEEEFF; + border: 1px solid #C0C0DD; + padding: 1ex; + margin-top: 1.33ex; + margin-bottom: 1.33ex; +} + +div.sidebar > p.title { + margin-top: 0.33ex; +} + +div.example > p.title, +div.figure > p.title, +div.table > p.title, +div.procedure > p.title, +div.equation > p.title { + color: #394986; + font-weight: bold; +} + +div.orderedlist, +div.calloutlist { + margin-top: 1.33ex; + margin-bottom: 1.33ex; +} + +div.orderedlist > table, +div.calloutlist > table { + margin: 0; +} + +div.orderedlist > table td, +div.calloutlist > table td { + vertical-align: baseline; +} + +div.footnote { + font-size: 0.9em; +} + +a:link:hover, +a:visited:hover { + text-decoration: underline; +} + +a:link { + text-decoration: none; + color: #004668; +} + +a:visited { + text-decoration: none; + color: #135678; +} + +span.term { + font-weight: bold; +} + +abbr, +acronym { + font-weight: bold; +} + +span.keycap, +span.keycode, +span.keysym, +span.mousebutton { + font-family: monospace; + font-size: 90%; + background-color: #EEEEEE; + padding: 0.2ex; +} + +span.guimenu, +span.guisubmenu, +span.guimenuitem, +span.guibutton, +span.guiicon, +span.interface, +span.guilabel { + font-weight: bold; +} + +a img { + border-style: none; +} + +hr.footnote-hr { + width: 100px; + margin-left: 0; + text-align: left; +} + +/* ------------------------------------------------------------------------ + | Syntax highlighting + +------------------------------------------------------------------------- */ + +.hl-keyword { + font-weight: bold; + color: #602060; +} + +.hl-string { + color: #A00000; +} + +.hl-number { + color: #B08000; +} + +.hl-comment { + font-style: italic; + color: #808080; +} + +.hl-doccomment { + color: #008080; +} + +.hl-directive { + color: #00A000; +} + +.hl-annotation { + font-weight: bold; + color: #808080; +} + +/* + * XML + */ + +.hl-tag { + font-weight: bold; + color: #602060; +} + +.hl-attribute { + color: #0050A0; +} + +.hl-value { + color: #A00000; +} + +.hl-doctype { + color: #008080; } diff --git a/doc/mgen.html b/doc/mgen.html index 9b526f43..28c1cc43 100644 --- a/doc/mgen.html +++ b/doc/mgen.html @@ -1,6 +1,6 @@ - MGEN User's and Reference Guide Version 5.0

MGEN User's and Reference Guide Version 5.0

Abstract

The Multi-Generator (MGEN) is open source software by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking (PROTEAN) group which provides the ability to perform IP network performance tests and measurements using UDP and TCP IP traffic. The toolset generates real-time traffic patterns so that the network can be loaded in a variety of ways. The generated traffic can also be received and logged for analyses. Script files are used to drive the generated loading patterns over the course of time. These script files can be used to emulate the traffic patterns of unicast and/or multicast UDP and TCP IP applications. The tool set can be scripted to dynamically join and leave IP multicast groups. MGEN log data can be used to calculate performance statistics on throughput, packet loss rates, communication delay, and more. MGEN currently runs on various Unix-based (including MacOS X) and WIN32 platforms.

The principal tool is the mgen program which can generate, receive, and log test traffic. This document provides information on mgen usage, message payload, and script and log file formats. Additional tools are available to facilitate automated script file creation and log file analyses.


Table of Contents

1. Quick Links
2. Mgen Usage
2.1. Example Usage
2.2. Example Script
3. Command-line Options
4. MGEN Run-Time Remote Control
5. MGEN Script Format
5.1. Transmission Events
5.1.1. ON Event
5.1.2. MOD Event
5.1.3. OFF Event
5.2. Transmission Event Options
5.2.1. Protocol (UDP/TCP/SINK)
5.2.2. Destination (DST)
5.2.3. Source Port (SRC)
5.2.4. COUNT
5.2.5. Pattern (PERIODIC, POISSON, BURST, JITTER, CLONE)
5.2.6. BROADCAST
5.2.7. LOGDATA
5.2.8. Type-Of-Service (TOS)
5.2.9. Multicast Time-To-Live (TTL)
5.2.10. Socket Transmit Buffer Size (TXBUFFER)
5.2.11. Socket Receive Buffer Size (RXBUFFER)
5.2.12. IPv6 Flow Label (LABEL)
5.2.13. Multicast Interface (INTERFACE)
5.2.14. Sequence Number Initialization (SEQUENCE)
5.2.15. UDP Connect (CONNECT)
5.3. Reception Events
5.3.1. LISTEN
5.3.2. IGNORE
5.3.3. JOIN
5.3.4. LEAVE
6. Global Commands
6.1. START
6.2. OFFSET
6.3. TOS
6.4. LABEL
6.5. TTL
6.6. TXBUFFER
6.7. RXBUFFER
6.8. LOCALTIME
6.9. QUEUE
6.10. DATA
6.11. INTERFACE
6.12. INPUT
6.13. OUTPUT
6.14. LOG
6.15. LOGDATA
6.16. SAVE
7. MGEN Log File Format
7.1. General Log Format
7.2. Log File RECV Events
7.3. Log File RERR Events
7.4. Log File SEND Events
7.5. Log File JOIN Events
7.6. Log File LEAVE Events
7.7. Log File LISTEN Events
7.8. Log File IGNORE Events
7.9. Log File ON Events
7.10. Log File CONNECT Events
7.11. Log File ACCEPT Events
7.. Log File SHUTDOWN Events
7.13. Log File DISCONNECT Events
7.14. Log File OFF Events
7.15. Log File START and STOP Events
8. Binary Log File Format
8.1. Binary Log File RECV Events
8.2. Binary Log File TCP Connection Events
8.3. Binary Log File RERR Events
8.4. Binary Log File SEND Events
8.5. Binary Log File LISTEN/IGNORE Events
8.6. Binary Log File JOIN/LEAVE Events
8.7. Binary Log File START/STOP Events
9. MGEN Message Payload
10. Compile options
10.1. RANDOM_FILL
10.2. HAVE_IPV6
10.3. SIMULATE
10.4. HAVE_GPS
10.5. HAVE_PCAP
10.6. Other
11. Known issues
11.1. Macosx Windows TCP Interaction

1. Quick Links

The Multi-Generator (MGEN) is open source software by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking (PROTEAN) group which provides the ability to perform IP network performance tests and measurements using UDP and TCP IP traffic. The toolset generates real-time traffic patterns so that the network can be loaded in a variety of ways. The generated traffic can also be received and logged for analyses. Script files are used to drive the generated loading patterns over the course of time. These script files can be used to emulate the traffic patterns of unicast and/or multicast UDP and TCP IP applications. The tool set can be scripted to dynamically join and leave IP multicast groups. MGEN log data can be used to calculate performance statistics on throughput, packet loss rates, communication delay, and more. MGEN currently runs on various Unix-based (including MacOS X) and WIN32 platforms.

The principal tool is the mgen program which can generate, receive, and log test traffic. This document provides information on mgen usage, message payload, and script and log file formats. Additional tools are available to facilitate automated script file creation and log file analyses.

2. Mgen Usage

The mgen version 5.0 program must currently be launched from a command-line. In the future, a simple graphical user interface similar to that of mgen version 3.x will be provided to simplify management of multiple sender and receiver instances. To launch mgen use the following command-line syntax:

mgen [ipv4][ipv6][input <scriptFile>][save <saveFile>]
+   MGEN User's and Reference Guide Version 5.0

MGEN User's and Reference Guide Version 5.0

Abstract

The Multi-Generator (MGEN) is open source software by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking (PROTEAN) group which provides the ability to perform IP network performance tests and measurements using UDP and TCP IP traffic. The toolset generates real-time traffic patterns so that the network can be loaded in a variety of ways. The generated traffic can also be received and logged for analyses. Script files are used to drive the generated loading patterns over the course of time. These script files can be used to emulate the traffic patterns of unicast and/or multicast UDP and TCP IP applications. The tool set can be scripted to dynamically join and leave IP multicast groups. MGEN log data can be used to calculate performance statistics on throughput, packet loss rates, communication delay, and more. MGEN currently runs on various Unix-based (including MacOS X) and WIN32 platforms.

The principal tool is the mgen program which can generate, receive, and log test traffic. This document provides information on mgen usage, message payload, and script and log file formats. Additional tools are available to facilitate automated script file creation and log file analyses.


Table of Contents

1. Quick Links
2. Mgen Usage
2.1. Example Usage
2.2. Example Script
3. Command-line Options
4. MGEN Run-Time Remote Control
5. MGEN Script Format
5.1. Transmission Events
5.1.1. ON Event
5.1.2. MOD Event
5.1.3. OFF Event
5.2. Transmission Event Options
5.2.1. Protocol (UDP/TCP/SINK)
5.2.2. Destination (DST)
5.2.3. Source Port (SRC)
5.2.4. COUNT
5.2.5. Pattern (PERIODIC, POISSON, BURST, JITTER, CLONE)
5.2.6. BROADCAST
5.2.7. LOGDATA
5.2.8. Type-Of-Service (TOS)
5.2.9. Multicast Time-To-Live (TTL)
5.2.10. Socket Transmit Buffer Size (TXBUFFER)
5.2.11. Socket Receive Buffer Size (RXBUFFER)
5.2.12. IPv6 Flow Label (LABEL)
5.2.13. Multicast Interface (INTERFACE)
5.2.14. Sequence Number Initialization (SEQUENCE)
5.2.15. UDP Connect (CONNECT)
5.3. Reception Events
5.3.1. LISTEN
5.3.2. IGNORE
5.3.3. JOIN
5.3.4. LEAVE
6. Global Commands
6.1. START
6.2. OFFSET
6.3. TOS
6.4. LABEL
6.5. TTL
6.6. TXBUFFER
6.7. RXBUFFER
6.8. LOCALTIME
6.9. QUEUE
6.10. DATA
6.11. INTERFACE
6.12. INPUT
6.13. OUTPUT
6.14. LOG
6.15. LOGDATA
6.16. SAVE
7. MGEN Log File Format
7.1. General Log Format
7.2. Log File RECV Events
7.3. Log File RERR Events
7.4. Log File SEND Events
7.5. Log File JOIN Events
7.6. Log File LEAVE Events
7.7. Log File LISTEN Events
7.8. Log File IGNORE Events
7.9. Log File ON Events
7.10. Log File CONNECT Events
7.11. Log File ACCEPT Events
7.. Log File SHUTDOWN Events
7.13. Log File DISCONNECT Events
7.14. Log File OFF Events
7.15. Log File START and STOP Events
8. Binary Log File Format
8.1. Binary Log File RECV Events
8.2. Binary Log File TCP Connection Events
8.3. Binary Log File RERR Events
8.4. Binary Log File SEND Events
8.5. Binary Log File LISTEN/IGNORE Events
8.6. Binary Log File JOIN/LEAVE Events
8.7. Binary Log File START/STOP Events
9. MGEN Message Payload
10. Compile options
10.1. RANDOM_FILL
10.2. HAVE_IPV6
10.3. SIMULATE
10.4. HAVE_GPS
10.5. HAVE_PCAP
10.6. Other
11. Known issues
11.1. Macosx Windows TCP Interaction

1. Quick Links

The Multi-Generator (MGEN) is open source software by the Naval Research Laboratory (NRL) PROTocol Engineering Advanced Networking (PROTEAN) group which provides the ability to perform IP network performance tests and measurements using UDP and TCP IP traffic. The toolset generates real-time traffic patterns so that the network can be loaded in a variety of ways. The generated traffic can also be received and logged for analyses. Script files are used to drive the generated loading patterns over the course of time. These script files can be used to emulate the traffic patterns of unicast and/or multicast UDP and TCP IP applications. The tool set can be scripted to dynamically join and leave IP multicast groups. MGEN log data can be used to calculate performance statistics on throughput, packet loss rates, communication delay, and more. MGEN currently runs on various Unix-based (including MacOS X) and WIN32 platforms.

The principal tool is the mgen program which can generate, receive, and log test traffic. This document provides information on mgen usage, message payload, and script and log file formats. Additional tools are available to facilitate automated script file creation and log file analyses.

2. Mgen Usage

The mgen version 5.0 program must currently be launched from a command-line. In the future, a simple graphical user interface similar to that of mgen version 3.x will be provided to simplify management of multiple sender and receiver instances. To launch mgen use the following command-line syntax:

mgen [ipv4][ipv6][input <scriptFile>][save <saveFile>]
      [output <logFile>][log <logFile>]
      [binary][txlog][nolog][flush][hostAddr {on|off}]
      [event "<mgen event>"][port <recvPortList>]
@@ -15,7 +15,10 @@
      [txcheck][rxcheck][check][stop]
      [convert <binaryLog>][debug <debugLevel>]
      [localtime <localtime>] [queue <queue>]
-     [broadcast {on|off}] [logdata {on|off}]

2.1. Example Usage

To run mgen with script file "script.mgn" and log to stdout (by default):

mgen input script.mgn

To monitor ports 5000,5004,5005, and 5006 for received UDP traffic and log to a specific file "log.drc":

mgen port 5000,5004-5006 output log.drc

The "event" command can be used to achieve equivalent operation with the command-line syntax:

mgen event "listen udp 5000,5004-5006" output log.drc

The "event" command allows for use of mgen without script files for "quick and dirty" runs. In the future, MGEN will be capable of being dynamically scripted during run time with "event" commands passed to MGEN via inter-process communication.

Note: In previous versions, two different programs (each with different scripts) were used to separately generate and receive test traffic. The traffic generation capability of the former mgen program and the receive-side functionality of the Dynamic-Receiver (drec) program have now been integrated into a single executable mgen program.

The file extensions ".mgn" for MGEN scripts and ".drc" for MGEN log files are suggested conventions that users might wish to use for consistency. The ".drc" naming is in honor of the deprecated drec program.

The "sink" and "source" commands can be used to stream MGEN messages via alternative transport processes (e.g. reliable multicast, ssh, peer-to-peer protocols, etc). Here is an example using ssh to set up a TCP connection to a remote machine, start an mgen receiver at the remote machine to log receive messages, and attempt to transmit a 2 Mbps stream of MGEN messages via the ssh connection:

mgen event "ON 1 SINK DST 127.0.0.1/5001 PERIODIC [200 1250]" \ sink STDOUT output /dev/null | ssh <remoteHost> sh -c "cat | \ mgen source STDIN output mgenLog.drc"

Note that the mgen executable must be present on the remote machine. Also note the importance of directing the MGEN sender's log output to /dev/null so that it doesn't get piped to the ssh process, mixed with the binary "sink" message stream.

2.2. Example Script

Below is an example MGEN script which generates two "flows" of UDP traffic and sends a single 1 megabyte TCP message. In this example, UDP flow 1 is sent to the loopback interface address (127.0.0.1) port 5001 and UDP flow 2 is sent to an IP multicast group on port number 5002. Flow 3 will send a 1 megabyte tcp "message" as it is turned off immediately after being started. (Note that the targeted TCP server must be listening for tcp connections on the port specified). Locally, a LISTEN command is used to monitor these (and other) ports so that mgen can receive its own traffic for demonstration purposes. This script illustrates the usage of a number of MGEN script commands.

# MGEN script begins here
+     [broadcast {on|off}] [logdata {on|off}]
+     [loggpsdata {on|off"]
+
+

2.1. Example Usage

To run mgen with script file "script.mgn" and log to stdout (by default):

mgen input script.mgn

To monitor ports 5000,5004,5005, and 5006 for received UDP traffic and log to a specific file "log.drc":

mgen port 5000,5004-5006 output log.drc

The "event" command can be used to achieve equivalent operation with the command-line syntax:

mgen event "listen udp 5000,5004-5006" output log.drc

The "event" command allows for use of mgen without script files for "quick and dirty" runs. In the future, MGEN will be capable of being dynamically scripted during run time with "event" commands passed to MGEN via inter-process communication.

Note: In previous versions, two different programs (each with different scripts) were used to separately generate and receive test traffic. The traffic generation capability of the former mgen program and the receive-side functionality of the Dynamic-Receiver (drec) program have now been integrated into a single executable mgen program.

The file extensions ".mgn" for MGEN scripts and ".drc" for MGEN log files are suggested conventions that users might wish to use for consistency. The ".drc" naming is in honor of the deprecated drec program.

The "sink" and "source" commands can be used to stream MGEN messages via alternative transport processes (e.g. reliable multicast, ssh, peer-to-peer protocols, etc). Here is an example using ssh to set up a TCP connection to a remote machine, start an mgen receiver at the remote machine to log receive messages, and attempt to transmit a 2 Mbps stream of MGEN messages via the ssh connection:

mgen event "ON 1 SINK DST 127.0.0.1/5001 PERIODIC [200 1250]" \ sink STDOUT output /dev/null | ssh <remoteHost> sh -c "cat | \ mgen source STDIN output mgenLog.drc"

Note that the mgen executable must be present on the remote machine. Also note the importance of directing the MGEN sender's log output to /dev/null so that it doesn't get piped to the ssh process, mixed with the binary "sink" message stream.

2.2. Example Script

Below is an example MGEN script which generates two "flows" of UDP traffic and sends a single 1 megabyte TCP message. In this example, UDP flow 1 is sent to the loopback interface address (127.0.0.1) port 5001 and UDP flow 2 is sent to an IP multicast group on port number 5002. Flow 3 will send a 1 megabyte tcp "message" as it is turned off immediately after being started. (Note that the targeted TCP server must be listening for tcp connections on the port specified). Locally, a LISTEN command is used to monitor these (and other) ports so that mgen can receive its own traffic for demonstration purposes. This script illustrates the usage of a number of MGEN script commands.

# MGEN script begins here
 # These are some "Transmission Event" script lines
 
 # Originate two UDP flows
@@ -41,12 +44,27 @@
 # Join an IP multicast group
 0.0 JOIN 224.225.1.2 INTERFACE eth0
 
+# Join a SSM multicast group (Supported only for *nix)
+#0.0 JOIN 232.1.1.1 SRC 25.25.25.1 INTERFACE eth0
+
 # For WIN32, use the "PORT" option
 0.0 JOIN 224.225.1.2 PORT 5002
 
+# For OSX use the "interface" option if a default multicast route is not defined
+#0.0 JOIN 224.1.2.3 interface en0
+
+# Join a multicast group across a range of ports
+0.0 JOIN 224.1.2.5 PORT 5005-5010
+
+# On IPv6 systems set the port option when IPv4 group membership is requested
+0.0 JOIN 224.1.2.4 port 5001
+
 # Later, leave the group
 5.0 LEAVE 224.225.1.2 INTERFACE eth0
 
+# This SSM LEAVE is for UNIX (Currently SSM is supported only in UNIX)
+#5.0 LEAVE 224.224.1.2 SRC 25.25.25.1 INTERFACE eth0
+
 # Incrementally ignore some receive traffic
 6.0 IGNORE UDP 5000-500
 18.0 IGNORE UDP 5001,6000,6003
@@ -55,13 +73,13 @@
 10.0 OFF 
 110.0 OFF 2
 
-# MGEN script ends here

3. Command-line Options

Some of these command-line options can also be included in MGEN script files as "global" commands or defaults. Note the command-line (or commands sent via MGEN's remote control interface) will always override settings from script files.

ipv4Forces mgen to open sockets for IPv4 operation (i.e. AF_INET domain sockets) only. The default behavior for mgen is to open sockets with the domain based on environment (e.g. RES_OPTIONS) variables and the type of IP addresses used in the script file used.
ipv6Forces mgen to open sockets for IPv6 operation (i.e. AF_INET6 domain sockets) only. The default behavior for mgen is to open sockets with the domain based on environment (e.g. RES_OPTIONS) variables and the type of IP addresses used in the script file used.
input<scriptFile>Causes mgen to parse the given <scriptFile> at startup and schedule any transmission or reception events given in the script.
save<saveFile>Causes mgen to save the sequence number state of any pending transmit flows and the current relative script "offset" time to <saveFile> in the form of an MGEN script. The <saveFile> may be used as an additional input script on a subsequent launch of mgento return mgen to the same state as when previously exited. See the equivalent global SAVE command for further detail on usage.
output<logFile>Cause mgen to output logged information to the indicated <logFile>. By default, mgen will log to stdout. With the output command, an existing <logFile> of the same name will be overwritten. Use the log command to append to an existing log file.
log<logFile>This is the same as the output command except that if <logFile> already exists, it will be appended instead of replaced.
binaryCauses mgen to save output logging information in a smaller-sized binary file format. This option should come before the output or log command.
txlogThis enables transmission logging. This results in SEND events being added to the log file every time a packet is sent by mgen.
nologThis disables logging completely.
flushThis causes the output log file to be flushed with each line written. This is useful for real-time monitoring of MGEN logging
hostAddr {on|off}Turning this option on causes mgen to include the "host" field in MGEN messages sent. The "host" field contains an educated guess of the machines local IP address to help identify the source of messages in log files. When the "host" field is present, MGEN log file SEND and RECV events contain a "host>" field indicating the sender's original address. This can be useful when Network Address Translation (NAT) or other tunneling occurs in test networks.
event"<mgen event>"The event command allows the user to enter the equivalent of MGEN script lines into mgen via the command-line. Multiple event commands can be used to pass the equivalent of a multi-line script to MGEN. Note that MGEN script events generally contain spaces and thus must be encapsulated in quotes on the command line. Note that the <eventTime> may be omitted and the action indicated will be taken by mgen immediately. When the

event

command is issued during run-time, the <eventTime> (if provided) specifies a delay relative to the current time (e.g. the event will occur with after the given delay).
instance<instanceName>If a pre-existing mgen application instance is _not_ already running, this command registers the running mgen program as an instance identified by the <instanceName>. On UNIX, this corresponds to a Unix-domain datagram socket named "/tmp/<instanceName>" being opened and monitored for MGEN commands (On WIN32, a "mailslot" named "\\.\mailslot\<instanceName>" is created and used). These interprocess channels allow for run-time control of mgen processes. This is the preferred methodology for run-time control of the mgen application.If an application instance as identified by the <instanceName> parameter is already running, any subsequent command-line options are transmitted to the remote instance already running, and the new mgen instance will then exit.This allows run-time control of possibly multiple background mgeninstances from the "shell" or via scripting. The event command may be used to dispatch MGEN script events to mgen instances at run-time.
command{<path>|STDIN}This specifies a file or device which mgen will monitor for run-time command input. If the "STDIN" key is used, mgenmonitors the "stdin" (console) input which can provide a crude run-time user interface for mgen. Commands sent to mgen in this fashion must be delimited by line-breaks or the ';' character. See the instance command for a more flexible, and the preferred option for mgen run-time control.
port<recvPortList>Causes mgen to monitor the given port numbers for received UDP traffic. The format of the <recvPortList> is a comma-delimited list of individual or inclusive ranges of port values (No spaces allowed in the list). Note this is the equivalent of a scripted

0.0 LISTEN UDP <recvPortList>

reception event and can also be equivalently achieved with the

event

command using the syntax:

mgen event "LISTEN UDP <portList>"Example:mgen port 5000,5002,5005-5009
sink<sinkFile>Causes mgento use the file or device (e.g. stdout) indicated as a "sink" or destination for transmitted message flows of protocol type "SINK". I.e., MGEN message flows of type "SINK" are written to the "sink" device instead of to a UDP or TCP socket. Piping mgen output to stdout allows MGEN messages to use alternative transport provided by another process (e.g. ssh, norm, etc). The special <sinkFile> value "STDOUT" will direct MGEN SINK flows to the mgen process stdout.
source<sourceFile>This is the complement to the

sink

command. This allows mgen to directly receive a binary stream of MGEN messaging from the <sourceFile> which may be the piped stdoutfrom another process (e.g. ssh, norm, etc). The special <sourceFile> string "STDIN" causes mgen to get input from its stdin stream. Messages read from the <sourceFile> (or stream) are time-stamped and logged in the MGEN log file as usual.
start<hr:min:sec>[GMT]Causes mgen to delay processing events in script file relative to the indicated absolute time. The optional "GMT" keyword indicates the time is Greenwich Mean Time instead of the default local time. This command establishes an absolute time for the relative script time of 0.0 seconds.
offset<sec>Causes mgen to skip <sec> seconds of relative time into the execution of the script file used. Note that if an absolute start time is given using the start command, the offset into the script will correspond to that absolute time. The default offset for MGEN is 0.0 seconds.
precise{on|off}When the precise mode is enable, mgen performs polling (only as needed) to precisely time packet transmission. While this is sometimes helpful at high packet transmission rates, it comes at a cost of high CPU utilization by mgen. The default for this option is "off".
ifinfo<interfaceName>This option can be used to have MGEN print a summary of statistics to stderr upon exit for the specified network interface. These stats include counts of frames sent/received. This can be used to augment/verify MGEN performance with or without logging enabled
convert<binaryLogFile>Causes mgen to convert the indicated <binaryLogFile> to a text-based log file. The text-based log file information will be directed to stdout unless you specify a filename with the output or log command. Mgen will exit after the file conversion is complete.
interface<interfaceName>Causes mgen to set the default network interface for IP multicast and/or root node flow transmission to <interfaceName>. <interfaceName> will override any default interface specified within an mgenscript file. <interfaceName> is a "per socket" attribute, and in its absence, MGEN will behave according to the operating system's default behavior.
ttl<timeToLive>Causes mgen to set the hop count for IP multicast traffic generated by MGEN. <timeToLive> will override any default ttl indicated within an mgen script file. <timeToLive> is a "per socket" attribute. If no ttl option is used, MGEN will behave according to the operating system's default behavior.
tos<typeOfService>Causes mgen to set the IPv4 type-of-service field (within the packet header) to <typeOfService>. <typeOfService> will override any default tos indicated within an mgen script file. As with ttl and interface, tos is a "per socket" attribute. If no tos option is used, MGEN will behave according to the operating system's default behavior.
label<value>Causes mgen to set <value> as the

default

flow label for IPv6 flows. The <value> corresponds to the 28-bit IPv6 flow label field and may be specified in decimal or hex.
txbuffer<bufferSize>Causes mgen to set the socket transmit buffer size to a value ?at least? as large as <bufferSize>. If <bufferSize> is larger that the maximum allowed by the system, <bufferSize> will be set to the system maximum.
rxbuffer<bufferSize>Causes mgento set the socket receive buffer size to a value ?at least? as large as <bufferSize>. If <bufferSize> is larger that the maximum allowed by the system, <bufferSize> will be set to the system maximum.
txcheckCauses mgen to include an optional 32-bit cyclic redundancy checksum (CRC) at the end of its messages. The CHECKSUM flag is set to indicate the presence of the checksum content.
rxcheckForces mgen receivers to validate the checksum portion (last 4 bytes) of MGEN messages whether or not the CHECKSUM flag is set in the MGEN "flags" message field. Use this option when it is _known_ that the MGEN sender is supplying checksums to cover the case when the "flags" field itself is possibly corrupted.
checkSets mgen behavior as if both the txcheck _and_ rxcheck commands were applied. This is the recommended option when MGEN checksum operation is desired so that both senders and receivers are providing and validating checksums, respectively.
stopThis command causes mgen to exit. This is useful for run-time control of mgen instances.
localtimeThis enables logging of events and error messages in localtime. By default, events are logged in Greenwich Mean Time.
queue<queueSize>This global command will cause mgen to buffer <queueSize> mgen packets for each flow during periods of congestion. (Note that flow specific limits specified at the transmission event level will override this global). When the number of pending messages for a flow exceeds this limit, the message transmission timer will be temporarily deactivated and any pending messages will transmitted as quickly as possible. The timer will be reactivated once the pending message count falls below the queue limit, and message transmission will return to the previously scheduled rate of transmission. If no global command is specified, a default <queueSize> of "0" will be in effect which will result in no queuing behavior, e.g. the transmission timer will continue to fire at its regularly scheduled interval regardless of transport congestion. No pending message count will be accumulated and message transmission will suceed or fail depending on transport availability. See QUEUE for more details about the queueing mechanism.
broadcast {on|off}Causes MGEN to set the socket option SO_BROADCAST to allow or disallow sending (and sometimes receiving) broadcasts from the socket. As with tos, ttl and interface, broadcast is a "per socket" attribute. By default BROADCAST is set to ON.
logdata {on|off}Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.

4. MGEN Run-Time Remote Control

To use the mgen "remote control interface":

  1. Start one (or more) instance(s) of mgen to control:

    mgen instance mgen1

  2. Subsequent invocations of mgen with the same instance name will pass provided commands to the first instance and then exit:

    mgen instance mgen1 event "on 1 udp dst 127.0.0.1/5000 periodic [1 1024]"

The second instance (Step #2) will exit after it has passed its commands to the first running instance as identified by the <instanceName>. Note this can allow run-time control of multiple mgen instances by user(s), shell scripts, or other processes. A programmer comfortable with use of Unix-domain sockets (or WIN32 mailslots) or using the NRL Protolib "ProtoPipe" C++ class can also write software for run-time control of MGEN processes.

5. MGEN Script Format

MGEN scripts are text files containing a sequence of commands and scheduled events describing traffic generation patterns, ports and/or multicast groups to be monitored, and other options. Each line in the script corresponds to either a "Transmission Event", or "Reception Event", or "Global Command". Lengthy script lines can be continued to multiple text file lines by using a trailing backslash '\' character at the end of the line. Additionally, blank lines are permitted and comment lines can be included by providing a leading '#' character at the beginning of lines. (Note comment lines cannot be inserted in between "continued" script lines). Currently mgen is case-sensitive in parsing the script file format (commands, options, etc are all upper case), but will be modified to be case-insensitive in the future.

Scheduled transmission and reception events in the script use lines in the format of:

[<eventTime>] <eventType> <parameters ...> [<options ...>]

These "events" are scheduled to be executed by MGEN at the relative time given by the <eventTime> field. The value of this field is a floating point number which denotes the relative time (in seconds) of the associated event. The time is relative to the start of the MGEN program or the time dictated by the global START command. If the <eventTime> is omitted, an <eventTime> of 0.0 (or immediately if MGEN is already started) is assumed (This can used with MGEN's "event" command to directly control the operation of ns-2 Agent/MGEN instances within an ns-2 TCL (Tool Command Language) script without use of an external MGEN script.

Global commands are generally used to define default behaviors for MGEN operation or other options independent of event scheduling. The format for global command script lines is:

<commandType> [<command parameters ...>]

5.1. Transmission Events

MGEN "Transmission Event" script lines are used to schedule and characterize mgen traffic generation. An instance of mgen can simultaneously transmit traffic to multiple destinations with different patterns of transmission. The MGEN script format uses "flow identifiers" (<flowIds>) to tag specific "threads" of MGEN traffic generation. While the <flowIds> are placed in the payload of associated MGEN messages, the primary purpose of the <flowId> is to simply tie together a sequence of script "transmission events" as a single "flow" or "thread".

The sequence of events pertaining to a "flow" of MGEN traffic generation consist of ON, MOD, and OFF . The script line syntax for these event types is:

<eventTime> {ON|MOD|OFF} <flowId> [<options ...>]

The first scripted event for a given flow identified by a <flowId> must be an ON event. Subsequently, MOD, events can be used to modify characteristics of the given flow until it is terminated with an OFF event. After a flow has been terminated with the OFF command, a flow with the same <flowId> value may be initiated with another ON event. The <options> fields are used to describe the characteristics of flows initiated with ON events and modified with subsequence MOD events. The OFF event uses no options.

5.1.1. ON Event

Script syntax:

<eventTime> ON <flowId> <protocol> [connect] DST <addr>/<port> <pattern [params]> [<options ...>] [DATA [<hex><hex>]]

This transmission event type is used to initiate a new flow at the time given by the <eventTime>. The <flowId> is used to identify the flow within the script and can be used by subsequent MOD, or OFF events to reference the flow initiated here.

The <protocol> field indicates the transport protocol to be used for the generated MGEN test messages. Current supported <protocol> types include "UDP", "TCP", and "SINK". The flow destination address and port must be specified for the ON event using the DST option and the <pattern> of message generation must be given as well. Other flow <options> may be specified to further characterize the flow. User defined message payload can be specified with the DATA command. The data should be a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data.

The "UDP" and "TCP" protocol types encapsulate generated MGEN messages for the flow into IP packets for the appropriate protocol and transmit them over the network. (Note that an mgen instance must be "listening" for a TCP connection on the destination port at the target node or the connection attempt will fail and the flow will be turned off). Messages for the "SINK" protocol type are written to the file/device/stream indicated by the mgen "sink" command-line option. In the future, other protocol types will be available for MGEN traffic flows.

The optional UDP CONNECT attribute will direct MGEN to open a "connected" UDP socket. If the connection cannot be established or is not available for a time period, MGEN will continue to attempt to send packets until the flow is stopped. (Note that Windows and some Unix implementations may not always report IGMP port unreachable messages returned by the destination address when a socket is not listening to the requested port.)

Example:

This script line will originate a "flow" of MGEN UDP destined for the loopback address (IP address 127.0.0.1) port number 5000 beginning immediately when the script is executed. The messages will consist of 1024 byte messages at a regular rate of 1.0 per second:

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

5.1.2. MOD Event

Script syntax:

<eventTime> MOD <flowId> [<options ...>]

This transmission event type is used to modify the characteristics of an existing flow identified by the <flowId> field. The given transmission event <options> determine which specific characteristics of the flow (e.g. PATTERN, TOS, destination (DST), connection status (CONNECT), broadcast, etc) will be affected. Multiple options may be specified in the script line. Note that the protocol type and source port number (SRC) cannot be changed with the MOD event type (the referenced flow should be terminated with an OFF event and re-initiated with an ON event to accomplish this goal). If no <options>are given, the flow will remain unaltered. A script parse error will result if the identified flow was not previously initiated with an ONevent.

Example:

This script line will modify "flow 1" to change it packet transmission pattern 5.0 seconds after script execution. The changed "flow 1" will then generate messages 512 bytes in size at an average rate of 10.0 messages per second following a Poisson (exponentially-distributed interval)

5.0 MOD 1 POISSON [10.0 512]

Example:

These commands will connect a previously unconnected UDP socket. Note that the original socket will be closed and any pending queue for the flow will be cleared.

ON 1 UDP SRC 5000 DST 192.168.1.101/5001 PERIODIC [1 1024]

5.0 MOD 1 CONNECT

Example:

These commands will disconnect a previously connected socket and change the source port to 5001. To keep the socket connected you must also specify the CONNECT attribute on the MOD command.

ON 1 UDP CONNECT SRC 5000 DST 192.168.1.101/5001 PERIODIC [1 1024]

5.0 MOD 1 SRC 5001

5.1.3. OFF Event

Script syntax:

<eventTime> OFF <flowId>

This transmission event type terminates message transmission for the flow identified by the <flowId> field at the time given in the <eventTime> field. There are no options applicable to this event type. A script parse error will result if the identified flow was not previously initiated with an ON event.

Example:

This script line will terminate generation of MGEN message traffic for "flow 1" at 10.0 seconds after script execution.

10.0 OFF 1

5.2. Transmission Event Options

This section describes options which may be applied to ON or MOD, transmission events in MGEN script files. Note that ON event lines require specification of at least the <protocol>, <destination>, and <pattern> options, while only the options to be changed need to be specified as part of MOD event lines.

5.2.1. Protocol (UDP/TCP/SINK)

Option syntax:

... <protocolType> ...

The transport protocol for MGEN messages generated by a flow must be specified as part of any ON events.

Example:

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

0.0 ON 2 TCP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

0.0 ON 3 SINK DST 127.0.0.1/5000 PERIODIC [1.0 1024]

5.2.2. Destination (DST)

Option syntax:

... DST <addr>/<port> ...

The destination address for a flow must be specified for ON events and may be altered as part of MOD, events. The <addr> field specifies the destination IP address (IPv4 or IPv6) and the <port> field specifies the destination host port number. The destination address may be a unicast (point-to-point) or multicast address.

Examples:

#Start a flow to loopback address port 5000

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

#Modify flow 1 to a different destination port

0.0 MOD 1 DST 127.0.0.1/5001

5.2.3. Source Port (SRC)

Option syntax:

... SRC <port> ...

The source port number used for generated traffic may be optionally specified as part of an ON event. The <port> field identifies the host port number to be used. When the SRC option is not specified or set to "0", the flow will use a free port number picked by the operating system. Note that MGEN UDP flows may share the same source port and the associated flow will "inherit" some attributes (e.g.TOS, TTL, BROADCAST etc) which may have been set for other flows which use that same source port. This is because some of these attributes tend to be maintained by operating systems on a "per socket" basis. Also, any such attributes set for this flow will affect other existing flows using the same source port. Thus, the SRC option is useful when it is desired to explicitly create different flows with distinct "per socket" attributes such as TOS or multicast TTL.

NOTE: Under the windows operating system, the ability to reestablish TCP connections to a common SRC addr/port DST addr/port pair is limited by TCP's TIME_WAIT interval which can range from 2 minutes to 30 seconds. During this operating system dependent interval, any attempt to reuse the socket pair will fail. Allowing the operating system to provide the SRC port will allow connections to a common dst/port to be successful within this interval. This behavior may also manifest under certain Linux distributions as well.

Example:

Here, two flows are created with the same destination address, but different source ports. Flow 1 is also assigned non-default type-of-service using the TOS option. The use of the SRC option ensures that two different sockets are used to support the two different types of service.

#Start flow 1 using source port 5001(TOS = 0x10) and flow 2 using port 5002

0.0 ON 1 UDP DST 127.0.0.1/5000 SRC 5001 PERIODIC [1.0 1024] TOS 0x10

0.0 ON 2 UDP DST 127.0.0.1/5000 SRC 5002 PERIODIC [10.0 512]

5.2.4. COUNT

Option syntax:

... COUNT <msgCount> ...

The optional COUNT attribute specifies the number of messages that are to be sent for the flow, e.g. a COUNT value of 1 means that one and only one mgen message will be sent. This attribute defaults to "-1", meaning mgen will send an unlimited number of messages until an OFF event occurs or the mgen program completes.

Note that an OFF event will override any message COUNT specified (e.g. the flow will be terminated even if <msgCount> messages have not been sent) and that the QUEUE attribute will override (defer) OFF events.

5.2.5. Pattern (PERIODIC, POISSON, BURST, JITTER, CLONE)

Option syntax:

... <patternType> [parameters ...] ...

(Note: The '[' and ']' characters are explicitly required at the beginning and end of the pattern parameter set. Different pattern types may use different parameter sets.)

Traffic generated by MGEN consists of a series of sequence-numbered messages. The messaging generated by MGEN may vary in size and frequency of transmission to stress the network in a controlled fashion or possibly emulate other network applications. The "Pattern" of message generation must be specified in ON events and may be altered as part of subsequent MOD, events. Currently MGEN supports four pattern types, "PERIODIC", "POISSON", "BURST", "JITTER", and "CLONE". Complex traffic patterns can be created by using a compound of multiple "flows" (with the same SRC/DST) with different pattern types and parameters. Other pattern types (e.g. MARKOV), including ones with statistically varying payload sizes, will be added eventually.

5.2.5.1. PERIODIC Pattern:

Option syntax:

... PERIODIC [<rate> <size>]...

This pattern type generates messages of a fixed <size> (in bytes) at a very regular <rate> (in messages/second). For UDP protocol, the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at a rate of 10.0 per second

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [10.0 1024]

#Reduce the flow rate to one 512 byte message

#every 2.0 seconds

0.0 MOD 1 PERIODIC [0.5 512]

5.2.5.2. POISSON Pattern:

Option syntax:

... POISSON [<aveRate (msg/sec)> <size (bytes)>] ...

This pattern type generates messages of a fixed <size> (in bytes) at statistically varying intervals at an average <rate> (in messages/second). For UDP protocol, the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at an average rate of 10.0 per second

0.0 ON 1 UDP DST 127.0.0.1/5000 POISSON [10.0 1024]

#Reduce the flow rate to an average of one

#512 byte message every 2.0 seconds

0.0 MOD 1 POISSON [0.5 512]

5.2.5.3. BURST Pattern:

Option syntax:

... BURST [REGULAR|RANDOM <aveInterval (sec)> <patternType> [<patternParams>] FIXED|EXPONENTIAL <aveDuration (sec)>] ...

The BURST pattern generates bursts of other MGEN pattern types at a specified average interval. The first parameter of the BURST pattern is either "REGULAR" resulting in periodic burst uniformly distributed in time by the <aveInterval> value, or "RANDOM" which exponentially distributes the traffic generation bursts in time with an average burst interval as specified by the <aveInterval> parameter value. The characteristics of the MGEN messages generated during a burst is given by the <patternType> and associated <patternParams> parameters. The <patternType> may any MGEN pattern type including PERIODIC, POISSON, or, yes, even BURST. The <patternParams> must be appropriate for the given <patternType>. When a traffic generation burst occurs, its duration is either of a FIXED value as given by the <aveDuration> or a randomly varying duration with EXPONENTIAL statistics and an average duration as given by the <aveDuration> parameter.

An example use of the BURST pattern would be to roughly emulate the "talk spurts" which might result from Voice Over IP (VOIP) applications. As a voice conversation commences, a user's burst of activity (talk spurts) might be RANDOM with some average interval and the duration talk spurts approximate EXPONENTIAL statistics. > When the talk spurt (burst) occurs, the voice compression codec might generate messages following something like a PERIODIC flow with packet rates and packet sizes dependent upon the voice codec in use.

Other uses of the BURST pattern might be to roughly model message/packet generation occurring with random use of a network such as web browsing, etc. The BURST model provided by MGEN does not presuppose any specific traffic model, but might be useful in approximating some models of regular or intermittent network activity.

The average traffic generation rate for this pattern should be approximately the average transmission rate of the core <patternType> and <patternParams> multiplied by the burst duty cycle (<aveDuration> / <aveInterval>). Note that when average burst duration tends to exceed the average burst interval, the flow will tend to follow the characteristics of the core pattern (i.e. 100% duty cycle).

Example:

#Start a bursty MGEN flow with bursts of 1024 byte messages

#with a periodic rate of 10.0 messages per second. The

#bursts will occur at random intervals with an average

#interval from the start of one burst until the start of

#the next of 10.0 seconds. The duration of each burst is

#of exponential statistics with an average burst duration

#of 5.0 seconds.

0.0 ON 1 UDP DST 127.0.0.1/5000 BURST [RANDOM 10.0 PERIODIC [10.0 1024] EXP 5.0]

5.2.5.4. JITTER Pattern:

Option syntax:

... JITTER [<rate> <size> <jitterFraction>]...

This pattern type generates messages of a fixed <size> (in bytes) with the specified jitter pattern defined by the <rate> (in messages/second) and <jitterFraction>. The jitterFraction defines the interval of deviation from the rate and must be greater than zero and less than 0.5. A jitter pattern of "JITTER [1 1024 .5]" will result in packets being sent at a random interval between 0.5 seconds and 1.5 seconds. For the UDP protocol the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at a random interval between 0.5 and 1.5 seconds.

0.0 ON 1 UDP DST 127.0.0.1/5000 JITTER [1.0 1024 .5]

5.2.5.5. CLONE Pattern:

Option syntax:

... CLONE [<fileType> <fileName> [<repeatCount>]]...

This pattern type will incrementally read a file of the specified <fileType> to determine mgen packet sizes and message transmission intervals. Currently only tcpdump binary files are supported. It is assumed that the tcpdump file has been filtered to contain only the traffic that is to be "cloned".

At the flow event start time mgen will send a packet corresponding to the size of the first packet read from the file. Note that mgen assumes the records contain IPv4 UDP headers and therefore subtracts 42 bytes from the captured frame size reported by tcpdump. The second packet will be read from the file and a the second mgen packet of the same size will be sent as scheduled by the interval between the first and second packets. When the file is rewound, the first packet will not be transmitted. The second packet in the file will be scheduled to be sent after the last packet in the file according to the interval between the first and second packets in the file.

At present the only valid <fileType> is "tcpdump". The tcpdump file must be in binary format (created with tcpdump's -w option) and is assumed to be filtered to contain only the traffic that is to be cloned.

<fileName> is the name of the file containing the data to be used as the template for the MGEN pattern timing (packet intervals) and packet size(s).

<repeatCount> is an optional parameter that specifies the number of times the file is to be processed. <repeatCount> can be set to "-1" (the default), "0", or a positive integer. "-1" causes the file to be continuously read until the flow is stopped by an OFF event or the mgen program ends. "0" directs mgen to clone the file once and stop. A positive integer "N" indicates the number of repititions through the file, e.g. a value of 1 will cause the file to be read twice, once plus the repeat.

Out of sequence time stamps have been seen occasionally in tcpdump output. MGEN will schedule these packets for immediate transmission and if running at debug level 2, will log a warning message.

Note that some Linux distributions enable "segmentation/reassembly offload". This feature causes the network driver to do TCP segmentation and reassembly. In such case, larger packets than MGEN can clone will be logged in the pcap files. Disable this feature to successfully process this data. (e.g. ethtool --offload eth0 gso off; ethtool --offload eth0 tso off; ethtool --offload eth0 gro off).

Example:

#Start an MGEN flow and clone the contents of the specified file once

0.0 ON 1 UDP DST 127.0.0.1/5000 CLONE [tcpdump tcpdump.dat [0]]

5.2.6. BROADCAST

Option syntax:

... BROADCAST {ON|OFF} ...

This sets the SO_BROADCAST socket option to enable or disable the sending (and sometimes receiving) of broadcast messages. By default BROADCAST is ON.

5.2.7. LOGDATA

Option syntax:

... LOGDATA {ON|OFF} ...

Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is ON.

5.2.8. Type-Of-Service (TOS)

Option syntax:

... TOS <value> ...

The IP TOS (type-of-service) field can be controlled for IP packets associated with MGEN traffic generation. The <value> field specifies the value of the 8-bit TOS field in IPv4 packets. (IPv6 packets do not have a TOS field. MGEN will soon support control of the similar FLOW_ID field for IPv6 operation.) The <value> field must be in the range of 0-255 in decimal or hexadecimal notation. The interpretation of the TOS value by different computer operating systems and network devices may vary. In some cases, computer hosts will not allow all possible values to be used, and in others "super user" (root) privileges may be required to set the IP TOS field to certain values. Below are some notes on suggested interpretation by the Internet Engineering Task Force (IETF). Note that TOS is maintained on a "per socket" basis and that setting the TOS for a flow will affect other flows sharing the same network socket. See the SRC option to make sure different flows use different sockets.

Example:

#Start flow 1 with default TOS

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

#Modify flow 1 to TOS = 0x10 (low delay)

5.0 MOD 1 TOS 0x10

Notes on the value of the IP TOS field:

    
+# MGEN script ends here

3. Command-line Options

Some of these command-line options can also be included in MGEN script files as "global" commands or defaults. Note the command-line (or commands sent via MGEN's remote control interface) will always override settings from script files.

ipv4Forces mgen to open sockets for IPv4 operation (i.e. AF_INET domain sockets) only. The default behavior for mgen is to open sockets with the domain based on environment (e.g. RES_OPTIONS) variables and the type of IP addresses used in the script file used.
ipv6Forces mgen to open sockets for IPv6 operation (i.e. AF_INET6 domain sockets) only. The default behavior for mgen is to open sockets with the domain based on environment (e.g. RES_OPTIONS) variables and the type of IP addresses used in the script file used.
input<scriptFile>Causes mgen to parse the given <scriptFile> at startup and schedule any transmission or reception events given in the script.
save<saveFile>Causes mgen to save the sequence number state of any pending transmit flows and the current relative script "offset" time to <saveFile> in the form of an MGEN script. The <saveFile> may be used as an additional input script on a subsequent launch of mgento return mgen to the same state as when previously exited. See the equivalent global SAVE command for further detail on usage.
output<logFile>Cause mgen to output logged information to the indicated <logFile>. By default, mgen will log to stdout. With the output command, an existing <logFile> of the same name will be overwritten. Use the log command to append to an existing log file.
log<logFile>This is the same as the output command except that if <logFile> already exists, it will be appended instead of replaced.
binaryCauses mgen to save output logging information in a smaller-sized binary file format. This option should come before the output or log command.
txlogThis enables transmission logging. This results in SEND events being added to the log file every time a packet is sent by mgen.
nologThis disables logging completely.
flushThis causes the output log file to be flushed with each line written. This is useful for real-time monitoring of MGEN logging
hostAddr {on|off}Turning this option on causes mgen to include the "host" field in MGEN messages sent. The "host" field contains an educated guess of the machines local IP address to help identify the source of messages in log files. When the "host" field is present, MGEN log file SEND and RECV events contain a "host>" field indicating the sender's original address. This can be useful when Network Address Translation (NAT) or other tunneling occurs in test networks.
event"<mgen event>"The event command allows the user to enter the equivalent of MGEN script lines into mgen via the command-line. Multiple event commands can be used to pass the equivalent of a multi-line script to MGEN. Note that MGEN script events generally contain spaces and thus must be encapsulated in quotes on the command line. Note that the <eventTime> may be omitted and the action indicated will be taken by mgen immediately. When the

event

command is issued during run-time, the <eventTime> (if provided) specifies a delay relative to the current time (e.g. the event will occur with after the given delay).
instance<instanceName>If a pre-existing mgen application instance is _not_ already running, this command registers the running mgen program as an instance identified by the <instanceName>. On UNIX, this corresponds to a Unix-domain datagram socket named "/tmp/<instanceName>" being opened and monitored for MGEN commands (On WIN32, a "mailslot" named "\\.\mailslot\<instanceName>" is created and used). These interprocess channels allow for run-time control of mgen processes. This is the preferred methodology for run-time control of the mgen application.If an application instance as identified by the <instanceName> parameter is already running, any subsequent command-line options are transmitted to the remote instance already running, and the new mgen instance will then exit.This allows run-time control of possibly multiple background mgeninstances from the "shell" or via scripting. The event command may be used to dispatch MGEN script events to mgen instances at run-time.
command{<path>|STDIN}This specifies a file or device which mgen will monitor for run-time command input. If the "STDIN" key is used, mgenmonitors the "stdin" (console) input which can provide a crude run-time user interface for mgen. Commands sent to mgen in this fashion must be delimited by line-breaks or the ';' character. See the instance command for a more flexible, and the preferred option for mgen run-time control.
port<recvPortList>Causes mgen to monitor the given port numbers for received UDP traffic. The format of the <recvPortList> is a comma-delimited list of individual or inclusive ranges of port values (No spaces allowed in the list). Note this is the equivalent of a scripted

0.0 LISTEN UDP <recvPortList>

reception event and can also be equivalently achieved with the

event

command using the syntax:

mgen event "LISTEN UDP <portList>"Example:mgen port 5000,5002,5005-5009
sink<sinkFile>Causes mgento use the file or device (e.g. stdout) indicated as a "sink" or destination for transmitted message flows of protocol type "SINK". I.e., MGEN message flows of type "SINK" are written to the "sink" device instead of to a UDP or TCP socket. Piping mgen output to stdout allows MGEN messages to use alternative transport provided by another process (e.g. ssh, norm, etc). The special <sinkFile> value "STDOUT" will direct MGEN SINK flows to the mgen process stdout.
source<sourceFile>This is the complement to the

sink

command. This allows mgen to directly receive a binary stream of MGEN messaging from the <sourceFile> which may be the piped stdoutfrom another process (e.g. ssh, norm, etc). The special <sourceFile> string "STDIN" causes mgen to get input from its stdin stream. Messages read from the <sourceFile> (or stream) are time-stamped and logged in the MGEN log file as usual.
start<hr:min:sec>[GMT]Causes mgen to delay processing events in script file relative to the indicated absolute time. The optional "GMT" keyword indicates the time is Greenwich Mean Time instead of the default local time. This command establishes an absolute time for the relative script time of 0.0 seconds.
offset<sec>Causes mgen to skip <sec> seconds of relative time into the execution of the script file used. Note that if an absolute start time is given using the start command, the offset into the script will correspond to that absolute time. The default offset for MGEN is 0.0 seconds.
precise{on|off}When the precise mode is enable, mgen performs polling (only as needed) to precisely time packet transmission. While this is sometimes helpful at high packet transmission rates, it comes at a cost of high CPU utilization by mgen. The default for this option is "off".
ifinfo<interfaceName>This option can be used to have MGEN print a summary of statistics to stderr upon exit for the specified network interface. These stats include counts of frames sent/received. This can be used to augment/verify MGEN performance with or without logging enabled
convert<binaryLogFile>Causes mgen to convert the indicated <binaryLogFile> to a text-based log file. The text-based log file information will be directed to stdout unless you specify a filename with the output or log command. Mgen will exit after the file conversion is complete.
interface<interfaceName>Causes mgen to set the default network interface for IP multicast and/or root node flow transmission to <interfaceName>. <interfaceName> will override any default interface specified within an mgenscript file. <interfaceName> is a "per socket" attribute, and in its absence, MGEN will behave according to the operating system's default behavior.
ttl<timeToLive>Causes mgen to set the hop count for IP multicast traffic generated by MGEN. <timeToLive> will override any default ttl indicated within an mgen script file. <timeToLive> is a "per socket" attribute. If no ttl option is used, MGEN will behave according to the operating system's default behavior.
tos<typeOfService>Causes mgen to set the IPv4 type-of-service field (within the packet header) to <typeOfService>. <typeOfService> will override any default tos indicated within an mgen script file. As with ttl and interface, tos is a "per socket" attribute. If no tos option is used, MGEN will behave according to the operating system's default behavior.
label<value>Causes mgen to set <value> as the

default

flow label for IPv6 flows. The <value> corresponds to the 28-bit IPv6 flow label field and may be specified in decimal or hex.
txbuffer<bufferSize>Causes mgen to set the socket transmit buffer size to a value ?at least? as large as <bufferSize>. If <bufferSize> is larger that the maximum allowed by the system, <bufferSize> will be set to the system maximum.
rxbuffer<bufferSize>Causes mgento set the socket receive buffer size to a value ?at least? as large as <bufferSize>. If <bufferSize> is larger that the maximum allowed by the system, <bufferSize> will be set to the system maximum.
txcheckCauses mgen to include an optional 32-bit cyclic redundancy checksum (CRC) at the end of its messages. The CHECKSUM flag is set to indicate the presence of the checksum content.
rxcheckForces mgen receivers to validate the checksum portion (last 4 bytes) of MGEN messages whether or not the CHECKSUM flag is set in the MGEN "flags" message field. Use this option when it is _known_ that the MGEN sender is supplying checksums to cover the case when the "flags" field itself is possibly corrupted.
checkSets mgen behavior as if both the txcheck _and_ rxcheck commands were applied. This is the recommended option when MGEN checksum operation is desired so that both senders and receivers are providing and validating checksums, respectively.
stopThis command causes mgen to exit. This is useful for run-time control of mgen instances.
localtimeThis enables logging of events and error messages in localtime. By default, events are logged in Greenwich Mean Time.
queue<queueSize>This global command will cause mgen to buffer <queueSize> mgen packets for each flow during periods of congestion. (Note that flow specific limits specified at the transmission event level will override this global). When the number of pending messages for a flow exceeds this limit, the message transmission timer will be temporarily deactivated and any pending messages will transmitted as quickly as possible. The timer will be reactivated once the pending message count falls below the queue limit, and message transmission will return to the previously scheduled rate of transmission. If no global command is specified, a default <queueSize> of "0" will be in effect which will result in no queuing behavior, e.g. the transmission timer will continue to fire at its regularly scheduled interval regardless of transport congestion. No pending message count will be accumulated and message transmission will suceed or fail depending on transport availability. See QUEUE for more details about the queueing mechanism.
broadcast {on|off}Causes MGEN to set the socket option SO_BROADCAST to allow or disallow sending (and sometimes receiving) broadcasts from the socket. As with tos, ttl and interface, broadcast is a "per socket" attribute. By default BROADCAST is set to ON.
logdata {on|off}Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.
loggpsdata {on|off}Controls whether MGEN will log the gps data fields at MGEN receivers. It does not affect whether MGEN senders send the GPS data. By default LOGGPSDATA is set to ON. Note that as opposed to the logdata attribute, GPS data will be saved in any interim binary log file regardless of this flag. This flag only controls whether the gps data is logged in the formatted log files.
boostThe boost option sets the mgen process to realtime process priority. Care should be taken using the "precise" and "boost" options together as the mgen process can take over a machine at high packet rates (e.g. ctrl-c may not be handled).

4. MGEN Run-Time Remote Control

To use the mgen "remote control interface":

  1. Start one (or more) instance(s) of mgen to control:

    mgen instance mgen1

  2. Subsequent invocations of mgen with the same instance name will pass provided commands to the first instance and then exit:

    mgen instance mgen1 event "on 1 udp dst 127.0.0.1/5000 periodic [1 1024]"

The second instance (Step #2) will exit after it has passed its commands to the first running instance as identified by the <instanceName>. Note this can allow run-time control of multiple mgen instances by user(s), shell scripts, or other processes. A programmer comfortable with use of Unix-domain sockets (or WIN32 mailslots) or using the NRL Protolib "ProtoPipe" C++ class can also write software for run-time control of MGEN processes.

5. MGEN Script Format

MGEN scripts are text files containing a sequence of commands and scheduled events describing traffic generation patterns, ports and/or multicast groups to be monitored, and other options. Each line in the script corresponds to either a "Transmission Event", or "Reception Event", or "Global Command". Lengthy script lines can be continued to multiple text file lines by using a trailing backslash '\' character at the end of the line. Additionally, blank lines are permitted and comment lines can be included by providing a leading '#' character at the beginning of lines. (Note comment lines cannot be inserted in between "continued" script lines). Currently mgen is case-sensitive in parsing the script file format (commands, options, etc are all upper case), but will be modified to be case-insensitive in the future.

Scheduled transmission and reception events in the script use lines in the format of:

[<eventTime>] <eventType> <parameters ...> [<options ...>]

These "events" are scheduled to be executed by MGEN at the relative time given by the <eventTime> field. The value of this field is a floating point number which denotes the relative time (in seconds) of the associated event. The time is relative to the start of the MGEN program or the time dictated by the global START command. If the <eventTime> is omitted, an <eventTime> of 0.0 (or immediately if MGEN is already started) is assumed (This can used with MGEN's "event" command to directly control the operation of ns-2 Agent/MGEN instances within an ns-2 TCL (Tool Command Language) script without use of an external MGEN script.

Global commands are generally used to define default behaviors for MGEN operation or other options independent of event scheduling. The format for global command script lines is:

<commandType> [<command parameters ...>]

5.1. Transmission Events

MGEN "Transmission Event" script lines are used to schedule and characterize mgen traffic generation. An instance of mgen can simultaneously transmit traffic to multiple destinations with different patterns of transmission. The MGEN script format uses "flow identifiers" (<flowIds>) to tag specific "threads" of MGEN traffic generation. While the <flowIds> are placed in the payload of associated MGEN messages, the primary purpose of the <flowId> is to simply tie together a sequence of script "transmission events" as a single "flow" or "thread".

The sequence of events pertaining to a "flow" of MGEN traffic generation consist of ON, MOD, and OFF . The script line syntax for these event types is:

<eventTime> {ON|MOD|OFF} <flowId> [<options ...>]

The first scripted event for a given flow identified by a <flowId> must be an ON event. Subsequently, MOD, events can be used to modify characteristics of the given flow until it is terminated with an OFF event. After a flow has been terminated with the OFF command, a flow with the same <flowId> value may be initiated with another ON event. The <options> fields are used to describe the characteristics of flows initiated with ON events and modified with subsequence MOD events. The OFF event uses no options.

5.1.1. ON Event

Script syntax:

<eventTime> ON <flowId> <protocol> [connect] DST <addr>/<port> <pattern [params]> [<options ...>] [DATA [<hex><hex>]]

This transmission event type is used to initiate a new flow at the time given by the <eventTime>. The <flowId> is used to identify the flow within the script and can be used by subsequent MOD, or OFF events to reference the flow initiated here.

The <protocol> field indicates the transport protocol to be used for the generated MGEN test messages. Current supported <protocol> types include "UDP", "TCP", and "SINK". The flow destination address and port must be specified for the ON event using the DST option and the <pattern> of message generation must be given as well. Other flow <options> may be specified to further characterize the flow. User defined message payload can be specified with the DATA command. The data should be a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data.

The "UDP" and "TCP" protocol types encapsulate generated MGEN messages for the flow into IP packets for the appropriate protocol and transmit them over the network. (Note that an mgen instance must be "listening" for a TCP connection on the destination port at the target node or the connection attempt will fail and the flow will be turned off). Messages for the "SINK" protocol type are written to the file/device/stream indicated by the mgen "sink" command-line option. In the future, other protocol types will be available for MGEN traffic flows.

The optional UDP CONNECT attribute will direct MGEN to open a "connected" UDP socket. If the connection cannot be established or is not available for a time period, MGEN will continue to attempt to send packets until the flow is stopped. (Note that Windows and some Unix implementations may not always report IGMP port unreachable messages returned by the destination address when a socket is not listening to the requested port.)

Example:

This script line will originate a "flow" of MGEN UDP destined for the loopback address (IP address 127.0.0.1) port number 5000 beginning immediately when the script is executed. The messages will consist of 1024 byte messages at a regular rate of 1.0 per second:

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

5.1.2. MOD Event

Script syntax:

<eventTime> MOD <flowId> [<options ...>]

This transmission event type is used to modify the characteristics of an existing flow identified by the <flowId> field. The given transmission event <options> determine which specific characteristics of the flow (e.g. PATTERN, TOS, destination (DST), connection status (CONNECT), broadcast, etc) will be affected. Multiple options may be specified in the script line. Note that the protocol type and source port number (SRC) cannot be changed with the MOD event type (the referenced flow should be terminated with an OFF event and re-initiated with an ON event to accomplish this goal). If no <options>are given, the flow will remain unaltered. A script parse error will result if the identified flow was not previously initiated with an ONevent.

Example:

This script line will modify "flow 1" to change it packet transmission pattern 5.0 seconds after script execution. The changed "flow 1" will then generate messages 512 bytes in size at an average rate of 10.0 messages per second following a Poisson (exponentially-distributed interval)

5.0 MOD 1 POISSON [10.0 512]

Example:

These commands will connect a previously unconnected UDP socket. Note that the original socket will be closed and any pending queue for the flow will be cleared.

ON 1 UDP SRC 5000 DST 192.168.1.101/5001 PERIODIC [1 1024]

5.0 MOD 1 CONNECT

Example:

These commands will disconnect a previously connected socket and change the source port to 5001. To keep the socket connected you must also specify the CONNECT attribute on the MOD command.

ON 1 UDP CONNECT SRC 5000 DST 192.168.1.101/5001 PERIODIC [1 1024]

5.0 MOD 1 SRC 5001

5.1.3. OFF Event

Script syntax:

<eventTime> OFF <flowId>

This transmission event type terminates message transmission for the flow identified by the <flowId> field at the time given in the <eventTime> field. There are no options applicable to this event type. A script parse error will result if the identified flow was not previously initiated with an ON event.

Example:

This script line will terminate generation of MGEN message traffic for "flow 1" at 10.0 seconds after script execution.

10.0 OFF 1

5.2. Transmission Event Options

This section describes options which may be applied to ON or MOD, transmission events in MGEN script files. Note that ON event lines require specification of at least the <protocol>, <destination>, and <pattern> options, while only the options to be changed need to be specified as part of MOD event lines.

5.2.1. Protocol (UDP/TCP/SINK)

Option syntax:

... <protocolType> ...

The transport protocol for MGEN messages generated by a flow must be specified as part of any ON events.

Example:

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

0.0 ON 2 TCP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

0.0 ON 3 SINK DST 127.0.0.1/5000 PERIODIC [1.0 1024]

5.2.2. Destination (DST)

Option syntax:

... DST <addr>/<port> ...

The destination address for a flow must be specified for ON events and may be altered as part of MOD, events. The <addr> field specifies the destination IP address (IPv4 or IPv6) and the <port> field specifies the destination host port number. The destination address may be a unicast (point-to-point) or multicast address.

Examples:

#Start a flow to loopback address port 5000

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

#Modify flow 1 to a different destination port

0.0 MOD 1 DST 127.0.0.1/5001

5.2.3. Source Port (SRC)

Option syntax:

... SRC <port> ...

The source port number used for generated traffic may be optionally specified as part of an ON event. The <port> field identifies the host port number to be used. When the SRC option is not specified or set to "0", the flow will use a free port number picked by the operating system. Note that MGEN UDP flows may share the same source port and the associated flow will "inherit" some attributes (e.g.TOS, TTL, BROADCAST etc) which may have been set for other flows which use that same source port. This is because some of these attributes tend to be maintained by operating systems on a "per socket" basis. Also, any such attributes set for this flow will affect other existing flows using the same source port. Thus, the SRC option is useful when it is desired to explicitly create different flows with distinct "per socket" attributes such as TOS or multicast TTL.

NOTE: Under the windows operating system, the ability to reestablish TCP connections to a common SRC addr/port DST addr/port pair is limited by TCP's TIME_WAIT interval which can range from 2 minutes to 30 seconds. During this operating system dependent interval, any attempt to reuse the socket pair will fail. Allowing the operating system to provide the SRC port will allow connections to a common dst/port to be successful within this interval. This behavior may also manifest under certain Linux distributions as well.

Example:

Here, two flows are created with the same destination address, but different source ports. Flow 1 is also assigned non-default type-of-service using the TOS option. The use of the SRC option ensures that two different sockets are used to support the two different types of service.

#Start flow 1 using source port 5001(TOS = 0x10) and flow 2 using port 5002

0.0 ON 1 UDP DST 127.0.0.1/5000 SRC 5001 PERIODIC [1.0 1024] TOS 0x10

0.0 ON 2 UDP DST 127.0.0.1/5000 SRC 5002 PERIODIC [10.0 512]

5.2.4. COUNT

Option syntax:

... COUNT <msgCount> ...

The optional COUNT attribute specifies the number of messages that are to be sent for the flow, e.g. a COUNT value of 1 means that one and only one mgen message will be sent. This attribute defaults to "-1", meaning mgen will send an unlimited number of messages until an OFF event occurs or the mgen program completes. If a message count is specified, the mgen flow will be stopped after the requested number of messages has been sent.

Note that an OFF event will override any message COUNT specified (e.g. the flow will be terminated even if <msgCount> messages have not been sent) and that the QUEUE attribute will override (defer) OFF events.

5.2.5. Pattern (PERIODIC, POISSON, BURST, JITTER, CLONE)

Option syntax:

... <patternType> [parameters ...] ...

(Note: The '[' and ']' characters are explicitly required at the beginning and end of the pattern parameter set. Different pattern types may use different parameter sets.)

Traffic generated by MGEN consists of a series of sequence-numbered messages. The messaging generated by MGEN may vary in size and frequency of transmission to stress the network in a controlled fashion or possibly emulate other network applications. The "Pattern" of message generation must be specified in ON events and may be altered as part of subsequent MOD, events. Currently MGEN supports four pattern types, "PERIODIC", "POISSON", "BURST", "JITTER", and "CLONE". Complex traffic patterns can be created by using a compound of multiple "flows" (with the same SRC/DST) with different pattern types and parameters. Other pattern types (e.g. MARKOV), including ones with statistically varying payload sizes, will be added eventually.

5.2.5.1. PERIODIC Pattern:

Option syntax:

... PERIODIC [<rate> <size>]...

This pattern type generates messages of a fixed <size> (in bytes) at a very regular <rate> (in messages/second). For UDP protocol, the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at a rate of 10.0 per second

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [10.0 1024]

#Reduce the flow rate to one 512 byte message

#every 2.0 seconds

0.0 MOD 1 PERIODIC [0.5 512]

5.2.5.2. POISSON Pattern:

Option syntax:

... POISSON [<aveRate (msg/sec)> <size (bytes)>] ...

This pattern type generates messages of a fixed <size> (in bytes) at statistically varying intervals at an average <rate> (in messages/second). For UDP protocol, the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at an average rate of 10.0 per second

0.0 ON 1 UDP DST 127.0.0.1/5000 POISSON [10.0 1024]

#Reduce the flow rate to an average of one

#512 byte message every 2.0 seconds

0.0 MOD 1 POISSON [0.5 512]

5.2.5.3. BURST Pattern:

Option syntax:

... BURST [REGULAR|RANDOM <aveInterval (sec)> <patternType> [<patternParams>] FIXED|EXPONENTIAL <aveDuration (sec)>] ...

The BURST pattern generates bursts of other MGEN pattern types at a specified average interval. The first parameter of the BURST pattern is either "REGULAR" resulting in periodic burst uniformly distributed in time by the <aveInterval> value, or "RANDOM" which exponentially distributes the traffic generation bursts in time with an average burst interval as specified by the <aveInterval> parameter value. The characteristics of the MGEN messages generated during a burst is given by the <patternType> and associated <patternParams> parameters. The <patternType> may any MGEN pattern type including PERIODIC, POISSON, or, yes, even BURST. The <patternParams> must be appropriate for the given <patternType>. When a traffic generation burst occurs, its duration is either of a FIXED value as given by the <aveDuration> or a randomly varying duration with EXPONENTIAL statistics and an average duration as given by the <aveDuration> parameter.

An example use of the BURST pattern would be to roughly emulate the "talk spurts" which might result from Voice Over IP (VOIP) applications. As a voice conversation commences, a user's burst of activity (talk spurts) might be RANDOM with some average interval and the duration talk spurts approximate EXPONENTIAL statistics. > When the talk spurt (burst) occurs, the voice compression codec might generate messages following something like a PERIODIC flow with packet rates and packet sizes dependent upon the voice codec in use.

Other uses of the BURST pattern might be to roughly model message/packet generation occurring with random use of a network such as web browsing, etc. The BURST model provided by MGEN does not presuppose any specific traffic model, but might be useful in approximating some models of regular or intermittent network activity.

The average traffic generation rate for this pattern should be approximately the average transmission rate of the core <patternType> and <patternParams> multiplied by the burst duty cycle (<aveDuration> / <aveInterval>). Note that when average burst duration tends to exceed the average burst interval, the flow will tend to follow the characteristics of the core pattern (i.e. 100% duty cycle).

Example:

#Start a bursty MGEN flow with bursts of 1024 byte messages

#with a periodic rate of 10.0 messages per second. The

#bursts will occur at random intervals with an average

#interval from the start of one burst until the start of

#the next of 10.0 seconds. The duration of each burst is

#of exponential statistics with an average burst duration

#of 5.0 seconds.

0.0 ON 1 UDP DST 127.0.0.1/5000 BURST [RANDOM 10.0 PERIODIC [10.0 1024] EXP 5.0]

5.2.5.4. JITTER Pattern:

Option syntax:

... JITTER [<rate> <size> <jitterFraction>]...

This pattern type generates messages of a fixed <size> (in bytes) with the specified jitter pattern defined by the <rate> (in messages/second) and <jitterFraction>. The jitterFraction defines the interval of deviation from the rate and must be greater than zero and less than 0.5. A jitter pattern of "JITTER [1 1024 .5]" will result in packets being sent at a random interval between 0.5 seconds and 1.5 seconds. For the UDP protocol the <size> field must be greater or equal to the minimum MGEN message size and less than or equal to the maximum UDP message size of 8192 bytes. For TCP protocol, <size> parameter is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols.

Example:

#Start an MGEN flow sending 1024 byte messages

#at a random interval between 0.5 and 1.5 seconds.

0.0 ON 1 UDP DST 127.0.0.1/5000 JITTER [1.0 1024 .5]

5.2.5.5. CLONE Pattern:

Option syntax:

... CLONE [<fileType> <fileName> [<repeatCount>]]...

This pattern type will incrementally read a file of the specified <fileType> to determine mgen packet sizes and message transmission intervals. Currently only tcpdump binary files are supported. It is assumed that the tcpdump file has been filtered to contain only the traffic that is to be "cloned".

At the flow event start time mgen will send a packet corresponding to the size of the first packet read from the file. Note that mgen assumes the records contain IPv4 UDP headers and therefore subtracts 42 bytes from the captured frame size reported by tcpdump. The second packet will be read from the file and a the second mgen packet of the same size will be sent as scheduled by the interval between the first and second packets. When the file is rewound, the first packet will not be transmitted. The second packet in the file will be scheduled to be sent after the last packet in the file according to the interval between the first and second packets in the file.

At present the only valid <fileType> is "tcpdump". The tcpdump file must be in binary format (created with tcpdump's -w option) and is assumed to be filtered to contain only the traffic that is to be cloned.

<fileName> is the name of the file containing the data to be used as the template for the MGEN pattern timing (packet intervals) and packet size(s).

<repeatCount> is an optional parameter that specifies the number of times the file is to be processed. <repeatCount> can be set to "-1" (the default), "0", or a positive integer. "-1" causes the file to be continuously read until the flow is stopped by an OFF event or the mgen program ends. "0" directs mgen to clone the file once and stop. A positive integer "N" indicates the number of repititions through the file, e.g. a value of 1 will cause the file to be read twice, once plus the repeat.

Out of sequence time stamps have been seen occasionally in tcpdump output. MGEN will schedule these packets for immediate transmission and if running at debug level 2, will log a warning message.

Note that some Linux distributions enable "segmentation/reassembly offload". This feature causes the network driver to do TCP segmentation and reassembly. In such case, larger packets than MGEN can clone will be logged in the pcap files. Disable this feature to successfully process this data. (e.g. ethtool --offload eth0 gso off; ethtool --offload eth0 tso off; ethtool --offload eth0 gro off).

Example:

#Start an MGEN flow and clone the contents of the specified file once

0.0 ON 1 UDP DST 127.0.0.1/5000 CLONE [tcpdump tcpdump.dat [0]]

5.2.6. BROADCAST

Option syntax:

... BROADCAST {ON|OFF} ...

This sets the SO_BROADCAST socket option to enable or disable the sending (and sometimes receiving) of broadcast messages. By default BROADCAST is ON.

5.2.7. LOGDATA

Option syntax:

... LOGDATA {ON|OFF} ...

Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is ON.

5.2.8. Type-Of-Service (TOS)

Option syntax:

... TOS <value> ...

The IP TOS (type-of-service) field can be controlled for IP packets associated with MGEN traffic generation. The <value> field specifies the value of the 8-bit TOS field in IPv4 packets. (IPv6 packets do not have a TOS field. MGEN will soon support control of the similar FLOW_ID field for IPv6 operation.) The <value> field must be in the range of 0-255 in decimal or hexadecimal notation. The interpretation of the TOS value by different computer operating systems and network devices may vary. In some cases, computer hosts will not allow all possible values to be used, and in others "super user" (root) privileges may be required to set the IP TOS field to certain values. Below are some notes on suggested interpretation by the Internet Engineering Task Force (IETF). Note that TOS is maintained on a "per socket" basis and that setting the TOS for a flow will affect other flows sharing the same network socket. See the SRC option to make sure different flows use different sockets.

Example:

#Start flow 1 with default TOS

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024]

#Modify flow 1 to TOS = 0x10 (low delay)

5.0 MOD 1 TOS 0x10

Notes on the value of the IP TOS field:

    
 	
   0     1     2     3     4     5     6     7   
 +-----+-----+-----+-----+-----+-----+-----+-----+
 |   PRECEDENCE    |          TOS          | MBZ |
 +-----+-----+-----+-----+-----+-----+-----+-----+
-

The Type-of-Service byte in the IP header is divided into three sections: the Precedence field (high-order 3 bits), a field that is called Type of Service or TOS (next 4 bits), and a reserved bit (the low order bit). The TOS bits can be set to 5 different settings including the default setting of 0000, while the PRECEDENCE can be set to 8 different setting including default 000.

TOS definitions:

 IPTOS_TOS_MASKIPTOS_TOS(tos)0x1E= ((tos) & IPTOS_TOS_MASK) 
1000 --IP_TOS_LOWDELAY0x10TOS = 16
0100 --IP_TOS_THROUGHPUT0x08TOS = 8
0010 --IPTOS_RELIABILITY0x04TOS = 4
0001 --IPTOS_LOWCOST0x02TOS = 2
0000 --normal service0x00TOS = 0

Precedence definitions:

111 --IPTOS_PREC_MASKIPTOS_PREC(tos)0xe0= ((tos) &IPTOS_PREC_MASK) 
111 --IPTOS_PREC_NETCONTROL0xe0TOS = 224
110 --IPTOS_PREC_INTERNETCONTROL0xc0TOS = 192
101 --IPTOS_PREC_CRITIC_ECP0xa0TOS = 160
100 --IPTOS_PREC_FLASHOVERRIDE0x80TOS = 128
011 --IPTOS_PREC_FLASH0x60TOS = 96
010 --IPTOS_PREC_IMMEDIATE0x40TOS = 64
001 --IPTOS_PREC_PRIORITY0x20TOS = 32
000 --IPTOS_PREC_ROUTINE0x00TOS = 0

If TOS = 164 (or 0xa4), the Precedence would be IPTOS_PREC_CRITIC_ECP and the TOS would be IPTOS_RELIABILITY. The IP TOS field bits would be set as 10100100.

5.2.9. Multicast Time-To-Live (TTL)

Option syntax:

... TTL <value> ...

The time-to-live (TTL) hop count can be controlled for IP multicast traffic generated by MGEN. As with TOS, this is generally a "per socket" attribute and care should be taken if it is desired to specify different TTL values for different MGEN flows. This can be accomplished by using different SRC (source ports) for different MGEN flows. The <value> field must be in the range of 1-255. The default multicast TTL assumed by MGEN is 3.

Example:

#Start an IP multicast flow with a maximum hop count ttl = 2

0.0 ON 1 UDP DST 224.1.2.3/5000 PERIODIC [1.0 256] TTL 2

5.2.10. Socket Transmit Buffer Size (TXBUFFER)

Option syntax:

... TXBUFFER <txBufferSize> ...

This option allows users to set the socket transmit buffer size to a value at least as large as <txBufferSize>. If <txBufferSize> is larger that the maximum allowed by the system, <txBufferSize> will be set to the system maximum. To date, this option has only been tested on linux systems.

5.2.11. Socket Receive Buffer Size (RXBUFFER)

Option syntax:

... RXBUFFER <rxBufferSize> ...

This option allows users to set the socket receive buffer size to a value at least as large as <rxBufferSize>. If <rxBufferSize> is larger that the maximum allowed by the system, <rxBufferSize> will be set to the system maximum. To date, this option has only been tested on linux systems.

5.2.12. IPv6 Flow Label (LABEL)

Option syntax:

... label <value> ...

This option allows users to specify the value applied to the IPv6 packet header "flow label" field. Although this field is 28 bits, different operating systems may restrict which portions of the field may be set. For example, the current Linux kernel (circa Jan 2003) only allows bits in the first octet of the flow label to be set. Other values are invalid on Linux, and generate an error message. Thus, using hexadecimal format for the <value> specified, legal values for Linux are restricted to <value> = 0x0??00000 where "??" specifies the first octet of the flow label. Other operating systems may behave differently.

Example:

# Start an IPv6 flow with flow label = 0x03d00000

0.0 ON 1 UDP LABEL 0x03d00000 SRC 5000 DST5f1b:df00:ce3e:e200:0800:2078:e3e3/5001 PERIODIC [1 1024]

5.2.13. Multicast Interface (INTERFACE)

Option syntax:... INTERFACE <interfaceName> ...

The network interface to use for IP multicast flow transmission can be controlled with this option. The <interfaceName> is the network interface device name to be used for IP multicast transmission for the associated flow. Again, as with TOS and TTL, this is generally a "per socket" attribute and care should be taken if it is desired to specify different multicast interfaces for different MGEN flows. This can be accomplished by using different SRC (source ports) for different MGEN flows. If no INTERFACE option is used, MGEN will behave according to the operating system's default behavior.

Example:

#Start an IP multicast flow on Ethernet interface named "eth1"

0.0 ON 1 UDP DST 224.1.2.3/5000 PERIODIC [1.0 256] INTERFACE eth1 SRC 5001

5.2.14. Sequence Number Initialization (SEQUENCE)

Option syntax:

... SEQUENCE <sequenceNumber> ...

This option sets the sequence number of the next message transmitted for the flow. MGEN flows are normally initialized to a sequence number of zero upon the first "ON" event for the flow. The sequence number is incremented by one with each message transmitted. The SEQUENCE option allows the user to override this behavior. It (along with the OFFSET command) is used by the SAVE command with MOD events for pending flows when it is desired that mgen return to a particular point in a script after being stopped and restarted.

Example:

#Modify the sequence number of an existing flow such that

#the next message is transmitted with sequence number 452.

12.0 MOD 1 SEQUENCE 452

5.2.15. UDP Connect (CONNECT)

Option syntax:

... CONNECT ...

The optional UDP CONNECT attribute will direct MGEN to open a "connected" UDP socket. If the connection cannot be established or is not available for a time period, MGEN will continue to attempt to send packets until the flow is stopped.

Example:

#Open up a CONNECTED UDP socket

1.0 ON 1 UDP CONNECT DST 192.168.1.100/500 PER [1 1024]

5.3. Reception Events

For simple reception and logging of unicast traffic, it is generally sufficient just to launch mgen with the port command line option specifying the port numbers to monitor. However, for IP multicast operation or more complex behavior, an MGEN script with "Reception Events" is required.; "Reception Events" in the MGEN script file format include LISTEN and IGNORE types to control which ports are being monitored when; and JOIN and LEAVE types to dynamically control IP group membership. The MGEN script syntax of "Reception Events" is:

<eventTime> <eventType> <parameters ...> [<options ...>]

5.3.1. LISTEN

Script syntax:

<eventTime> LISTEN <protocol> <portList>

The LISTEN event is used to prompt mgen to begin monitoring one or more ports for received traffic. The <eventTime> denotes the time (in seconds) relative to script execution. The <protocol> field specifies the transport protocol type. Currently, "UDP" and "TCP" transports are supported. The <portList> field is a comma-delimited list of individual or inclusive ranges of the port numbers (no spaces allowed) to begin monitoring. Port ranges within the list are specified in the format "<lowValue>-<hiValue>".

Example:

#Monitor UDP port numbers 5000, 5003, 5004, 5005, 5009

#and TCP port number 6000, 6003, 6004, 6005

#beginning at time 0.0

0.0 LISTEN UDP 5000,5003-5005,5009

0.0 LISTEN TCP 6000,6003-6005

5.3.2. IGNORE

Script syntax:

<eventTime> IGNORE <protocol> <portList>

The IGNORE event type is the converse to the LISTEN event type. An IGNORE event causes mgen tostop monitoring (and logging) received traffic on the specified <portList>. The <eventTime> denotes the time (in seconds) relative to script execution. The <protocol> field specifies the transport protocol type. "UDP" and "TCP" transports are supported. The <portList> field is a comma-delimited list of individual or inclusive ranges of the port numbers (no spaces allowed) to begin monitoring. Port ranges within the list are specified in the format "<lowValue>-<hiValue>".

Example:

#Stop monitoring UDP port numbers 5003, 5004, 5005, 5009

#and TCP port numbers 6003, 6004, 6005

#beginning at time 10.0

10.0 IGNORE UDP 5003-5005,5009

10.0 IGNORE TCP 6003-6005

5.3.3. JOIN

Script syntax:

<eventTime> JOIN<groupAddress> [INTERFACE<interfaceName>] [PORT<portNumber>]

The JOIN event is used to prompt mgen to "join" the specific IP multicast group indicated by the <groupAddress> field. The INTERFACE option forces the membership join request on the network interface identified by the <interfaceName> field. If no INTERFACE option is given, the operating system's default behavior is observed. Note it is possible to join the same group on multiple, different interfaces.

The PORT option is provided principally for operation on WIN32 systems where the IP multicast join must be performed on the same socket bound to a specific <portNumber>. Note that a corresponding LISTEN event for the indicated <portNumber> is required in order to receive traffic. Unix-based operating systems generally allow for IP multicast group membership to be independent of specific socket port bindings.

As many IP group memberships as the operating system will support is permitted by mgen. This is generally a limit of the maximum number of open sockets per process or in the system at large if multiple mgen instances are used. Note that WIN32 imposes a limitation of one IP multicast group membership per socket while Unix-based systems can allow for many memberships (often 20, but OS-specific) per socket.

Examples:

#JOIN group 224.1.2.3 at time 0.0

0.0 JOIN 224.1.2.3

#JOIN group 224.1.2.4 on interface "eth1"

0.0 JOIN 224.1.2.4 INTERFACE eth1

#JOIN group 224.1.2.5 using socket bound to port 5000

0.0 JOIN 224.1.2.5 PORT 5000

5.3.4. LEAVE

Script syntax:

<eventTime> LEAVE <groupAddress> [INTERFACE<interfaceName>] [PORT <portNumber]

The LEAVE event is used to prompt mgen to "leave" the specific IP multicast group indicated by the <groupAddress> field. The <groupAddress> must have been joined with a prior JOIN event. The INTERFACE and/or PORT options must be used if they were used with the corresponding JOIN event.

Examples:

#LEAVE group 224.1.2.3 at time 10.0

10.0 LEAVE 224.1.2.3

#LEAVE group 224.1.2.4 on interface "eth1" at time 10.0

10.0 LEAVE 224.1.2.4 INTERFACE eth1

#LEAVE group 224.1.2.4 on interface "eth1"and

#port 5000 at time 10.0

10.0 LEAVE 224.1.2.4 INTERFACE eth1 PORT 5000

6. Global Commands

The MGEN script file format supports a subset of commands which are independent of normal transmission and reception event scheduling. These are referred to as "Global Commands". This subset includes commands to specify an absolute script execution start time (START command) and to specify default traffic generation characteristics (e.g. multicast INTERFACE, multicast TTL, IP TOS, etc).

The format of script lines containing global commands is:<command> <parameters>

In general, a script file should contain only one occurrence of each global command type. If there are multiple occurrences of a command type, the last occurrence will determine mgen's behavior. These commands can also be given on the mgen command-line. Global commands given on the mgen command-line will override any corresponding global commands in the script file(s).

The MGEN "Global Command" set includes:

STARTSpecifies an absolute start time for script processing.
OFFSETSpecifies an offset time into script for MGEN activity.
TOSSpecifies a default IPv4 TOS value for IPv4 flows.
LABELSpecifies a default IPv6 Flow Label for IPv6 flows.
TTLSpecifies a default TTL (time-to-live) hop count for transmitted multicast packets.
INTERFACESpecifies the name of the default interface to use for IP multicast.
INPUTSpecifies the name of a script file to be loaded and parsed.
OUTPUTSpecifies the name of the log file to record logged events. If the named log file pre-exists, it is overwritten.
LOGSame as OUTPUT, except that pr-existing log files are appended instead of overwritten.
SAVESpecifies a file to which MGEN should store sequence number state for any pending or active flows as well as the current relative script offset time when mgen is terminated.
TXBUFFERSpecifies a default socket transmit buffer size.
RXBUFFERSpecifies a default socket receive buffer size.
LOCALTIMESpecifies that mgen events and error messages are logged in localtime rather than the default Greenwich Mean Time.
QUEUESpecifies the default number of mgen messages that should be queued before mgen turns off the transmission timer for a flow.
LOGDATAControls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.

6.1. START

Script syntax:

START <hour:min:sec>[GMT]

The START command designates an absolute time as indicated by the <hour:min:sec> field to correspond to the relative script time of 0.0 seconds. All transmission and reception events will be scheduled relative to this absolute start time. The optional GMT suffix (no white space after the time) indicates that the clock time given is Greenwich Mean Time (GMT) rather than the operating systems local time zone. If no START command is given, mgen schedules transmission and reception events relative to program startup.

Example:

#Start MGEN exactly at 1:30PM local time

START 13:30:00

#Start MGEN at 30 seconds past 8:30 GMT

START 8:30:30GMT

6.2. OFFSET

Script syntax:

OFFSET <seconds>

The OFFSET global command specifies a relative time offset (in seconds)into script processing where MGEN should begin its activity. This allows multiple instances of MGEN using the same script to be dithered as desired. Additionally, this command may be used to immediately restore MGEN to a specific scripted state other than the beginning of the script upon launch.

Example:

#Skip the first 10 seconds of an MGEN script

OFFSET 10.0

6.3. TOS

Script syntax:

TOS <value>

The TOS command specifies ...

Example:

#Specify default ttl = 0x10 (low delay)

TOS 0x10

6.4. LABEL

Script syntax:

LABEL <value>

The LABEL command specifies a default value to be used as the "flow label" for IPv6 flows. The "flow label" is the corresponding 28-bit field in the IPv6 packet header. Refer to the Transmission Event LABEL option for further details..

Example:

#Specify default IPv6 flow label = 0x02500000

LABEL 0x02500000

6.5. TTL

Script syntax:

TTL <value>

The TTL command specifies the default time-to-live (TTL) hop count for generated IP multicast traffic according to the <value> field. The <value> must be in the range of 1-255. If the global TTL command is not used, mgen assumes a default multicast TTL value of 3. Note that the transmission event TTL option will override the default specification given by this global command.

Example:

#Specify default multicast flow ttl = 32

TTL 32

6.6. TXBUFFER

Script syntax:

TXBUFFER <txBufferSize> ...

This option allows users to set the default socket transmit buffer size to a value at least as large as <txBufferSize>. The exact behavior of this option may be operating system dependent. The TXBUFFER option given on transmission event script lines will override this default for the socket used by the corresponding flow.

6.7. RXBUFFER

Script syntax:

RXBUFFER <rxBufferSize> ...

This option allows users to set the default socket receive buffer size to a value ?at least? as large as <rxBufferSize>. The exact behavior of this option may be operating system dependent. The RXBUFFER option given on transmission event script lines will override this default for the socket used by the corresponding flow.

6.8. LOCALTIME

Script syntax:

LOCALTIME

This option allows users to specify that events and error messages be logged in localtime rather than the default Greenwich Mean Time.

6.9. QUEUE

Script syntax:

QUEUE

This global command will cause mgen to buffer <queueSize> mgen packets for each flow during periods of congestion. (Note that flow specific limits specified at the transmission event level will override this global). When the number of pending messages for a flow exceeds this limit, the message transmission timer will be temporarily deactivated and any pending messages will transmitted as quickly as possible. The timer will be reactivated once the pending message count falls below the queue limit, and message transmission will return to the previously scheduled rate of transmission.

If no global command is specified, a default <queueSize> of "0" will be in effect which will result in no queuing behavior, e.g. the transmission timer will continue to fire at its regularly scheduled interval regardless of transport congestion. No pending message count will be accumulated and message transmission will suceed or fail depending on transport availability.

When multiple flows are sending messages over a common mgen transport, the flows that have exceeded their pending message limit(s) will be serviced in a round robin fashion until all pending messages have been sent for all flows. Transmissions for flows that have fallen below this threshold will be interleaved as scheduled.

A <queueSize> threshold of "-1" sets an unlimited queue size. This means that a congested flow's transmission timer will continue to fire (thereby building up it's pending message count), but any pending messages will be sent as quickly as possible until congestion clears.

Any pending messages for a flow will be sent before the flow will be shutdown by a scheduled OFF event. Likewise, the pending message queue for a flow that is being restarted will be cleared. Note however, if any of the content of the mgen message header is changed (src or dst addresses, etc.) the pending message count will be reset. All other flow attribute changes (rage, message size, payload content, ttl, etc.) will be effected immediately, including any pending messages.

6.10. DATA

Script Syntax:

DATA [<hex>,<hex>]

User defined message payload can be specified with the DATA command. The data should be a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data. The contents will be placed in every packet generated by the flow.

6.11. INTERFACE

Script syntax:

<interfaceName>

The INTERFACE command specifies a default IP network interface to use for multicast traffic generation and group membership. If no INTERFACE command is given, the default operating system behavior is observed. Note that the transmission event INTERFACE option or the JOIN reception event INTERFACE option will override the default specification given by this global command.

Example:

#Specify "eth1" as the default network interface

#for multicast transmission and group joins

INTERFACE eth1

6.12. INPUT

Script syntax:

INPUT <scriptFile>

The INPUT command cause MGEN to load and parse the given <scriptFile>. (Circular references are not detected by mgen and should be avoided_). This allows scripts to "include" other scripts. The parsing occurs in the order that the INPUT commands are encountered on the command-line and within the script files themselves.

Example:

#Load and parse the MGEN script file "script2.mgn"

INPUT script2.mgn

6.13. OUTPUT

Script syntax:

OUTPUT <logFile>

The OUTPUT command cause mgen to direct its log output to the indicated <logFile>. The last occurring OUTPUT command determines the log file to be used and the command-line takes precedence over any scripts provided as input to mgen. The file named by <logFile> will be overwritten if it already exists.

Example:

#Use the file "logFile.drc" for logging

OUTPUT logFile.drc

6.14. LOG

Script syntax:

LOG <logFile>

The LOG command cause mgen to direct its log output to the indicated <logFile>. The last occurring LOG command determines the log file to be used and the command-line takes precedence over any scripts provided as input to mgen. The file named by <logFile> will be appended if it already exists.

Example:

#Append the file "logFile.drc"

LOG logFile.drc

6.15. LOGDATA

Script syntax:

LOGDATA {on|off}}

Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.

Example:

#Don't log optional data attribute at receiver

LOGDATA off

6.16. SAVE

Script syntax:

SAVE <saveFile>

The SAVE command causes mgen to write a short MGEN script upon exit which includes current sequence number state for pending and active transmission flows as well as the current relative script offset time. If the <saveFile> created is given as an additional input script (with the same input script(s) given for the mgen instance which created <saveFile>), on a subsequent launch of mgen, mgen will return to the same state as it was when it previously exited.

The SAVE command can be used when it is desired to conduct separate runs of mgen, but preserve a continuous sequence number space across the multiple runs. An example script performing this function is given below. Note the same behavior can also be achieved via the mgen command-line using:

"mgen input <scriptFile> input <saveFile> save <saveFile> log <logFile>"

if an empty <saveFile> is provided on the first launch of mgen.

Example:

# This script executes another MGEN script, using

# "saveFile.mgn" for state recovery upon subsequent

# restarts after mgen is exited.

# (If "saveFile.mgn" is empty or non-existent upon

# initial startup, the "scriptFile.mgn" is run

# from the beginning.)

# (The "log" command is used to repeatedly append

# the "logFile.drc" file upon stop and restart)

INPUT scriptFile.mgn

INPUT saveFile.mgn

SAVE saveFile.mgn

LOG logFile.drc

7. MGEN Log File Format

The MGEN message format contains information to facilitate network performance measurements through post-analysis of MGEN log files. Some of the types of performance statistics which can be determined include:

Message ThroughputThe time or arrival and size of received messages are logged by MGEN receivers. Network throughput can be assessed with this information.
Message Delivery LatencyMGEN messages contain a timestamp reflecting when they were sent and the time of reception is logged by MGEN receivers. Delivery latency statistics (jitter or absolute if clock synchronization (e.g. NTP) is possible) can be determined with this information.
Message Loss RateMGEN messages are sequence numbered. Message loss can be accounted for via analysis of logged sequence number information.
Message Re-orderingThe logged MGEN sequence number information can also be used to determine message re-ordering statistics.
Multicast JOIN/LEAVE LatencyThe occurrence and time of JOIN/LEAVE events are logged by MGEN receivers. The JOIN latency can be determined by comparing the arrival time of the first message associated with a particular multicast group to the time the group was joined. The LEAVE latency can be determined by comparing the time of the _last_ packet arrival time to the time the receiver left that multicast group (Note that you need a packet sniffing program like tcpdump to see packets after you leave the group).

Many of the above performance measures and statistics can be measured and optionally graphed using the NRL trpr (trace plot real-time) program. This program can parse the MGEN log file format and tcpdump traces.

7.1. General Log Format

Each line of the MGEN text log file format corresponds to a unique event and follows the convention:<eventTime> <eventType> <event attributes ...>The <eventTime> field is in the form hrs:min:sec and represents the computer's system Greenwich Mean Time (GMT) at the time of the event.

The <eventType> field is one of the following:

RECVDenotes the arrival of a received MGEN message.
RERRIndicates an invalid MGEN message was received.
SENDDenotes the transmission of an MGEN message.
JOINMarks a join to an IP multicast group.
LEAVEMarks the departure from an IP multicast group.
LISTENIndicates when mgen began monitoring a specific port
IGNOREIndicates when mgen ended monitoring of a specific port
ONIndicates when mgen initiated a TCP connection to the indicated destination ip address and port or when a UDP flow began transmitting.
CONNECTIndicates when an mgen TCP "client" or "sender" has established a TCP connection from the indicated source port or to the destination ip address and port.
ACCEPTIndicates when an mgen TCP "server" or "listener" has accepted a TCP connection from the indicated source ip address and port to the destination port.
SHUTDOWNIndicates when an mgen TCP connection was shutdown after a scheduled >OFF< event on the client side or when an active connection is shutdown by the server on the server side. When TCP completes the shutdown procedure, an OFF or a DISCONNECT event will be logged as appropriate.
DISCONNECTIndicates when an mgen TCP connection was disconnected prior to a scheduled >OFF< event on either the client or server side. This event indicates a TCP error has occurred on the connection. (NOTE: this indication of an unscheduled TCP shutdown is currently reliable only on Linux systems.)
OFFIndicates that an mgen flow was stopped by a scheduled >OFF< event on the client or by a server IGNORE event on the sever. (Only available when transmission logging is enabled on the client side).
STARTIndicates when mgen started processing Transmission and Reception events.
STOPIndicates when mgen stopped processing Transmission and Reception events.

Different event types will have different event attribute sets. The <event attribute> fields are explicitly labeled so that log file parsing programs can seek specific attributes of interest for given event types.

7.2. Log File RECV Events

The format of the RECV event log file line is:

<eventTime> RECV proto><protocol> flow><flowId> seq><sequenceNumber> src><addr> /<port> dst><addr>/<port> sent><txTime> size><bytes> [host><addr>/<port>] [gps><status>,<lat>,<long>,<alt>] [data><len>:<data>] [flags><flag>]

The <eventTime> corresponds to when the message was received. The <protocol> specifies the protocol (udp,tcp,sink).The <flowId>, <sequenceNumber>, and <txTime>, are from the payload of the MGEN message. The <txTime> is in the same format as the <eventTime> (i.e. <hr:min:sec> GMT)

The "dst" <addr>/<port> is from the message payload and corresponds to the destination address to which the source addressed the MGEN message.

The "src" <addr>/<port> is the source address determined from the corresponding recvfrom() call for UDP transport or the address to which the TCP connection was made. (An optional "host" address will be embedded in the payload by the MGEN message source and made available as an attribute of the logged RECV event in the future).

The message "size" in <bytes> is also from the payload, but for UDP transport, should also correspond to the UDP packet payload size. Note that TCP mgen messages can be larger than the maximum UDP message size of 8192 bytes and can be of unlimited size. Therefore, mgen breaks large TCP messages into mgen message "fragments" of a maximum size of 65535 and sets a flag on the mgen message to indicate that it is a TCP message "fragment". Message fragments are flagged with 0x01 to indicate that the message is not complete. The last fragment in a TCP message is flagged 0x02 to indicate "end of message".

For example, a TCP mgen message of size 66559 will be received and logged by the receiving node as two messages as follows:

00:33:36.427143 RECV proto>TCP flow>1 seq>1 src>192.168.1.102/35056 dst>192.168.1.100/5000 sent>00:36:11.377105 size>65535 gps>INVALID,999.000000,999.000000,-999 flags>0x01

00:33:36.427499 RECV proto>TCP flow>1 seq>1 src>192.168.1.102/35056 dst>192.168.1.100/5000 sent>00:36:11.380137 size>1024 gps>INVALID,999.000000,999.000000,-999 flags>0x02

Also note that a single SEND message will be logged by the transmitting node with a size corresponding to the TCP message size, e.g.:

00:29:51.396962 SEND proto>TCP flow>1 seq>1 srcPort>0 dst>192.168.1.102/5000 size>66559

The "host" <addr>/<port> corresponds to the MGEN message source's "perceived" default local address. Note that this may be different from the source address contained in the MGEN log file due to firewalls, Network Address Translation (NAT) devices, multi-homed sources, etc. The accuracy of this information depends upon the source host's configuration with regards to domain name service (DNS), etc. Note this field is optional and may not be present if this information is not valid (The current initial MGEN release does not yet support this option).

The "src", "dst", and "host" <addr> fields are dotted decimal IPv4 addresses or colon-delimited IPv6 addresses.

The "flags" field is discussed above.

The global positioning system (GPS) information is available when the MGEN message source is used in conjunction with the NRL gpsLogger program. This program monitors an attached GPS receiver for position information and "publishes" it in shared memory. When mgen is run and detects that it can "subscribe" to GPS position information, it places it in the MGEN message payload. Note that gpsLogger can also be used with a pulse-per-second (PPS) capable GPS receiver to provide accurate time synchronization for hosts running the MGEN toolset. This may be useful for mobile network test environments. The MGEN log file "gps" attribute has the following comma-delimited fields:

<status>This indicates the validity of the GPS information and may be either "INVALID", "CURRENT", or "STALE".
<lat>This is the GPS latitude in degrees. A negative value denotes South while a positive value denotes North.
<long>This is the GPS longitude in degrees. A negative value denotes West while a positive value denotes East.
<alt>This is the GPS altitude in meters.

The optional "data" attribute is present only if the received MGEN message contains optional user-defined payload. If present, the <len> indicates the length (in bytes) of the user-defined payload and the <data> following the colon character':' is a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data. Thus, the number of characters in the <data> field will be 2 * <len>. (The "data" option was supported in MGEN 3.x via the MGEN Payload Manager (mpmgr) tool and is not yet supported in MGEN 4.x. The documentation will be updated when this option is supported).

Example RECV event log lines:

22:59:52.312721 RECV proto><protocol> flow>1 seq>1 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024

23:59:53.312721 RECV proto><protocol> flow>1 seq>2 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024 host>132.250.68.21/5000 gps>CURRENT,35.123,79.234,57

23:59:53.312721 RECV proto><protocol> flow>1 seq>2 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024 host>132.250.68.21/5000 gps>CURRENT,35.123,79.234,57 data>10:01a97b34458cff0021e8

7.3. Log File RERR Events

The format of the RERR (Receive Error) event log file line is:

<eventTime> RERR proto><protocol> type><errorType> src><addr>/<port>

The <eventTime> corresponds to when the message in error was received. The <errorType> is one of "none", "version", "checksum", or "dstaddr". An receive error of type "version" indicates the MGEN sender is using an mgen executable with an incompatible version number. The "checksum" error indicates the received message failed checksum validation, and the "dstaddr" error indicates an invalid or unsupported destination address type in the MGEN message received. The <src> attribute indicates the source address of the message in error.

7.4. Log File SEND Events

The format of the SEND event log file line is:

<eventTime> SEND proto><protocol> flow><flowId> seq><sequenceNumber> src><srcPort> dst><addr>/<port> size><bytes> [host><addr>/<port>]

The <eventTime> corresponds to when the message was sent, and it should precisely match the <txTime> logged by the machine the packet is sent to, if the packet is received correctly.

All the data items are the same as those used in the Log File RECV Events.

7.5. Log File JOIN Events

The format of the JOIN log file event line is:

<eventTime> JOIN group> <groupAddress> [interface> <interfaceName>]

The <groupAddress> is the IP multicast group address which was joined. The format of this field is either a dotted decimal IPv4 address or a colon-delimited IPv6 address. The <interfaceName> is given only when the executed MGEN script used the INTERFACE option in the corresponding JOIN script event.

Example JOIN event log lines:

22:59:50:234757 JOIN group>224.1.2.3

22:59:51:129574 JOIN group>224.1.2.4 interface>eth1

7.6. Log File LEAVE Events

The format of log file LEAVE event lines is:

<eventTime> LEAVE group><groupAddress> [interface><interfaceName>]

The <groupAddress> is the IP multicast group address which was left. The format of this field is either a dotted decimal IPv4 address or a colon-delimited IPv6 address. The <interfaceName> is given only when the executed MGEN script used the INTERFACE option in the corresponding LEAVE script event.

Example LEAVE event log lines:

22:59:59:234757 LEAVE group>224.1.2.3

22:59:59:753683 LEAVE group>224.1.2.4 interface>eth1

7.7. Log File LISTEN Events

The format of the LISTEN event log file line is:

<eventTime> LISTEN proto><protocol> port><portNumber>

The <protocol> field corresponds to the transport protocol type being used. Supported protocols include "UDP" and "TCP". The <portNumber> field is the host port number to be monitored.

Example LISTEN event log lines:

22:59:48:834205 LISTEN proto>UDP port>5000

22:59:49:328039 LISTEN proto>UDP port>5001

7.8. Log File IGNORE Events

The format of the IGNORE event log file line is:

<eventTime> IGNORE proto><protocol> port><portNumber>

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP". The <portNumber> field is the host port number to be no longer monitored.

Example IGNORE event log lines:

23:00:00:723467 IGNORE proto>UDP port>5000

23:01:00:235629 IGNORE proto>UDP port>5001

7.9. Log File ON Events

The format of the ON event log file line is:

<eventTime> ON flow><flowID> srcPort><srcPort> dst><dst>/<portNumber>

This event indicates that mgen has attempted to establish a TCP connection with the target destination address and port or a UDP flow has begun transmitting. It does not indicate that the connection has been successfully established, only that a connection has been attempted. The <flowID> field corresponds to the TCP flow ID of the connection. The <srcPort> is either the OS provided or user specified src port for the flow. The <dst> field corresponds to the destination of the TCP connection. The <portNumber> field is the destination port number of the TCP connection.

Example ON event log lines:

23:00:00:723467 ON flow>1 srcPort>4000 dst>192.168.1.100/5000

7.10. Log File CONNECT Events

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP".

The format of the CONNECT event log file line is:

<eventTime> CONNECT flow><flowId> srcPort><srcPort> dst><dst>/<portNumber>

The <src> and <dst> fields correspond to the local source port and destination ip address/port of the TCP connection. The <flowID> is the transmitting flow id. If multiple flows are sharing the connection, CONNECT events will be logged for each flow.

Example CONNECT event log line:

23:00:00:723467 CONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000

7.11. Log File ACCEPT Events

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP".

The format of the ACCEPT event log file line is:

<eventTime> ACCEPT srcPort><srcAddr><srcPort> dstPort><dstPort>

The <src> and <dst> fields correspond to the source ip address and port and local receiving(dst) port of the TCP connection.

Example ACCEPT event log line (server):

23:00:00:723467 ACCEPT srcPort>4007 dst>192.168.1.100/5000

7.. Log File SHUTDOWN Events

The format of the SHUTDOWN event log file line is:

<eventTime> SHUTDOWN flow><flowID> srcPort><srcPort> dst><dstAddr><dstPort> (client)

<eventTime> SHUTDOWN src><srcAddr><srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the dst indicated address and port was shutdown after a client OFF event or by the server after a server IGNORE event has been processed and client connections remain active on the dst port being listened to. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was attempting to connect to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was prematurely terminated, no SHUTDOWN event will be logged.

Example Client SHUTDOWN event log line (client):

23:00:00:723467 SHUTDOWN flow><flowId> src>192.168.1.102/5000 dstPort>6000

Example Server SHUTDOWN event log line (server):

23:00:00:723467 SHUTDOWN src>192.168.1.100/5000 dst>6000

If multiple flows are sharing the same connection, the shutdown event will be logged only when the last flow has stopped sending to the socket pair. An "OFF" event will be logged for any connections ending while other flows are still transmitting, e.g.:

22:35:52.458531 OFF flow>1 srcPort>4000 dst>192.168.1.100/5000

22:35:52.458542 SEND proto>TCP flow>2 seq>3 srcPort>4000 dst>192.168.1.100/5000 size>8192

22:35:52.458598 SHUTDOWN flow>2 srcPort>4000 dst>192.168.1.100/5000

22:35:52.460419 OFF flow>2 srcPort>4000 dst>192.168.1.100/5000

7.13. Log File DISCONNECT Events

The format of the DISCONNECT event log file line is:

<eventTime> DISCONNECT flow><flowID> srcPort><srcPort> dst><dstAddr><dstPort> (client)

<eventTime> DISCONNECT src><srcAddr</<srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the indicated address and port has disconnected either because the connection could not be established in the first place or because the connection was prematurely terminated. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was attempting to connect to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was not prematurely terminated, no DISCONNECT event will be logged. (NOTE: Indication of unscheduled TCP disconnection is not available relieably under windows at this time.)

Example Client DISCONNECT event log line:

23:00:00:723467 DISCONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000

Example Server DISCONNECT event log line :

23:00:00:723467 DISCONNECT src>192.168.1.100/4000 dstPort>5000

7.14. Log File OFF Events

The format of the OFF event log file line is:

<eventTime> OFF flow> <flowID> srcPort><srcPort> dst><dstAddr>/<dstPort> (client)

<eventTime> OFF src><srcAddr><srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the indicated address and port has been successfully shutdown (e.g. disconnected) after a scheduled mgen OFF event. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was connected to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was prematurely terminated by either the client or the server, a DISCONNECT event will be logged instead of an OFF event. (NOTE: Under Windows operating systems, the DISCONNECT event is not reliable and the OFF event may be logged for both planned and unplanned socket disconnects.)

Example Client OFF event log line (client):

23:00:00:723467 OFF flow>1 srcPort>4000 dst>192.168.1.102/5000

Example Server OFF event log line (server):

23:00:00:723467 OFF src>192.168.1.100/4000 dstPort>5000

Note that the server will only log a single OFF event if multiple tcp flows are being recevied over the socket pair, although the client will log OFF events for each flow.

7.15. Log File START and STOP Events

The format of the START and STOP event log file line is:

<eventTime> STARTor<eventTime>STOP

These log file lines indicate the time at which MGEN began and ended its operation. The "START" time corresponds to the relative time zero for any executed scripts. This "START" time is when the mgen program was executed unless the global START command was invoked. The "STOP" command corresponds to when the mgen program was halted.

8. Binary Log File Format

At the beginning of binary log files, there is a plain text line to make it easy to tell what kind of file it is. It has the mgen version number, as well as the type of file ("binary_log"). This line is terminated with a line feed and a NULL ('\0') character. Following the NULL, the file contains a series of binary formatted records. There are several different types of records in the binary log file format. Each record consists of a number of fields. The first single-byte field indicates the record type. A record type of 0 is considered invalid. All multiple-byte fields are in standard network byte order (i.e. most significant byte first). Each record in the binary log file corresponds to a single unique Mgen event, just as each line in the text-based log file does. Each binary log file record contains the same information that every line of the text-format log file has. The text-format log file can actually be recreated from a binary log file using the "convert" command of mgen.

8.1. Binary Log File RECV Events

The format of the RECV event binary log file record is:

+

The Type-of-Service byte in the IP header is divided into three sections: the Precedence field (high-order 3 bits), a field that is called Type of Service or TOS (next 4 bits), and a reserved bit (the low order bit). The TOS bits can be set to 5 different settings including the default setting of 0000, while the PRECEDENCE can be set to 8 different setting including default 000.

TOS definitions:

 IPTOS_TOS_MASKIPTOS_TOS(tos)0x1E= ((tos) & IPTOS_TOS_MASK) 
1000 --IP_TOS_LOWDELAY0x10TOS = 16
0100 --IP_TOS_THROUGHPUT0x08TOS = 8
0010 --IPTOS_RELIABILITY0x04TOS = 4
0001 --IPTOS_LOWCOST0x02TOS = 2
0000 --normal service0x00TOS = 0

Precedence definitions:

111 --IPTOS_PREC_MASKIPTOS_PREC(tos)0xe0= ((tos) &IPTOS_PREC_MASK) 
111 --IPTOS_PREC_NETCONTROL0xe0TOS = 224
110 --IPTOS_PREC_INTERNETCONTROL0xc0TOS = 192
101 --IPTOS_PREC_CRITIC_ECP0xa0TOS = 160
100 --IPTOS_PREC_FLASHOVERRIDE0x80TOS = 128
011 --IPTOS_PREC_FLASH0x60TOS = 96
010 --IPTOS_PREC_IMMEDIATE0x40TOS = 64
001 --IPTOS_PREC_PRIORITY0x20TOS = 32
000 --IPTOS_PREC_ROUTINE0x00TOS = 0

If TOS = 164 (or 0xa4), the Precedence would be IPTOS_PREC_CRITIC_ECP and the TOS would be IPTOS_RELIABILITY. The IP TOS field bits would be set as 10100100.

5.2.9. Multicast Time-To-Live (TTL)

Option syntax:

... TTL <value> ...

The time-to-live (TTL) hop count can be controlled for IP multicast traffic generated by MGEN. As with TOS, this is generally a "per socket" attribute and care should be taken if it is desired to specify different TTL values for different MGEN flows. This can be accomplished by using different SRC (source ports) for different MGEN flows. The <value> field must be in the range of 1-255. The default multicast TTL assumed by MGEN is 3.

Example:

#Start an IP multicast flow with a maximum hop count ttl = 2

0.0 ON 1 UDP DST 224.1.2.3/5000 PERIODIC [1.0 256] TTL 2

5.2.10. Socket Transmit Buffer Size (TXBUFFER)

Option syntax:

... TXBUFFER <txBufferSize> ...

This option allows users to set the socket transmit buffer size to a value at least as large as <txBufferSize>. If <txBufferSize> is larger that the maximum allowed by the system, <txBufferSize> will be set to the system maximum. To date, this option has only been tested on linux systems.

5.2.11. Socket Receive Buffer Size (RXBUFFER)

Option syntax:

... RXBUFFER <rxBufferSize> ...

This option allows users to set the socket receive buffer size to a value at least as large as <rxBufferSize>. If <rxBufferSize> is larger that the maximum allowed by the system, <rxBufferSize> will be set to the system maximum. To date, this option has only been tested on linux systems.

5.2.12. IPv6 Flow Label (LABEL)

Option syntax:

... label <value> ...

This option allows users to specify the value applied to the IPv6 packet header "flow label" field. Although this field is 28 bits, different operating systems may restrict which portions of the field may be set. For example, the current Linux kernel (circa Jan 2003) only allows bits in the first octet of the flow label to be set. Other values are invalid on Linux, and generate an error message. Thus, using hexadecimal format for the <value> specified, legal values for Linux are restricted to <value> = 0x0??00000 where "??" specifies the first octet of the flow label. Other operating systems may behave differently.

Example:

# Start an IPv6 flow with flow label = 0x03d00000

0.0 ON 1 UDP LABEL 0x03d00000 SRC 5000 DST5f1b:df00:ce3e:e200:0800:2078:e3e3/5001 PERIODIC [1 1024]

5.2.13. Multicast Interface (INTERFACE)

Option syntax:... INTERFACE <interfaceName> ...

The network interface to use for IP multicast flow transmission can be controlled with this option. The <interfaceName> is the network interface device name to be used for IP multicast transmission for the associated flow. Again, as with TOS and TTL, this is generally a "per socket" attribute and care should be taken if it is desired to specify different multicast interfaces for different MGEN flows. This can be accomplished by using different SRC (source ports) for different MGEN flows. If no INTERFACE option is used, MGEN will behave according to the operating system's default behavior.

Example:

#Start an IP multicast flow on Ethernet interface named "eth1"

0.0 ON 1 UDP DST 224.1.2.3/5000 PERIODIC [1.0 256] INTERFACE eth1 SRC 5001

5.2.14. Sequence Number Initialization (SEQUENCE)

Option syntax:

... SEQUENCE <sequenceNumber> ...

This option sets the sequence number of the next message transmitted for the flow. MGEN flows are normally initialized to a sequence number of zero upon the first "ON" event for the flow. The sequence number is incremented by one with each message transmitted. The SEQUENCE option allows the user to override this behavior. It (along with the OFFSET command) is used by the SAVE command with MOD events for pending flows when it is desired that mgen return to a particular point in a script after being stopped and restarted.

Example:

#Modify the sequence number of an existing flow such that

#the next message is transmitted with sequence number 452.

12.0 MOD 1 SEQUENCE 452

5.2.15. UDP Connect (CONNECT)

Option syntax:

... CONNECT ...

The optional UDP CONNECT attribute will direct MGEN to open a "connected" UDP socket. If the connection cannot be established or is not available for a time period, MGEN will continue to attempt to send packets until the flow is stopped.

Example:

#Open up a CONNECTED UDP socket

1.0 ON 1 UDP CONNECT DST 192.168.1.100/500 PER [1 1024]

5.3. Reception Events

For simple reception and logging of unicast traffic, it is generally sufficient just to launch mgen with the port command line option specifying the port numbers to monitor. However, for IP multicast operation or more complex behavior, an MGEN script with "Reception Events" is required.; "Reception Events" in the MGEN script file format include LISTEN and IGNORE types to control which ports are being monitored when; and JOIN and LEAVE types to dynamically control IP group membership. The MGEN script syntax of "Reception Events" is:

<eventTime> <eventType> <parameters ...> [<options ...>]

5.3.1. LISTEN

Script syntax:

<eventTime> LISTEN <protocol> <portList>

The LISTEN event is used to prompt mgen to begin monitoring one or more ports for received traffic. The <eventTime> denotes the time (in seconds) relative to script execution. The <protocol> field specifies the transport protocol type. Currently, "UDP" and "TCP" transports are supported. The <portList> field is a comma-delimited list of individual or inclusive ranges of the port numbers (no spaces allowed) to begin monitoring. Port ranges within the list are specified in the format "<lowValue>-<hiValue>".

Example:

#Monitor UDP port numbers 5000, 5003, 5004, 5005, 5009

#and TCP port number 6000, 6003, 6004, 6005

#beginning at time 0.0

0.0 LISTEN UDP 5000,5003-5005,5009

0.0 LISTEN TCP 6000,6003-6005

5.3.2. IGNORE

Script syntax:

<eventTime> IGNORE <protocol> <portList>

The IGNORE event type is the converse to the LISTEN event type. An IGNORE event causes mgen tostop monitoring (and logging) received traffic on the specified <portList>. The <eventTime> denotes the time (in seconds) relative to script execution. The <protocol> field specifies the transport protocol type. "UDP" and "TCP" transports are supported. The <portList> field is a comma-delimited list of individual or inclusive ranges of the port numbers (no spaces allowed) to begin monitoring. Port ranges within the list are specified in the format "<lowValue>-<hiValue>".

Example:

#Stop monitoring UDP port numbers 5003, 5004, 5005, 5009

#and TCP port numbers 6003, 6004, 6005

#beginning at time 10.0

10.0 IGNORE UDP 5003-5005,5009

10.0 IGNORE TCP 6003-6005

5.3.3. JOIN

Script syntax:

<eventTime> JOIN <groupAddress> [SRC <srcAddress>] [INTERFACE <interfaceName>] [PORT <portNumber| portList>]

The JOIN event is used to prompt mgen to "join" the specific IP multicast group indicated by the <groupAddress> field. The SRC option can be used to join a source specific multicast (SSM) channel. Note that the SRC option is not presently available on windows. The INTERFACE option forces the membership join request on the network interface identified by the <interfaceName> field. If no INTERFACE option is given, the operating system's default behavior is observed. Note it is possible to join the same group on multiple, different interfaces.

The PORT option should be used on WIN32 systems where the IP multicast join must be performed on the same socket bound to a specific <portNumber>.

Unix-based operating systems generally allow for IP multicast group membership to be independent of specific socket port bindings. Note that a corresponding LISTEN event for the indicated <portNumber> is required in order to receive traffic if not set as a JOIN command option. Specify the PORT option as a JOIN command option if your Unix based system does not support port binding independence.

Not that on IPv6 systems (and when mgen is compiled with the HAVE_IPV6 compile option) the JOIN port option must be specified when joining an IPv4 group.

On OSX systems, the interface option must be used if a default multicast route is not defined on the system.

As many IP group memberships as the operating system will support is permitted by mgen. This is generally a limit of the maximum number of open sockets per process or in the system at large if multiple mgen instances are used. Note that WIN32 imposes a limitation of one IP multicast group membership per socket while Unix-based systems can allow for many memberships (often 20, but OS-specific) per socket.

Examples:

#JOIN group 224.1.2.3 at time 0.0

0.0 JOIN 224.1.2.3

#JOIN group 224.1.2.4 on interface "eth1"

0.0 JOIN 224.1.2.4 INTERFACE eth1

#JOIN SSM channel 232.1.1.1 with source 26.26.26.1 on interface "eth1"

0.0 JOIN 224.1.2.4 SRC 25.25.25.1 INTERFACE eth1

#JOIN group 224.1.2.5 using socket bound to port 5000

0.0 JOIN 224.1.2.5 PORT 5000

#JOIN group 224.1.2.6 using sockets bound to ports 5001-5005

0.0 JOIN 224.1.2.6 PORT 5001-5005

5.3.4. LEAVE

Script syntax:

<eventTime> LEAVE <groupAddress> [SRC <srcAddress>] [INTERFACE <interfaceName>] [PORT <portNumber]

The LEAVE event is used to prompt mgen to "leave" the specific IP multicast group indicated by the <groupAddress> field. The <groupAddress> must have been joined with a prior JOIN event. The INTERFACE and/or PORT options must be used if they were used with the corresponding JOIN event. Note that the SSM SRC option is not presently available on windows.

Examples:

#LEAVE group 224.1.2.3 at time 10.0

10.0 LEAVE 224.1.2.3

#LEAVE group 224.1.2.4 on interface "eth1" at time 10.0

10.0 LEAVE 224.1.2.4 INTERFACE eth1

#LEAVE SSM channel 232.1.1.1 with source 25.25.25.1 on interface "eth1" at time 10.0

10.0 LEAVE 224.1.2.4 SRC 25.25.25.1 INTERFACE eth1

#LEAVE group 224.1.2.4 on interface "eth1"and port 5000 at time 10.0

10.0 LEAVE 224.1.2.4 INTERFACE eth1 PORT 5000

6. Global Commands

The MGEN script file format supports a subset of commands which are independent of normal transmission and reception event scheduling. These are referred to as "Global Commands". This subset includes commands to specify an absolute script execution start time (START command) and to specify default traffic generation characteristics (e.g. multicast INTERFACE, multicast TTL, IP TOS, etc).

The format of script lines containing global commands is:<command> <parameters>

In general, a script file should contain only one occurrence of each global command type. If there are multiple occurrences of a command type, the last occurrence will determine mgen's behavior. These commands can also be given on the mgen command-line. Global commands given on the mgen command-line will override any corresponding global commands in the script file(s).

The MGEN "Global Command" set includes:

STARTSpecifies an absolute start time for script processing.
OFFSETSpecifies an offset time into script for MGEN activity.
TOSSpecifies a default IPv4 TOS value for IPv4 flows.
LABELSpecifies a default IPv6 Flow Label for IPv6 flows.
TTLSpecifies a default TTL (time-to-live) hop count for transmitted multicast packets.
INTERFACESpecifies the name of the default interface to use for IP multicast.
INPUTSpecifies the name of a script file to be loaded and parsed.
OUTPUTSpecifies the name of the log file to record logged events. If the named log file pre-exists, it is overwritten.
LOGSame as OUTPUT, except that pr-existing log files are appended instead of overwritten.
SAVESpecifies a file to which MGEN should store sequence number state for any pending or active flows as well as the current relative script offset time when mgen is terminated.
TXBUFFERSpecifies a default socket transmit buffer size.
RXBUFFERSpecifies a default socket receive buffer size.
LOCALTIMESpecifies that mgen events and error messages are logged in localtime rather than the default Greenwich Mean Time.
QUEUESpecifies the default number of mgen messages that should be queued before mgen turns off the transmission timer for a flow.
LOGDATAControls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.

6.1. START

Script syntax:

START <hour:min:sec>[GMT]

The START command designates an absolute time as indicated by the <hour:min:sec> field to correspond to the relative script time of 0.0 seconds. All transmission and reception events will be scheduled relative to this absolute start time. The optional GMT suffix (no white space after the time) indicates that the clock time given is Greenwich Mean Time (GMT) rather than the operating systems local time zone. If no START command is given, mgen schedules transmission and reception events relative to program startup.

Example:

#Start MGEN exactly at 1:30PM local time

START 13:30:00

#Start MGEN at 30 seconds past 8:30 GMT

START 8:30:30GMT

6.2. OFFSET

Script syntax:

OFFSET <seconds>

The OFFSET global command specifies a relative time offset (in seconds)into script processing where MGEN should begin its activity. This allows multiple instances of MGEN using the same script to be dithered as desired. Additionally, this command may be used to immediately restore MGEN to a specific scripted state other than the beginning of the script upon launch.

Example:

#Skip the first 10 seconds of an MGEN script

OFFSET 10.0

6.3. TOS

Script syntax:

TOS <value>

The TOS command specifies ...

Example:

#Specify default ttl = 0x10 (low delay)

TOS 0x10

6.4. LABEL

Script syntax:

LABEL <value>

The LABEL command specifies a default value to be used as the "flow label" for IPv6 flows. The "flow label" is the corresponding 28-bit field in the IPv6 packet header. Refer to the Transmission Event LABEL option for further details..

Example:

#Specify default IPv6 flow label = 0x02500000

LABEL 0x02500000

6.5. TTL

Script syntax:

TTL <value>

The TTL command specifies the default time-to-live (TTL) hop count for generated IP multicast traffic according to the <value> field. The <value> must be in the range of 1-255. If the global TTL command is not used, mgen assumes a default multicast TTL value of 3. Note that the transmission event TTL option will override the default specification given by this global command.

Example:

#Specify default multicast flow ttl = 32

TTL 32

6.6. TXBUFFER

Script syntax:

TXBUFFER <txBufferSize> ...

This option allows users to set the default socket transmit buffer size to a value at least as large as <txBufferSize>. The exact behavior of this option may be operating system dependent. The TXBUFFER option given on transmission event script lines will override this default for the socket used by the corresponding flow.

6.7. RXBUFFER

Script syntax:

RXBUFFER <rxBufferSize> ...

This option allows users to set the default socket receive buffer size to a value ?at least? as large as <rxBufferSize>. The exact behavior of this option may be operating system dependent. The RXBUFFER option given on transmission event script lines will override this default for the socket used by the corresponding flow.

6.8. LOCALTIME

Script syntax:

LOCALTIME

This option allows users to specify that events and error messages be logged in localtime rather than the default Greenwich Mean Time.

6.9. QUEUE

Script syntax:

QUEUE

This global command will cause mgen to buffer <queueSize> mgen packets for each flow during periods of congestion. (Note that flow specific limits specified at the transmission event level will override this global). When the number of pending messages for a flow exceeds this limit, the message transmission timer will be temporarily deactivated and any pending messages will transmitted as quickly as possible. The timer will be reactivated once the pending message count falls below the queue limit, and message transmission will return to the previously scheduled rate of transmission.

If no global command is specified, a default <queueSize> of "0" will be in effect which will result in no queuing behavior, e.g. the transmission timer will continue to fire at its regularly scheduled interval regardless of transport congestion. No pending message count will be accumulated and message transmission will suceed or fail depending on transport availability.

When multiple flows are sending messages over a common mgen transport, the flows that have exceeded their pending message limit(s) will be serviced in a round robin fashion until all pending messages have been sent for all flows. Transmissions for flows that have fallen below this threshold will be interleaved as scheduled.

A <queueSize> threshold of "-1" sets an unlimited queue size. This means that a congested flow's transmission timer will continue to fire (thereby building up it's pending message count), but any pending messages will be sent as quickly as possible until congestion clears.

Any pending messages for a flow will be sent before the flow will be shutdown by a scheduled OFF event. Likewise, the pending message queue for a flow that is being restarted will be cleared. Note however, if any of the content of the mgen message header is changed (src or dst addresses, etc.) the pending message count will be reset. All other flow attribute changes (rage, message size, payload content, ttl, etc.) will be effected immediately, including any pending messages.

6.10. DATA

Script Syntax:

DATA [<hex>,<hex>]

User defined message payload can be specified with the DATA command. The data should be a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data. The contents will be placed in every packet generated by the flow.

6.11. INTERFACE

Script syntax:

<interfaceName>

The INTERFACE command specifies a default IP network interface to use for multicast traffic generation and group membership. If no INTERFACE command is given, the default operating system behavior is observed. Note that the transmission event INTERFACE option or the JOIN reception event INTERFACE option will override the default specification given by this global command.

Example:

#Specify "eth1" as the default network interface

#for multicast transmission and group joins

INTERFACE eth1

6.12. INPUT

Script syntax:

INPUT <scriptFile>

The INPUT command cause MGEN to load and parse the given <scriptFile>. (Circular references are not detected by mgen and should be avoided_). This allows scripts to "include" other scripts. The parsing occurs in the order that the INPUT commands are encountered on the command-line and within the script files themselves.

Example:

#Load and parse the MGEN script file "script2.mgn"

INPUT script2.mgn

6.13. OUTPUT

Script syntax:

OUTPUT <logFile>

The OUTPUT command cause mgen to direct its log output to the indicated <logFile>. The last occurring OUTPUT command determines the log file to be used and the command-line takes precedence over any scripts provided as input to mgen. The file named by <logFile> will be overwritten if it already exists.

Example:

#Use the file "logFile.drc" for logging

OUTPUT logFile.drc

6.14. LOG

Script syntax:

LOG <logFile>

The LOG command cause mgen to direct its log output to the indicated <logFile>. The last occurring LOG command determines the log file to be used and the command-line takes precedence over any scripts provided as input to mgen. The file named by <logFile> will be appended if it already exists.

Example:

#Append the file "logFile.drc"

LOG logFile.drc

6.15. LOGDATA

Script syntax:

LOGDATA {on|off}}

Controls whether MGEN will log the optional data attribute field at MGEN receivers (including within MGEN binary log files). It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON.

Example:

#Don't log optional data attribute at receiver

LOGDATA off

6.16. SAVE

Script syntax:

SAVE <saveFile>

The SAVE command causes mgen to write a short MGEN script upon exit which includes current sequence number state for pending and active transmission flows as well as the current relative script offset time. If the <saveFile> created is given as an additional input script (with the same input script(s) given for the mgen instance which created <saveFile>), on a subsequent launch of mgen, mgen will return to the same state as it was when it previously exited.

The SAVE command can be used when it is desired to conduct separate runs of mgen, but preserve a continuous sequence number space across the multiple runs. An example script performing this function is given below. Note the same behavior can also be achieved via the mgen command-line using:

"mgen input <scriptFile> input <saveFile> save <saveFile> log <logFile>"

if an empty <saveFile> is provided on the first launch of mgen.

Example:

# This script executes another MGEN script, using

# "saveFile.mgn" for state recovery upon subsequent

# restarts after mgen is exited.

# (If "saveFile.mgn" is empty or non-existent upon

# initial startup, the "scriptFile.mgn" is run

# from the beginning.)

# (The "log" command is used to repeatedly append

# the "logFile.drc" file upon stop and restart)

INPUT scriptFile.mgn

INPUT saveFile.mgn

SAVE saveFile.mgn

LOG logFile.drc

7. MGEN Log File Format

The MGEN message format contains information to facilitate network performance measurements through post-analysis of MGEN log files. Some of the types of performance statistics which can be determined include:

Message ThroughputThe time or arrival and size of received messages are logged by MGEN receivers. Network throughput can be assessed with this information.
Message Delivery LatencyMGEN messages contain a timestamp reflecting when they were sent and the time of reception is logged by MGEN receivers. Delivery latency statistics (jitter or absolute if clock synchronization (e.g. NTP) is possible) can be determined with this information.
Message Loss RateMGEN messages are sequence numbered. Message loss can be accounted for via analysis of logged sequence number information.
Message Re-orderingThe logged MGEN sequence number information can also be used to determine message re-ordering statistics.
Multicast JOIN/LEAVE LatencyThe occurrence and time of JOIN/LEAVE events are logged by MGEN receivers. The JOIN latency can be determined by comparing the arrival time of the first message associated with a particular multicast group to the time the group was joined. The LEAVE latency can be determined by comparing the time of the _last_ packet arrival time to the time the receiver left that multicast group (Note that you need a packet sniffing program like tcpdump to see packets after you leave the group).

Many of the above performance measures and statistics can be measured and optionally graphed using the NRL trpr (trace plot real-time) program. This program can parse the MGEN log file format and tcpdump traces.

7.1. General Log Format

Each line of the MGEN text log file format corresponds to a unique event and follows the convention:<eventTime> <eventType> <event attributes ...>The <eventTime> field is in the form hrs:min:sec and represents the computer's system Greenwich Mean Time (GMT) at the time of the event.

The <eventType> field is one of the following:

RECVDenotes the arrival of a received MGEN message.
RERRIndicates an invalid MGEN message was received.
SENDDenotes the transmission of an MGEN message.
JOINMarks a join to an IP multicast group.
LEAVEMarks the departure from an IP multicast group.
LISTENIndicates when mgen began monitoring a specific port
IGNOREIndicates when mgen ended monitoring of a specific port
ONIndicates when mgen initiated a TCP connection to the indicated destination ip address and port or when a UDP flow began transmitting.
CONNECTIndicates when an mgen TCP "client" or "sender" has established a TCP connection from the indicated source port or to the destination ip address and port.
ACCEPTIndicates when an mgen TCP "server" or "listener" has accepted a TCP connection from the indicated source ip address and port to the destination port.
SHUTDOWNIndicates when an mgen TCP connection was shutdown after a scheduled >OFF< event on the client side or when an active connection is shutdown by the server on the server side. When TCP completes the shutdown procedure, an OFF or a DISCONNECT event will be logged as appropriate.
DISCONNECTIndicates when an mgen TCP connection was disconnected prior to a scheduled >OFF< event on either the client or server side. This event indicates a TCP error has occurred on the connection. (NOTE: this indication of an unscheduled TCP shutdown is currently reliable only on Linux systems.)
OFFIndicates that an mgen flow was stopped by a scheduled >OFF< event on the client or by a server IGNORE event on the sever. (Only available when transmission logging is enabled on the client side).
STARTIndicates when mgen started processing Transmission and Reception events.
STOPIndicates when mgen stopped processing Transmission and Reception events.

Different event types will have different event attribute sets. The <event attribute> fields are explicitly labeled so that log file parsing programs can seek specific attributes of interest for given event types.

7.2. Log File RECV Events

The format of the RECV event log file line is:

<eventTime> RECV proto><protocol> flow><flowId> seq><sequenceNumber> src><addr> /<port> dst><addr>/<port> sent><txTime> size><bytes> [host><addr>/<port>] [gps><status>,<lat>,<long>,<alt>] [data><len>:<data>] [flags><flag>]

The <eventTime> corresponds to when the message was received. The <protocol> specifies the protocol (udp,tcp,sink).The <flowId>, <sequenceNumber>, and <txTime>, are from the payload of the MGEN message. The <txTime> is in the same format as the <eventTime> (i.e. <hr:min:sec> GMT)

The "dst" <addr>/<port> is from the message payload and corresponds to the destination address to which the source addressed the MGEN message.

The "src" <addr>/<port> is the source address determined from the corresponding recvfrom() call for UDP transport or the address to which the TCP connection was made. (An optional "host" address will be embedded in the payload by the MGEN message source and made available as an attribute of the logged RECV event in the future).

The message "size" in <bytes> is also from the payload, but for UDP transport, should also correspond to the UDP packet payload size. Note that TCP mgen messages can be larger than the maximum UDP message size of 8192 bytes and can be of unlimited size. Therefore, mgen breaks large TCP messages into mgen message "fragments" of a maximum size of 65535 and sets a flag on the mgen message to indicate that it is a TCP message "fragment". Message fragments are flagged with 0x01 to indicate that the message is not complete. The last fragment in a TCP message is flagged 0x02 to indicate "end of message".

For example, a TCP mgen message of size 66559 will be received and logged by the receiving node as two messages as follows:

00:33:36.427143 RECV proto>TCP flow>1 seq>1 src>192.168.1.102/35056 dst>192.168.1.100/5000 sent>00:36:11.377105 size>65535 gps>INVALID,999.000000,999.000000,-999 flags>0x01

00:33:36.427499 RECV proto>TCP flow>1 seq>1 src>192.168.1.102/35056 dst>192.168.1.100/5000 sent>00:36:11.380137 size>1024 gps>INVALID,999.000000,999.000000,-999 flags>0x02

Also note that a single SEND message will be logged by the transmitting node with a size corresponding to the TCP message size, e.g.:

00:29:51.396962 SEND proto>TCP flow>1 seq>1 srcPort>0 dst>192.168.1.102/5000 size>66559

The "host" <addr>/<port> corresponds to the MGEN message source's "perceived" default local address. Note that this may be different from the source address contained in the MGEN log file due to firewalls, Network Address Translation (NAT) devices, multi-homed sources, etc. The accuracy of this information depends upon the source host's configuration with regards to domain name service (DNS), etc. Note this field is optional and may not be present if this information is not valid (The current initial MGEN release does not yet support this option).

The "src", "dst", and "host" <addr> fields are dotted decimal IPv4 addresses or colon-delimited IPv6 addresses.

The "flags" field is discussed above.

The global positioning system (GPS) information is available when the MGEN message source is used in conjunction with the NRL gpsLogger program. This program monitors an attached GPS receiver for position information and "publishes" it in shared memory. When mgen is run and detects that it can "subscribe" to GPS position information, it places it in the MGEN message payload. Note that gpsLogger can also be used with a pulse-per-second (PPS) capable GPS receiver to provide accurate time synchronization for hosts running the MGEN toolset. This may be useful for mobile network test environments. The MGEN log file "gps" attribute has the following comma-delimited fields:

<status>This indicates the validity of the GPS information and may be either "INVALID", "CURRENT", or "STALE".
<lat>This is the GPS latitude in degrees. A negative value denotes South while a positive value denotes North.
<long>This is the GPS longitude in degrees. A negative value denotes West while a positive value denotes East.
<alt>This is the GPS altitude in meters.

The optional "data" attribute is present only if the received MGEN message contains optional user-defined payload. If present, the <len> indicates the length (in bytes) of the user-defined payload and the <data> following the colon character':' is a hexadecimal representation of the user data where each pair of characters corresponds to one byte of user data. Thus, the number of characters in the <data> field will be 2 * <len>. (The "data" option was supported in MGEN 3.x via the MGEN Payload Manager (mpmgr) tool and is not yet supported in MGEN 4.x. The documentation will be updated when this option is supported).

Example RECV event log lines:

22:59:52.312721 RECV proto><protocol> flow>1 seq>1 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024

23:59:53.312721 RECV proto><protocol> flow>1 seq>2 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024 host>132.250.68.21/5000 gps>CURRENT,35.123,79.234,57

23:59:53.312721 RECV proto><protocol> flow>1 seq>2 src>132.250.68.21/5000 dst>132.259.43.96/5002 sent>22:59:52.310324 size>1024 host>132.250.68.21/5000 gps>CURRENT,35.123,79.234,57 data>10:01a97b34458cff0021e8

7.3. Log File RERR Events

The format of the RERR (Receive Error) event log file line is:

<eventTime> RERR proto><protocol> type><errorType> src><addr>/<port>

The <eventTime> corresponds to when the message in error was received. The <errorType> is one of "none", "version", "checksum", or "dstaddr". An receive error of type "version" indicates the MGEN sender is using an mgen executable with an incompatible version number. The "checksum" error indicates the received message failed checksum validation, and the "dstaddr" error indicates an invalid or unsupported destination address type in the MGEN message received. The <src> attribute indicates the source address of the message in error.

7.4. Log File SEND Events

The format of the SEND event log file line is:

<eventTime> SEND proto><protocol> flow><flowId> seq><sequenceNumber> src><srcPort> dst><addr>/<port> size><bytes> [host><addr>/<port>]

The <eventTime> corresponds to when the message was sent, and it should precisely match the <txTime> logged by the machine the packet is sent to, if the packet is received correctly.

All the data items are the same as those used in the Log File RECV Events.

7.5. Log File JOIN Events

The format of the JOIN log file event line is:

<eventTime> JOIN group> <groupAddress> [src> <srcAddress>] [interface> <interfaceName>]

The <groupAddress> is the IP multicast group address which was joined. The format of this field is either a dotted decimal IPv4 address or a colon-delimited IPv6 address. The <interfaceName> is given only when the executed MGEN script used the INTERFACE option in the corresponding JOIN script event.

Example JOIN event log lines:

22:59:50:234757 JOIN group>224.1.2.3

22:59:51:129574 JOIN group>224.1.2.4 interface>eth1

22:59:51:129574 JOIN group>224.1.2.4 src>25.25.25.1 interface>eth1

7.6. Log File LEAVE Events

The format of log file LEAVE event lines is:

<eventTime> LEAVE group><groupAddress> [src> <srcAddress>] [interface><interfaceName>]

The <groupAddress> is the IP multicast group address which was left. The format of this field is either a dotted decimal IPv4 address or a colon-delimited IPv6 address. The <interfaceName> is given only when the executed MGEN script used the INTERFACE option in the corresponding LEAVE script event.

Example LEAVE event log lines:

22:59:59:234757 LEAVE group>224.1.2.3

22:59:59:753683 LEAVE group>224.1.2.4 interface>eth1

22:59:59:753683 LEAVE group>224.1.2.4 src>25.25.25.1 interface>eth1

7.7. Log File LISTEN Events

The format of the LISTEN event log file line is:

<eventTime> LISTEN proto><protocol> port><portNumber>

The <protocol> field corresponds to the transport protocol type being used. Supported protocols include "UDP" and "TCP". The <portNumber> field is the host port number to be monitored.

Example LISTEN event log lines:

22:59:48:834205 LISTEN proto>UDP port>5000

22:59:49:328039 LISTEN proto>UDP port>5001

7.8. Log File IGNORE Events

The format of the IGNORE event log file line is:

<eventTime> IGNORE proto><protocol> port><portNumber>

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP". The <portNumber> field is the host port number to be no longer monitored.

Example IGNORE event log lines:

23:00:00:723467 IGNORE proto>UDP port>5000

23:01:00:235629 IGNORE proto>UDP port>5001

7.9. Log File ON Events

The format of the ON event log file line is:

<eventTime> ON flow><flowID> srcPort><srcPort> dst><dst>/<portNumber>

This event indicates that mgen has attempted to establish a TCP connection with the target destination address and port or a UDP flow has begun transmitting. It does not indicate that the connection has been successfully established, only that a connection has been attempted. The <flowID> field corresponds to the TCP flow ID of the connection. The <srcPort> is either the OS provided or user specified src port for the flow. The <dst> field corresponds to the destination of the TCP connection. The <portNumber> field is the destination port number of the TCP connection.

Example ON event log lines:

23:00:00:723467 ON flow>1 srcPort>4000 dst>192.168.1.100/5000

7.10. Log File CONNECT Events

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP".

The format of the CONNECT event log file line is:

<eventTime> CONNECT flow><flowId> srcPort><srcPort> dst><dst>/<portNumber>

The <src> and <dst> fields correspond to the local source port and destination ip address/port of the TCP connection. The <flowID> is the transmitting flow id. If multiple flows are sharing the connection, CONNECT events will be logged for each flow.

Example CONNECT event log line:

23:00:00:723467 CONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000

7.11. Log File ACCEPT Events

The <protocol> field corresponds to the transport protocol type which was being used. Supported protocols include "UDP" and "TCP".

The format of the ACCEPT event log file line is:

<eventTime> ACCEPT srcPort><srcAddr><srcPort> dstPort><dstPort>

The <src> and <dst> fields correspond to the source ip address and port and local receiving(dst) port of the TCP connection.

Example ACCEPT event log line (server):

23:00:00:723467 ACCEPT srcPort>4007 dst>192.168.1.100/5000

7.. Log File SHUTDOWN Events

The format of the SHUTDOWN event log file line is:

<eventTime> SHUTDOWN flow><flowID> srcPort><srcPort> dst><dstAddr><dstPort> (client)

<eventTime> SHUTDOWN src><srcAddr><srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the dst indicated address and port was shutdown after a client OFF event or by the server after a server IGNORE event has been processed and client connections remain active on the dst port being listened to. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was attempting to connect to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was prematurely terminated, no SHUTDOWN event will be logged.

Example Client SHUTDOWN event log line (client):

23:00:00:723467 SHUTDOWN flow><flowId> src>192.168.1.102/5000 dstPort>6000

Example Server SHUTDOWN event log line (server):

23:00:00:723467 SHUTDOWN src>192.168.1.100/5000 dst>6000

If multiple flows are sharing the same connection, the shutdown event will be logged only when the last flow has stopped sending to the socket pair. An "OFF" event will be logged for any connections ending while other flows are still transmitting, e.g.:

22:35:52.458531 OFF flow>1 srcPort>4000 dst>192.168.1.100/5000

22:35:52.458542 SEND proto>TCP flow>2 seq>3 srcPort>4000 dst>192.168.1.100/5000 size>8192

22:35:52.458598 SHUTDOWN flow>2 srcPort>4000 dst>192.168.1.100/5000

22:35:52.460419 OFF flow>2 srcPort>4000 dst>192.168.1.100/5000

7.13. Log File DISCONNECT Events

The format of the DISCONNECT event log file line is:

<eventTime> DISCONNECT flow><flowID> srcPort><srcPort> dst><dstAddr><dstPort> (client)

<eventTime> DISCONNECT src><srcAddr</<srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the indicated address and port has disconnected either because the connection could not be established in the first place or because the connection was prematurely terminated. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was attempting to connect to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was not prematurely terminated, no DISCONNECT event will be logged. (NOTE: Indication of unscheduled TCP disconnection is not available relieably under windows at this time.)

Example Client DISCONNECT event log line:

23:00:00:723467 DISCONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000

Example Server DISCONNECT event log line :

23:00:00:723467 DISCONNECT src>192.168.1.100/4000 dstPort>5000

7.14. Log File OFF Events

The format of the OFF event log file line is:

<eventTime> OFF flow> <flowID> srcPort><srcPort> dst><dstAddr>/<dstPort> (client)

<eventTime> OFF src><srcAddr><srcPort> dstPort><dstPort> (server)

This event indicates that a TCP connection with the indicated address and port has been successfully shutdown (e.g. disconnected) after a scheduled mgen OFF event. In the TCP client's log file, the dst address and port reflect the address and port of the node the client was connected to. In the TCP server's log file, the src address and port reflects the address and port of the connecting node. The <flowID> field corresponds to the TCP flow ID of the connection (this field is only available in the client's event log). Note that if a TCP connection was prematurely terminated by either the client or the server, a DISCONNECT event will be logged instead of an OFF event. (NOTE: Under Windows operating systems, the DISCONNECT event is not reliable and the OFF event may be logged for both planned and unplanned socket disconnects.)

Example Client OFF event log line (client):

23:00:00:723467 OFF flow>1 srcPort>4000 dst>192.168.1.102/5000

Example Server OFF event log line (server):

23:00:00:723467 OFF src>192.168.1.100/4000 dstPort>5000

Note that the server will only log a single OFF event if multiple tcp flows are being recevied over the socket pair, although the client will log OFF events for each flow.

7.15. Log File START and STOP Events

The format of the START and STOP event log file line is:

<eventTime> STARTor<eventTime>STOP

These log file lines indicate the time at which MGEN began and ended its operation. The "START" time corresponds to the relative time zero for any executed scripts. This "START" time is when the mgen program was executed unless the global START command was invoked. The "STOP" command corresponds to when the mgen program was halted.

8. Binary Log File Format

At the beginning of binary log files, there is a plain text line to make it easy to tell what kind of file it is. It has the mgen version number, as well as the type of file ("binary_log"). This line is terminated with a line feed and a NULL ('\0') character. Following the NULL, the file contains a series of binary formatted records. There are several different types of records in the binary log file format. Each record consists of a number of fields. The first single-byte field indicates the record type. A record type of 0 is considered invalid. All multiple-byte fields are in standard network byte order (i.e. most significant byte first). Each record in the binary log file corresponds to a single unique Mgen event, just as each line in the text-based log file does. Each binary log file record contains the same information that every line of the text-format log file has. The text-format log file can actually be recreated from a binary log file using the "convert" command of mgen.

8.1. Binary Log File RECV Events

The format of the RECV event binary log file record is:

 The format of the RECV event binary log file record is:
 
  0                   1                   2                   3
@@ -244,4 +262,4 @@
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                          checksum                             |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-

All multiple-byte fields are in standard network byte order (i.e. most significant byte first).

The <messageSize> field indicates the total size (including the <messageSize>, <version>, <flags>, etc fields) of the MGEN message in bytes. The current UDP-only transport limits this to a maximum of 8192 bytes. In the future, larger message sizes will be supported and in conjunction with the <flags> field, very large messages will be supported as a concatenation of MGEN messages to support emulation of large file transfers, etc.

The <version> field is the MGEN message protocol version number. This will enable future versions of MGEN to b backwards compatible and prevent older versions of MGEN from attempting to parse packets in unknown format.

Currently a single <flags> value (CHECKSUM = 0x01) is defined. When this flag is set, it indicates the presence of the <checksum> field at the end of the MGEN message. It is expected that additional flags will be useful as MGEN adds support for transport types besides UDP.

The <mgenFlowId> contains the flow/thread identification value associated with the MGEN flow in the corresponding script which created the flow. Note that each flow identified from an MGEN source has its own sequence number space.

The <sequenceNumber> contains the 32-bit sequence number which is incremented with each message generated for an MGEN flow. This will wrap to zero when the maximum is reached.

The <txTimeSeconds> and <txTimeMicroseconds> fields are used to mark the time of transmission of the MGEN message. The time is the source computer's system time in Greenwich Mean Time (GMT).

The <dstPort> is the destination port number to which the MGEN message addressed by the source.

The <dstAddrType> field indicates the type of destination address encapsulated in following fields. Possible types and values include:

INVALID_ADDRESS0
IPv41
IPv62

The <dstAddrLen> field indicates the length in bytes of the destination address field <dstAddr> to follow. The length should be 0 (zero) for the INVALID_ADDRESS type, 4 for IPv4 addresses, and 16 for IPv6 addresses.

The <dstAddr> contains the destination address to which the source addressed the MGEN message. The address is in network byte order.

Note that the following fields are optional and the MGEN message length my be truncated at any point after here. Any incomplete optional fields are considered invalid.

The <hostPort> and <hostAddr> (if present and valid) contain the MGEN message source's default local address. Note that this may be different from the source address contained in the MGEN log file due to firewalls, Network Address Translation (NAT) devices, multi-homed sources, etc.

The <hostPort> is the destination port number to which the MGEN message was addressed by the source.

The <hostAddrType> field indicates the type of destination address encapsulated in following fields. The possible values are the same as for the <dstAddrType> described above.

The <hostAddrLen> field indicates the length in bytes of the destination address field <hostAddr> to follow.

The <hostAddr> contains the source's perception of its local default network address. In mgen, this is determined by a system call to gethostname(), followed by a call to name resolution. This address may be incorrect if the host is not correctly configured or domain name service (DNS) is unavailable.

The <latitude>, <longitude>, and <altitude> fields contain values corresponding to GPS information for the MGEN source if it was available. The <latitude> and <longitude> fields are encoded as follows:

<fieldValue> = (unsigned long)((<actualValue>+180.0)*60000.0)

The <altitude> field is the direct representation of the altitude value available from the source's GPS system.

The <gpsStatus> indicates the validity of the GPS information which was encoded. Possible status types and values currently include:

INVALID_GPS0
STALE1
CURRENT2

In addition to the <gpsStatus> field, actual values of 999.0 for latitude and longitude, and ?999 for altitude also correspond to invalid values.

The <payloadLen> field, when of non-zero value, indicates the presence of optional user-defined content in the MGEN message. The <payloadLen> value indicates the quantity (in bytes) of user-defined content which follows.

The <payload> field contains the user-defined content and is of length <payloadLen> bytes. Note that a short MGEN <messageSize> could truncate this field. If the MGEN user provides the optional user-defined content, it is up to the user to ensure that the generated MGEN messages are of sufficient size as not to truncate the <payload> content.

The <padding> portion of MGEN messages contain undefined data content.

The <checksum> field is optional and is present when the CHECKSUM (0x01) flag is set in the <flags> field. Note that corrupted messages may result in MGEN messages with the <flags> field itself corrupted, so it may be useful for MGEN implementations to have an option to validate checksums even when the CHECKSUM flag is not set if it is known that the sender is providing checksum content.

Note: The total size of the MGEN message is defined by the <messageSize> field. The optional fields may be truncated if the <messageSize> is small. The minimum MGEN message size will depend upon the IP address types being used. For example, the minimum allowed MGEN message size using IPv4 addresses with no optional fields is 28 bytes (i.e. for UDP, the UDP payload size would be 28 bytes). If GPS information is to be included without truncation, the minimum message size becomes 52 bytes with the inclusion of the <hostAddr> and GPS information. For IPv6 destination addresses, the minimum allowed MGEN message size is 40 bytes with no optional fields. If GPS information is included the minimum message size with truncating information is 76 bytes.

10. Compile options

10.1. RANDOM_FILL

Adding the RANDOM_FILL compile time option will cause MGEN to fill the payload with random content. Otherwise, the payload will be zero filled. (Alternatively, the DATA option may be used).

10.2. HAVE_IPV6

The HAVE_IPV6 compile time option indicates that the system is IPV6 capable. IPV6 packets will be generated.

10.3. SIMULATE

The SIMULATE compile time option indicates that MGEN will be running in a simulation environment.

10.4. HAVE_GPS

The HAVE_GPS compile time option indicates that a GPS service is available. GPS information will be put into the MGEN message payload.

10.5. HAVE_PCAP

The HAVE_PCAP compile time option indicates that the system has PCAP installed. This option should be used when MGEN will be "cloning" a TCPDUMP file.

10.6. Other

Operating system compile time options include UNIX, _WIN32_WCE, WIN32, LINUX, MACOSX. These should be set as appropriate to the operation system type. UNICODE log file output may be specified for WIN32 operating systems. On Solaris (and possibly other Unix) operating systems, the IP_MAX_MEMBERSHIPS option will set the IP_MAX_MEMBERSHIP limit per socket to -1 as no pre-defined limit is set in the OS.

11. Known issues

11.1. Macosx Windows TCP Interaction

There is a negative interaction between Nagle's TCP Algorithm and Delayed ACK that causes a TCP performance delay between traffic flowing from some Windows OSs to macosx. This can be alleviated somewhat by setting the sysctl net.inet.tcp.delayed_ack value to 1 (always employ delayed ack, 6 packets can get 1 ack) although performance may still be still be impacted. Windows-7 is impacted more than Vista. The phenomenon varies by traffic pattern.

\ No newline at end of file +

All multiple-byte fields are in standard network byte order (i.e. most significant byte first).

The <messageSize> field indicates the total size (including the <messageSize>, <version>, <flags>, etc fields) of the MGEN message in bytes. The current UDP-only transport limits this to a maximum of 8192 bytes. In the future, larger message sizes will be supported and in conjunction with the <flags> field, very large messages will be supported as a concatenation of MGEN messages to support emulation of large file transfers, etc.

The <version> field is the MGEN message protocol version number. This will enable future versions of MGEN to b backwards compatible and prevent older versions of MGEN from attempting to parse packets in unknown format.

Currently a single <flags> value (CHECKSUM = 0x01) is defined. When this flag is set, it indicates the presence of the <checksum> field at the end of the MGEN message. It is expected that additional flags will be useful as MGEN adds support for transport types besides UDP.

The <mgenFlowId> contains the flow/thread identification value associated with the MGEN flow in the corresponding script which created the flow. Note that each flow identified from an MGEN source has its own sequence number space.

The <sequenceNumber> contains the 32-bit sequence number which is incremented with each message generated for an MGEN flow. This will wrap to zero when the maximum is reached.

The <txTimeSeconds> and <txTimeMicroseconds> fields are used to mark the time of transmission of the MGEN message. The time is the source computer's system time in Greenwich Mean Time (GMT).

The <dstPort> is the destination port number to which the MGEN message addressed by the source.

The <dstAddrType> field indicates the type of destination address encapsulated in following fields. Possible types and values include:

INVALID_ADDRESS0
IPv41
IPv62

The <dstAddrLen> field indicates the length in bytes of the destination address field <dstAddr> to follow. The length should be 0 (zero) for the INVALID_ADDRESS type, 4 for IPv4 addresses, and 16 for IPv6 addresses.

The <dstAddr> contains the destination address to which the source addressed the MGEN message. The address is in network byte order.

Note that the following fields are optional and the MGEN message length my be truncated at any point after here. Any incomplete optional fields are considered invalid.

The <hostPort> and <hostAddr> (if present and valid) contain the MGEN message source's default local address. Note that this may be different from the source address contained in the MGEN log file due to firewalls, Network Address Translation (NAT) devices, multi-homed sources, etc.

The <hostPort> is the destination port number to which the MGEN message was addressed by the source.

The <hostAddrType> field indicates the type of destination address encapsulated in following fields. The possible values are the same as for the <dstAddrType> described above.

The <hostAddrLen> field indicates the length in bytes of the destination address field <hostAddr> to follow.

The <hostAddr> contains the source's perception of its local default network address. In mgen, this is determined by a system call to gethostname(), followed by a call to name resolution. This address may be incorrect if the host is not correctly configured or domain name service (DNS) is unavailable.

The <latitude>, <longitude>, and <altitude> fields contain values corresponding to GPS information for the MGEN source if it was available. The <latitude> and <longitude> fields are encoded as follows:

<fieldValue> = (unsigned long)((<actualValue>+180.0)*60000.0)

The <altitude> field is the direct representation of the altitude value available from the source's GPS system.

The <gpsStatus> indicates the validity of the GPS information which was encoded. Possible status types and values currently include:

INVALID_GPS0
STALE1
CURRENT2

In addition to the <gpsStatus> field, actual values of 999.0 for latitude and longitude, and ?999 for altitude also correspond to invalid values.

The <payloadLen> field, when of non-zero value, indicates the presence of optional user-defined content in the MGEN message. The <payloadLen> value indicates the quantity (in bytes) of user-defined content which follows.

The <payload> field contains the user-defined content and is of length <payloadLen> bytes. Note that a short MGEN <messageSize> could truncate this field. If the MGEN user provides the optional user-defined content, it is up to the user to ensure that the generated MGEN messages are of sufficient size as not to truncate the <payload> content.

The <padding> portion of MGEN messages contain undefined data content.

The <checksum> field is optional and is present when the CHECKSUM (0x01) flag is set in the <flags> field. Note that corrupted messages may result in MGEN messages with the <flags> field itself corrupted, so it may be useful for MGEN implementations to have an option to validate checksums even when the CHECKSUM flag is not set if it is known that the sender is providing checksum content.

Note: The total size of the MGEN message is defined by the <messageSize> field. The optional fields may be truncated if the <messageSize> is small. The minimum MGEN message size will depend upon the IP address types being used. For example, the minimum allowed MGEN message size using IPv4 addresses with no optional fields is 28 bytes (i.e. for UDP, the UDP payload size would be 28 bytes). If GPS information is to be included without truncation, the minimum message size becomes 52 bytes with the inclusion of the <hostAddr> and GPS information. For IPv6 destination addresses, the minimum allowed MGEN message size is 40 bytes with no optional fields. If GPS information is included the minimum message size with truncating information is 76 bytes.

10. Compile options

10.1. RANDOM_FILL

Adding the RANDOM_FILL compile time option will cause MGEN to fill the payload with random content. Otherwise, the payload will be zero filled. (Alternatively, the DATA option may be used).

10.2. HAVE_IPV6

The HAVE_IPV6 compile time option indicates that the system is IPV6 capable. IPV6 packets will be generated.

10.3. SIMULATE

The SIMULATE compile time option indicates that MGEN will be running in a simulation environment.

10.4. HAVE_GPS

The HAVE_GPS compile time option indicates that a GPS service is available. GPS information will be put into the MGEN message payload.

10.5. HAVE_PCAP

The HAVE_PCAP compile time option indicates that the system has PCAP installed. This option should be used when MGEN will be "cloning" a TCPDUMP file.

10.6. Other

Operating system compile time options include UNIX, _WIN32_WCE, WIN32, LINUX, MACOSX. These should be set as appropriate to the operation system type. UNICODE log file output may be specified for WIN32 operating systems. On Solaris (and possibly other Unix) operating systems, the IP_MAX_MEMBERSHIPS option will set the IP_MAX_MEMBERSHIP limit per socket to -1 as no pre-defined limit is set in the OS.

11. Known issues

11.1. Macosx Windows TCP Interaction

There is a negative interaction between Nagle's TCP Algorithm and Delayed ACK that causes a TCP performance delay between traffic flowing from some Windows OSs to macosx. This can be alleviated somewhat by setting the sysctl net.inet.tcp.delayed_ack value to 1 (always employ delayed ack, 6 packets can get 1 ack) although performance may still be still be impacted. Windows-7 is impacted more than Vista. The phenomenon varies by traffic pattern.

\ No newline at end of file diff --git a/doc/mgen.pdf b/doc/mgen.pdf index 7b34f51b..18a26bf6 100755 Binary files a/doc/mgen.pdf and b/doc/mgen.pdf differ diff --git a/doc/mgen.xml b/doc/mgen.xml index 2bed816d..fa4f0074 100644 --- a/doc/mgen.xml +++ b/doc/mgen.xml @@ -6,11 +6,11 @@ <inlinemediaobject> <imageobject> - <imagedata fileref="mgenLogo.gif" /> + <imagedata fileref="mgenLogo.gif"/> </imageobject> </inlinemediaobject><inlinemediaobject> <imageobject> - <imagedata fileref="drecLogo.gif" /> + <imagedata fileref="drecLogo.gif"/> </imageobject> </inlinemediaobject>MGEN User's and Reference Guide Version 5.0 @@ -127,23 +127,26 @@ [txcheck][rxcheck][check][stop] [convert <binaryLog>][debug <debugLevel>] [localtime <localtime>] [queue <queue>] - [broadcast {on|off}] + [broadcast {on|off}] [logdata {on|off}] + [loggpsdata {on|off"] + + Example Usage To run mgen with script file "script.mgn" and log to stdout (by - default): + default): mgen input script.mgn To monitor ports 5000,5004,5005, and 5006 for received UDP traffic - and log to a specific file "log.drc": + and log to a specific file "log.drc": mgen port 5000,5004-5006 output log.drc The "event" command can be used to achieve equivalent operation - with the command-line syntax: + with the command-line syntax: mgen event "listen udp 5000,5004-5006" output log.drc @@ -170,8 +173,7 @@ ssh, peer-to-peer protocols, etc). Here is an example using ssh to set up a TCP connection to a remote machine, start an mgen receiver at the remote machine to log receive messages, and attempt to transmit a 2 Mbps - stream of MGEN messages via the ssh - connection: + stream of MGEN messages via the ssh connection: mgen event "ON 1 SINK DST 127.0.0.1/5001 PERIODIC [200 1250]" \ sink STDOUT output /dev/null | ssh <remoteHost> sh -c @@ -196,7 +198,7 @@ LISTEN command is used to monitor these (and other) ports so that mgen can receive its own traffic for demonstration purposes. This script illustrates the usage of a number of MGEN script - commands. + commands. # MGEN script begins here # These are some "Transmission Event" script lines @@ -224,12 +226,27 @@ # Join an IP multicast group 0.0 JOIN 224.225.1.2 INTERFACE eth0 +# Join a SSM multicast group (Supported only for *nix) +#0.0 JOIN 232.1.1.1 SRC 25.25.25.1 INTERFACE eth0 + # For WIN32, use the "PORT" option 0.0 JOIN 224.225.1.2 PORT 5002 +# For OSX use the "interface" option if a default multicast route is not defined +#0.0 JOIN 224.1.2.3 interface en0 + +# Join a multicast group across a range of ports +0.0 JOIN 224.1.2.5 PORT 5005-5010 + +# On IPv6 systems set the port option when IPv4 group membership is requested +0.0 JOIN 224.1.2.4 port 5001 + # Later, leave the group 5.0 LEAVE 224.225.1.2 INTERFACE eth0 +# This SSM LEAVE is for UNIX (Currently SSM is supported only in UNIX) +#5.0 LEAVE 224.224.1.2 SRC 25.25.25.1 INTERFACE eth0 + # Incrementally ignore some receive traffic 6.0 IGNORE UDP 5000-500 18.0 IGNORE UDP 5001,6000,6003 @@ -252,6 +269,10 @@ + + + + ipv4 @@ -365,7 +386,7 @@ spaces and thus must be encapsulated in quotes on the command line. Note that the <eventTime> may be omitted and the action indicated will be taken by mgen immediately. When the - eventcommand + eventcommand is issued during run-time, the <eventTime> (if provided) specifies a delay relative to the current time (e.g. the event will occur with after the given delay). @@ -412,11 +433,11 @@ UDP traffic. The format of the <recvPortList> is a comma-delimited list of individual or inclusive ranges of port values (No spaces allowed in the list). Note this is the - equivalent of a scripted 0.0 LISTEN UDP + equivalent of a scripted 0.0 LISTEN UDP <recvPortList>reception event and can also be equivalently achieved with the event command using the - syntax: mgen event "LISTEN UDP + syntax: mgen event "LISTEN UDP <portList>"Example:mgen port 5000,5002,5005-5009 @@ -638,6 +659,35 @@ socket. As with tos, ttl and interface, broadcast is a "per socket" attribute. By default BROADCAST is set to ON. + + + logdata {on|off} + + Controls whether MGEN will log the optional data attribute + field at MGEN receivers (including within MGEN binary log files). + It does not affect whether MGEN senders send the requested data + attribute. By default LOGDATA is set to ON. + + + + loggpsdata {on|off} + + Controls whether MGEN will log the gps data fields at MGEN + receivers. It does not affect whether MGEN senders send the GPS + data. By default LOGGPSDATA is set to ON. Note that as opposed to + the logdata attribute, GPS data will be saved in any interim + binary log file regardless of this flag. This flag only controls + whether the gps data is logged in the formatted log files. + + + + boost + + The boost option sets the mgen process to realtime process + priority. Care should be taken using the "precise" and "boost" + options together as the mgen process can take over a machine at + high packet rates (e.g. ctrl-c may not be handled). + @@ -693,7 +743,7 @@ future. Scheduled transmission and reception events in the script use lines - in the format of: + in the format of: [<eventTime>] <eventType> <parameters ...> [<options ...>] @@ -711,7 +761,7 @@ Global commands are generally used to define default behaviors for MGEN operation or other options independent of event scheduling. The - format for global command script lines is: + format for global command script lines is: <commandType> [<command parameters ...>] @@ -738,16 +788,15 @@ <eventTime> {ON|MOD|OFF} <flowId> [<options ...>] - The first scripted event for a given flow - identified by a <flowId> must be an ON event. Subsequently, MOD, events can be used to modify - characteristics of the given flow until it is terminated with an OFF event. After a flow has been terminated - with the OFF command, a flow with the - same <flowId> value may be initiated with another ON event. The <options> fields are used - to describe the characteristics of flows initiated with The first scripted event for a given flow identified by + a <flowId> must be an ON event. + Subsequently, MOD, events can be used + to modify characteristics of the given flow until it is terminated with + an OFF event. After a flow has been + terminated with the OFF command, a + flow with the same <flowId> value may be initiated with another + ON event. The <options> fields + are used to describe the characteristics of flows initiated with ON events and modified with subsequence MOD events. The OFF event uses no options. @@ -755,7 +804,7 @@ ON Event - Script syntax: + Script syntax: <eventTime> ON <flowId> <protocol> [connect] DST <addr>/<port> <pattern [params]> @@ -804,7 +853,7 @@ for the loopback address (IP address 127.0.0.1) port number 5000 beginning immediately when the script is executed. The messages will consist of 1024 byte messages at a regular rate of 1.0 per - second: + second: 0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1.0 1024] @@ -813,7 +862,7 @@ MOD Event - Script syntax: + Script syntax: <eventTime> MOD <flowId> [<options ...>] @@ -838,7 +887,7 @@ transmission pattern 5.0 seconds after script execution. The changed "flow 1" will then generate messages 512 bytes in size at an average rate of 10.0 messages per second following a Poisson - (exponentially-distributed interval) + (exponentially-distributed interval) 5.0 MOD 1 POISSON [10.0 512] @@ -884,7 +933,7 @@ This script line will terminate generation of MGEN message traffic for "flow 1" at 10.0 seconds after script - execution. + execution. 10.0 OFF 1 @@ -927,7 +976,7 @@ Destination (DST) - Option syntax: + Option syntax: ... DST <addr>/<port> ... @@ -939,7 +988,7 @@ destination address may be a unicast (point-to-point) or multicast address. - Examples: + Examples: #Start a flow to loopback address port 5000 @@ -956,7 +1005,7 @@ Source Port (SRC) - Option syntax: + Option syntax: ... SRC <port> ... @@ -994,7 +1043,7 @@ but different source ports. Flow 1 is also assigned non-default type-of-service using the TOS option. The use of the SRC option ensures that two different sockets are used to support the two - different types of service. + different types of service. #Start flow 1 using source port 5001(TOS = 0x10) and flow 2 using port 5002 @@ -1009,7 +1058,7 @@ COUNT - Option syntax: + Option syntax: ... COUNT <msgCount> ... @@ -1018,7 +1067,8 @@ one and only one mgen message will be sent. This attribute defaults to "-1", meaning mgen will send an unlimited number of messages until an OFF event occurs or the mgen program - completes. + completes. If a message count is specified, the mgen flow will be + stopped after the requested number of messages has been sent. Note that an OFF event will override any message COUNT specified (e.g. the flow will be terminated @@ -1030,7 +1080,7 @@ Pattern (PERIODIC, POISSON, BURST, JITTER, CLONE) - Option syntax: + Option syntax: ... <patternType> [parameters ...] ... @@ -1055,7 +1105,7 @@ PERIODIC Pattern: - Option syntax: + Option syntax: ... PERIODIC [<rate> <size>]... @@ -1068,7 +1118,7 @@ is unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols. - Example: + Example: #Start an MGEN flow sending 1024 byte messages @@ -1089,7 +1139,7 @@ POISSON Pattern: - Option syntax: + Option syntax: ... POISSON [<aveRate (msg/sec)> <size (bytes)>] ... @@ -1103,7 +1153,7 @@ unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols. - Example: + Example: #Start an MGEN flow sending 1024 byte messages @@ -1125,7 +1175,7 @@ BURST Pattern: - Option syntax: + Option syntax: ... BURST [REGULAR|RANDOM <aveInterval (sec)> <patternType> [<patternParams>] FIXED|EXPONENTIAL @@ -1173,7 +1223,7 @@ interval, the flow will tend to follow the characteristics of the core pattern (i.e. 100% duty cycle). - Example: + Example: #Start a bursty MGEN flow with bursts of 1024 byte messages @@ -1202,7 +1252,7 @@ JITTER Pattern: - Option syntax: + Option syntax: ... JITTER [<rate> <size> <jitterFraction>]... @@ -1220,7 +1270,7 @@ unlimited. Note the <rate> must be greater than or equal to 0.0 messages/second for the TCP and UDP protocols. - Example: + Example: #Start an MGEN flow sending 1024 byte messages @@ -1302,7 +1352,7 @@ BROADCAST - Option syntax: + Option syntax: ... BROADCAST {ON|OFF} ... @@ -1311,10 +1361,23 @@ default BROADCAST is ON. + + LOGDATA + + Option syntax: + + ... LOGDATA {ON|OFF} ... + + Controls whether MGEN will log the optional data attribute field + at MGEN receivers (including within MGEN binary log files). It does + not affect whether MGEN senders send the requested data attribute. By + default LOGDATA is ON. + + Type-Of-Service (TOS) - Option syntax: + Option syntax: ... TOS <value> ... @@ -1335,7 +1398,7 @@ socket. See the SRC option to make sure different flows use different sockets. - Example: + Example: #Start flow 1 with default TOS @@ -1370,7 +1433,7 @@ - + IPTOS_TOS_MASKIPTOS_TOS(tos) @@ -1536,7 +1599,7 @@ Multicast Time-To-Live (TTL) - Option syntax: + Option syntax: ... TTL <value> ... @@ -1550,7 +1613,7 @@ MGEN flows. The <value> field must be in the range of 1-255. The default multicast TTL assumed by MGEN is 3. - Example: + Example: #Start an IP multicast flow with a maximum hop count ttl = 2 @@ -1562,7 +1625,7 @@ Socket Transmit Buffer Size (TXBUFFER) - Option syntax: + Option syntax: ... TXBUFFER <txBufferSize> ... @@ -1577,7 +1640,7 @@ Socket Receive Buffer Size (RXBUFFER) - Option syntax: + Option syntax: ... RXBUFFER <rxBufferSize> ... @@ -1592,7 +1655,7 @@ IPv6 Flow Label (LABEL) - Option syntax: + Option syntax: ... label <value> ... @@ -1607,7 +1670,7 @@ 0x0??00000 where "??" specifies the first octet of the flow label. Other operating systems may behave differently. - Example: + Example: # Start an IPv6 flow with flow label = 0x03d00000 @@ -1636,7 +1699,7 @@ MGEN flows. If no INTERFACE option is used, MGEN will behave according to the operating system's default behavior. - Example: + Example: #Start an IP multicast flow on Ethernet interface named "eth1" @@ -1648,7 +1711,7 @@ Sequence Number Initialization (SEQUENCE) - Option syntax: + Option syntax: ... SEQUENCE <sequenceNumber> ... @@ -1662,7 +1725,7 @@ events for pending flows when it is desired that mgen return to a particular point in a script after being stopped and restarted. - Example: + Example: #Modify the sequence number of an existing flow such that @@ -1715,7 +1778,7 @@ LISTEN - Script syntax: + Script syntax: <eventTime> LISTEN <protocol> <portList> @@ -1730,7 +1793,7 @@ the list are specified in the format "<lowValue>-<hiValue>". - Example: + Example: #Monitor UDP port numbers 5000, 5003, 5004, 5005, 5009 @@ -1748,7 +1811,7 @@ IGNORE - Script syntax: + Script syntax: <eventTime> IGNORE <protocol> <portList> @@ -1764,7 +1827,7 @@ monitoring. Port ranges within the list are specified in the format "<lowValue>-<hiValue>". - Example: + Example: #Stop monitoring UDP port numbers 5003, 5004, 5005, 5009 @@ -1781,27 +1844,40 @@ JOIN - Script syntax: + Script syntax: - <eventTime> JOIN<groupAddress> - [INTERFACE<interfaceName>] - [PORT<portNumber>] + <eventTime> JOIN <groupAddress> [SRC + <srcAddress>] [INTERFACE <interfaceName>] [PORT + <portNumber| portList>] The JOIN event is used to prompt mgen to "join" the specific IP - multicast group indicated by the <groupAddress> field. The + multicast group indicated by the <groupAddress> field. The SRC + option can be used to join a source specific multicast (SSM) channel. + Note that the SRC option is not presently available on windows. The INTERFACE option forces the membership join request on the network interface identified by the <interfaceName> field. If no INTERFACE option is given, the operating system's default behavior is observed. Note it is possible to join the same group on multiple, different interfaces. - The PORT option is provided principally for operation on WIN32 - systems where the IP multicast join must be performed on the same - socket bound to a specific <portNumber>. Note that a - corresponding LISTEN event for the - indicated <portNumber> is required in order to receive traffic. - Unix-based operating systems generally allow for IP multicast group - membership to be independent of specific socket port bindings. + The PORT option should be used on WIN32 systems where the IP + multicast join must be performed on the same socket bound to a + specific <portNumber>. + + Unix-based operating systems generally allow for IP multicast + group membership to be independent of specific socket port bindings. + Note that a corresponding LISTEN event + for the indicated <portNumber> is required in order to receive + traffic if not set as a JOIN command option. Specify the PORT option + as a JOIN command option if your Unix based system does not support + port binding independence. + + Not that on IPv6 systems (and when mgen is compiled with the + HAVE_IPV6 compile option) the JOIN port option must be specified when + joining an IPv4 group. + + On OSX systems, the interface option must be used if a default + multicast route is not defined on the system. As many IP group memberships as the operating system will support is permitted by mgen. This is generally a limit of the maximum @@ -1811,7 +1887,7 @@ systems can allow for many memberships (often 20, but OS-specific) per socket. - Examples: + Examples: #JOIN group 224.1.2.3 at time 0.0 @@ -1822,19 +1898,30 @@ 0.0 JOIN 224.1.2.4 INTERFACE eth1 + #JOIN SSM channel 232.1.1.1 with source 26.26.26.1 on + interface "eth1" + + 0.0 JOIN 224.1.2.4 SRC 25.25.25.1 INTERFACE + eth1 + #JOIN group 224.1.2.5 using socket bound to port 5000 0.0 JOIN 224.1.2.5 PORT 5000 + + #JOIN group 224.1.2.6 using sockets bound to ports + 5001-5005 + + 0.0 JOIN 224.1.2.6 PORT 5001-5005 LEAVE - Script syntax: + Script syntax: - <eventTime> LEAVE <groupAddress> - [INTERFACE<interfaceName>] [PORT + <eventTime> LEAVE <groupAddress> [SRC + <srcAddress>] [INTERFACE <interfaceName>] [PORT <portNumber] The LEAVE event is used to prompt mgen to "leave" the specific @@ -1842,9 +1929,10 @@ <groupAddress> must have been joined with a prior JOIN event. The INTERFACE and/or PORT options must be used if they were used with the - corresponding JOIN event. + corresponding JOIN event. Note that the + SSM SRC option is not presently available on windows. - Examples: + Examples: #LEAVE group 224.1.2.3 at time 10.0 @@ -1855,10 +1943,14 @@ 10.0 LEAVE 224.1.2.4 INTERFACE eth1 - #LEAVE group 224.1.2.4 on interface - "eth1"and + #LEAVE SSM channel 232.1.1.1 with source 25.25.25.1 on + interface "eth1" at time 10.0 + + 10.0 LEAVE 224.1.2.4 SRC 25.25.25.1 INTERFACE + eth1 - #port 5000 at time 10.0 + #LEAVE group 224.1.2.4 on interface "eth1"and port 5000 + at time 10.0 10.0 LEAVE 224.1.2.4 INTERFACE eth1 PORT 5000 @@ -1986,6 +2078,15 @@ be queued before mgen turns off the transmission timer for a flow. + + + LOGDATA + + Controls whether MGEN will log the optional data attribute + field at MGEN receivers (including within MGEN binary log files). + It does not affect whether MGEN senders send the requested data + attribute. By default LOGDATA is set to ON. + @@ -1993,7 +2094,7 @@ START - Script syntax: + Script syntax: START <hour:min:sec>[GMT] @@ -2020,7 +2121,7 @@ OFFSET - Script syntax: + Script syntax: OFFSET <seconds> @@ -2041,7 +2142,7 @@ TOS - Script syntax: + Script syntax: TOS <value> @@ -2057,7 +2158,7 @@ LABEL - Script syntax: + Script syntax: LABEL <value> @@ -2078,7 +2179,7 @@ TTL - Script syntax: + Script syntax: TTL <value> @@ -2099,7 +2200,7 @@ TXBUFFER - Script syntax: + Script syntax: TXBUFFER <txBufferSize> ... @@ -2113,7 +2214,7 @@ RXBUFFER - Script syntax: + Script syntax: RXBUFFER <rxBufferSize> ... @@ -2139,7 +2240,7 @@ QUEUE - Script syntax: + Script syntax: QUEUE @@ -2197,7 +2298,7 @@ INTERFACE - Script syntax: + Script syntax: <interfaceName> @@ -2222,7 +2323,7 @@ INPUT - Script syntax: + Script syntax: INPUT <scriptFile> @@ -2243,7 +2344,7 @@ OUTPUT - Script syntax: + Script syntax: OUTPUT <logFile> @@ -2253,7 +2354,7 @@ scripts provided as input to mgen. The file named by <logFile> will be overwritten if it already exists. - Example: + Example: #Use the file "logFile.drc" for logging @@ -2263,7 +2364,7 @@ LOG - Script syntax: + Script syntax: LOG <logFile> @@ -2273,17 +2374,37 @@ scripts provided as input to mgen. The file named by <logFile> will be appended if it already exists. - Example: + Example: #Append the file "logFile.drc" LOG logFile.drc + + LOGDATA + + Script syntax: + + LOGDATA {on|off}} + + Controls whether MGEN will log the optional data attribute field + at MGEN receivers (including within MGEN binary log files). It does not + affect whether MGEN senders send the requested data attribute. By + default LOGDATA is set to ON. + + Example: + + #Don't log optional data attribute at + receiver + + LOGDATA off + + SAVE - Script syntax: + Script syntax: SAVE <saveFile> @@ -2308,7 +2429,7 @@ if an empty <saveFile> is provided on the first launch of mgen. - Example: + Example: # This script executes another MGEN script, using @@ -2345,7 +2466,7 @@ MGEN Log File Format - The MGEN message format contains + The MGEN message format contains information to facilitate network performance measurements through post-analysis of MGEN log files. Some of the types of performance statistics which can be determined include: @@ -2679,7 +2800,7 @@ not yet supported in MGEN 4.x. The documentation will be updated when this option is supported). - Example RECV event log lines: + Example RECV event log lines: 22:59:52.312721 RECV proto><protocol> flow>1 seq>1 src>132.250.68.21/5000 dst>132.259.43.96/5002 @@ -2701,7 +2822,7 @@ Log File RERR Events The format of the RERR (Receive Error) event log file line - is: + is: <eventTime> RERR proto><protocol> type><errorType> @@ -2720,8 +2841,7 @@ Log File SEND Events - The format of the SEND event log file line - is: + The format of the SEND event log file line is: <eventTime> SEND proto><protocol> flow><flowId> seq><sequenceNumber> @@ -2742,8 +2862,8 @@ The format of the JOIN log file event line is: - <eventTime> JOIN group> <groupAddress> - [interface> <interfaceName>] + <eventTime> JOIN group> <groupAddress> [src> + <srcAddress>] [interface> <interfaceName>] The <groupAddress> is the IP multicast group address which was joined. The format of this field is either a dotted decimal IPv4 @@ -2757,6 +2877,9 @@ 22:59:51:129574 JOIN group>224.1.2.4 interface>eth1 + + 22:59:51:129574 JOIN group>224.1.2.4 src>25.25.25.1 + interface>eth1 @@ -2764,8 +2887,8 @@ The format of log file LEAVE event lines is: - <eventTime> LEAVE group><groupAddress> - [interface><interfaceName>] + <eventTime> LEAVE group><groupAddress> [src> + <srcAddress>] [interface><interfaceName>] The <groupAddress> is the IP multicast group address which was left. The format of this field is either a dotted decimal IPv4 @@ -2774,19 +2897,21 @@ the corresponding LEAVE script event. - Example LEAVE event log lines: + Example LEAVE event log lines: 22:59:59:234757 LEAVE group>224.1.2.3 22:59:59:753683 LEAVE group>224.1.2.4 interface>eth1 + + 22:59:59:753683 LEAVE group>224.1.2.4 + src>25.25.25.1 interface>eth1 Log File LISTEN Events - The format of the LISTEN event log file line - is: + The format of the LISTEN event log file line is: <eventTime> LISTEN proto><protocol> port><portNumber> @@ -2795,7 +2920,7 @@ type being used. Supported protocols include "UDP" and "TCP". The <portNumber> field is the host port number to be monitored. - Example LISTEN event log lines: + Example LISTEN event log lines: 22:59:48:834205 LISTEN proto>UDP port>5000 @@ -2817,7 +2942,7 @@ The <portNumber> field is the host port number to be no longer monitored. - Example IGNORE event log lines: + Example IGNORE event log lines: 23:00:00:723467 IGNORE proto>UDP port>5000 @@ -2829,8 +2954,7 @@ Log File ON Events - The format of the ON event log file line - is: + The format of the ON event log file line is: <eventTime> ON flow><flowID> srcPort><srcPort> @@ -2870,7 +2994,7 @@ sharing the connection, CONNECT events will be logged for each flow. - Example CONNECT event log line: + Example CONNECT event log line: 23:00:00:723467 CONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000 @@ -2922,14 +3046,12 @@ Note that if a TCP connection was prematurely terminated, no SHUTDOWN event will be logged. - Example Client SHUTDOWN event log line - (client): + Example Client SHUTDOWN event log line (client): 23:00:00:723467 SHUTDOWN flow><flowId> src>192.168.1.102/5000 dstPort>6000 - Example Server SHUTDOWN event log line - (server): + Example Server SHUTDOWN event log line (server): 23:00:00:723467 SHUTDOWN src>192.168.1.100/5000 dst>6000 @@ -2978,14 +3100,12 @@ be logged. (NOTE: Indication of unscheduled TCP disconnection is not available relieably under windows at this time.) - Example Client DISCONNECT event log - line: + Example Client DISCONNECT event log line: 23:00:00:723467 DISCONNECT flow>1 srcPort>4000 dst>192.168.1.102/5000 - Example Server DISCONNECT event log line - : + Example Server DISCONNECT event log line : 23:00:00:723467 DISCONNECT src>192.168.1.100/4000 dstPort>5000 @@ -3017,14 +3137,12 @@ OFF event may be logged for both planned and unplanned socket disconnects.) - Example Client OFF event log line - (client): + Example Client OFF event log line (client): 23:00:00:723467 OFF flow>1 srcPort>4000 dst>192.168.1.102/5000 - Example Server OFF event log line - (server): + Example Server OFF event log line (server): 23:00:00:723467 OFF src>192.168.1.100/4000 dstPort>5000 @@ -3038,7 +3156,7 @@ Log File START and STOP Events The format of the START and STOP event log file line - is: + is: <eventTime> STARTor<eventTime>STOP @@ -3749,7 +3867,7 @@ The format of the RECV event binary log file record is: Compile options - + RANDOM_FILL @@ -3804,7 +3922,7 @@ The format of the RECV event binary log file record is: Known issues - + Macosx Windows TCP Interaction diff --git a/include/mgen.h b/include/mgen.h index 0e6ff788..b0b5cd00 100644 --- a/include/mgen.h +++ b/include/mgen.h @@ -13,6 +13,7 @@ class MgenController virtual void OnMsgReceive(MgenMsg& msg) = 0; virtual void OnOffEvent(char * buffer,int len) = 0; + virtual void OnStopEvent(char * buffer, int len) = 0; protected: MgenController() {}; @@ -34,12 +35,14 @@ class DrecGroupList bool JoinGroup(Mgen& mgen, const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL, UINT16 thePort = 0, bool deferred = false); bool LeaveGroup(Mgen& mgen, - const ProtoAddress& groupAddress, + const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL, UINT16 thePort = 0); @@ -51,6 +54,7 @@ class DrecGroupList friend class DrecGroupList; public: DrecMgenTransport(const ProtoAddress& groupAddr, + const ProtoAddress& sourceAddr, const char* interfaceName, UINT16 thePort); ~DrecMgenTransport(); @@ -71,6 +75,7 @@ class DrecGroupList private: MgenTransport* flow_transport; ProtoAddress group_addr; + ProtoAddress source_addr; // Source address used for SSM (src specific mcast) char interface_name[16]; UINT16 port; DrecMgenTransport* prev; @@ -78,6 +83,7 @@ class DrecGroupList }; // end class DrecGroupList::DrecMgenTransport DrecMgenTransport* FindMgenTransportByGroup(const ProtoAddress& groupAddr, + const ProtoAddress& sourceAddr, const char* interfaceName = NULL, UINT16 thePort = 0); @@ -133,15 +139,15 @@ class Mgen FLUSH, // flush log after _each_ event CHECKSUM, // turn on _both_ tx and rx checksum options TXCHECKSUM,// include checksums in transmitted MGEN messages - RXCHECKSUM, // force checksum validation at receiver _always_ - LOGDATA, // log payload data on/off - QUEUE // Turn off tx_timer when pending queue exceeds this limit + RXCHECKSUM,// force checksum validation at receiver _always_ + QUEUE, // Turn off tx_timer when pending queue exceeds this limit + REUSE // Toggle socket reuse on and off }; static Command GetCommandFromString(const char* string); enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG}; static const char* GetCmdName(Command cmd); static CmdType GetCmdType(const char* cmd); - void SetController(MgenController* theController) + void SetController(MgenController* theController) {controller = theController;} MgenController* GetController() {return controller;} ProtoSocket::Notifier& GetSocketNotifier() {return socket_notifier;} @@ -151,6 +157,7 @@ class Mgen bool GetChecksumEnable() {return checksum_enable;} bool GetChecksumForce() {return checksum_force;} bool GetLogData() {return log_data;} + bool GetLogGpsData() {return log_gps_data;} bool OpenLog(const char* path, bool append, bool binary); void CloseLog(); void SetLogFile(FILE* filePtr); @@ -159,6 +166,7 @@ class Mgen bool GetLocalTime() {return local_time;} bool GetLogFlush() {return log_flush;} bool GetLogTx() {return log_tx;} + bool GetReuse() {return reuse;} typedef int (*LogFunction)(FILE*, const char*, ...); #ifndef _WIN32_WCE static LogFunction Log; @@ -183,6 +191,8 @@ class Mgen {addr_type = addrType;} ProtoAddress::Type GetDefaultSocketType() {return addr_type;} + void SetDefaultReuse(bool reuseTemp) { reuse = reuseTemp;} + void SetPositionCallback(MgenPositionFunc* callback, const void* clientData) { @@ -191,7 +201,11 @@ class Mgen } void SetSinkPath(const char* theSinkPath) { - strncpy(sink_path,theSinkPath,strlen(theSinkPath) + 1); + strncpy(sink_path, theSinkPath, PATH_MAX); + } + void SetSourcePath(const char* theSourcePath) + { + strncpy(source_path, theSourcePath, PATH_MAX); } void SetSinkBlocking(bool sinkNonBlocking) {sink_non_blocking = sinkNonBlocking;} void SetHostAddress(const ProtoAddress hostAddr) @@ -202,6 +216,10 @@ class Mgen { log_data = logData; } + void SetLogGpsData(bool logGpsData) + { + log_gps_data = logGpsData; + } void ClearHostAddress() { host_addr.Invalidate(); @@ -244,13 +262,16 @@ class Mgen MgenTransport* FindMgenTransportBySocket(const ProtoSocket& socket); MgenTransport* FindTransportByInterface(const char* interfaceName, - UINT16 thePort = 0); + UINT16 thePort = 0, + ProtoAddress::Type addrType = ProtoAddress::INVALID); bool LeaveGroup(MgenTransport* transport, - const ProtoAddress& groupAddress, + const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL); - MgenTransport* JoinGroup(const ProtoAddress& groupAddress, + MgenTransport* JoinGroup(const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName, UINT16 thePort); @@ -392,9 +413,11 @@ class Mgen bool default_queue_limit_lock; char sink_path[PATH_MAX]; + char source_path[PATH_MAX]; bool sink_non_blocking; bool log_data; + bool log_gps_data; ProtoAddress host_addr; bool checksum_enable; @@ -423,6 +446,7 @@ class Mgen bool log_tx; bool log_open; bool log_empty; + bool reuse; }; // end class Mgen diff --git a/include/mgenEvent.h b/include/mgenEvent.h index 531133b4..b5a4b40e 100644 --- a/include/mgenEvent.h +++ b/include/mgenEvent.h @@ -60,6 +60,7 @@ class DrecEvent : public MgenBaseEvent Type GetType() const {return event_type;}; Protocol GetProtocol() const {return protocol;} const ProtoAddress& GetGroupAddress() const {return group_addr;} + const ProtoAddress& GetSourceAddress() const {return source_addr;} const char* GetInterface() const {return (('\0' != interface_name[0]) ? interface_name : (const char*)NULL);} UINT16 GetPortCount() const {return port_count;} @@ -74,6 +75,7 @@ class DrecEvent : public MgenBaseEvent INTERFACE, PORT, RXBUFFER, + SRC, INVALID_OPTION }; static const StringMapper OPTION_LIST[]; @@ -87,6 +89,7 @@ class DrecEvent : public MgenBaseEvent Protocol protocol; // JOIN/LEAVE event parameters ProtoAddress group_addr; + ProtoAddress source_addr; // Source address for SSM char interface_name[16]; // LISTEN/IGNORE event parameters UINT16 port_count; // (port_count is also used to hold the JOIN event PORT option) diff --git a/include/mgenFlow.h b/include/mgenFlow.h index dc96d028..c444ee26 100644 --- a/include/mgenFlow.h +++ b/include/mgenFlow.h @@ -50,7 +50,7 @@ class MgenFlow #ifdef HAVE_GPS void SetPayloadHandle(GPSHandle payloadHandle) - {payload_handle = payloadHandle;} + {payload_handle = payloadHandle;} #endif // HAVE_GPS void SetQueueLimit(int queueLimit) {queue_limit = queueLimit;} @@ -99,7 +99,6 @@ class MgenFlow bool new_transport; int queue_limit; int message_limit; - int messages_sent; UINT32 flow_id; Protocol protocol; diff --git a/include/mgenGlobals.h b/include/mgenGlobals.h index db5b8681..52d7bf23 100644 --- a/include/mgenGlobals.h +++ b/include/mgenGlobals.h @@ -61,7 +61,8 @@ enum Protocol INVALID_PROTOCOL, UDP, TCP, - SINK + SINK, + SOURCE // pseudo transport type so an mgen can have distinct source/sink transports }; enum diff --git a/include/mgenMsg.h b/include/mgenMsg.h index e24ec8a3..bb4bf660 100644 --- a/include/mgenMsg.h +++ b/include/mgenMsg.h @@ -101,7 +101,7 @@ class MgenMsg MgenMsg& operator=(const MgenMsg&); UINT16 Pack(char* buffer, UINT16 bufferLen, bool includeChecksum, UINT32& tx_checksum); - bool Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,bool logData); + bool Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,bool log_data); static bool WriteChecksum(UINT32& tx_checksum, UINT8* buffer, UINT32 buflen); @@ -153,6 +153,7 @@ class MgenMsg bool logBinary, bool local_time, bool log_data, + bool log_gps_data, char* msgBuffer, bool flush, const struct timeval& theTime); diff --git a/include/mgenPayloadMgr.h b/include/mgenPayloadMgr.h new file mode 100644 index 00000000..aca1eb99 --- /dev/null +++ b/include/mgenPayloadMgr.h @@ -0,0 +1,122 @@ +#ifndef _MGENPAYLOADMGR +#define _MGENPAYLOADMGR + +#ifndef _MGENPAYLOADMGR_VERSION +#define MGENPAYLOADMGR_VERSION "0.0.1" +#endif // _MGENPAYLOADMGR_VERSION + +enum {SCRIPT_LINE_MAX = 512}; + +#include "mgen.h" +#include "protokit.h" + +#include + +class MgenPayloadMgr +{ + public: + MgenPayloadMgr(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier, + Mgen& mgen); + virtual ~MgenPayloadMgr(); + Mgen& GetMgen() {return mgen;} + bool Start(); + void Stop(); + void SetSocketNotifier(ProtoSocket::Notifier* socketNotifier) + { + socket_notifier = socketNotifier; + } + // A little utility class for reading script files line by line + class FastReader + { + public: + enum Result {OK, ERROR_, DONE}; // trailing '_' for WIN32 + FastReader(); + FastReader::Result Read(FILE* filePtr, char* buffer, unsigned int* len); + FastReader::Result Readline(FILE* filePtr, char* buffer, + unsigned int* len); + FastReader::Result ReadlineContinue(FILE* filePtr, char* buffer, + unsigned int* len, + unsigned int* lineCount = NULL); + + private: + enum {BUFSIZE = 1024}; + char savebuf[BUFSIZE]; + char* saveptr; + unsigned int savecount; + + }; // end class FastReader + + + // MgenPayloadMgr "global command" set + enum Command + { + // Mgen Global commands + INVALID_COMMAND, + EVENT, + START, // specify absolute start time + INPUT, // input and parse an RAPR script + OVERWRITE_MPMLOG,// open rapr output (log) file + MPMLOG, // open rapr log file for appending + OVERWRITE_MGENLOG,// open mgen output (log) file + MGENLOG, // open mgen log file for appending + SAVE, // save info on exit. + DEBUG, // specify debug level + TXLOG, // turn transmit logging on + LOCALTIME, // turn on localtime logging in mgen rather than gmtime (the default) + NOLOG, // no output + BINARY, // mgen binary log + FLUSH, // + LABEL, + RXBUFFER, + TXBUFFER, + TOS, + TTL, + INTERFACE, + CHECKSUM, + TXCHECKSUM, + RXCHECKSUM, + // MgenPayloadMgr Global Commands + // LOAD_DICTIONARY, // loads dictionary file + // MgenPayloadMgrApp Global Commands + MGENEVENT // mgen recv events + }; + + enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG}; + static CmdType GetCmdType(const char* cmd); + static Command GetCommandFromString(const char* string); + bool OnCommand(MgenPayloadMgr::Command cmd, const char* arg,bool override = false); + bool ParseEvent(const char* lineBuffer,unsigned int lineCount); + bool ParseScript(const char* path); + void LogEvent(const char* cmd,const char* val); + bool SendMgenCommand(const char* cmd, const char* val); + bool OpenLog(const char* path, bool append, bool binary); + void CloseLog(); + void SetLogFile(FILE* filePtr); + bool OnTxTimeout(ProtoTimer& theTimer); + + private: + ProtoTimerMgr& timer_mgr; + Mgen& mgen; + static const StringMapper COMMAND_LIST[]; + ProtoTimer payload_timer; + bool started; + bool stopped; + ProtoTimer start_timer; + unsigned int start_hour; //absolute start time + unsigned int start_min; + double start_sec; + bool start_gmt; + bool start_time_lock; + FILE* log_file; + bool log_binary; // not yet implemented but needed for common mgen functions + bool local_time; + bool log_flush; + bool log_open; + bool log_empty; + + ProtoSocket::Notifier* socket_notifier; + +}; // end class mgenPayloadMgr + +#endif // _MGENPAYLOADMGR diff --git a/include/mgenPayloadMgrApp.h b/include/mgenPayloadMgrApp.h new file mode 100644 index 00000000..83400179 --- /dev/null +++ b/include/mgenPayloadMgrApp.h @@ -0,0 +1,39 @@ +#ifndef _MGENPAYLOADMGRAPP +#define _MGENPAYLOADMGRAPP + +#include "protokit.h" +#include "mgen.h" +#include "mgenPayloadMgr.h" + +class MgenPayloadMgrApp : public ProtoApp, public MgenController +{ + public: + MgenPayloadMgrApp(); + virtual ~MgenPayloadMgrApp(); + + enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG}; + static const char* const CMD_LIST[]; + void Usage(); + + // MgenController virtual methods + void OnMsgReceive(MgenMsg& msg); + void OnOffEvent(char* buffer, int len); + void OnStopEvent(char* buffer, int len); + + virtual bool OnStartup(int argc, const char*const* argv); + virtual bool ProcessCommands(int argc, const char*const* argv); + virtual void OnShutdown(); + bool OnCommand(const char* cmd, const char* val); + static CmdType GetCmdType(const char* cmd); + + private: + void OnControlEvent(ProtoSocket& theSocket, ProtoSocket::Event theEvent); + MgenPayloadMgr mgenPayloadMgr; + Mgen mgen; + ProtoPipe control_pipe; + bool control_remote; + ProtoSocket socket; + ProtoAddress dstAddr; +}; // end class mgenPayloadMgrApp + +#endif //_MGENPAYLOADMGRAPP diff --git a/include/mgenTransport.h b/include/mgenTransport.h index 2bdc8df0..61856c64 100644 --- a/include/mgenTransport.h +++ b/include/mgenTransport.h @@ -73,7 +73,7 @@ class MgenTransport virtual void IsClient(bool isClient) {;} virtual bool IsConnected() {return true;} virtual bool IsConnecting() {return false;} - virtual bool IsListening() {return false;} + virtual bool IsListening() {return true;} virtual bool Listen(UINT16 port,ProtoAddress::Type addrType,bool bindOnOpen) {return false;} virtual bool SetRxBufferSize(unsigned int rxBufferSize) {return false;} // for multicast joins in mgen virtual void SetEventOptions(const MgenEvent* theEvent) {;} @@ -81,8 +81,11 @@ class MgenTransport virtual bool TransmittingFlow(UINT32 flowId) {return false;} virtual unsigned int GroupCount() {return 0;} virtual bool JoinGroup(const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL) {return false;} + virtual ProtoAddress::Type GetAddressType() { return ProtoAddress::INVALID; } virtual bool LeaveGroup(const ProtoAddress& theAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL) {return false;} #ifdef HAVE_IPV6 virtual void SetFlowLabel(UINT32 label) {;} @@ -143,7 +146,8 @@ class MgenTransport DMSG(0,"SocketTransport::SocketTransport() Error: Invalid protocol specified.\n"); return ProtoSocket::INVALID_PROTOCOL; } - + int GetMessagesSent() {return messages_sent;} + void SetMessagesSent(int messagesSent) {messages_sent = messagesSent;} Mgen& GetMgen() {return mgen;} private: MgenTransport* prev; @@ -158,6 +162,7 @@ class MgenTransport MgenFlow* pending_head; MgenFlow* pending_tail; MgenFlow* pending_current; + int messages_sent; }; // end class MgenTransport /** @@ -224,6 +229,7 @@ class MgenSocketTransport : public MgenTransport virtual ~MgenSocketTransport(); bool Listen(UINT16 port,ProtoAddress::Type addrType, bool bindOnOpen); + ProtoAddress::Type GetAddressType() { return socket.GetAddressType(); } bool broadcast; unsigned char tos; @@ -250,8 +256,10 @@ class MgenUdpTransport : public MgenSocketTransport void OnEvent(ProtoSocket& theSocket,ProtoSocket::Event theEvent); bool Open(ProtoAddress::Type addrType, bool bindOnOpen); bool JoinGroup(const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL); bool LeaveGroup(const ProtoAddress& theAddress, + const ProtoAddress& sourceAddress, const char* interfaceName = NULL); bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); bool Listen(UINT16 port,ProtoAddress::Type addrType, bool bindOnOpen); @@ -363,7 +371,7 @@ class MgenTcpTransport : public MgenSocketTransport char rx_msg_buffer[TX_BUFFER_SIZE]; unsigned int rx_buffer_index; char rx_checksum_buffer[4]; - UINT16 rx_fragment_pending; + UINT16 rx_fragment_pending; UINT16 rx_msg_index; UINT32 rx_checksum; @@ -382,7 +390,7 @@ class MgenSinkTransport : public MgenTransport ~MgenSinkTransport(); // MgenSinkTransport implementation - static MgenSinkTransport* Create(Mgen& theMgen); + static MgenSinkTransport* Create(Mgen& theMgen, Protocol theProtocol); // SINK or SOURCE bool IsOpen() {return true;} void Close() {return;} bool HasListener() {return true;} @@ -445,7 +453,7 @@ class MgenAppSinkTransport : public MgenSinkTransport, public ProtoChannel bool Open(); bool OnOutputReady(); bool Write(char* buffer, unsigned int* nbytes); - bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); + bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); bool OnInputReady(); bool Read(char* buffer, UINT32 nBytes, UINT32& bytesRead); void OnEvent(ProtoChannel& theChannel,ProtoChannel::Notification theNotification); diff --git a/include/mgenVersion.h b/include/mgenVersion.h index 8d275351..8a10b3e5 100644 --- a/include/mgenVersion.h +++ b/include/mgenVersion.h @@ -1,6 +1,6 @@ #ifndef _MGEN_VERSION -#define MGEN_VERSION "5.02" +#define MGEN_VERSION "5.02b" #endif // _MGEN_VERSION diff --git a/makefiles/Makefile.common b/makefiles/Makefile.common index 6d45ccbb..f0fd26b2 100644 --- a/makefiles/Makefile.common +++ b/makefiles/Makefile.common @@ -13,7 +13,7 @@ UNIX = ../makefiles INCLUDES = $(SYSTEM_INCLUDES) -I$(UNIX) -I$(INCLUDE) -I$(PROTOLIB)/include -CFLAGS = -g -DPROTO_DEBUG -D_RAPR_JOURNAL -DHAVE_GPS -DUNIX -Wall -Wcast-align -pedantic -fPIC $(SYSTEM_HAVES) $(INCLUDES) +CFLAGS = -g -DPROTO_DEBUG -DHAVE_GPS -DUNIX -Wall -Wcast-align -pedantic -fPIC $(SYSTEM_HAVES) $(INCLUDES) #CFLAGS = -g -fno-inline -D_HAVE_PCAP -DPROTO_DEBUG -DHAVE_GPS -DUNIX -Wall -Wcast-align -pedantic -fPIC $(SYSTEM_HAVES) $(INCLUDES) @@ -22,13 +22,13 @@ LDFLAGS = $(SYSTEM_LDFLAGS) LIBS = $(SYSTEM_LIBS) -lm #LIBS = $(SYSTEM_LIBS) -lm -lpcap -TARGETS = mgen mpmgr +TARGETS = mgen mpmgr # Rule for C++ .cpp extension .cpp.o: $(CC) -c $(CFLAGS) -o $*.o $*.cpp -all: mgen mpmgr +all: mgen mpmgr # MGEN depends upon the NRL Protean Group's development library LIBPROTO = $(PROTOLIB)/lib/libprotokit.a @@ -43,35 +43,44 @@ MGEN_SRC = $(COMMON)/mgen.cpp $(COMMON)/mgenEvent.cpp \ $(COMMON)/gpsPub.cpp $(COMMON)/mgenAppSinkTransport.cpp MGEN_OBJ = $(MGEN_SRC:.cpp=.o) - MGEN_APP_SRC = $(COMMON)/mgenApp.cpp MGEN_APP_OBJ = $(MGEN_APP_SRC:.cpp=.o) mgen: $(MGEN_APP_OBJ) $(MGEN_OBJ) $(LIBPROTO) - $(CC) -g $(CFLAGS) -o $@ $(MGEN_APP_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) - + $(CC) -g $(CFLAGS) -o $@ $(MGEN_APP_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) MPMGR_SRC = $(COMMON)/mpmgr.cpp $(COMMON)/gpsPub.cpp MPMGR_OBJ = $(MPMGR_SRC:.cpp=.o) +# Mgen shared memory payload manager mpmgr: $(MPMGR_OBJ) $(LIBPROTO) - $(CC) -g $(CFLAGS) -o $@ $(MPMGR_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) + $(CC) -g $(CFLAGS) -o $@ $(MPMGR_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) # pcap2mgen utility (converts UDP content of appropriate pcap file to mgen log P2M_SRC = $(COMMON)/pcap2mgen.cpp P2M_OBJ = $(P2M_SRC:.cpp=.o) pcap2mgen: $(P2M_OBJ) $(MGEN_OBJ) $(LIBPROTO) - $(CC) -g $(CFLAGS) -o $@ $(P2M_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBS) $(LIBPROTO) + $(CC) -g $(CFLAGS) -o $@ $(P2M_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) + +MPM_SRC = $(COMMON)/mgenPayloadMgr.cpp +MPM_OBJ = $(MPM_SRC:.cpp=.o) + +MPM_APP_SRC = $(COMMON)/mgenPayloadMgrApp.cpp +MPM_APP_OBJ = $(MPM_APP_SRC:.cpp=.o) + +# mgenPayloadMgr (template for mgen payload manager application) +mgenPayloadMgr: $(MPM_APP_OBJ) $(MPM_OBJ) $(LIBPROTO) $(MGEN_OBJ) + $(CC) -g $(CFLAGS) -o $@ $(MPM_APP_OBJ) $(MPM_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) # mgenBlast is a simple program to benchmark mgen performance MM_SRC = $(COMMON)/mgenBlast.cpp MM_OBJ = $(MM_SRC:.cpp=.o) mgenBlast: $(MM_OBJ) $(MGEN_OBJ) $(LIBPROTO) - $(CC) -g $(CFLAGS) -o $@ $(MM_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBS) $(LIBPROTO) + $(CC) -g $(CFLAGS) -o $@ $(MM_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) clean: rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/mgen $(UNIX)/mpmgr $(NS)/*.o; diff --git a/makefiles/Makefile.macosx b/makefiles/Makefile.macosx index e67040f7..7b71f015 100644 --- a/makefiles/Makefile.macosx +++ b/makefiles/Makefile.macosx @@ -9,8 +9,14 @@ # 1) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # -SYSTEM_INCLUDES = -I/opt/local/include -SYSTEM_LDFLAGS = +# Use libpcap installed by Xcode +#SYSTEM_INCLUDES = -I/opt/local/include +#SYSTEM_LDFLAGS = + +# Use libpcap installed from tcpdump.org +SYSTEM_INCLUDES = -I/usr/local/include +SYSTEM_LDFLAGS = -L/usr/local/lib + SYSTEM_LIBS = -lresolv -lpthread -lpcap # 2) System specific capabilities @@ -39,7 +45,8 @@ SYSTEM_LIBS = -lresolv -lpthread -lpcap # (We export these for other Makefiles as needed) # -export SYSTEM_HAVES = -D_HAVE_PCAP -DHAVE_IPV6 -DMACOSX -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DSOCKLEN_T=int +export SYSTEM_HAVES = -D_HAVE_PCAP -DHAVE_IPV6 -DMACOSX -DHAVE_ASSERT -DHAVE_GETLOGIN \ +-DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DUSE_SELECT -DSOCKLEN_T=int SYSTEM = macosx CC = g++ diff --git a/makefiles/android/AndroidManifest.xml b/makefiles/android/AndroidManifest.xml new file mode 100644 index 00000000..05f682e2 --- /dev/null +++ b/makefiles/android/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/makefiles/android/ant.properties b/makefiles/android/ant.properties new file mode 100644 index 00000000..b0971e89 --- /dev/null +++ b/makefiles/android/ant.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/makefiles/android/build.xml b/makefiles/android/build.xml new file mode 100644 index 00000000..5b4c241d --- /dev/null +++ b/makefiles/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/makefiles/android/jni/Android.mk b/makefiles/android/jni/Android.mk new file mode 100644 index 00000000..54a4b2b6 --- /dev/null +++ b/makefiles/android/jni/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := mgen +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../../protolib/include \ + $(LOCAL_PATH)/../../../include +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_STATIC_LIBRARIES := protolib + +ifeq ($(APP_OPTIM),debug) + LOCAL_CFLAGS += -DMGEN_DEBUG +endif +LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) + +LOCAL_SRC_FILES := \ + ../../../src/common/mgen.cpp \ + ../../../src/common/mgenEvent.cpp \ + ../../../src/common/mgenFlow.cpp \ + ../../../src/common/mgenMsg.cpp \ + ../../../src/common/mgenTransport.cpp \ + ../../../src/common/mgenPattern.cpp \ + ../../../src/common/mgenPayload.cpp \ + ../../../src/common/mgenSequencer.cpp \ + ../../../src/common/mgenAppSinkTransport.cpp \ + ../../../src/common/mgenApp.cpp +include $(BUILD_EXECUTABLE) + +$(call import-module,protolib/makefiles/android/jni) diff --git a/makefiles/android/jni/Application.mk b/makefiles/android/jni/Application.mk new file mode 100644 index 00000000..5c358d08 --- /dev/null +++ b/makefiles/android/jni/Application.mk @@ -0,0 +1,3 @@ +APP_ABI := all +APP_PLATFORM := android-8 +NDK_MODULE_PATH := ../..:../../protolib/ diff --git a/makefiles/android/local.properties b/makefiles/android/local.properties new file mode 100644 index 00000000..720fcda3 --- /dev/null +++ b/makefiles/android/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/Users/adamson/code/android/android-sdk diff --git a/makefiles/android/proguard-project.txt b/makefiles/android/proguard-project.txt new file mode 100644 index 00000000..f2fe1559 --- /dev/null +++ b/makefiles/android/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/makefiles/android/project.properties b/makefiles/android/project.properties new file mode 100644 index 00000000..cd0ca122 --- /dev/null +++ b/makefiles/android/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +android.library=true +# Project target. +target=android-8 diff --git a/makefiles/win32/mgen.sln b/makefiles/win32/mgen.sln index dbb437eb..a8eb40b4 100755 --- a/makefiles/win32/mgen.sln +++ b/makefiles/win32/mgen.sln @@ -1,12 +1,9 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgen", "mgen.vcproj", "{992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}" - ProjectSection(ProjectDependencies) = postProject - {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} = {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} - EndProjectSection +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgen", "mgen.vcxproj", "{992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Protokit", "..\..\protolib\makefiles\win32\Protokit.vcproj", "{DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Protokit", "..\..\protolib\makefiles\win32\Protokit.vcxproj", "{DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/makefiles/win64/mgen.sln b/makefiles/win64/mgen.sln new file mode 100755 index 00000000..75d68d7a --- /dev/null +++ b/makefiles/win64/mgen.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgen", "mgen.vcxproj", "{992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}" + ProjectSection(ProjectDependencies) = postProject + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} = {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Protokit", "..\..\protolib\makefiles\win64\Protokit.vcxproj", "{DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Debug|Win32.ActiveCfg = Debug|Win32 + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Debug|Win32.Build.0 = Debug|Win32 + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Release|Win32.ActiveCfg = Release|Win32 + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Release|Win32.Build.0 = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Debug|Win32.Build.0 = Debug|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.ActiveCfg = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/makefiles/win64/mgen.vcproj b/makefiles/win64/mgen.vcproj new file mode 100755 index 00000000..ebb966a4 --- /dev/null +++ b/makefiles/win64/mgen.vcproj @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..d13ba38f --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from distutils.core import setup + +# Note that the 'mgen' package has a dependency +# on the Protolib Python 'protokit' package and +# also requires that the 'mgen' binary be installed/ +# located in the user's executable PATH. + + +# TBD - invoke the "protolib/setup.py" automatically? +# (good intern task to do this the right way) + +setup(name='mgen', + version='1.0', + package_dir = {'' : 'src/python'}, + py_modules=['mgen'] +) + diff --git a/src/common/mgen.cpp b/src/common/mgen.cpp index f98cacb4..d2985921 100644 --- a/src/common/mgen.cpp +++ b/src/common/mgen.cpp @@ -35,7 +35,6 @@ int Mgen::LogToDebug(FILE* /*filePtr*/, const char* format, ...) char charBuffer[2048]; charBuffer[2048] = '\0'; int count = _vsnprintf(charBuffer, 2047, format, args); - TRACE("%s", charBuffer); va_end(args); return count; } // end Mgen::LogToDebug() @@ -61,12 +60,13 @@ Mgen::Mgen(ProtoTimerMgr& timerMgr, default_tx_buffer_lock(false), default_rx_buffer_lock(false), default_interface_lock(false), default_queue_limit_lock(false), sink_non_blocking(true), - log_data(true), + log_data(true), log_gps_data(true), checksum_enable(false), addr_type(ProtoAddress::IPv4), get_position(NULL), get_position_data(NULL), log_file(NULL), log_binary(false), local_time(false), log_flush(false), - log_file_lock(false), log_tx(false), log_open(false), log_empty(true) + log_file_lock(false), log_tx(false), log_open(false), log_empty(true), + reuse(true) { start_timer.SetListener(this, &Mgen::OnStartTimeout); @@ -79,6 +79,7 @@ Mgen::Mgen(ProtoTimerMgr& timerMgr, default_interface[0] = '\0'; sink_path[0] = '\0'; + source_path[0] = '\0'; } @@ -198,7 +199,7 @@ bool Mgen::Start() else // Schedule absolute start time { // Make sure there are pending events - if(!drec_event_list.IsEmpty() || !flow_list.IsEmpty()) + //if(!drec_event_list.IsEmpty() || !flow_list.IsEmpty()) { // Calculate start time delta and schedule start_timer // (can delay start up to 12 hours into future) @@ -208,14 +209,14 @@ bool Mgen::Start() UINT32 minutes = (currentTime.tv_sec - (3600*hours)) / 60; UINT32 seconds = currentTime.tv_sec - (3600*hours) - (60*minutes); hours = hours % 24; - double nowSec = hours*3600 + minutes*60 + seconds; + double nowSec = hours*3600 + minutes*60 + seconds + 1.0e-06*((double)currentTime.tv_usec); #else struct tm now; if (start_gmt) memcpy(&now, gmtime((time_t*)¤tTime.tv_sec), sizeof(struct tm)); else memcpy(&now, localtime((time_t*)¤tTime.tv_sec), sizeof(struct tm)); - double nowSec = now.tm_hour*3600 + now.tm_min*60 + now.tm_sec; + double nowSec = now.tm_hour*3600 + now.tm_min*60 + now.tm_sec + 1.0e-06*((double)currentTime.tv_usec); #endif // if/else _WIN32_WCE double startSec = start_hour*3600 + start_min*60 + start_sec; double delta = startSec - nowSec; @@ -225,6 +226,8 @@ bool Mgen::Start() DMSG(0, "Mgen::Start() Error: Specified start time has already elapsed\n"); return false; } + if (start_timer.IsActive()) start_timer.Deactivate(); + start_timer.SetInterval(delta); timer_mgr.ActivateTimer(start_timer); } @@ -235,6 +238,7 @@ bool Mgen::Start() } // end Mgen::Start() MgenTransport* Mgen::JoinGroup(const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName, UINT16 thePort) { @@ -258,11 +262,11 @@ MgenTransport* Mgen::JoinGroup(const ProtoAddress& groupAddress, #endif // SIMULATE // Sockets with space to join are at top of list - // (TBD) find socket of approprate ProtoAddress::Type ??? + // find socket of approprate ProtoAddress::Type bool newTransport = false; - MgenTransport* mgenTransport = FindTransportByInterface(interfaceName, thePort); - + MgenTransport* mgenTransport = FindTransportByInterface(interfaceName, thePort,groupAddress.GetType()); + if (!mgenTransport || ((IP_MAX_MEMBERSHIPS > 0) && (mgenTransport->GroupCount() >= (unsigned int)IP_MAX_MEMBERSHIPS))) @@ -273,11 +277,11 @@ MgenTransport* Mgen::JoinGroup(const ProtoAddress& groupAddress, { DMSG(0, "Mgen::JoinGroup() memory allocation error: %s\n", GetErrorString()); - return false; + return NULL; } newTransport = true; } - if (mgenTransport->JoinGroup(groupAddress, interfaceName)) + if (mgenTransport->JoinGroup(groupAddress, sourceAddress, interfaceName)) { if ((IP_MAX_MEMBERSHIPS > 0) && (mgenTransport->GroupCount() >= (unsigned int)IP_MAX_MEMBERSHIPS)) @@ -300,9 +304,10 @@ MgenTransport* Mgen::JoinGroup(const ProtoAddress& groupAddress, bool Mgen::LeaveGroup(MgenTransport* mgenTransport, const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName) { - if (mgenTransport->LeaveGroup(groupAddress, interfaceName)) + if (mgenTransport->LeaveGroup(groupAddress, sourceAddress, interfaceName)) { transport_list.Remove(mgenTransport); transport_list.Prepend(mgenTransport); @@ -332,8 +337,8 @@ MgenTransport* Mgen::FindMgenTransport(Protocol theProtocol, while (next) { // Same protocol and srcPort? - if ((next->GetProtocol() == theProtocol) && - (next->srcPort == srcPort) && + if ((next->GetProtocol() == theProtocol) && + (srcPort == 0 || next->srcPort == srcPort) && // ignore events && unconnected udp sockets // have invalid addrs and should match @@ -364,15 +369,23 @@ MgenTransport* Mgen::FindMgenTransport(Protocol theProtocol, /** * This search finds an mgenTransport suitable for joining a multicast group - * We want a matching multicast interface name, a matching port number + * We want a matching multicast interface name & type, and a matching port number * if "port" is non-zero */ MgenTransport* Mgen::FindTransportByInterface(const char* interfaceName, - UINT16 thePort) + UINT16 thePort, + ProtoAddress::Type addrType) { + MgenTransport* nextTransport = transport_list.head; while (nextTransport) { + if (nextTransport->GetAddressType() != addrType) + { + nextTransport = nextTransport->next; + continue; + } + if (nextTransport->GetProtocol() == UDP) { MgenUdpTransport* next = static_cast(nextTransport); @@ -382,7 +395,7 @@ MgenTransport* Mgen::FindTransportByInterface(const char* interfaceNam if (thePort == next->srcPort) { // OK, protocol and port matches, so ... - if (interfaceName) + if (NULL != interfaceName) { if ((NULL == next->GetMulticastInterface()) && // unspecified interface && (0 == next->GroupCount())) // no joins yet, so we'll @@ -394,8 +407,9 @@ MgenTransport* Mgen::FindTransportByInterface(const char* interfaceNam { if ((next->GetMulticastInterface() && interfaceName) && !strncmp(next->GetMulticastInterface(), interfaceName, 16)) - return nextTransport; // it's a "match" - + { + return nextTransport; // it's a "match" + } else { DMSG(0, "Mgen::FindMgenTransportByInterface() matching port but interface mismatch!\n"); @@ -468,7 +482,7 @@ MgenTransport* Mgen::GetMgenTransport(Protocol theProtocol, if (theTransport) return theTransport; - + switch (theProtocol) { case UDP: @@ -493,8 +507,9 @@ MgenTransport* Mgen::GetMgenTransport(Protocol theProtocol, break; } case SINK: + case SOURCE: { - MgenSinkTransport* theTransport = MgenSinkTransport::Create(*this); + MgenSinkTransport* theTransport = MgenSinkTransport::Create(*this, theProtocol); if (!theTransport) { @@ -503,7 +518,10 @@ MgenTransport* Mgen::GetMgenTransport(Protocol theProtocol, return NULL; } // ljt set these in constructor's too? - theTransport->SetPath(sink_path); + if (SINK == theProtocol) + theTransport->SetPath(sink_path); + else + theTransport->SetPath(source_path); theTransport->SetSinkBlocking(sink_non_blocking); transport_list.Prepend(theTransport); return theTransport; @@ -653,37 +671,96 @@ void Mgen::ProcessDrecEvent(const DrecEvent& event) switch (event.GetType()) { case DrecEvent::JOIN: - - if (!drec_group_list.JoinGroup(*this, - event.GetGroupAddress(), - event.GetInterface(), - event.GetGroupPort(), - offset_pending)) { - DMSG(0, "Mgen::ProcessDrecEvent(JOIN) Warning: error joining group\n"); - } - else + const UINT16* port = event.GetPortList(); + UINT16 portCount = event.GetPortCount(); + + // if no port given find first available socket to join + // this is the legacy behavior (the preferred command + // is to set the port on the join statement) + if (portCount == 0) { - MgenMsg theMsg; - theMsg.LogDrecEvent(JOIN_EVENT, &event, event.GetGroupPort(),*this); + if (!drec_group_list.JoinGroup(*this, + event.GetGroupAddress(), + event.GetSourceAddress(), + event.GetInterface(), + event.GetGroupPort(), + offset_pending)) + { + DMSG(0, "Mgen::ProcessDrecEvent(JOIN) Warning: error joining group\n"); + } + else + { + MgenMsg theMsg; + theMsg.LogDrecEvent(JOIN_EVENT, &event, event.GetGroupPort(),*this); + } } - break; - - case DrecEvent::LEAVE: - if (!drec_group_list.LeaveGroup(*this, - event.GetGroupAddress(), - event.GetInterface(), - event.GetGroupPort())) + else { - DMSG(0, "Mgen::ProcessDrecEvent(LEAVE) Warning: error leaving group\n"); + for (UINT16 i = 0; i < portCount; i++) + { + if (!drec_group_list.JoinGroup(*this, + event.GetGroupAddress(), + event.GetSourceAddress(), + event.GetInterface(), + port[i], + offset_pending)) + { + DMSG(0,"Mgen::ProcessDrecEvent(JOIN) Warning: error joining group\n"); + } + else + { + MgenMsg theMsg; + theMsg.LogDrecEvent(JOIN_EVENT,&event, port[i], *this); + } + } } - else - { - MgenMsg theMsg; - theMsg.LogDrecEvent(LEAVE_EVENT, &event, event.GetGroupPort(),*this); } + break; + case DrecEvent::LEAVE: + { + const UINT16* port = event.GetPortList(); + UINT16 portCount = event.GetPortCount(); + + if (portCount == 0) + { + if (!drec_group_list.LeaveGroup(*this, + event.GetGroupAddress(), + event.GetSourceAddress(), + event.GetInterface(), + event.GetGroupPort())) + { + DMSG(0, "Mgen::ProcessDrecEvent(LEAVE) Warning: error leaving group\n"); + } + else + { + MgenMsg theMsg; + theMsg.LogDrecEvent(LEAVE_EVENT, &event, event.GetGroupPort(),*this); + } + } else + { + for (UINT16 i = 0; i < portCount; i++) + { + if (!drec_group_list.LeaveGroup(*this, + event.GetGroupAddress(), + event.GetSourceAddress(), + event.GetInterface(), + port[i])) + { + DMSG(0,"Mgen::ProcessDrecEvent(LEAVE) warning: error leaving group\n"); + } + else + { + MgenMsg theMsg; + theMsg.LogDrecEvent(LEAVE_EVENT, &event, port[i] ,*this); + } + } + } + } + break; + case DrecEvent::LISTEN: { const UINT16* port = event.GetPortList(); @@ -777,7 +854,7 @@ void Mgen::ProcessDrecEvent(const DrecEvent& event) { DMSG(0,"Mgen::ProcessDrecEvent(IGNORE) Error: no socket on port %hu\n",port[i]); } - next = mgenTransport; + next = mgenTransport; } } break; @@ -1061,11 +1138,10 @@ bool Mgen::ParseEvent(const char* lineBuffer, unsigned int lineCount) // Update flow specific queue limit if specified if (theEvent->GetQueueLimit()) theFlow->SetQueueLimit(theEvent->GetQueueLimit()); - - - double currentTime = started ? GetCurrentOffset() : 0.0; + bool reallyStarted = (started && !start_timer.IsActive()); + double currentTime = reallyStarted ? GetCurrentOffset() : 0.0; if (currentTime < 0.0) currentTime = 0.0; - if (!theFlow->InsertEvent(theEvent, started, currentTime)) + if (!theFlow->InsertEvent(theEvent, reallyStarted, currentTime)) { DMSG(0, "Mgen::ParseEvent() Error: invalid mgen script line: %lu\n", lineCount); delete theEvent; @@ -1125,7 +1201,7 @@ bool Mgen::ParseEvent(const char* lineBuffer, unsigned int lineCount) void Mgen::InsertDrecEvent(DrecEvent* theEvent) { double eventTime = theEvent->GetTime(); - if (started) + if (started && !start_timer.IsActive()) { double currentTime = GetCurrentOffset(); if (currentTime < 0.0) currentTime = 0.0; @@ -1194,7 +1270,7 @@ const StringMapper Mgen::COMMAND_LIST[] = {"-TXCHECKSUM", TXCHECKSUM}, {"-RXCHECKSUM", RXCHECKSUM}, {"+QUEUE", QUEUE}, - {"+LOGDATA", LOGDATA}, + {"+REUSE", REUSE}, {"+OFF", INVALID_COMMAND}, // to deconflict "offset" from "off" event {NULL, INVALID_COMMAND} }; @@ -1275,6 +1351,7 @@ Mgen::CmdType Mgen::GetCmdType(const char* cmd) bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) { + switch (cmd) { case START: @@ -1307,7 +1384,6 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) start_gmt = true; else start_gmt = false; - if (start_hour == 0 && start_min == 0 && start_sec == 0) start_sec = -1.0; } @@ -1326,6 +1402,7 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) } } start_time_lock = override; // record START command precedence + if (started) Start(); // Adamson reschedule any prior START directive } // end if (override || !start_time_lock) break; } // end case START @@ -1541,6 +1618,36 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) case TXLOG: log_tx = true; break; + + case REUSE: + if (!arg) + { + DMSG(0, "Mgen::OnCommand() Error: missing argument to REUSE\n"); + return false; + } + { + bool reuseTemp; + // convert to upper case for case-insensitivity + char temp[4]; + unsigned int len = strlen(arg); + len = len < 4 ? len : 4; + unsigned int i; + for (i = 0 ; i < len; i++) + temp[i] = toupper(arg[i]); + temp[i] = '\0'; + if(!strncmp("ON", temp, len)) + reuseTemp = true; + else if(!strncmp("OFF", temp, len)) + reuseTemp = false; + else + { + DMSG(0, "Mgen::OnCommand() Error: wrong argument to REUSE: %s\n", arg); + return false; + } + SetDefaultReuse(reuseTemp); + break; + } + break; case LOCALTIME: local_time = true; @@ -1581,35 +1688,7 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) } SetDefaultQueueLimit(tmpQueueLimit,override); break; - - case LOGDATA: - - if (!arg) - { - DMSG(0,"Mgen::OnCommand() Error: missing argument to LOGDATA\n"); - return false; - } - else - { - char temp[4]; - unsigned int len = strlen(arg); - len = len < 4 ? len : 4; - unsigned int i; - for (i = 0; i < len; i++) - temp[i] = toupper(arg[i]); - temp[i] = '\0'; - if (!strncmp("ON", temp, len)) - SetLogData(true); - else if (!strncmp("OFF", temp, len)) - SetLogData(false); - else - { - DMSG(0,"Mgen::OnCommand() Error: wrong argument to logData: %s\n",arg); - return false; - } - } - break; - + case INVALID_COMMAND: DMSG(0, "Mgen::OnCommand() Error: invalid command\n"); return false; @@ -1641,6 +1720,7 @@ void DrecGroupList::Destroy(Mgen& mgen) if (NULL != current->flow_transport) mgen.LeaveGroup(current->flow_transport, current->group_addr, + current->source_addr, current->GetInterface()); delete current; @@ -1650,11 +1730,12 @@ void DrecGroupList::Destroy(Mgen& mgen) bool DrecGroupList::JoinGroup(Mgen& mgen, const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName, UINT16 thePort, bool deferred) { - DrecMgenTransport* transport = FindMgenTransportByGroup(groupAddress, interfaceName, thePort); + DrecMgenTransport* transport = FindMgenTransportByGroup(groupAddress, sourceAddress, interfaceName, thePort); if (transport && transport->IsActive()) { DMSG(0, "DrecGroupList::JoinGroup() Error: group already joined\n"); @@ -1664,7 +1745,7 @@ bool DrecGroupList::JoinGroup(Mgen& mgen, { if (!transport) { - if (!(transport = new DrecMgenTransport(groupAddress, interfaceName, thePort))) + if (!(transport = new DrecMgenTransport(groupAddress, sourceAddress, interfaceName, thePort))) { DMSG(0, "DrecGroupList::JoinGroup() Error: DrecGroupList::DrecMgenTransport memory allocation error: %s\n", GetErrorString()); @@ -1681,17 +1762,19 @@ bool DrecGroupList::JoinGroup(Mgen& mgen, bool DrecGroupList::LeaveGroup(Mgen& mgen, const ProtoAddress& groupAddress, + const ProtoAddress& sourceAddress, const char* interfaceName, UINT16 thePort) { - DrecMgenTransport* transport = FindMgenTransportByGroup(groupAddress, interfaceName, thePort); + DrecMgenTransport* transport = FindMgenTransportByGroup(groupAddress, sourceAddress, interfaceName, thePort); if (transport) { if (transport->IsActive()) { if (!mgen.LeaveGroup(transport->flow_transport, - groupAddress, - interfaceName)) + groupAddress, + sourceAddress, + interfaceName)) { DMSG(0, "DrecGroupList::LeaveGroup() Error: group leave error\n"); return false; @@ -1723,9 +1806,11 @@ bool DrecGroupList::JoinDeferredGroups(Mgen& mgen) } // end DrecGroupList::JoinDeferredGroups() -DrecGroupList::DrecMgenTransport* DrecGroupList::FindMgenTransportByGroup(const ProtoAddress& groupAddr, - const char* interfaceName, - UINT16 thePort) +DrecGroupList::DrecMgenTransport* DrecGroupList::FindMgenTransportByGroup( + const ProtoAddress& groupAddr, + const ProtoAddress& sourceAddr, + const char* interfaceName, + UINT16 thePort) { DrecMgenTransport* next = head; while (next) @@ -1737,8 +1822,11 @@ DrecGroupList::DrecMgenTransport* DrecGroupList::FindMgenTransportByGroup(const !strcmp(nextInterface, interfaceName)); bool groupIsEqual = next->group_addr.IsValid() ? next->group_addr.HostIsEqual(groupAddr) : true; - bool portIsEqual = thePort == next->GetPort(); - if (interfaceIsEqual && groupIsEqual && portIsEqual) + + bool sourceIsEqual = !next->source_addr.IsValid() ? + !sourceAddr.IsValid() : + sourceAddr.IsValid() && next->source_addr.HostIsEqual(sourceAddr); bool portIsEqual = thePort == next->GetPort(); + if (interfaceIsEqual && groupIsEqual && sourceIsEqual && portIsEqual) return next; next = next->next; } @@ -1771,9 +1859,10 @@ void DrecGroupList::Remove(DrecMgenTransport* transport) // DrecGroupList::DrecMgenTransport implementation DrecGroupList::DrecMgenTransport::DrecMgenTransport(const ProtoAddress& groupAddr, + const ProtoAddress& sourceAddr, const char* interfaceName, UINT16 thePort) - : flow_transport(NULL), group_addr(groupAddr), port(thePort), + : flow_transport(NULL), group_addr(groupAddr), source_addr(sourceAddr), port(thePort), prev(NULL), next(NULL) { if (interfaceName) @@ -1790,7 +1879,7 @@ DrecGroupList::DrecMgenTransport::~DrecMgenTransport() bool DrecGroupList::DrecMgenTransport::Activate(Mgen& mgen) { const char* iface = GetInterface(); - flow_transport = mgen.JoinGroup(group_addr,iface, port); + flow_transport = mgen.JoinGroup(group_addr, source_addr, iface, port); return IsActive(); } diff --git a/src/common/mgenApp.cpp b/src/common/mgenApp.cpp index 4c4ef86a..b9806c24 100644 --- a/src/common/mgenApp.cpp +++ b/src/common/mgenApp.cpp @@ -40,7 +40,7 @@ void MgenApp::Usage() { fprintf(stderr, "mgen [ipv4][ipv6][input ][save ]\n" " [output ][log ][hostAddr {on|off}\n" - " [logData {on|off}\n" + " [logData {on|off}][logGpsData {on|off}]\n" " [binary][txlog][nolog][flush]\n" " [event \"\"][port ]\n" " [instance ][command ]\n" @@ -52,8 +52,8 @@ void MgenApp::Usage() " [precise {on|off}][ifinfo ]\n" " [txcheck][rxcheck][check]\n" " [queue ][broadcast {on|off}]\n" - " [convert ][debug ]\n" - " [boost]\n"); + " [convert ][debug ]\n" + " [boost] [reuse {on|off}]\n"); } // end MgenApp::Usage() @@ -71,9 +71,11 @@ const char* const MgenApp::CMD_LIST[] = "+instance", // indicate mgen instance name "-stop", // exit program instance "+command", // specifies an input command file/device - "+hostAddr", // turn "host" field on/off in sent messages + "+hostaddr", // turn "host" field on/off in sent messages "-boost", // boost process priority "-help", // print usage and exit + "+logdata", // log optional data attribute? default ON + "+loggpsdata", // log gps data? default ON NULL }; @@ -81,12 +83,19 @@ MgenApp::CmdType MgenApp::GetCmdType(const char* cmd) { if (!cmd) return CMD_INVALID; unsigned int len = strlen(cmd); + bool matched = false; CmdType type = CMD_INVALID; const char* const* nextCmd = CMD_LIST; while (*nextCmd) { - if (!strncmp(cmd, *nextCmd+1, len)) + char lowerCmd[32]; // all commands < 32 characters + len = len < 31 ? len : 31; + unsigned int i; + for (i = 0; i < (len + 1); i++) + lowerCmd[i] = tolower(cmd[i]); + + if (!strncmp(lowerCmd, *nextCmd+1, len)) { if (matched) { @@ -100,6 +109,11 @@ MgenApp::CmdType MgenApp::GetCmdType(const char* cmd) type = CMD_ARG; else type = CMD_NOARG; + if (len == 3 && + !strncmp(lowerCmd,"log", len)) + // let mgen handle log events as name conflicts with logdata * loggpsdata + type = CMD_INVALID; + } } nextCmd++; @@ -185,13 +199,18 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) } else { - DMSG(0, "MgenApp::ProcessCommand(%s) error sending command to remote process\n", cmd); + DMSG(0, "MgenApp::OnCommand(%s) error sending command to remote process\n", cmd); return false; } } CmdType type = GetCmdType(cmd); unsigned int len = strlen(cmd); + char lowerCmd[32]; // all commands < 32 characters + len = len < 31 ? len : 31; + unsigned int i; + for (i = 0; i < (len + 1); i++) + lowerCmd[i] = tolower(cmd[i]); if (CMD_INVALID == type) { @@ -220,7 +239,7 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) DMSG(0, "MgenApp::ProcessCommand(%s) missing argument\n", cmd); return false; } - else if (!strncmp("port", cmd, len)) + else if (!strncmp("port", lowerCmd, len)) { // "port" == implicit "0.0 LISTEN UDP " script char* string = new char[strlen(val) + 64]; @@ -246,11 +265,11 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) have_ports = true; mgen.InsertDrecEvent(event); } - else if (!strncmp("ipv4", cmd, len)) + else if (!strncmp("ipv4", lowerCmd, len)) { mgen.SetDefaultSocketType(ProtoAddress::IPv4); } - else if (!strncmp("ipv6", cmd, len)) + else if (!strncmp("ipv6", lowerCmd, len)) { #ifdef HAVE_IPV6 ProtoSocket::SetHostIPv6Capable(); @@ -260,35 +279,33 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) #endif // HAVE_IPV6 DMSG(0, "MgenApp::ProcessCommand(ipv6) Warning: system not IPv6 capable?\n"); } - else if (!strncmp("background", cmd, len)) + else if (!strncmp("background", lowerCmd, len)) { // do nothing (this command was scanned immediately at startup) } - else if (!strcmp("convert", cmd)) + else if (!strcmp("convert", lowerCmd)) { convert = true; // set flag to do the conversion strcpy(convert_path, val); // save path of file to convert } - else if (!strncmp("sink", cmd, len)) + else if (!strncmp("sink", lowerCmd, len)) { mgen.SetSinkPath(val); } - else if (!strncmp("block", cmd, len)) + else if (!strncmp("block", lowerCmd, len)) { mgen.SetSinkBlocking(false); } - else if (!strncmp("source", cmd, len)) + else if (!strncmp("source", lowerCmd, len)) { - mgen.SetSinkPath(val); - + mgen.SetSourcePath(val); ProtoAddress tmpAddress; - MgenTransport* theMgenTransport = mgen.GetMgenTransport(SINK,0,tmpAddress,true,false); + MgenTransport* theMgenTransport = mgen.GetMgenTransport(SOURCE,0,tmpAddress,true,false); if (!theMgenTransport) { DMSG(0,"MgenApp::OnCommand() Error getting MgenAppSinkTransport.\n"); return false; } - MgenAppSinkTransport* theTransport = static_cast(theMgenTransport); theTransport->SetSource(true); if (!theTransport->Open()) return false; @@ -301,12 +318,12 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) theTransport->StartInputNotification(); #endif // !WIN32 } - else if (!strncmp("ifinfo", cmd, len)) + else if (!strncmp("ifinfo", lowerCmd, len)) { strncpy(ifinfo_name, val, 63); ifinfo_name[63] = '\0'; } - else if (!strncmp("precise", cmd, len)) + else if (!strncmp("precise", lowerCmd, len)) { char status[4]; // valid status is "on" or "off" strncpy(status, val, 3); @@ -328,7 +345,7 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) return false; } } - else if (!strncmp("instance", cmd, len)) + else if (!strncmp("instance", lowerCmd, len)) { if (control_pipe.IsOpen()) control_pipe.Close(); @@ -342,7 +359,7 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) return false; } } - else if (!strncmp("command", cmd, len)) + else if (!strncmp("command", lowerCmd, len)) { if (!OpenCmdInput(val)) { @@ -350,7 +367,7 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) return false; } } - else if (!strncmp("hostaddr", cmd, len)) + else if (!strncmp("hostaddr", lowerCmd, len)) { char status[4]; // valid status is "on" or "off" strncpy(status, val, 3); @@ -372,33 +389,60 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) return false; } } - else if (!strncmp("off", status, len)) - { - mgen.ClearHostAddress(); - } - else - { - DMSG(0, "MgenApp::ProcessCommand(precise) Error: invalid \n"); - return false; - } } - else if (!strncmp("stop", cmd, len)) + else if (!strncmp("logdata", lowerCmd, len)) + { + char status[4]; // valid status is "on" or "off" + strncpy(status, val, 3); + status[3] = '\0'; + unsigned int len = strlen(status); + for (unsigned int i = 0; i < len; i++) + status[i] = tolower(status[i]); + if (!strncmp("on", status, len)) + mgen.SetLogData(true); + else if (!strncmp("off",status,len)) + mgen.SetLogData(false); + else + { + DMSG(0, "MgenApp::ProcessCommand(logData) Error: wrong argument to logData:%s\n",status); + return false; + } + } + else if (!strncmp("loggpsdata", lowerCmd, len)) + { + char status[4]; // valid status is "on" or "off" + strncpy(status, val, 3); + status[3] = '\0'; + unsigned int len = strlen(status); + for (unsigned int i = 0; i < len; i++) + status[i] = tolower(status[i]); + if (!strncmp("on", status, len)) + mgen.SetLogGpsData(true); + else if (!strncmp("off",status,len)) + mgen.SetLogGpsData(false); + else + { + DMSG(0, "MgenApp::ProcessCommand(loggpsdata) Error: wrong argument to loggpsdata:%s\n",status); + return false; + } + } + else if (!strncmp("stop", lowerCmd, len)) { - Stop(); + Stop(); } - else if (!strncmp("boost", cmd, len)) + else if (!strncmp("boost", lowerCmd, len)) { - if (!dispatcher.BoostPriority()) - fprintf(stderr,"Unable to boost process priority.\n"); + if (!dispatcher.BoostPriority()) + fprintf(stderr,"Unable to boost process priority.\n"); } - else if (!strncmp("help", cmd, len)) + else if (!strncmp("help", lowerCmd, len)) { - fprintf(stderr, "mgen: version %s\n", MGEN_VERSION); - Usage(); - return false; + fprintf(stderr, "mgen: version %s\n", MGEN_VERSION); + Usage(); + return false; } return true; -} // end MgenApp::OnCommand() + } // end MgenApp::OnCommand() bool MgenApp::OnStartup(int argc, const char*const* argv) { diff --git a/src/common/mgenAppSinkTransport.cpp b/src/common/mgenAppSinkTransport.cpp index 93b68612..da141a1d 100644 --- a/src/common/mgenAppSinkTransport.cpp +++ b/src/common/mgenAppSinkTransport.cpp @@ -14,9 +14,9 @@ class Mgen; -MgenSinkTransport* MgenSinkTransport::Create(Mgen& theMgen) +MgenSinkTransport* MgenSinkTransport::Create(Mgen& theMgen, Protocol theProtocol) { - return static_cast(new MgenAppSinkTransport(theMgen,SINK)); + return static_cast(new MgenAppSinkTransport(theMgen,theProtocol)); } MgenAppSinkTransport::MgenAppSinkTransport(Mgen& theMgen, @@ -142,7 +142,7 @@ bool MgenAppSinkTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) } if (descriptor < 0) { - DMSG(0, "MgenAppSinkTransport::Open() error opening file: %s\n", GetErrorString()); + DMSG(0, "MgenAppSinkTransport::Open() open(%s) error: %s\n", path, GetErrorString()); descriptor = ProtoDispatcher::INVALID_DESCRIPTOR; return false; } @@ -190,6 +190,7 @@ bool MgenAppSinkTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_a struct timeval currentTime; ProtoSystemTime(currentTime); LogEvent(SEND_EVENT,&theMsg,currentTime,txBuffer); + messages_sent++; return true; } // end MgenAppSinkTransport::SendMessage @@ -354,7 +355,7 @@ bool MgenAppSinkTransport::Open() } if (descriptor < 0) { - DMSG(0, "MgenAppSinkTransport::Open() error opening file: %s\n", GetErrorString()); + DMSG(0, "MgenAppSinkTransport::Open() open(%s) error: %s\n", path, GetErrorString()); descriptor = ProtoDispatcher::INVALID_DESCRIPTOR; return false; } diff --git a/src/common/mgenEvent.cpp b/src/common/mgenEvent.cpp index ca9d865e..627f90d4 100644 --- a/src/common/mgenEvent.cpp +++ b/src/common/mgenEvent.cpp @@ -691,6 +691,8 @@ DrecEvent::DrecEvent() port_count(0), port_list(NULL), rx_buffer_size(0) { interface_name[0] = '\0'; + group_addr.Invalidate(); + source_addr.Invalidate(); } const StringMapper DrecEvent::TYPE_LIST[] = @@ -740,6 +742,7 @@ const StringMapper DrecEvent::OPTION_LIST[] = {"INTERFACE", INTERFACE}, {"PORT", PORT}, {"RXBUFFER", RXBUFFER}, + {"SRC", SRC}, {"XXXX", INVALID_OPTION} }; @@ -821,7 +824,7 @@ bool DrecEvent::InitFromString(const char* string) switch(event_type) { - case JOIN: // "{JOIN|LEAVE} [][PORT ]" + case JOIN: // "{JOIN|LEAVE} [SRC ] [INTERFACE ][PORT ]" case LEAVE: if (1 != sscanf(ptr, "%s", fieldBuffer)) { @@ -838,7 +841,7 @@ bool DrecEvent::InitFromString(const char* string) ptr += strlen(fieldBuffer); while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; - // Look for options [INTERFACE ] or [PORT ] + // Look for options [SRC ] [INTERFACE ] or [PORT /] while ('\0' != *ptr) { // Read option label @@ -868,22 +871,61 @@ bool DrecEvent::InitFromString(const char* string) break; case PORT: - // Read + // Read / if (1 != sscanf(ptr, "%s", fieldBuffer)) { - DMSG(0, "DrecEvent::InitFromString() Error: missing \n"); + DMSG(0, "DrecEvent::InitFromString() Error: missing /\n"); return false; } - if (1 != sscanf(ptr, "%hu", &port_count)) + // Parse port list and build array + if (!(port_list = CreatePortArray(fieldBuffer, &port_count))) { - DMSG(0, "DrecEvent::InitFromString() Error: invalid \n"); + DMSG(0,"DrecEvent::InitFromString() Error: missing /\n"); + return false; + } + // Point to next field, skipping any white space + ptr += strlen(fieldBuffer); + while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + break; + + case SRC: // Source address for SSM + + if (1 != sscanf(ptr, "%s", fieldBuffer)) + { + DMSG( 0, "DrecEvent::InitFromString() Error: " + "missing \n" ); + return false; + } + + // Source address must not be unspecified, multicast + // or a broadcast address + if (!source_addr.ResolveFromString(fieldBuffer) || + source_addr.IsUnspecified() || + source_addr.IsMulticast() || + source_addr.IsBroadcast() ) + { + DMSG( 0, "DrecEvent::InitFromString() Error: " + "invalid \n" ); + return false; + } + + // Compare type of source-address and group-address, + // both must be same.. + if ( group_addr.GetType() != source_addr.GetType() ) { + DMSG( 0, "DrecEvent::InitFromString() Error: " + " and are " + " not of same type\n" ); return false; } + // Point to next field, skipping any white space ptr += strlen(fieldBuffer); while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + break; + + case RXBUFFER: break; //RXBUFFER is not a leave option, however this case gets rid of a compiler warning. case INVALID_OPTION: diff --git a/src/common/mgenFlow.cpp b/src/common/mgenFlow.cpp index c536c21d..4bd99955 100644 --- a/src/common/mgenFlow.cpp +++ b/src/common/mgenFlow.cpp @@ -3,6 +3,10 @@ #include "mgen.h" #include // for gmtime(), struct tm, etc +#ifndef ENABLE_EVENT_VALIDATION +#define _VALIDATE_EVENTS_OFF +#endif + MgenFlow::MgenFlow(unsigned int flowId, ProtoTimerMgr& timerMgr, MgenController* theController, @@ -10,7 +14,7 @@ MgenFlow::MgenFlow(unsigned int flowId, int defaultQueueLimit, UINT32 defaultV6Label) : off_pending(false),old_transport(NULL),queue_limit(defaultQueueLimit), - message_limit(-1), messages_sent(0), + message_limit(-1), flow_id(flowId), payload(0), flow_label(defaultV6Label), flow_transport(NULL), seq_num(0), pending_messages(0), @@ -47,7 +51,6 @@ bool MgenFlow::InsertEvent(MgenEvent* theEvent, bool mgenStarted, double current if (mgenStarted) { - // Process "immediate" events or enqueue "scheduled" events if (eventTime < currentTime) { @@ -56,6 +59,8 @@ bool MgenFlow::InsertEvent(MgenEvent* theEvent, bool mgenStarted, double current if (ValidateEvent(theEvent)) { Update(theEvent); + // LJT event-test + event_list.Remove(theEvent); } else { @@ -109,6 +114,9 @@ bool MgenFlow::InsertEvent(MgenEvent* theEvent, bool mgenStarted, double current */ bool MgenFlow::ValidateEvent(const MgenEvent* event) { +#ifdef _VALIDATE_EVENTS_OFF + return true; +#endif const MgenEvent* prevEvent = (MgenEvent*)event->Prev(); MgenEvent::Type prevType = prevEvent ? prevEvent->GetType() : MgenEvent::INVALID_TYPE; @@ -195,8 +203,9 @@ bool MgenFlow::DoOnEvent(const MgenEvent* event) dst_addr = event->GetDstAddr(); if (event->OptionIsSet(MgenEvent::COUNT)) - message_limit = event->GetCount(); - + { + message_limit = event->GetCount(); + } #ifdef WIN32 if (protocol == TCP) { @@ -216,8 +225,15 @@ bool MgenFlow::DoOnEvent(const MgenEvent* event) if (event->GetQueueLimit()) queue_limit = event->GetQueueLimit(); - flow_transport = mgen.GetMgenTransport(protocol, src_port,event->GetDstAddr(),false,event->GetConnect()); - + // When we have a message_limit the transport keeps track of + // how many messages we have successfully sent so (for now + // we should provide a better fix for this - have flow keep track?) + // we should find closed sockets only. + if (message_limit > 0) + flow_transport = mgen.GetMgenTransport(protocol, src_port,event->GetDstAddr(),true,event->GetConnect()); + else + flow_transport = mgen.GetMgenTransport(protocol, src_port,event->GetDstAddr(),false,event->GetConnect()); + if (!flow_transport) { DMSG(0, "MgenFlow::Update() Error: unable to get %s flow transport.\n",MgenEvent::GetStringFromProtocol(protocol)); @@ -238,7 +254,7 @@ bool MgenFlow::DoOnEvent(const MgenEvent* event) theMsg.SetFlowId(flow_id); struct timeval currentTime; ProtoSystemTime(currentTime); - + if (off_pending) { off_pending = false; @@ -464,8 +480,8 @@ bool MgenFlow::DoGenericEvent(const MgenEvent* event) if (event->OptionIsSet(MgenEvent::COUNT)) { - messages_sent = 0; - message_limit = event->GetCount(); + flow_transport->SetMessagesSent(0); + message_limit = event->GetCount(); } char *tmpPayload = event->GetPayload(); @@ -489,8 +505,9 @@ bool MgenFlow::Update(const MgenEvent* event) { case MgenEvent::ON: { +#ifndef _VALIDATE_EVENTS_OFF ASSERT(!tx_timer.IsActive()); - +#endif if (!DoOnEvent(event)) return false; // Note the lack of "break" here is _intentional_ @@ -500,6 +517,13 @@ bool MgenFlow::Update(const MgenEvent* event) { // Do MOD specific events, remember we fall thru! +#ifdef _VALIDATE_EVENTS_OFF + if (!flow_transport) + { + DMSG(0,"MgenFlow::Update() Error MgenFlow() flow>%d not started yet.\n",flow_id); + break; + } +#endif DoModEvent(event); // Do ON ~and~ MOD events, remember we fall thru! @@ -562,7 +586,16 @@ bool MgenFlow::Update(const MgenEvent* event) if (tx_timer.IsActive()) tx_timer.Deactivate(); break; } - + + // Inform rapr so it can reuse the flowid + if (controller) + { + char buffer [512]; + sprintf(buffer, "offevent flow>%lu", (unsigned long)flow_id); + unsigned int len = strlen(buffer); + controller->OnOffEvent(buffer,len); + } + StopFlow(); break; } @@ -636,21 +669,30 @@ bool MgenFlow::GetNextInterval() // an OFF_EVENT or when COUNT has been exceeded. void MgenFlow::StopFlow() { - pending_messages = message_limit = messages_sent = 0; + pending_messages = message_limit = 0; + if (flow_transport) flow_transport->SetMessagesSent(0); off_pending = false; // Inform rapr so it can reuse the flowid if (controller) { char buffer [512]; - sprintf(buffer, "offevent flow>%lu", (unsigned long)flow_id); + sprintf(buffer, "stopFlow flow>%lu", (unsigned long)flow_id); unsigned int len = strlen(buffer); - controller->OnOffEvent(buffer,len); + controller->OnStopEvent(buffer,len); } // remove flow from pending flows list if (flow_transport) flow_transport->RemoveFlow(this); if (tx_timer.IsActive()) tx_timer.Deactivate(); - + +#ifdef _VALIDATE_EVENTS_OFF + // Since we aren't validating events when controlled by rapr, we may not have an off + // even that will deactivate the timer. + if (event_timer.IsActive()) + { + event_timer.Deactivate(); + } +#endif // _VALIDATE_EVENTS_OFF if (flow_transport) { MgenMsg theMsg; @@ -680,6 +722,18 @@ void MgenFlow::StopFlow() // we don't log another off event for this flow // later on in the shutdown process flow_transport->LogEvent(OFF_EVENT,&theMsg,currentTime); + + // Tell rapr we've turned the flow off, may result in + // multiple attempts to unlock the flow_id but that should + // be ok + if (controller) + { + char buffer [512]; + sprintf(buffer, "offevent flow>%lu",(unsigned long)flow_id); + unsigned int len = strlen(buffer); + controller->OnOffEvent(buffer,len); + } + // the close event will ensure were aren't closing a // socket another flow is using flow_transport->Close(); @@ -711,7 +765,7 @@ bool MgenFlow::SendMessage() return false; } - if (message_limit > 0 && messages_sent >= message_limit) + if (!flow_transport || message_limit > 0 && flow_transport->GetMessagesSent() >= message_limit) { // Deactivate timer but wait for an OFF_EVENT to actually // stop flow, unless we have an unlimited rate - in that @@ -732,14 +786,16 @@ bool MgenFlow::SendMessage() #else theMsg.SetSeqNum(MgenSequencer::GetNextSequence(flow_id)); #endif - struct timeval currentTime; ProtoSystemTime(currentTime); - // TxTime is set here initially but updated the transport's + // TxTime is set here initially but updated in the transport's // SendMessage function when the message is actually - // transmitted. (We may be delayed by pending messages) + // transmitted. (We may be delayed by pending messages and the + // tx time needs to be as close as possible to when we start + // sending data to the socket - for tcp in particular) theMsg.SetTxTime(currentTime); + theMsg.SetDstAddr(dst_addr); if (payload != NULL) theMsg.SetPayload(payload); @@ -760,7 +816,7 @@ bool MgenFlow::SendMessage() theMsg.SetGPSLongitude(999); theMsg.SetGPSAltitude(-999); #ifdef HAVE_GPS - if (get_position) + if (NULL != get_position) { GPSPosition pos; get_position(get_position_data, pos); @@ -776,7 +832,7 @@ bool MgenFlow::SendMessage() theMsg.SetGPSStatus(MgenMsg::CURRENT); } } - if (payload_handle) + if (NULL != payload_handle) { unsigned char payloadLen = 0; GPSGetMemory(payload_handle,0,(char*)&payloadLen,1); @@ -785,6 +841,44 @@ bool MgenFlow::SendMessage() } #endif // HAVE_GPS +#ifdef ANDROID + // For Android, we have implemented a temporary hack that depends upon + // the freely available "GPSLogger" Android application. This mgen + // code assumes that GPSLogger is configured to log (in text file format) + // to the file "sdcard/Android/data/com.mendhak.gpslogger/files/gpslogger.txt" + // If the file is not available or empty, a null GPS position is reported + GPSPosition pos; + memset(&pos, 0, sizeof(GPSPosition)); // init to invalid (null) position + const char* cmd = "tail -1 /storage/sdcard0/Android/data/com.mendhak.gpslogger/files/gpslogger.txt"; + FILE* filePtr = popen(cmd, "r"); + if (NULL != filePtr) + { + int year, month, day, hour, minute, second; + double lat,lon, alt; + if (9 == fscanf(filePtr, "%d-%d-%dT%d:%d:%dZ,%lf,%lf,%lf", + &year, &month, &day, &hour, &minute, &second, + &lat, &lon, &alt)) + { + pos.x = lon; + pos.y = lat; + pos.z = alt; + pos.sys_time = currentTime; // TBD - parse the logged time and see if not stale + pos.gps_time = currentTime; // TBD - parse the logged time and see if not stale + pos.xyvalid = pos.zvalid = true; + pos.tvalid = pos.stale = false; + theMsg.SetGPSLatitude(pos.y); + theMsg.SetGPSLongitude(pos.x); + if (pos.zvalid) + theMsg.SetGPSAltitude((INT32)(pos.z+0.5)); + if (pos.stale) + theMsg.SetGPSStatus(MgenMsg::STALE); + else + theMsg.SetGPSStatus(MgenMsg::CURRENT); + } + } + +#endif // ANDROID + #ifdef HAVE_IPV6 if (ProtoAddress::IPv6 == dst_addr.GetType()) { @@ -797,8 +891,11 @@ bool MgenFlow::SendMessage() bool success = false; // txbuffer only used by udp and sink transports - success = flow_transport->SendMessage(theMsg,dst_addr,txBuffer); - + if (flow_transport != NULL) + success = flow_transport->SendMessage(theMsg,dst_addr,txBuffer); + else + success = 0; + if (!success) { // message was not sent, so sequence number is decremented back one @@ -829,8 +926,7 @@ bool MgenFlow::SendMessage() } else { - messages_sent++; - if (GetPending()) pending_messages--; + if (GetPending()) pending_messages--; } return success; @@ -841,11 +937,12 @@ bool MgenFlow::SendMessage() bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) { - if (message_limit > 0 && messages_sent >= message_limit) + if (!flow_transport || message_limit > 0 && flow_transport->GetMessagesSent() >= message_limit) { - // deactivate timer but wait for an OFF_EVENT - // to actually stop flow + // deactivate timer and stopMgenSequencer flow immediately rather than + // waiting for an OFF_EVENT . if (tx_timer.IsActive()) tx_timer.Deactivate(); + StopFlow(); return false; } // If we moved to a new transport, finish sending @@ -902,6 +999,14 @@ bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) flow_transport->StartOutputNotification(); return true; } + // Inform rapr so it can reuse the flowid + if (controller) + { + char buffer [512]; + sprintf(buffer, "offevent flow>%lu", (unsigned long)flow_id); + unsigned int len = strlen(buffer); + controller->OnOffEvent(buffer,len); + } StopFlow(); return false; } @@ -1022,6 +1127,9 @@ bool MgenFlow::OnEventTimeout(ProtoTimer& /*theTimer*/) // 1) Update flow as needed using "next_event" Update(next_event); + // ljt event test + MgenEvent* processedEvent = next_event; + // 2) Set (or kill) event_timer according to "next_event->next" double currentTime = next_event->GetTime(); next_event = (MgenEvent*)next_event->Next(); @@ -1030,11 +1138,18 @@ bool MgenFlow::OnEventTimeout(ProtoTimer& /*theTimer*/) double nextInterval = next_event->GetTime() - currentTime; nextInterval = nextInterval > 0.0 ? nextInterval : 0.0; event_timer.SetInterval(nextInterval); + // ljt event test + event_list.Remove(processedEvent); return true; } else { +#ifdef _VALIDATE_EVENTS_OFF + if (event_timer.IsActive()) +#endif // _VALIDATE_EVENTS_OFF event_timer.Deactivate(); + // ljt event test + event_list.Remove(processedEvent); return false; } } // end MgenFlow::OnEventTimeout() diff --git a/src/common/mgenMsg.cpp b/src/common/mgenMsg.cpp index 3b6b18e9..9d759083 100644 --- a/src/common/mgenMsg.cpp +++ b/src/common/mgenMsg.cpp @@ -329,10 +329,9 @@ UINT16 MgenMsg::Pack(char* buffer,UINT16 bufferLen, bool includeChecksum,UINT32& } return msgLen; } // end MgenMsg::Pack() -bool MgenMsg::Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,bool logData) +bool MgenMsg::Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,bool log_data) { // init optional fields - host_addr.Invalidate(); gps_status = INVALID_GPS; reserved = 0; @@ -392,6 +391,7 @@ bool MgenMsg::Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,boo memcpy(&temp16, buffer+len, sizeof(INT16)); UINT16 dstPort = ntohs(temp16); len += sizeof(INT16); + // dst_addr(type) ProtoAddress::Type addrType; switch (buffer[len++]) @@ -471,26 +471,26 @@ bool MgenMsg::Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,boo // GPS position information if ((len+13) <= bufferLen) { - // latitude - memcpy(&temp32, buffer+len, sizeof(INT32)); - latitude = ((double)ntohl(temp32))/60000.0 - 180.0; - len += sizeof(INT32); - // longitude - memcpy(&temp32, buffer+len, sizeof(INT32)); - longitude = ((double)ntohl(temp32))/60000.0 - 180.0; - len += sizeof(INT32); - // altitude - memcpy(&temp32, buffer+len, sizeof(INT32)); - altitude = ntohl(temp32); - len += sizeof(INT32); - // status - gps_status = (GPSStatus)buffer[len++]; + // latitude + memcpy(&temp32, buffer+len, sizeof(INT32)); + latitude = ((double)ntohl(temp32))/60000.0 - 180.0; + len += sizeof(INT32); + // longitude + memcpy(&temp32, buffer+len, sizeof(INT32)); + longitude = ((double)ntohl(temp32))/60000.0 - 180.0; + len += sizeof(INT32); + // altitude + memcpy(&temp32, buffer+len, sizeof(INT32)); + altitude = ntohl(temp32); + len += sizeof(INT32); + // status + gps_status = (GPSStatus)buffer[len++]; } else - { + { packet_header_len = len; return true; - } + } // "reserved" field if (len < bufferLen) @@ -511,7 +511,7 @@ bool MgenMsg::Unpack(const char* buffer, UINT16 bufferLen,bool forceChecksum,boo if (0 != payload_len) { payload_len = payload_len < (bufferLen - len) ? payload_len : (bufferLen - len); - if (logData) + if (log_data) { payload = new MgenPayload(); char *tmpStr = new char[payload_len]; @@ -1005,6 +1005,7 @@ bool MgenMsg::LogRecvEvent(FILE* logFile, bool logBinary, bool local_time, bool log_data, + bool log_gps_data, char* msgBuffer, bool flush, const struct timeval& theTime) @@ -1156,9 +1157,10 @@ bool MgenMsg::LogRecvEvent(FILE* logFile, DMSG(0, "MgenMsg::LogRecvEvent() invalid GPS status\n"); Mgen::Log(logFile, "\n"); return false; - } // end switch (gps_status) - Mgen::Log(logFile, "gps>%s,%f,%f,%ld ", statusString, - latitude, longitude, altitude); + } // end switch (gps_status) + if (log_gps_data) + Mgen::Log(logFile, "gps>%s,%f,%f,%ld ", statusString, + latitude, longitude, altitude); UINT16 payload_len = payload == NULL ? 0 : payload->GetPayloadLen(); if (payload_len && log_data) { @@ -1223,6 +1225,11 @@ bool MgenMsg::LogSendEvent(FILE* logFile, memcpy(header+index, &temp16, sizeof(INT16)); index += sizeof(INT16); + // the tx_time in the txBuffer is used as the + // SEND message event time. For TCP messages + // this needs to be the time of the first + // TCP section sent. + // Write mgen_msg_size since we are relying // on mgen_len for segment size in recv // processing... @@ -1257,24 +1264,24 @@ bool MgenMsg::LogSendEvent(FILE* logFile, #ifdef _WIN32_WCE struct tm timeStruct; - timeStruct.tm_hour = tx_time.tv_sec / 3600; + timeStruct.tm_hour = theTime.tv_sec / 3600; UINT32 hourSecs = 3600 * timeStruct.tm_hour; - timeStruct.tm_min = (tx_time.tv_sec - hourSecs) / 60; - timeStruct.tm_sec = tx_time.tv_sec - hourSecs - (60*timeStruct.tm_min); + timeStruct.tm_min = (theTime.tv_sec - hourSecs) / 60; + timeStruct.tm_sec = theTime.tv_sec - hourSecs - (60*timeStruct.tm_min); timeStruct.tm_hour = timeStruct.tm_hour % 24; struct tm* timePtr = &timeStruct; #else struct tm* timePtr; if (local_time) - timePtr = localtime((time_t*)&tx_time.tv_sec); + timePtr = localtime((time_t*)&theTime.tv_sec); else - timePtr = gmtime((time_t*)&tx_time.tv_sec); + timePtr = gmtime((time_t*)&theTime.tv_sec); #endif // if/else _WIN32_WCE Mgen::Log(logFile, "%02d:%02d:%02d.%06lu ", timePtr->tm_hour, timePtr->tm_min, timePtr->tm_sec, - (UINT32)tx_time.tv_usec); + (UINT32)theTime.tv_usec); Mgen::Log(logFile,"SEND proto>%s flow>%lu seq>%lu srcPort>%hu dst>%s/%hu", MgenEvent::GetStringFromProtocol(protocol), @@ -1444,6 +1451,19 @@ void MgenMsg::LogDrecEvent(LogEventType eventType, const DrecEvent *event, UINT1 timePtr->tm_hour, timePtr->tm_min, timePtr->tm_sec, (UINT32)eventTime.tv_usec, event->GetGroupAddress().GetHostString()); + + // If source is valid, it means it is SSM, print source as well + if ( event->GetSourceAddress().IsValid() ) + { + const char* source; + + source = event->GetSourceAddress().GetHostString(); + if (source) + { + Mgen::Log(logFile, " source>%s", source ); + } + } + const char* iface = event->GetInterface(); if (iface) Mgen::Log(logFile, " interface>%s", iface); if (portNumber) @@ -1458,6 +1478,20 @@ void MgenMsg::LogDrecEvent(LogEventType eventType, const DrecEvent *event, UINT1 timePtr->tm_hour, timePtr->tm_min, timePtr->tm_sec, (UINT32)eventTime.tv_usec, event->GetGroupAddress().GetHostString()); + + // If source is valid, it means it is SSM, print source as well + if ( event->GetSourceAddress().IsValid() ) + { + const char* source; + + source = event->GetSourceAddress().GetHostString(); + + if (source) + { + Mgen::Log(logFile, " source>%s", source ); + } + } + const char* iface = event->GetInterface(); if (iface) Mgen::Log(logFile, " interface>%s", iface); if (portNumber) @@ -1498,6 +1532,7 @@ bool MgenMsg::ConvertBinaryLog(const char* path,Mgen& mgen) bool local_time = mgen.GetLocalTime(); bool log_flush = mgen.GetLogFlush(); bool log_data = mgen.GetLogData(); + bool log_gps_data = mgen.GetLogGpsData(); if (NULL == log_file) return false; FILE* file = fopen(path, "rb"); @@ -1685,12 +1720,13 @@ bool MgenMsg::ConvertBinaryLog(const char* path,Mgen& mgen) msg.SetSrcAddr(srcAddr); msg.SetTxTime(eventTime); msg.Unpack(buffer+index, recordLength - index, false, log_data); - msg.LogRecvEvent(log_file, false, local_time, log_data, NULL, log_flush,eventTime); + msg.LogRecvEvent(log_file, false, local_time, log_data, log_gps_data, NULL, log_flush,eventTime); break; } case SEND_EVENT: { + MgenMsg msg; // get tcp mgen_msg_len if (theProtocol == TCP) @@ -1703,7 +1739,7 @@ bool MgenMsg::ConvertBinaryLog(const char* path,Mgen& mgen) } msg.SetProtocol(theProtocol); msg.Unpack(buffer+index, recordLength, false, log_data); - msg.LogSendEvent(log_file,false, local_time, NULL, log_flush,msg.tx_time); + msg.LogSendEvent(log_file,false, local_time, NULL, log_flush, msg.tx_time); break; } case LISTEN_EVENT: diff --git a/src/common/mgenPayloadMgr.cpp b/src/common/mgenPayloadMgr.cpp new file mode 100644 index 00000000..36ca832e --- /dev/null +++ b/src/common/mgenPayloadMgr.cpp @@ -0,0 +1,853 @@ +/********************************************************************* + * + * AUTHORIZATION TO USE AND DISTRIBUTE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: + * + * (1) source code distributions retain this paragraph in its entirety, + * + * (2) distributions including binary code include this paragraph in + * its entirety in the documentation or other materials provided + * with the distribution, and + * + * (3) all advertising materials mentioning features or use of this + * software display the following acknowledgment: + * + * "This product includes software written and developed + * by Brian Adamson and Joe Macker of the Naval Research + * Laboratory (NRL)." + * + * The name of NRL, the name(s) of NRL employee(s), or any entity + * of the United States Government may not be used to endorse or + * promote products derived from this software, nor does the + * inclusion of the NRL written and developed software directly or + * indirectly suggest NRL or United States Government endorsement + * of this product. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ********************************************************************/ + +#include "mgen.h" +#include "mgenPayloadMgr.h" +#include "mgenPayloadMgrApp.h" + +MgenPayloadMgr::MgenPayloadMgr(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier, + Mgen& mgen) + : timer_mgr(timerMgr), + mgen(mgen), + started(false),stopped(false), + start_hour(0), start_min(0), start_sec(-1.0), + start_gmt(false),start_time_lock(false), + log_file(NULL), log_binary(false),local_time(false),log_flush(false), + log_open(false),log_empty(true) +{ + SetSocketNotifier(&socketNotifier); + + // TBD: Create a timer to keep our app alive + payload_timer.SetListener(this,&MgenPayloadMgr::OnTxTimeout); + +} + +MgenPayloadMgr::~MgenPayloadMgr() +{ + Stop(); +} + +bool MgenPayloadMgr::OnTxTimeout(ProtoTimer& /*theTimer*/) +{ + DMSG(2,"MgenPayloadMgrApp::OnTxTimeout() 5 second heartbeat...\n"); + return true; +} + +bool MgenPayloadMgr::Start() +{ + if (!mgen.Start()) + { + DMSG(0,"MgenPayloadMgr::Start() Error: Error starting Mgen!\n"); + } + + // TODO: Heartbeat tbd + payload_timer.SetInterval(5.0); + payload_timer.SetRepeat(-1); + OnTxTimeout(payload_timer); + if (!payload_timer.IsActive()) timer_mgr.ActivateTimer(payload_timer); + + started = true; + return true; +} +void MgenPayloadMgr::Stop() +{ + if (payload_timer.IsActive()) payload_timer.Deactivate(); + + // TODO: cleanup +} + +bool MgenPayloadMgr::SendMgenCommand(const char* cmd, const char* val) +{ + + if (!mgen.OnCommand(Mgen::GetCommandFromString(cmd),val,false)) + { + if (mgen.IsStarted()) + DMSG(0,"MgenPayloadMgr::SendMgenCommand() Error: processing mgen command: %s\n",val); + else + DMSG(0,"MgenPayloadMgr::SendMgenCommand() Error: processing mgen command: %s Mgen not started.\n",val); + + + return false; + } + return true; + +} // end MgenPayloadMgr::SendMgenCommand + +// This tells if the command is valid and whether args are expected +MgenPayloadMgr::CmdType MgenPayloadMgr::GetCmdType(const char* cmd) +{ + if (!cmd) return CMD_INVALID; + char upperCmd[32]; // all commands < 32 characters + unsigned int len = strlen(cmd); + len = len < 31 ? len : 31; + unsigned int i; + for (i = 0; i < 31; i++) + upperCmd[i] = toupper(cmd[i]); + + bool matched = false; + const StringMapper* m = COMMAND_LIST; + CmdType type = CMD_INVALID; + while (INVALID_COMMAND != (*m).key) + { + if (!strncmp(upperCmd, (*m).string+1, len)) + { + if (matched) + { + // ambiguous command (command should match only once) + return CMD_INVALID; + } + else + { + matched = true; + if ('+' == (*m).string[0]) + type = CMD_ARG; + else + type = CMD_NOARG; + } + } + m++; + } + return type; + +} // end MgenPayloadMgr::GetCmdType() + +// Global command processing +const StringMapper MgenPayloadMgr::COMMAND_LIST[] = +{ + // Mgen global commands: + {"+START", START}, + {"+EVENT", EVENT}, + {"+INPUT", INPUT}, + {"+MPMLOG", MPMLOG}, + {"+OVERWRITE_MPMLOG", OVERWRITE_MPMLOG}, + {"+MGENLOG", MGENLOG}, + {"+OVERWRITE_MGENLOG", OVERWRITE_MGENLOG}, + {"+DEBUG", DEBUG}, + {"-TXLOG", TXLOG}, + {"-LOCALTIME", LOCALTIME}, + {"-NOLOG", NOLOG}, + {"-BINARY", BINARY}, + {"-FLUSH", FLUSH}, + {"+LABEL", LABEL}, + {"+RXBUFFER", RXBUFFER}, + {"+TXBUFFER", TXBUFFER}, + {"+TOS", TOS}, + {"+TTL", TTL}, + {"+INTERFACE", INTERFACE}, + {"-CHECKSUM", CHECKSUM}, + {"-TXCHECKSUM", TXCHECKSUM}, + {"-RXCHECKSUM", RXCHECKSUM}, + {"+SAVE", SAVE}, + {"+OFF", INVALID_COMMAND}, // to deconflict "offset" from "off" event + {NULL, INVALID_COMMAND} +}; + + +MgenPayloadMgr::Command MgenPayloadMgr::GetCommandFromString(const char* string) +{ + // Make comparison case-insensitive + char upperString[16]; + unsigned int len = strlen(string); + + len = len < 16 ? len : 16; + + for (unsigned int i = 0 ; i < len; i++) + upperString[i] = toupper(string[i]); + const StringMapper* m = COMMAND_LIST; + MgenPayloadMgr::Command theCommand = INVALID_COMMAND; + while (NULL != (*m).string) + { + if (!strncmp(upperString, (*m).string+1, len)) { + theCommand = ((Command)((*m).key)); + } + m++; + } + return theCommand; +} // end MgenPayloadMgr::GetCommandFromString() + +bool MgenPayloadMgr::OnCommand(MgenPayloadMgr::Command cmd, const char* arg,bool override) +{ + DMSG(0,"Command %s\n",arg); + + switch (cmd) + { + case START: + { + if (!arg) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: missing \n"); + return false; + + } + if (override || !start_time_lock) + { + // convert to upper case for case-insensitivity + // search for "GMT" or "NOW" keywords + + char temp[32]; + unsigned int len = strlen(arg); + len = len < 31 ? len : 31; + unsigned int i; + for (i = 0 ; i < len; i++) + temp[i] = toupper(arg[i]); + temp[i] = '\0'; + + unsigned int startHour, startMin; + double startSec; + // arg should be "hr:min:sec[GMT]" or "NOW" + if (3 == sscanf(temp, "%u:%u:%lf", &startHour, &startMin, &startSec)) + { + start_hour = startHour; + start_min = startMin; + start_sec = startSec; + if (strstr(temp, "GMT")) + start_gmt = true; + else + start_gmt = false; + } + else + { + // Check for "NOW" keywork (case-insensitive) + if (strstr(temp, "NOW")) + { + // negative start_time_sec indicates immediate start + start_sec = -1.0; + } + else + { + DMSG(0, "MgenPayloadMgr::OnCommand() Error: invalid START time\n"); + return false; + } + } + start_time_lock = override; //record START command precedence + } // end if (override || !start_time_lock) + break; + } // end case START + + case EVENT: + { + if (!mgen.ParseEvent(arg,0)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: error parsing event\n"); + return false; + } + break; + } + case INPUT: + { + if (!ParseScript(arg)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: error parsing script\n"); + return false; + } + break; + } + case MPMLOG: + { + if (!OpenLog(arg,true,false)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: mgenPayloadMgr log file open error: %s\n", strerror(errno)); + return false; + } + break; + } + case OVERWRITE_MPMLOG: + { + if (!OpenLog(arg,false,false)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: rapr log file open error: %s\n", strerror(errno)); + return false; + } + break; + } + case MGENLOG: + { + char tmpOutput[512]; + if (1 != sscanf(arg,"%s",tmpOutput)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: Log file name required\n"); + return false; + } + char buffer[8192]; + sprintf(buffer," LOG %s",tmpOutput); + SendMgenCommand("event",buffer); + break; + } + case OVERWRITE_MGENLOG: + { + char tmpOutput[512]; + if (1 != sscanf(arg,"%s",tmpOutput)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: Log file name required\n"); + return false; + } + char buffer[8192]; + sprintf(buffer," OUTPUT %s",tmpOutput); + SendMgenCommand("event",buffer); + break; + } + case SAVE: + { + char tmpOutput[512]; + if (1 != sscanf(arg,"%s",tmpOutput)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: Log file name required\n"); + return false; + } + char buffer[8192]; + sprintf(buffer," SAVE %s",tmpOutput); + SendMgenCommand("event",buffer); + break; + } + case DEBUG: + { + SetDebugLevel(atoi(arg)); + + break; + } + case TXLOG: + { + char buffer[8192]; + sprintf(buffer," TXLOG"); + SendMgenCommand("event",buffer); + break; + } + case LOCALTIME: + { + char buffer [8192]; + sprintf(buffer," LOCALTIME"); + local_time = true; + SendMgenCommand("LOCALTIME",buffer); + break; + } + case NOLOG: + { + char buffer[8192]; + sprintf(buffer," NOLOG"); + SendMgenCommand("event",buffer); + break; + } + case BINARY: + { + char buffer[8192]; + sprintf(buffer," BINARY"); + SendMgenCommand("event",buffer); + break; + } + case FLUSH: + { + // Set RAPR log file to flush + log_flush = true; + + // Set MGEN log file to flush + char buffer[8192]; + sprintf(buffer," FLUSH"); + SendMgenCommand("event",buffer); + break; + } + case LABEL: + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: Label command not implemented.\n"); + return false; + + } + case RXBUFFER: + { + unsigned int sizeTemp; + if (1 != sscanf(arg,"%u",&sizeTemp)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: invalid rx buffer size\n"); + return false; + } + char buffer [8192]; + sprintf(buffer," RXBUFFER %d",sizeTemp); + SendMgenCommand("event",buffer); + break; + } + case TXBUFFER: + { + unsigned int sizeTemp; + if (1 != sscanf(arg,"%u",&sizeTemp)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: invalid tx buffer size\n"); + return false; + } + char buffer [8192]; + sprintf(buffer," TXBUFFER %d",sizeTemp); + SendMgenCommand("event",buffer); + break; + } + case TOS: + { + int tosTemp; + int result = sscanf(arg,"%i",&tosTemp); + if ((1 != result) || (tosTemp < 0) || (tosTemp > 255)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: invalid tos value\n"); + return false; + } + char buffer [8192]; + sprintf(buffer," TOS %i",tosTemp); + SendMgenCommand("event",buffer); + break; + } + case TTL: + { + int ttlTemp; + int result = sscanf(arg,"%i",&ttlTemp); + if ((1 != result) || (ttlTemp < 0) || (ttlTemp > 255)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: invalid ttl value\n"); + return false; + } + char buffer[8192]; + sprintf(buffer," TTL %i",ttlTemp); + SendMgenCommand("event",buffer); + break; + } + case INTERFACE: + { + char tmpOutput[512]; + if (1 != sscanf(arg,"%s",tmpOutput)) + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: multicast interface name required\n"); + return false; + } + + char buffer[8192]; + sprintf(buffer," INTERFACE %s",tmpOutput); + SendMgenCommand("event",buffer); + break; + } + case CHECKSUM: + { + char buffer[8192]; + sprintf(buffer," CHECKSUM"); + SendMgenCommand("event",buffer); + break; + } + case TXCHECKSUM: + { + char buffer[8192]; + sprintf(buffer," TXCHECKSUM"); + SendMgenCommand("event",buffer); + break; + } + case RXCHECKSUM: + { + char buffer[8192]; + sprintf(buffer," RXCHECKSUM"); + SendMgenCommand("event",buffer); + break; + } + case MGENEVENT: + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: Keyword is a raprApp keyword. Program error?\n"); + return false; + } + case INVALID_COMMAND: + { + DMSG(0,"MgenPayloadMgr::OnCommand() Error: invalid command\n"); + return false; + } + } // end switch(cmd) + return true; +} // end MgenPayloadMgr::OnCommand + +void MgenPayloadMgr::LogEvent(const char* cmd,const char* val) +{ + if (NULL == log_file) return; + + if (log_file) + { + struct timeval currentTime; + ProtoSystemTime(currentTime); + struct tm* timePtr; + if (local_time) + timePtr = localtime((time_t*)¤tTime.tv_sec); + else + timePtr = gmtime((time_t*)¤tTime.tv_sec); + + fprintf(log_file,"%02d:%02d:%02d.%06lu app>%s %s\n", + timePtr->tm_hour,timePtr->tm_min, + timePtr->tm_sec,(unsigned long) currentTime.tv_usec, + cmd,val); + if (log_flush) fflush(log_file); + } +} +bool MgenPayloadMgr::OpenLog(const char* path, bool append, bool binary) +{ + CloseLog(); + if (append) + { + struct stat buf; + if (stat(path, &buf)) // zero return value == success + log_empty = true; // error -- assume file is empty + else if (buf.st_size == 0) + log_empty = true; + else + log_empty = false; + } + else + { + log_empty = true; + } + const char* mode; + if (binary) + { + mode = append ? "ab" : "wb+"; + log_binary = true; + } + else + { + mode = append ? "a" : "w+"; + log_binary = false; + } + if (!(log_file = fopen(path, mode))) + { + DMSG(0, "MgenPayloadMgr::OpenLog() fopen() Error: %s\n", strerror(errno)); + return false; + } + log_open = true; + return true; +} // end MgenPayloadMgr::OpenLog() + +void MgenPayloadMgr::SetLogFile(FILE* filePtr) +{ + CloseLog(); + log_file = filePtr; + +} // end MgenPayloadMgr::SetLogFile() + +void MgenPayloadMgr::CloseLog() +{ + if (log_file) + { + if ((stdout != log_file) && (stderr != log_file)) + fclose(log_file); + log_file = NULL; + } +} // end MgenPayloadMgr::CloseLog() + +bool MgenPayloadMgr::ParseEvent(const char* lineBuffer,unsigned int lineCount) +{ + const char * ptr = lineBuffer; + if (!ptr) return true; + + lineBuffer = ptr; + + // Strip leading white space + while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + // Check for comment line (leading '#') + if ('#' == *ptr) return true; + char fieldBuffer[SCRIPT_LINE_MAX+1]; + // Script lines are in form {|} ... + if (1 != sscanf(ptr, "%s", fieldBuffer)) + { + // Blank line? + return true; + } + // Set ptr to next field in line, stripping white space + ptr += strlen(fieldBuffer); + while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + + Command cmd = GetCommandFromString(fieldBuffer); + if (EVENT == cmd) + { + // read in or + if (1 != sscanf(ptr, "%s", fieldBuffer)) + { + DMSG(0, "MgenPayloadMgr::ParseEvent() Error: empty EVENT command %s\n",fieldBuffer); + return false; + } + // Set ptr to next field in line, stripping white space + ptr += strlen(fieldBuffer); + while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + } + + // If it's not a "global command", assume it's an event. + if (INVALID_COMMAND == cmd) + { + cmd = EVENT; + } + + switch (cmd) + { + case EVENT: + { + DMSG(0,"MgenPayloadMgr::ParseEvent()"); + + if (!mgen.ParseEvent(lineBuffer,lineCount)) + { + DMSG(0,"MgenPaylogMgr::ParseEvent() mgen.ParseEvent error %s %d",lineBuffer,lineCount); + } + break; + } // end case EVENT + default: + // Is it a global command + if (INVALID_COMMAND != cmd) + { + if (!OnCommand(cmd,ptr)) + { + DMSG(0,"MgenPayloadMgr::ParseEvent() Error: Bad global command: %s\n",lineBuffer); + return false; + } + } + else + { + DMSG(0,"MgenPayloadMgr::ParseEvent() Error: invalid command: %s\n",lineBuffer); + return false; + } + break; + } + + return true; +} // end MgenPayloadMgr::ParseEvent() + +// Parse a MgenPayloadMgr script +bool MgenPayloadMgr::ParseScript(const char* path) +{ + // Open script file + FILE* scriptFile = fopen(path,"r"); + if (!scriptFile) + { + DMSG(0,"MgenPayloadMgr::ParseScript() fopen() Error: %s\n",strerror(errno)); + return false; + } + + // Read script file line by line using FastReader + FastReader reader; + unsigned int lineCount = 0; + unsigned int lines = 0; + while (1) + { + lineCount += lines; // for grouped (continued) lines + char lineBuffer[SCRIPT_LINE_MAX+1]; + unsigned int len = SCRIPT_LINE_MAX; + switch (reader.ReadlineContinue(scriptFile, lineBuffer, &len, &lines)) + { + case FastReader::OK: + lineCount++; + lines--; + break; + case FastReader::DONE: + fclose(scriptFile); + return true; // done with script file + case FastReader::ERROR_: + DMSG(0, "MgenPayloadMgr::ParseScript() Error: script file read error\n"); + fclose(scriptFile); + return false; + } + + // check for comment line (leading '#') + if ('#' == *lineBuffer) continue; + + if (!ParseEvent(lineBuffer, lineCount)) + { + DMSG(0, "MgenPayloadMgr::ParseScript() Error: invalid script line: %lu\n", lineCount); + fclose(scriptFile); + return false; + } + } // end while (1) + return true; + +} // end MgenPayloadMgr::ParseScript + +//////////////////////////////////////////////////////////////// +// MgenPayloadMgr::FastReader implementation + +MgenPayloadMgr::FastReader::FastReader() + : savecount(0) +{ + +} + +MgenPayloadMgr::FastReader::Result MgenPayloadMgr::FastReader::Read(FILE* filePtr, + char* buffer, + unsigned int* len) +{ + unsigned int want = *len; + if (savecount) + { + unsigned int ncopy = want < savecount ? want : savecount; + memcpy(buffer, saveptr, ncopy); + savecount -= ncopy; + saveptr += ncopy; + buffer += ncopy; + want -= ncopy; + } + while (want) + { + unsigned int result = fread(savebuf, sizeof(char), BUFSIZE, filePtr); + if (result) + { + unsigned int ncopy= want < result ? want : result; + memcpy(buffer, savebuf, ncopy); + savecount = result - ncopy; + saveptr = savebuf + ncopy; + buffer += ncopy; + want -= ncopy; + } + else // end-of-file + { + if (ferror(filePtr)) + { + if (EINTR == errno) continue; + } + *len -= want; + if (*len) + return OK; // we read at least something + else + return DONE; // we read nothing + } + } // end while(want) + return OK; +} // end MgenPayloadMgr::FastReader::Read() + +// An OK text readline() routine (reads what will fit into buffer incl. NULL termination) +// if *len is unchanged on return, it means the line is bigger than the buffer and +// requires multiple reads + + +MgenPayloadMgr::FastReader::Result MgenPayloadMgr::FastReader::Readline(FILE* filePtr, + char* buffer, + unsigned int* len) +{ + unsigned int count = 0; + unsigned int length = *len; + char* ptr = buffer; + while (count < length) + { + unsigned int one = 1; + switch (Read(filePtr, ptr, &one)) + { + case OK: + if (('\n' == *ptr) || ('\r' == *ptr)) + { + *ptr = '\0'; + *len = count; + return OK; + } + count++; + ptr++; + break; + + case ERROR_: + return ERROR_; + + case DONE: + return DONE; + } + } + // We've filled up the buffer provided with no end-of-line + return ERROR_; +} // end MgenPayloadMgr::FastReader::Readline() + +// This reads a line with possible ending '\' continuation character. +// Such "continued" lines are returned as one line with this function +// and the "lineCount" argument indicates the actual number of lines +// which comprise the long "continued" line. +// +// (Note: Lines ending with an even number '\\' are considered ending +// with one less '\' instead of continuing. So, to actually +// end a line with an even number of '\\', continue it with +// an extra '\' and follow it with a blank line.) + +MgenPayloadMgr::FastReader::Result MgenPayloadMgr::FastReader::ReadlineContinue(FILE* filePtr, + char* buffer, + unsigned int* len, + unsigned int* lineCount) +{ + unsigned int lines = 0; + unsigned int count = 0; + unsigned int length = *len; + char* ptr = buffer; + while (count < length) + { + unsigned int space = length - count; + switch (Readline(filePtr, ptr, &space)) + { + case OK: + { + lines++; + // 1) Doesn't the line continue? + char* cptr = space ? ptr + space - 1 : ptr; + // a) skip trailing white space + while (((' ' == *cptr) || ('\t' == *cptr)) && (cptr > ptr)) + { + space--; + cptr--; + } + + // If line "continues" to a blank line, skip it + if ((cptr == ptr) && ((*cptr == '\0') || isspace(*cptr))) + continue; + + if ('\\' == *cptr) + { + // Make sure line ends with odd number of '\' to continue + bool lineContinues = false; + while ((cptr >= ptr) && ('\\' == *cptr)) + { + cptr--; + lineContinues = lineContinues ? false : true; + } + // lose trailing '\' (continuation or extra '\' char) + *(ptr+space-1) = '\0'; + space -= 1; + if (lineContinues) + { + // get next line to continue + count += space; + ptr += space; + continue; + } + } + *len = count + space; + if (lineCount) *lineCount = lines; + return OK; + break; + } + + case ERROR_: + return ERROR_; + + case DONE: + return DONE; + } + } + // We've filled up the buffer provided with no end-of-line + return ERROR_; +} // end MgenPayloadMgr::FastReader::Readline() + +/* End MgenPayloadMgr::FastReader Implementation */ diff --git a/src/common/mgenPayloadMgrApp.cpp b/src/common/mgenPayloadMgrApp.cpp new file mode 100644 index 00000000..bda59438 --- /dev/null +++ b/src/common/mgenPayloadMgrApp.cpp @@ -0,0 +1,351 @@ +#include "mgenPayloadMgr.h" +#include "mgenPayloadMgrApp.h" +#include "mgen.h" + +MgenPayloadMgrApp::MgenPayloadMgrApp() + : mgenPayloadMgr(GetTimerMgr(), GetSocketNotifier(), + mgen), + mgen(GetTimerMgr(), GetSocketNotifier()), + control_pipe(ProtoPipe::MESSAGE), control_remote(false), + socket(ProtoSocket::UDP) +{ + mgen.SetController(this); + control_pipe.SetNotifier(&GetSocketNotifier()); + control_pipe.SetListener(this,&MgenPayloadMgrApp::OnControlEvent); + + UINT16 port = 55000; + + dstAddr.ResolveFromString("127.0.0.1"); + dstAddr.SetPort(port); + // Set up our output socket + socket.SetNotifier(&mgen.GetSocketNotifier()); + if (!socket.Open(port,ProtoAddress::IPv4,false)) + { + DMSG(0,"MgenPayloadMgrApp::Open() Error: Socket open error %s srcPort %d\n",GetErrorString(),port); + } + +} // end MgenPayloadMgrApp::MgenPayloadMgrApp + +const char* const MgenPayloadMgrApp::CMD_LIST[] = + { + "+instance", // mgenPayloadMgrApp instance name + "+error", // mgen error + "-stop", // exit program instance + "-version", // print MgenPayloadMgr version and exit + "-help", // print usage and exit + NULL + }; + +void MgenPayloadMgrApp::Usage() +{ + fprintf(stderr,"mgenPayloadMgr\n [input ]\n" + "[overwrite_mgenlog |mgenlog ]\n" + "[overwrite_mpmlog |mpmlog ]\n" + "[event \"\"]\n" + "[instance ]\n" + "[start ]\n" + "[verbose]\n" + "[txlog] [nolog] [flush]\n" + "[localtime]\n" + "[interface ]\n" + "[ttl ]\n" + "[tos ]\n" + "[txbuffer ]\n" + "[rxbuffer ]\n" + "[txcheck] [rxcheck] [check]\n"); + +} // end MgenPayloadMgrApp::Usage + +MgenPayloadMgrApp::~MgenPayloadMgrApp() +{ +} + +bool MgenPayloadMgrApp::OnStartup(int argc, const char*const* argv) +{ + mgen.SetLogFile(stdout); // log to stdout by default + mgenPayloadMgr.SetLogFile(stdout); + +#ifdef HAVE_IPV6 + if (ProtoSocket::HostIsIPv6Capable()) + mgen.SetDefaultSocketType(ProtoAddress::IPv6); +#endif // HAVE_IPV6 + + if (!ProcessCommands(argc, argv)) + { + fprintf(stderr,"MgenPayloadMgrApp::OnStartup() error while processing startup commands\n"); + return false; + } + + if (control_remote) + { + // We remoted commands, so we're finished... + return false; + } + + return mgenPayloadMgr.Start(); +} +void MgenPayloadMgrApp::OnControlEvent(ProtoSocket& /*theSocket*/, + ProtoSocket::Event theEvent) +{ + if (ProtoSocket::RECV == theEvent) + { + char buffer[8192]; + unsigned int len = 8191; + if (control_pipe.Recv(buffer, len)) + { + // (TBD) Delimit commands by line breaks and/or other delimiters ??? + buffer[len] = '\0'; + char* cmd = buffer; + char* arg = NULL; + for (unsigned int i = 0; i < len; i++) + { + if ('\0' == buffer[i]) + { + break; + } + else if (isspace(buffer[i])) + { + buffer[i] = '\0'; + arg = buffer+i+1; + break; + } + } + if (!OnCommand(cmd, arg)) + { + DMSG(0, "MgenPayloadMgrApp::OnControlEvent() error processing command\n"); + } + } + else + { + DMSG(0, "MgenPayloadMgrApp::OnControlEvent() receive error\n"); + } + } + else + { + DMSG(0, "MgenPayloadMgrApp::OnControlEvent() unhandled event type\n"); + } +} // end MgenPayloadMgrApp::OnControlEvent + + +void MgenPayloadMgrApp::OnShutdown() +{ + control_pipe.Close(); + mgenPayloadMgr.Stop(); + mgen.Stop(); +} +MgenPayloadMgrApp::CmdType MgenPayloadMgrApp::GetCmdType(const char* cmd) +{ + if (!cmd) return CMD_INVALID; + unsigned int len = strlen(cmd); + bool matched = false; + CmdType type = CMD_INVALID; + const char* const* nextCmd = CMD_LIST; + while (*nextCmd) + { + if (!strncmp(cmd, *nextCmd+1, len)) + { + if (matched) + { + // ambiguous command (command should match only once) + return CMD_INVALID; + } + else + { + matched = true; + if ('+' == *nextCmd[0]) + type = CMD_ARG; + else + type = CMD_NOARG; + } + } + nextCmd++; + } + return type; +} // end MgenPayloadMgrApp::GetCmdType() + +bool MgenPayloadMgrApp::ProcessCommands(int argc, const char*const* argv) +{ + int i = 1; + while (i < argc) + { + CmdType cmdType = GetCmdType(argv[i]); + if (CMD_INVALID == cmdType) + { + // Is it a mgenPayloadMgr command? + switch(MgenPayloadMgr::GetCmdType(argv[i])) + { + case MgenPayloadMgr::CMD_INVALID: + break; + case MgenPayloadMgr::CMD_NOARG: + cmdType = CMD_NOARG; + break; + case MgenPayloadMgr::CMD_ARG: + cmdType = CMD_ARG; + break; + } + } + switch (cmdType) + { + case CMD_INVALID: + DMSG(0,"MgeyPayloadMgrApp::ProcessCommands() Error: invalid command: %s\n", + argv[i]); + return false; + case CMD_NOARG: + if (!OnCommand(argv[i],NULL)) + { + DMSG(0,"MgenPayloadMgrApp::ProcessCommands() Error: OnCommand(%s) error\n", + argv[i]); + return false; + } + i++; + break; + case CMD_ARG: + if (!OnCommand(argv[i],argv[i+1])) + { + DMSG(0,"MgenPayloadMgrApp::ProcessCommands() Error: OnCommand(%s, %s) error\n", + argv[i],argv[i+1]); + return false; + } + i += 2; + break; + } + + } + return true; +} +bool MgenPayloadMgrApp::OnCommand(const char* cmd, const char* val) +{ + + if (control_remote) + { + char buffer[8192]; + strcpy(buffer, cmd); + if (val) + { + strcat(buffer, " "); + strncat(buffer, val, 8192 - strlen(buffer)); + } + unsigned int len = strlen(buffer); + if (control_pipe.Send(buffer, len)) + { + return true; + } + else + { + DMSG(0, "MgenPayloadMgrApp::ProcessCommand(%s) error sending command to remote process\n", cmd); + return false; + } + } + // Is it a mgenPayloadMgrApp command? + CmdType type = GetCmdType(cmd); + unsigned int len = strlen(cmd); + if (CMD_INVALID == type) + { + if (MgenPayloadMgr::CMD_INVALID != MgenPayloadMgr::GetCmdType(cmd)) + { + return mgenPayloadMgr.OnCommand(MgenPayloadMgr::GetCommandFromString(cmd),val,true); + } + else { + + DMSG(0,"MgenPayloadMgrApp::OnCommand(%s) Error: invalid command \n",cmd); + return false; + } + } + else if ((CMD_ARG == type) && !val) + { + DMSG(0,"MgenPayloadMgrApp::OnCommand(%s) Error: missing argument\n",cmd); + return false; + } + else if (!strncmp("stop",cmd,len)) + { + Stop(); + } + else if (!strncmp("instance", cmd, len)) + { + if (control_pipe.IsOpen()) + control_pipe.Close(); + if (control_pipe.Connect(val)) + { + control_remote = true; + } + else if (!control_pipe.Listen(val)) + { + DMSG(0, "MgenPayloadMgrApp::ProcessCommand(instance) error opening control pipe\n"); + return false; + } + } + else if (!strncmp("error",cmd,len)) + { + char msgBuffer[512]; + sprintf(msgBuffer,"type>Error action>mgenCmd cmd>\"%s\"",val); + mgenPayloadMgr.LogEvent("MGEN",msgBuffer); + + DMSG(0,"MgenPayloadMgrApp::Oncommand() Error: received from mgen for command: (%s)\n",val); + + return true; + } + else if (!strncmp("-version",cmd,len) || !strncmp("-v",cmd,len)) + { + fprintf(stderr,"version %s\n",MGENPAYLOADMGR_VERSION); + exit(0); + // return false; + } + + else if (!strncmp("help",cmd,len)) + { + fprintf(stderr,"version %s\n",MGENPAYLOADMGR_VERSION); + Usage(); + return false; + } + return true; +} // end MgenPayloadMgrApp::OnCommand() + + + +void MgenPayloadMgrApp::OnOffEvent(char* buffer, int len) +{ + DMSG(0,"MgenPayloadMgrApp::OnOffEvent %s\n",buffer); + +} // end MgenPayloadMgrApp::OnOffEvent +void MgenPayloadMgrApp::OnStopEvent(char* buffer, int len) +{ + +} // end MgenPayloadMgrApp::OnOffEvent + +void MgenPayloadMgrApp::OnMsgReceive(MgenMsg& msg) +{ + + char buffer[8192]; + DMSG(2,"MgenPayloadMgrApp::OnMsgReceive() src> %s/%hu dst> %s/%hu flowId>%d seq>%d payload>%s \n",msg.GetSrcAddr().GetHostString(),msg.GetSrcAddr().GetPort(),msg.GetDstAddr().GetHostString(),msg.GetDstAddr().GetPort(),msg.GetFlowId(),msg.GetSeqNum(),msg.GetPayload()); + + sprintf(buffer,"src>%s flow_id>%d",msg.GetSrcAddr().GetHostString(),msg.GetFlowId()); + mgenPayloadMgr.LogEvent("OnMsgReceive",buffer); + + if (!socket.SendTo(buffer,sizeof(buffer),dstAddr)) + { + DMSG(PL_ERROR,"MgenPayloadMgrApp::OnMsgReceive() socket.SendTo() error %s\n",GetErrorString()); + } + + /* + if (msg.GetFlowId() == 1) + { + sprintf(buffer,"1.0 ON 2 UDP DST %s/5001 PERIODIC [1 1024] DATA [050607] COUNT 1",msg.GetSrcAddr().GetHostString()); + mgenPayloadMgr.SendMgenCommand("event",buffer); + } + else + if (msg.GetFlowId() == 2) + { + sprintf(buffer,"1.0 ON 3 UDP DST %s/5000 PERIODIC [1 1024] DATA [050607] COUNT 1",msg.GetSrcAddr().GetHostString()); + mgenPayloadMgr.SendMgenCommand("event",buffer); + + } + else + { + // do nothing + } + */ +} // end MgenPayloadMgrApp::OnMsgReceive + +#ifdef _INSTANTIATE_APP +PROTO_INSTANTIATE_APP(MgenPayloadMgrApp) +#endif diff --git a/src/common/mgenTransport.cpp b/src/common/mgenTransport.cpp index 7f8b5648..b6bbd0e8 100644 --- a/src/common/mgenTransport.cpp +++ b/src/common/mgenTransport.cpp @@ -86,7 +86,8 @@ MgenTransport::MgenTransport(Mgen& theMgen, mgen(theMgen), pending_head(NULL), pending_tail(NULL), - pending_current(NULL) + pending_current(NULL), + messages_sent(0) { } @@ -115,7 +116,8 @@ MgenTransport::MgenTransport(Mgen& theMgen, mgen(theMgen), pending_head(NULL), pending_tail(NULL), - pending_current(NULL) + pending_current(NULL), + messages_sent(0) { dstAddress = theAddress; } @@ -319,6 +321,7 @@ void MgenTransport::LogEvent(LogEventType eventType,MgenMsg* theMsg,const struct mgen.GetLogBinary(), mgen.GetLocalTime(), mgen.GetLogData(), + mgen.GetLogGpsData(), buffer, mgen.GetLogFlush(), theTime); @@ -440,7 +443,6 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, socket(GetSocketProtocol(theProtocol)) { interface_name[0] = '\0'; - StopInputNotification(); socket.SetNotifier(&mgen.GetSocketNotifier()); // set defaults @@ -462,7 +464,6 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, socket(GetSocketProtocol(theProtocol)) { interface_name[0] = '\0'; - StopInputNotification(); socket.SetNotifier(&mgen.GetSocketNotifier()); // set defaults @@ -498,7 +499,7 @@ void MgenSocketTransport::SetEventOptions(const MgenEvent* event) if (event->OptionIsSet(MgenEvent::TTL)) { if (!SetTTL(event->GetTTL())) - DMSG(0, "MgenFlow::Update() error setting socket multicast interface\n"); + DMSG(0, "MgenFlow::Update() error setting socket TTL\n"); } if (event->OptionIsSet(MgenEvent::INTERFACE) && GetProtocol() == UDP) { @@ -510,6 +511,8 @@ void MgenSocketTransport::SetEventOptions(const MgenEvent* event) bool MgenSocketTransport::SetTTL(unsigned char ttlValue) { + + ttl = ttlValue; if (protocol == TCP) return true; @@ -518,7 +521,6 @@ bool MgenSocketTransport::SetTTL(unsigned char ttlValue) if (!socket.SetTTL(ttlValue)) return false; } - ttl = ttlValue; return true; } // end MgenSocketTransport::SetTTL() @@ -588,13 +590,25 @@ bool MgenSocketTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) } } } - else if (!socket.Open(srcPort, addrType, bindOnOpen)) + else if (!socket.Open(srcPort, addrType, false)) { + // SetLoopback asserts that the socket is open // socket.SetLoopback(false); // by default - DMSG(0, "MgenTransport::Open() Error: socket open error\n"); + DMSG(0, "MgenTransport::Open() Error: socket open error %s srcPort %d\n",GetErrorString(),srcPort); return false; - } + } else + { + // We want to set socket resuse so multiple processes + // can listen to a common multicast group. Note that + // kernel socket selection for reused unicast sockets + // is undefined. + + if (mgen.GetReuse()) + socket.SetReuse(true); + if (bindOnOpen) + socket.Bind(srcPort); + } // Reset src port in case it was os generated srcPort = GetSocketPort(); @@ -608,7 +622,7 @@ bool MgenSocketTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) if (tos) socket.SetTOS(tos); - if (ttl) + if (ttl >= 0) socket.SetTTL(ttl); if ('\0' != interface_name[0]) @@ -743,22 +757,44 @@ bool MgenUdpTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) * have zero port number and are left unbound */ bool MgenUdpTransport::JoinGroup(const ProtoAddress& groupAddress, - const char* interfaceName) + const ProtoAddress& sourceAddress, + const char* interfaceName) { + bool result; + //char group_interface_name[16]; + //group_interface_name[0] = '\0'; + //if (interfaceName) + //strncpy(group_interface_name,interfaceName,16); +#ifdef MACOSX + //else // use the default interface if not provided - interface required on osx for group joins + //strncpy(group_interface_name, interface_name, 16); +#endif + if (Open(groupAddress.GetType(), (0 != srcPort))) { - if (socket.JoinGroup(groupAddress, interfaceName)) +#ifdef _PROTOSOCKET_IGMPV3_SSM + //If source address is valid, it means its a SSM request + if ( sourceAddress.IsValid() ) { + result = socket.JoinGroup(groupAddress, interfaceName, sourceAddress.IsValid() ? &sourceAddress : NULL); + } + else +#endif // _PROTOSOCKET_IGMPV3_SSM + { + result = socket.JoinGroup(groupAddress, interfaceName); + } + if (result) + { socket.SetLoopback(true); group_count++; return true; - } + } else { Close(); // decrement reference count DMSG(0, "MgenUdpTransport::JoinGroup() Error: socket join error\n"); return false; - } + } } else { @@ -768,9 +804,22 @@ bool MgenUdpTransport::JoinGroup(const ProtoAddress& groupAddress, } // end MgenUdpTransport::JoinGroup() bool MgenUdpTransport::LeaveGroup(const ProtoAddress& groupAddress, - const char* interfaceName) + const ProtoAddress& sourceAddress, + const char* interfaceName) { - if (socket.LeaveGroup(groupAddress, interfaceName)) + bool result; +#ifdef _PROTOSOCKET_IGMPV3_SSM + /* If source address is valid, it means its a SSM request */ + if ( sourceAddress.IsValid() ) + { + result = socket.LeaveGroup(groupAddress, interfaceName, sourceAddress.IsValid() ? &sourceAddress : NULL); + } + else +#endif // _PROTOSOCKET_IGMPV3_SSM + { + result = socket.LeaveGroup(groupAddress, interfaceName); + } + if ( result ) { ASSERT(group_count); group_count--; @@ -883,8 +932,10 @@ bool MgenUdpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, return false; } + /* udp messages are one shot so the time in the message + * is our send time */ LogEvent(SEND_EVENT,&theMsg,theMsg.GetTxTime(),txBuffer); - + messages_sent++; return true; } // end MgenUdpTransport::SendMessage @@ -957,7 +1008,10 @@ void MgenTcpTransport::OnEvent(ProtoSocket& theSocket,ProtoSocket::Event theEven break; } } // Some other socket failure! - else break; + else + { + break; + } } SendPendingMessage(); @@ -1081,7 +1135,7 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, { // But not if the transport is transmitting anything... if (tx_msg_offset != 0) - return false; + return false; // Set the transport's tx_msg to the loaded msg tx_msg = theMsg; @@ -1089,12 +1143,12 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, // Gets the size of the first fragment that should be // sent and packs the message tx_fragment_pending = GetNextTxFragment(); - + if (!tx_fragment_pending || !tx_buffer_pending) - { - DMSG(0,"SendTcpMessage Error: No message length!\n"); - return false; - } + { + DMSG(0,"SendTcpMessage Error: No message length!\n"); + return false; + } // Send message, checking for error (log only on success) @@ -1108,7 +1162,7 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, if (tx_buffer_pending != 0 && numBytes == 0) { StartOutputNotification(); - return true; + return true; } // Otherwise keep track of what we've sent @@ -1141,12 +1195,16 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, { // else we've sent everything, clear state and move on UINT32 txChecksum = 0; - char txBuffer[MAX_SIZE]; + char txBuffer[MAX_SIZE]; + // Use the time of the first message fragment sent that + // we squirreled away earlier. Binary logging uses the + // tx_time in the message buffer, logfile logging uses + // the tx_time passed in. Should be cleaned up. + tx_msg.SetTxTime(tx_time); tx_msg.Pack(txBuffer,MAX_SIZE,mgen.GetChecksumEnable(),txChecksum); - // Use the time of the first message fragment - tx_msg.SetTxTime(tx_time); - LogEvent(SEND_EVENT,&tx_msg,tx_msg.tx_time,txBuffer); + LogEvent(SEND_EVENT,&tx_msg,tx_time,txBuffer); ResetTxMsgState(); + messages_sent++; StopOutputNotification(); // ljt 0516 - check if we need this? // we may still have pending stuff! return true; @@ -1155,7 +1213,9 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, } // other socket failure else { - DMSG(0,"MgenTcpTransport:SendMessage() error writing to output! \n"); + DMSG(PL_ERROR, "MgenTcpTransport::SendMessage() socket.Send() error: %s\n", GetErrorString()); + + // DMSG(0,"MgenTcpTransport:SendMessage() error writing to output! \n"); ResetTxMsgState(); StopOutputNotification(); // ljt 0516 delete me? return false; @@ -1499,12 +1559,18 @@ bool MgenTcpTransport::GetNextTxBuffer(unsigned int numBytes) // if (!tx_fragment_pending && (tx_msg_offset > 0 || tx_msg_offset == 0)) if (!tx_fragment_pending && tx_msg_offset > 0) { - // Entire message has been sent + // Entire message has been sent, log send event + // with the time we squirreled away earlier UINT32 txChecksum = 0; - char txBuffer[MAX_SIZE]; + char txBuffer[MAX_SIZE]; + // Use the time of the first message fragment sent that + // we squirreled away earlier. Binary logging uses the + // tx_time in the message buffer, logfile logging uses + // the tx_time passed in. Should be cleaned up. + tx_msg.SetTxTime(tx_time); tx_msg.Pack(txBuffer,MAX_SIZE,mgen.GetChecksumEnable(),txChecksum); - tx_msg.SetTxTime(tx_time); LogEvent(SEND_EVENT,&tx_msg,tx_time,txBuffer); + messages_sent++; ResetTxMsgState(); return false; } @@ -1579,31 +1645,39 @@ void MgenTcpTransport::CalcTxChecksum() UINT16 MgenTcpTransport::GetNextTxFragment() { - // Set tx_time and other state because we're - // sending a new fragment of the mgen message - - struct timeval currentTime; - ProtoSystemTime(currentTime); - tx_msg.SetTxTime(currentTime); + /** Set tx_time and other state because we're + * packing a new fragment of the mgen message + */ UINT16 tx_buffer_size = TX_BUFFER_SIZE; tx_msg_buffer[0] = '\0'; tx_checksum = 0; tx_buffer_index = 0; - /// Sets msg_len of fragment for us. + /** Sets msg_len and segment flags in the fragment for us. + * If GetNextTxFragmentSize() returns 0 we have + * sent the entire message. + */ if (!GetNextTxFragmentSize()) return 0; // In windows we might not have packed the msg yet! - /** GetNextTxFragmentSize sets the tx_time for us. If this is - * our first fragment squirrel the initial tx_time away so we - * can log the send message when we are done sending the entire - * mgen tcp message (not just the fragment) + /** If this is our first fragment (tx_msg_offset != 0) squirrel + * the initial tx_time away so we have it when we log the send + * message. This is also the time being logged as time sent + * in the mgen message payload. */ + struct timeval currentTime; + ProtoSystemTime(currentTime); + tx_msg.SetTxTime(currentTime); + + /** tx_msg_offset is the index into the mgen message + * not the fragment. */ if (!tx_msg_offset) tx_time = tx_msg.GetTxTime(); + + /* Account for checksum handling and pack the message */ if (mgen.GetChecksumEnable()) { if (((tx_msg.msg_len - TX_BUFFER_SIZE) < 4) && (tx_msg.msg_len != MIN_FRAG_SIZE)) @@ -1622,7 +1696,7 @@ UINT16 MgenTcpTransport::GetNextTxFragment() else if (tx_msg.msg_len > 0) - { + { tx_msg.SetFlag(MgenMsg::LAST_BUFFER); tx_buffer_pending = tx_msg.Pack(tx_msg_buffer,tx_msg.msg_len,mgen.GetChecksumEnable(),tx_checksum); tx_msg_offset += tx_buffer_pending; @@ -1634,7 +1708,7 @@ UINT16 MgenTcpTransport::GetNextTxFragment() tx_msg.WriteChecksum(tx_checksum,(unsigned char*)tx_msg_buffer,tx_msg.msg_len); } - } + } else { // no more to send @@ -1681,6 +1755,8 @@ UINT16 MgenTcpTransport::GetNextTxFragmentSize() else tx_msg.SetFlag(MgenMsg::END_OF_MSG); } + if (tx_msg.msg_len == 0) + TRACE(" MgenTcpTransport::GetNextTxFragmentSize() tx_msg.msg_len == 0!\n"); return tx_msg.msg_len; }// MgenTcpTransport::GetNextTxFragmentSize diff --git a/src/common/pcap2mgen.cpp b/src/common/pcap2mgen.cpp index 53d6a72c..d372c570 100644 --- a/src/common/pcap2mgen.cpp +++ b/src/common/pcap2mgen.cpp @@ -5,6 +5,11 @@ // Assumes UDP packets in tcpdump trace file (pcap file) are // MGEN packets and parses to build an MGEN log file +// Notes on options: +// +// 1) The "trace" option prepends MGEN log lines with epoch time and MAC src/addr information + + #include #include @@ -15,7 +20,7 @@ void Usage() { - fprintf(stderr, "pcap2mgen [trace][pcapInputFile [mgenOutputFile]]\n"); + fprintf(stderr, "pcap2mgen [trace][epoch][pcapInputFile [mgenOutputFile]]\n"); } int main(int argc, char* argv[]) @@ -37,6 +42,8 @@ int main(int argc, char* argv[]) } } + fprintf(stderr,"Pcap Version: %s\n",pcap_lib_version()); + // Use stdin/stdout by default FILE* infile = stdin; @@ -145,7 +152,7 @@ int main(int argc, char* argv[]) if (!udpPkt.InitFromPacket(ipPkt)) continue; // not a UDP packet MgenMsg msg; - if (!msg.Unpack((char*)udpPkt.GetPayload(), udpPkt.GetPayloadLength(), false)) + if (!msg.Unpack((char*)udpPkt.GetPayload(), udpPkt.GetPayloadLength(), false, false)) { fprintf(stderr, "pcap2mgen warning: UDP packet not an MGEN packet?\n"); continue; @@ -156,6 +163,7 @@ int main(int argc, char* argv[]) if (trace) { + fprintf(outfile, "%lu.%lu ", hdr.ts.tv_sec, hdr.ts.tv_usec); ProtoAddress ethAddr; ethPkt.GetSrcAddr(ethAddr); fprintf(outfile, "esrc>%s ", ethAddr.GetHostString()); @@ -163,7 +171,10 @@ int main(int argc, char* argv[]) fprintf(outfile, "edst>%s ", ethAddr.GetHostString()); } - msg.LogRecvEvent(outfile, false, false, (char*)udpPkt.AccessPayload(), false, hdr.ts); + msg.LogRecvEvent(outfile, false, false, false, true, (char*)udpPkt.AccessPayload(), false, hdr.ts); } // end while (pcap_next()) + if (stdin != infile) fclose(infile); + if (stdout != outfile) fclose(outfile); + return 0; } // end main() diff --git a/src/python/README.TXT b/src/python/README.TXT new file mode 100644 index 00000000..d5c0fb35 --- /dev/null +++ b/src/python/README.TXT @@ -0,0 +1,7 @@ +Utilities and Example for mgen controller: + +mgenBasicActor.py works as zerorpc controller interface that can be used stand alone for remote cotnrol testing of mgen instances or can also be used with CORE emulation distribution as a service. + +If using with CORE install the mgenBasicActor.py with executable permissions in /usr/local/bin. An mgenBasicActor.py template is installed within the Nrl Services distributed within the CORE packages. + + diff --git a/src/python/mgen.py b/src/python/mgen.py new file mode 100644 index 00000000..24f5a53a --- /dev/null +++ b/src/python/mgen.py @@ -0,0 +1,477 @@ +import os +import subprocess +import protokit + +import shlex +import datetime +import struct + +import warnings +import functools +import tempfile + +# Set to True to enable DeprecationWarning messages +ENABLE_DEPRECATION_WARNINGS = True + +def deprecated(func): + '''This is a decorator which can be used to mark functions + as deprecated. It will result in a warning being emitted + when the function is used.''' + @functools.wraps(func) + def new_func(*args, **kwargs): + if ENABLE_DEPRECATION_WARNINGS: + warnings.simplefilter('always', DeprecationWarning)#turn off filter + warnings.warn_explicit( + "Call to deprecated function {}.".format(func.__name__), + category=DeprecationWarning, + filename=func.func_code.co_filename, + lineno=func.func_code.co_firstlineno + 1 + ) + warnings.simplefilter('default', DeprecationWarning) #reset filter + return func(*args, **kwargs) + return new_func + + +class gps: + def __init__(self, lat=None, lon=None, alt=None): + if lat is None or lon is None: + self.valid = False + else: + self.valid = True + self.lat = lat + self.lon = lon + self.alt = alt + + +def get_payload_from_string(text): + if len(text) > 255: + print "get_payload_from_string() Error: Payload > 255",text + return None + return text.encode('hex','strict').rstrip() + +@deprecated +def GetPayloadFromString(text): + return get_payload_from_string(text) + +def get_time_from_string(text): + """Convert MGEN timestamp string to Python datetime.time object""" + field = text.split(':') + hr = int(field[0]) + mn = int(field[1]) + field = field[2].split('.') + sec = int(field[0]) + usec = int(field[1]) + return datetime.time(hr, mn, sec, usec) + +@deprecated +def TimeFromString(text): + return get_time_from_string(text) + + +def protocol_is_valid(protocol): + protocol_dict = dict.fromkeys(["udp", "tcp", "sink"], True) + if protocol_dict.get(protocol.lower()): + return True + else: + return False + +# TBD - create a mgen.Flow class" that contains MGEN flow description/parameters +# (In turn a "Flow" member could be used in the mgen.Event below for events +# that pertain to a flow such as SEND, RECV, etc) + +class Flow: + """ The mgen.Flow class contains parameters for a Flow + """ + def __init__(self, flowId, controller = None): + self.flow_id = flowId ;# must be unique per controller/mgen instance + self.protocol = None + self.dst_addr = None + self.dst_port = None + self.pattern = None + self.src_port = None + self.count = None + self.sequence = None + self.data = None + self.data_length = 0 + self.controller = None + if controller is not None: + controller.add_flow(self) + self.active = False + + def is_valid(self): + """Checks that the minimum parameters for a valid flow are set""" + if self.flow_id is None: + return False + elif self.protocol is None: + return False + elif self.dst_addr is None: + return False + elif self.dst_port is None: + return False + elif self.pattern is None: + return False + else: + return True + + def start(self, delay=0.0): + if self.controller and self.is_valid(): + cmd = "" + if (delay > 0.0): + cmd += str(delay) + " " + cmd += "on " + str(self.flow_id) + cmd += " " + self.protocol + " dst " + str(self.dst_addr) + '/' + str(self.dst_port) + cmd += " " + str(self.pattern) + if self.src_port is not None: + cmd += " src " + str(self.src_port) + if self.count is not None: + cmd += " count " + str(self.count) + if self.sequence is not None: + cmd += " sequence " + str(self.sequence) + if self.data is not None: + cmd += " data [" + self.data + "]" + self.controller.send_event(cmd) + self.active = True + + def stop(self): + if self.controller and self.active: + cmd = "off " + str(self.flow_id) + self.controller.send_event(cmd) + self.active = False + + def set_flow_id(self, flowId): + if (self.flow_id != flowId): + restart = self.active + if restart: + self.stop() + # If this flow is attached to a controller, + # we need remove/add since they are indexed + # by flowId + if self.controller: + controller.remove_flow(self) + self.flow_id = flowId + if self.controller: + controller.add_flow(self) + if restart: + self.start() + + def set_protocol(self, protocol): + if not protocol_is_valid(protocol): + return False + self.protocol = protocol + if self.active: + self.stop() + self.start() + + def set_destination(self, addr, port): + if addr is None: + raise ValueError('A valid IP address must be supplied!') + self.dst_addr = addr + self.dst_port = port + if self.active: + cmd = "mod %d dst %s/%d" % (self.flow_id, addr, port) + self.controller.send_event(cmd) + + def set_pattern(self, pattern): + self.pattern = pattern + if self.active: + cmd = "mod %d %s" % (self.flow_id, pattern) + self.controller.send_event(cmd) + + def set_count(self, count): + self.count = int(count) + if self.active: + cmd = "mod %d count %d" % (self.flow_id, self.count) + self.controller.send_event(cmd) + + def set_sequence(self, sequence): + self.sequence = int(sequence) + if self.active: + cmd = "mod %d sequence %d" % (self.flow_id, self.sequence) + self.controller.send_event(cmd) + + # TBD - we could store the flow payload data more efficiently + # as the raw data instead of hex-encoded + def set_text_payload(self, text): + self.data = text.encode('hex','strict').rstrip() + if self.active: + cmd = "mod %d data [%s]" % (self.flow_id, self.data) + self.controller.send_event(cmd) + + def set_binary_payload(self, buf): + self.data = binasci.hexlify(buf) + if self.active: + cmd = "mod %d data [%s]" % (self.flow_id, self.data) + self.controller.send_event(cmd) + + def set_struct_payload(self, theStruct, *args): + """ Uses Python struct module""" + self.data = theStruct.pack(*args).encode('hex','strict').rstrip() + if self.active: + cmd = "mod %d data [%s]" % (self.flow_id, self.data) + self.controller.send_event(cmd) + + + + +class Event: + """ The mgen.Event class provides information on logged events + (or potentially also events that may invoked (i.e. actions) + """ + def __init__(self, text = None): + self.rx_time = datetime.time() + self.type = None + self.protocol = None + self.flow_id = None + self.sequence = None + self.src_addr = None + self.src_port = None + self.dst_addr = None + self.dst_port = None + self.tx_time = datetime.time() + self.size = 0 + self.gps = None + self.data = None + self.data_length = None + if text is not None: + self.init_from_string(text) + + # A sort of "enum" of valid MGEN event types + RECV, RERR, SEND, JOIN, LEAVE, LISTEN, IGNORE, ON, CONNECT, \ + ACCEPT, SHUTDOWN, DISCONNECT, OFF, START, STOP = range(15) + + def get_event_type(self, text): + etype = Event.__dict__[text.upper()] + if etype is None: + return None + else: + return etype + + @deprecated + def GetEventType(self, text): + return self.get_event_type(text) + + def has_payload(self): + return self.data is not None + + def get_payload(self): + return self.data + + @deprecated + def GetPayload(self): + return self.get_payload() + + def get_struct_payload(self, theStruct): + '''This returns a tuple according to theStruct format''' + return theStruct.unpack(self.data) + + @deprecated + def GetStructPayload(self, theStruct): + return self.get_struct_payload(theStruct) + + # These "MgenCmd" payload methods will likely be deprecated? + @deprecated + def IsPayloadMgenCmd(self): + return self.data[0:2] == 'FF' + + @deprecated + def GetPayloadMgenCmd(self): + if self.data[0:2] == 'FF': + return self.data[2:] + else: + return None + + def init_from_string(self, text): + ''' Initialize mgen.Event from mgen log line ''' + # MGEN log format is "