From eced1cc12ddb11ed2efb71238d45f694893d1922 Mon Sep 17 00:00:00 2001 From: Jeff Weston Date: Wed, 11 Sep 2019 09:15:39 -0400 Subject: [PATCH] update to 5.02c --- README.md | 20 +- VERSION.TXT | 25 +- doc/mgen.html | 16 +- doc/mgen.pdf | Bin 215782 -> 224107 bytes doc/mgen.xml | 292 +- include/gpsPub.h | 2 + include/mgen.h | 43 +- include/mgenEvent.h | 37 +- include/mgenFlow.h | 3 +- include/mgenGlobals.h | 15 + include/mgenPattern.h | 10 +- include/mgenTransport.h | 30 +- include/mgenVersion.h | 2 +- makefiles/Makefile.common | 13 +- makefiles/Makefile.linux | 3 +- makefiles/README.TXT | 15 +- makefiles/android/change_target.sh | 34 + makefiles/android/jni/Application.mk | 4 +- makefiles/android/jni/Application.mk.r14 | 3 + makefiles/android/jni/Application.mk.r23 | 4 + makefiles/android/project.properties | 16 +- makefiles/android/project.properties.r14 | 15 + makefiles/android/project.properties.r23 | 15 + makefiles/gpsPub.i | 9 + makefiles/win32/mgen.sln | 16 +- makefiles/win32/mgen.vcxproj | 168 + makefiles/win64/mgen.sln | 15 +- setup.py | 22 +- src/common/gpsPub.cpp | 21 +- src/common/mgen.cpp | 102 +- src/common/mgenApp.cpp | 57 +- src/common/mgenAppSinkTransport.cpp | 18 +- src/common/mgenEvent.cpp | 37 +- src/common/mgenFlow.cpp | 276 +- src/common/mgenPattern.cpp | 153 +- src/common/mgenPayloadMgrApp.cpp | 5 - src/common/mgenTransport.cpp | 222 +- src/python/gpsFaker.py | 85 + src/python/gpsPub_wrap.c | 4975 ++++++++++++++++++++++ src/python/mgen.py | 106 +- src/python/mgenBasicActor.py | 248 +- src/python/mgenExample.py | 4 +- 42 files changed, 6643 insertions(+), 513 deletions(-) create mode 100755 makefiles/android/change_target.sh mode change 100644 => 120000 makefiles/android/jni/Application.mk create mode 100644 makefiles/android/jni/Application.mk.r14 create mode 100644 makefiles/android/jni/Application.mk.r23 mode change 100644 => 120000 makefiles/android/project.properties create mode 100644 makefiles/android/project.properties.r14 create mode 100644 makefiles/android/project.properties.r23 create mode 100644 makefiles/gpsPub.i create mode 100755 makefiles/win32/mgen.vcxproj create mode 100644 src/python/gpsFaker.py create mode 100644 src/python/gpsPub_wrap.c diff --git a/README.md b/README.md index 958df80b..fe623a81 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,17 @@ This directory contains source code for the NRL Multi-Generator MGEN 4.2b6. The transport classes have been abstracted and new features have been added. -Primary new features include: +Note: 5.02c now includes/is compiled against protolib-3.0b1 + +Primary new features included in 5.02c + +1) includes/is compiled with protolib-3.0b1 +2) IPV6 on linux is fixed +3) DF fragmentation bit on|off added +4) uniform random message size supporte e.g. [ ] +5) assorted bug fixes + +Primary new features included 5.02b: 1) Support for the TCP protocol. 2) New pattern options JITTER and CLONE. @@ -49,3 +59,11 @@ makefiles - Directory with os-specific Makefiles. Linux specific makefiles are at the top level, win32 and wince subdirectories contains windows build files. + +setup.py - Python installation script for installing the Python 'mgen' + package that provides for Python-based control and monitoring + of MGEN. This package assumes the 'mgen' binary is + installed/located in the executable "path" (e.g., "/usr/local/bin") + This package also requires that the Protolib (see above) + 'protokit' Python package has also been installed. There is a + similar 'setup.py' script in the "protolib" source tree. diff --git a/VERSION.TXT b/VERSION.TXT index ba5632ab..1d21ec53 100644 --- a/VERSION.TXT +++ b/VERSION.TXT @@ -1,15 +1,26 @@ +Version 5.02c +============= + + -The releases include/are compiled with protolib-3.0b1 + - includes/is compiled with protolib-3.0b1 + - IPV6 on linux is fixed + - DF fragmentation bit on|off added + - uniform random message size supporte e.g. [ ] + - assorted bug fixes + + 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. + - Fixed timing for tcp messages logging for systems under heavy load. Fixed binary send event times. + +Version 5.02a +============= + - Disabled mgen event validation by default. Use the ENABLE_EVENT_VALIDATION + flag to reenable. Version 5.02 ============ - - Contains bug fix to close open UDP sockets - - Contains bug fix to handle incoming tcp connections on windows - correctly + - Missing? Version 5.01c ============= diff --git a/doc/mgen.html b/doc/mgen.html index 28c1cc43..5b277e37 100644 --- a/doc/mgen.html +++ b/doc/mgen.html @@ -1,12 +1,13 @@ - 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, <sizeMin:sizeMax>)
5.2.6. BROADCAST
5.2.7. LOGDATA
5.2.8. Type-Of-Service (TOS)
5.2.9. Multicast/Unicast 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.2.16. DF (fragmentation bit)
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. UNICAST_TTL
6.7. TXBUFFER
6.8. RXBUFFER
6.9. LOCALTIME
6.10. QUEUE
6.11. DATA
6.12. INTERFACE
6.13. INPUT
6.14. OUTPUT
6.15. LOG
6.16. LOGDATA
6.17. SAVE
6.18. IPv6
6.19. IPv4
6.20. DF
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
11.2. Windows Buffer Sizes

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>]
      [instance <name>][command <cmdInput>]
      [sink <sinkFile>][block][source <sourceFile>]
-     [interface <interfaceName>][ttl <timeToLive>]
+     [interface <interfaceName>][ttl <multicastTimeToLive>]
+     [unicast_ttl <unicastTimeToLive>]
      [tos <typeOfService>][label <value>]
      [txbuffer <txSocketBufferSize>]
      [rxbuffer <rxSocketBufferSize>]
@@ -16,7 +17,8 @@
      [convert <binaryLog>][debug <debugLevel>]
      [localtime <localtime>] [queue <queue>]
      [broadcast {on|off}] [logdata {on|off}]
-     [loggpsdata {on|off"]
+     [loggpsdata {on|off}] [gpsfile <fileName>]
+     [df {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
@@ -30,7 +32,7 @@
 # Note that the "mgen message" will be received in multiple
 # "mgen fragments" by the target node.
 
-0.0 ON 1 TCP DST 192.168.1.102/5000 PERIODIC [1 1048576] COUNT 1
+0.0 ON 1 TCP DST 10.0.0.1/5000 PERIODIC [1 1048576] COUNT 1
 
 # Modify the pattern/rate of flow 2 4 seconds into the test
 
@@ -73,13 +75,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.
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:

    
+# 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 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 and the type of IP addresses used in the script file used.
dfControls whether the DF fragmentation bit is set. {ON|OFF}
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 <multicastTimeToLive>Causes mgen to set the hop count for IP multicast traffic generated by MGEN. <multicastTimeToLive> will override any default multicast ttl indicated within an mgen script file. <timeToLive> is a "per socket" attribute. If no ttl option is used, MGEN will set the default multicast ttl to 1.
unicast_ttl <unicastTimeToLive>Causes mgen to set the hop count for IP unicast traffic generated by MGEN. <unicastTimeToLive> will override any default unicast ttl indicated within an mgen script file. <unicastTimeToLive> is a "per socket" attribute. If no unicast_ttl option is used, MGEN will set the default unicast ttl to 255.
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).
gpsfile <gpsFile>Changes the default location of the gps shared memory file to <gpsFile>
df {on|off}Controls whether the df fragmentation bit is set for the flow.

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 10.0.0.1/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 10.0.0.1/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 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, <sizeMin:sizeMax>)

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.5.6. Uniform random message size:

Option syntax:

... <patternType> [<rate> <sizeMin:sizeMax>]...

Setting a message size range will send uniformly random message sizes within the range sizeMin to sizeMax. The minimum <sizeMin> must be as big as the minimum allowed message size.

Example:

#Start an MGEN flow and one message per second, uniformaly random in size from 824 bytes

# to 1224 bytes (e.g. 1024 byes average).

0.0 ON 1 UDP DST 127.0.0.1/5000 PERIODIC [1 824:1224]

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> [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 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/Unicast Time-To-Live (TTL)

Option syntax:

... TTL <value> ...

The time-to-live (TTL) hop count can be controlled for IP multicast traffic or Ip unicast traffic (as defined by the dstAddr) 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 1. The default unicast TTL assumed by MGEN is 255.

Example:

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

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

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

0.0 ON 1 UDP DST 10.0.0.1/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 10.0.0.1/500 PER [1 1024]

5.2.16. DF (fragmentation bit)

Option syntax:

... DF {ON|OFF} ...

The optional DF command controls whether the df fragmentation bit is set for the flow.

Example:

#Set fragmentation bit

1.0 ON 1 UDP DST 10.0.0.1/500 PER [1 1024] DF ON

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.
GSpecifies a default TTL (time-to-live) hop count for transmitted multicast packets.
UNICAST_TTLSpecifies a default TTL (time-to-live) hop count for transmitted unicast 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.
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 and the type of IP addresses used in the script file used.
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 and the type of IP addresses used in the script file used.
DFControls whether the DF fragmentation bit is set. {ON|OFF}

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 tos = 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 1. 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. UNICAST_TTL

Script syntax:

UNICAST_TTL <value>

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

Example:

#Specify default unicast flow ttl = 32

UNICAST_TTL 32

6.7. 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.8. 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.9. 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.10. 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.11. 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.12. 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.13. 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.14. 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.15. 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.16. 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.17. 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

6.18. IPv6

Script syntax:

IPv6

Forces 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 and the type of IP addresses used in the script file used.

Example:

# Global IPv6 option

IPV6

6.19. IPv4

Script syntax:

IPv4

Forces 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 and the type of IP addresses used in the script file used.

Example:

# Gloval IPv4 option

IPv4

6.20. DF

Script syntax:

DF {ON|OFF}

Controls whether the DF fragmentation bit is set.

Example:

# Set DF fragmentation bit

DF on

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>10.0.0.1/35056 dst>10.0.0.2/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>10.0.0.1/35056 dst>10.0.0.1/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>10.0.0.2/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>10.0.0.1/5000 dst>10.0.0.2/5002 sent>22:59:52.310324 size>1024

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

23:59:53.312721 RECV proto><protocol> flow>1 seq>2 src>10.0.0.1/5000 dst>10.0.0.1/5002 sent>22:59:52.310324 size>1024 host>10.0.0.1/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>10.0.0.1/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>10.0.0.2/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>10.0.0.2/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>10.0.0.2/5000 dstPort>6000

Example Server SHUTDOWN event log line (server):

23:00:00:723467 SHUTDOWN src>10.0.0.1/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>10.0.0.1/5000

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

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

22:35:52.460419 OFF flow>2 srcPort>4000 dst>10.0.0.1/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>10.0.0.2/5000

Example Server DISCONNECT event log line :

23:00:00:723467 DISCONNECT src>10.0.0.1/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>10.0.0.2/5000

Example Server OFF event log line (server):

23:00:00:723467 OFF src>10.0.0.1/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
@@ -262,4 +264,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.

11.2. Windows Buffer Sizes

As windows default buffer size 8192K it is recommended that adequate rx/tx buffers be set for UDP traffic via the TXBUFFER and RXBUFFER global or flow commands so UDP performance is not degraded.

\ No newline at end of file diff --git a/doc/mgen.pdf b/doc/mgen.pdf index 18a26bf669af60e4d08e0f8b6c39da8fd612dcb5..5ee261ada9dd475654d85efaa38a9caa02924546 100755 GIT binary patch literal 224107 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

}gj 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

i!KdI2u*)1mm7!#G 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 D(0QnX literal 215782 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�lN4Q}A_MTM8@?Fg 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

H=Gtd`QI*{oari_uDaE#=R9R*H1Gu@=Z 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 z @@ -212,7 +214,7 @@ # Note that the "mgen message" will be received in multiple # "mgen fragments" by the target node. -0.0 ON 1 TCP DST 192.168.1.102/5000 PERIODIC [1 1048576] COUNT 1 +0.0 ON 1 TCP DST 10.0.0.1/5000 PERIODIC [1 1048576] COUNT 1 # Modify the pattern/rate of flow 2 4 seconds into the test @@ -275,23 +277,31 @@ - ipv4 + ipv4 Forces 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. + open sockets with the domain based on environment and the type of + IP addresses used in the script file used. - ipv6 + ipv6 Forces 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. + open sockets with the domain based on environment and the type of + IP addresses used in the script file used. + + + + df + + Controls whether the DF fragmentation bit is set. + {ON|OFF} @@ -535,13 +545,25 @@ - ttl<timeToLive> + ttl <multicastTimeToLive> 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. + generated by MGEN. <multicastTimeToLive> will override any + default multicast ttl indicated within an mgen script file. + <timeToLive> is a "per socket" attribute. If no ttl option + is used, MGEN will set the default multicast ttl to 1. + + + + unicast_ttl + <unicastTimeToLive> + + Causes mgen to set the hop count for IP unicast traffic + generated by MGEN. <unicastTimeToLive> will override any + default unicast ttl indicated within an mgen script file. + <unicastTimeToLive> is a "per socket" attribute. If no + unicast_ttl option is used, MGEN will set the default unicast ttl + to 255. @@ -688,6 +710,20 @@ options together as the mgen process can take over a machine at high packet rates (e.g. ctrl-c may not be handled). + + + gpsfile <gpsFile> + + Changes the default location of the gps shared memory file + to <gpsFile> + + + + df {on|off} + + Controls whether the df fragmentation bit is set for the + flow. + @@ -897,7 +933,7 @@ 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 + ON 1 UDP SRC 5000 DST 10.0.0.1/5001 PERIODIC [1 1024] 5.0 MOD 1 CONNECT @@ -909,8 +945,8 @@ 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] + ON 1 UDP CONNECT SRC 5000 DST 10.0.0.1/5001 PERIODIC [1 + 1024] 5.0 MOD 1 SRC 5001 @@ -1025,7 +1061,7 @@ 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 TOS or TTL. NOTE: Under the windows operating system, the ability to @@ -1597,29 +1633,37 @@ - Multicast Time-To-Live (TTL) + Multicast/Unicast 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. + default multicast TTL assumed by MGEN is 1. The default unicast TTL + assumed by MGEN is 255. Example: - #Start an IP multicast flow with a maximum hop count - ttl = 2 + #Start an IP multicast flow with a maximum multicast + hop count ttl = 2 0.0 ON 1 UDP DST 224.1.2.3/5000 PERIODIC [1.0 256] TTL 2 + + #Start an IP unicast flow with a maximum unicast hop + count ttl = 2 + + 0.0 ON 1 UDP DST 10.0.0.1/5000 PERIODIC [1.0 256] TTL + 2 @@ -1752,9 +1796,27 @@ #Open up a CONNECTED UDP socket - 1.0 ON 1 UDP CONNECT DST 192.168.1.100/500 PER [1 + 1.0 ON 1 UDP CONNECT DST 10.0.0.1/500 PER [1 1024] + + + DF (fragmentation bit) + + Option syntax: + + ... DF {ON|OFF} ... + + The optional DF command controls whether the df fragmentation + bit is set for the flow. + + Example: + + #Set fragmentation bit + + 1.0 ON 1 UDP DST 10.0.0.1/500 PER [1 1024] DF + ON + @@ -1862,7 +1924,7 @@ 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>. + specific <portNumber>. Unix-based operating systems generally allow for IP multicast group membership to be independent of specific socket port bindings. @@ -2010,12 +2072,19 @@ - TTL + G Specifies a default TTL (time-to-live) hop count for transmitted multicast packets. + + UNICAST_TTL + + Specifies a default TTL (time-to-live) hop count for + transmitted unicast packets. + + INTERFACE @@ -2087,6 +2156,31 @@ It does not affect whether MGEN senders send the requested data attribute. By default LOGDATA is set to ON. + + + IPV6 + + Forces 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 and the type of + IP addresses used in the script file used. + + + + IPV4 + + Forces 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 and the type of + IP addresses used in the script file used. + + + + DF + + Controls whether the DF fragmentation bit is set. + {ON|OFF} + @@ -2150,7 +2244,7 @@ Example: - #Specify default ttl = 0x10 (low delay) + #Specify default tos = 0x10 (low delay) TOS 0x10 @@ -2186,7 +2280,7 @@ 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. + command is not used, mgen assumes a default multicast TTL value of 1. Note that the transmission event TTL option will override the default specification given by this global command. @@ -2197,6 +2291,28 @@ TTL 32 + + UNICAST_TTL + + Script syntax: + + UNICAST_TTL <value> + + The TTL command specifies the default unicast time-to-live (TTL) + hop count for generated IP unicast traffic according to the + <value> field. The <value> must be in the range of 1-255. If + the global UNICAST_TTL command is not used, mgen assumes a default + unicast TTL value of 255. Note that the transmission event TTL option + will override the default specification given by this global + command. + + Example: + + #Specify default unicast flow ttl = 32 + + UNICAST_TTL 32 + + TXBUFFER @@ -2461,6 +2577,60 @@ LOG logFile.drc + + + IPv6 + + Script syntax: + + IPv6 + + Forces 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 and the type of IP addresses used + in the script file used. + + Example: + + # Global IPv6 option + + IPV6 + + + + IPv4 + + Script syntax: + + IPv4 + + Forces 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 and the type of IP addresses used + in the script file used. + + Example: + + # Gloval IPv4 option + + IPv4 + + + + DF + + Script syntax: + + DF {ON|OFF} + + Controls whether the DF fragmentation bit is set. + + Example: + + # Set DF fragmentation bit + + DF on + @@ -2711,21 +2881,21 @@ 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 + src>10.0.0.1/35056 dst>10.0.0.2/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 + src>10.0.0.1/35056 dst>10.0.0.1/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 + dst>10.0.0.2/5000 size>66559 The "host" <addr>/<port> corresponds to the MGEN message source's "perceived" default local address. Note that this may @@ -2803,17 +2973,17 @@ 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 + seq>1 src>10.0.0.1/5000 dst>10.0.0.2/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 + seq>2 src>10.0.0.1/5000 dst>10.0.0.2/5002 + sent>22:59:52.310324 size>1024 host>10.0.0.1/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 + seq>2 src>10.0.0.1/5000 dst>10.0.0.1/5002 + sent>22:59:52.310324 size>1024 host>10.0.0.1/5000 gps>CURRENT,35.123,79.234,57 data>10:01a97b34458cff0021e8 @@ -2973,7 +3143,7 @@ Example ON event log lines: 23:00:00:723467 ON flow>1 srcPort>4000 - dst>192.168.1.100/5000 + dst>10.0.0.1/5000 @@ -2997,7 +3167,7 @@ Example CONNECT event log line: 23:00:00:723467 CONNECT flow>1 srcPort>4000 - dst>192.168.1.102/5000 + dst>10.0.0.2/5000 @@ -3018,8 +3188,7 @@ Example ACCEPT event log line (server): - 23:00:00:723467 ACCEPT srcPort>4007 - dst>192.168.1.100/5000 + 23:00:00:723467 ACCEPT srcPort>4007 dst>10.0.0.2/5000 @@ -3049,11 +3218,11 @@ Example Client SHUTDOWN event log line (client): 23:00:00:723467 SHUTDOWN flow><flowId> - src>192.168.1.102/5000 dstPort>6000 + src>10.0.0.2/5000 dstPort>6000 Example Server SHUTDOWN event log line (server): - 23:00:00:723467 SHUTDOWN src>192.168.1.100/5000 + 23:00:00:723467 SHUTDOWN src>10.0.0.1/5000 dst>6000 If multiple flows are sharing the same connection, the shutdown @@ -3062,16 +3231,16 @@ while other flows are still transmitting, e.g.: 22:35:52.458531 OFF flow>1 srcPort>4000 - dst>192.168.1.100/5000 + dst>10.0.0.1/5000 22:35:52.458542 SEND proto>TCP flow>2 seq>3 - srcPort>4000 dst>192.168.1.100/5000 size>8192 + srcPort>4000 dst>10.0.0.1/5000 size>8192 22:35:52.458598 SHUTDOWN flow>2 srcPort>4000 - dst>192.168.1.100/5000 + dst>10.0.0.1/5000 22:35:52.460419 OFF flow>2 srcPort>4000 - dst>192.168.1.100/5000 + dst>10.0.0.1/5000 @@ -3103,11 +3272,11 @@ Example Client DISCONNECT event log line: 23:00:00:723467 DISCONNECT flow>1 srcPort>4000 - dst>192.168.1.102/5000 + dst>10.0.0.2/5000 Example Server DISCONNECT event log line : - 23:00:00:723467 DISCONNECT src>192.168.1.100/4000 + 23:00:00:723467 DISCONNECT src>10.0.0.1/4000 dstPort>5000 @@ -3140,11 +3309,11 @@ Example Client OFF event log line (client): 23:00:00:723467 OFF flow>1 srcPort>4000 - dst>192.168.1.102/5000 + dst>10.0.0.2/5000 Example Server OFF event log line (server): - 23:00:00:723467 OFF src>192.168.1.100/4000 + 23:00:00:723467 OFF src>10.0.0.1/4000 dstPort>5000 Note that the server will only log a single OFF event if multiple @@ -3935,5 +4104,16 @@ The format of the RECV event binary log file record is: still be impacted. Windows-7 is impacted more than Vista. The phenomenon varies by traffic pattern. + + + Windows Buffer Sizes + + As windows default buffer size 8192K it is recommended that + adequate rx/tx buffers be set for UDP traffic via the TXBUFFER and + RXBUFFER global or flow commands so UDP performance is not + degraded. + + + diff --git a/include/gpsPub.h b/include/gpsPub.h index 2fde1415..2ad65df6 100644 --- a/include/gpsPub.h +++ b/include/gpsPub.h @@ -38,6 +38,8 @@ char* GPSMemoryInit(const char* keyFile, unsigned int size); inline GPSHandle GPSPublishInit(const char* keyFile) {return (GPSHandle)GPSMemoryInit(keyFile, sizeof(GPSPosition));} void GPSPublishUpdate(GPSHandle gpsHandle, const GPSPosition* currentPosition); + +void GPSPublishPos(GPSHandle gpsHandle, double x, double y, double z); void GPSPublishShutdown(GPSHandle gpsHandle, const char* keyFile); GPSHandle GPSSubscribe(const char* keyFile); diff --git a/include/mgen.h b/include/mgen.h index b0b5cd00..30832896 100644 --- a/include/mgen.h +++ b/include/mgen.h @@ -133,7 +133,9 @@ class Mgen LABEL, // IPv6 flow label BROADCAST, // send/receive broadcasts from socket TOS, // IPV4 Type-Of-Service - TTL, // IPV4 Time-To-Live + TTL, // Multicast Time-To-Live + UNICAST_TTL, // Unicast Time-To-Live + DF, // DF/Fragmentation status INTERFACE, //Multicast Interface BINARY, // turn binary logfile mode on FLUSH, // flush log after _each_ event @@ -250,6 +252,7 @@ class Mgen MgenTransport* GetMgenTransport(Protocol theProtocol, UINT16 srcPort, const ProtoAddress& dstAddress, + const char* theInterface, bool closedOnly = false, bool connect = false); @@ -257,7 +260,8 @@ class Mgen UINT16 srcPort, const ProtoAddress& dstAddress, bool closedOnly, - MgenTransport* mgenTransport); + MgenTransport* mgenTransport, + const char* theInterface); MgenTransport* FindMgenTransportBySocket(const ProtoSocket& socket); @@ -303,7 +307,9 @@ class Mgen MgenFlowList& GetFlowList() {return flow_list;} bool GetDefaultBroadcast() {return default_broadcast;} - unsigned int GetDefaultTtl() {return default_ttl;} + unsigned int GetDefaultMulticastTtl() {return default_multicast_ttl;} + unsigned int GetDefaultUnicastTtl() {return default_unicast_ttl;} + FragmentationStatus GetDefaultDF() {return default_df;} unsigned int GetDefaultTos() {return default_tos;} unsigned int GetDefaultTxBuffer() {return default_tx_buffer;} unsigned int GetDefaultRxBuffer() {return default_rx_buffer;} @@ -319,13 +325,28 @@ class Mgen broadcastValue; default_broadcast_lock = override ? true : default_broadcast_lock; } - void SetDefaultTtl(unsigned int ttlValue, bool override) + void SetDefaultMulticastTtl(unsigned int ttlValue, bool override) { - default_ttl = default_ttl_lock ? - (override ? ttlValue : default_ttl) : + default_multicast_ttl = default_multicast_ttl_lock ? + (override ? ttlValue : default_multicast_ttl) : ttlValue; - default_ttl_lock = override ? true : default_ttl_lock; + default_multicast_ttl_lock = override ? true : default_multicast_ttl_lock; } + void SetDefaultUnicastTtl(unsigned int ttlValue, bool override) + { + default_unicast_ttl = default_unicast_ttl_lock ? + (override ? ttlValue : default_unicast_ttl) : + ttlValue; + default_unicast_ttl_lock = override ? true : default_unicast_ttl_lock; + } + void SetDefaultDF(FragmentationStatus dfValue, bool override) + { + default_df = default_df_lock ? + (override ? dfValue : default_df) : + dfValue; + default_df_lock = override ? true : default_df_lock; + } + void SetDefaultTos(unsigned int tosValue, bool override) { default_tos = default_tos_lock ? @@ -400,13 +421,17 @@ class Mgen unsigned int default_rx_buffer; bool default_broadcast; unsigned char default_tos; - unsigned char default_ttl; // multicast ttl + unsigned char default_multicast_ttl; // multicast ttl + unsigned char default_unicast_ttl; // unicast ttl + FragmentationStatus default_df; // socket df/fragmentation char default_interface[16]; // multicast interface name int default_queue_limit; // Socket state bool default_broadcast_lock; bool default_tos_lock; - bool default_ttl_lock; + bool default_multicast_ttl_lock; + bool default_unicast_ttl_lock; + bool default_df_lock; bool default_tx_buffer_lock; bool default_rx_buffer_lock; bool default_interface_lock; diff --git a/include/mgenEvent.h b/include/mgenEvent.h index b5a4b40e..f1994426 100644 --- a/include/mgenEvent.h +++ b/include/mgenEvent.h @@ -119,23 +119,24 @@ class MgenEvent : public MgenBaseEvent // MGEN script option types/flags (indicates which options were invoked) enum Option { - INVALID_OPTION = 0x0000, - PROTOCOL = 0x0001, // flow protocol was set - DST = 0x0002, // flow destination address was set - SRC = 0x0004, // flow source port was set - PATTERN = 0x0008, // flow pattern was set - TOS = 0x0010, // flow TOS was set - RSVP = 0x0020, // flow RSVP spec was set - INTERFACE = 0x0040, // flow multicast interface was set - TTL = 0x0080, // flow ttl was set - SEQUENCE = 0x0100, // flow sequence number was set - LABEL = 0x0200, // flow label option for IPV6 - TXBUFFER = 0x0400, // Tx socket buffer size - DATA = 0x0800, // payload data - QUEUE = 0x1000, // queue limit - COUNT = 0x2000, // count - CONNECT = 0x4000, // connect src port for udp - BROADCAST = 0x8000 // send/receive broadcasts + INVALID_OPTION = 0x00000000, + PROTOCOL = 0x00000001, // flow protocol was set + DST = 0x00000002, // flow destination address was set + SRC = 0x00000004, // flow source port was set + PATTERN = 0x00000008, // flow pattern was set + TOS = 0x00000010, // flow TOS was set + RSVP = 0x00000020, // flow RSVP spec was set + INTERFACE = 0x00000040, // flow multicast interface was set + TTL = 0x00000080, // flow ttl was set + SEQUENCE = 0x00000100, // flow sequence number was set + LABEL = 0x00000200, // flow label option for IPV6 + TXBUFFER = 0x00000400, // Tx socket buffer size + DATA = 0x00000800, // payload data + QUEUE = 0x00001000, // queue limit + COUNT = 0x00002000, // count + CONNECT = 0x00004000, // connect src port for udp + BROADCAST = 0x00008000, // send/receive broadcasts + DF = 0x00010000 // fragmentation status }; MgenEvent(); @@ -159,6 +160,7 @@ class MgenEvent : public MgenBaseEvent UINT32 GetFlowLabel() const {return flow_label;} unsigned char GetTTL() const {return ttl;} unsigned int GetTxBuffer() const {return tx_buffer_size;} + FragmentationStatus GetDF() const {return df;} int GetQueueLimit() const {return queue;} UINT32 GetSequence() const {return sequence;} char *GetPayload() const {return payload;} @@ -190,6 +192,7 @@ class MgenEvent : public MgenBaseEvent UINT32 flow_label; unsigned int tx_buffer_size; unsigned char ttl; + FragmentationStatus df; UINT32 sequence; char interface_name[16]; unsigned int option_mask; diff --git a/include/mgenFlow.h b/include/mgenFlow.h index c444ee26..eb2d0fbc 100644 --- a/include/mgenFlow.h +++ b/include/mgenFlow.h @@ -96,7 +96,6 @@ class MgenFlow bool OnEventTimeout(ProtoTimer& theTimer); bool off_pending; MgenTransport* old_transport; - bool new_transport; int queue_limit; int message_limit; @@ -121,7 +120,7 @@ class MgenFlow MgenEvent* next_event; ProtoTimer event_timer; bool started; - + bool socket_error; ProtoTimerMgr& timer_mgr; MgenPositionFunc* get_position; diff --git a/include/mgenGlobals.h b/include/mgenGlobals.h index 52d7bf23..67cb5fce 100644 --- a/include/mgenGlobals.h +++ b/include/mgenGlobals.h @@ -76,5 +76,20 @@ enum MIN_FRAG_SIZE = 76 // ljt what should this be? // we're going with IPV6 + gps max for now }; +enum FragmentationStatus +{ + DF_OFF, // df = false + DF_ON, // df = true + DF_DEFAULT // leave socket DF option in its default state + +}; + +enum MessageStatus + { + MSG_SEND_FAILED, + MSG_SEND_BLOCKED, + MSG_SEND_OK + + }; #endif // _MGEN_GLOBALS diff --git a/include/mgenPattern.h b/include/mgenPattern.h index fe76d882..db4428ba 100644 --- a/include/mgenPattern.h +++ b/include/mgenPattern.h @@ -63,6 +63,11 @@ class MgenPattern double range = max - min; return (((((double)rand()) * range) / ((double)RAND_MAX)) + min); } + static unsigned int UniformRandUnsigned(unsigned int min, unsigned int max) + { + unsigned int range = max - min + 1; + return ((unsigned int)rand() % range + min); + } static double ExponentialRand(double mean) { @@ -76,7 +81,8 @@ class MgenPattern Type type; double interval_ave; double interval_remainder; - unsigned int pkt_size; + unsigned int pkt_size_min; + unsigned int pkt_size_max; double jitter_min; // = jitterFraction * interval_ave double jitter_max; // = interval_ave + jitterFraction Burst burst_type; @@ -85,7 +91,7 @@ class MgenPattern double burst_duration_ave; double burst_duration; struct timeval last_time; - bool unlimitedRate; + bool unlimitedRate; #ifdef _HAVE_PCAP pcap_t* pcap_device; diff --git a/include/mgenTransport.h b/include/mgenTransport.h index 61856c64..43778bb9 100644 --- a/include/mgenTransport.h +++ b/include/mgenTransport.h @@ -26,7 +26,8 @@ class MgenTransportList enum { - DEFAULT_TTL = 3, // default multicast ttl + DEFAULT_MULTICAST_TTL = 1, // default multicast ttl + DEFAULT_UNICAST_TTL = 255, // default unicast ttl DEFAULT_TOS = 0 // default type of service }; @@ -97,7 +98,7 @@ class MgenTransport virtual bool IsOpen() = 0; virtual void Close() = 0; virtual bool HasListener() = 0; - virtual bool SendMessage(MgenMsg& theMsg, + virtual MessageStatus SendMessage(MgenMsg& theMsg, const ProtoAddress& dst_addr, char* txBuffer) = 0; virtual bool StartOutputNotification() {return true;} @@ -105,6 +106,7 @@ class MgenTransport virtual bool StartInputNotification() {return true;} virtual void StopInputNotification() {;} virtual bool Shutdown() {return false;} + virtual const char* GetInterface() = 0; // base class implementation UINT16 GetSrcPort() {return srcPort;} @@ -213,14 +215,21 @@ class MgenSocketTransport : public MgenTransport bool SetBroadcast(bool broadcast); bool SetTxBufferSize(unsigned int txBufferSize); bool SetRxBufferSize(unsigned int rxBufferSize); - virtual bool SetTTL(unsigned char TTL); + virtual bool SetMulticastTTL(unsigned char TTL); + virtual bool SetUnicastTTL(unsigned char TTL); + virtual bool SetDF(FragmentationStatus df); virtual bool SetMulticastInterface(const char* interfaceName) { if (interfaceName != NULL && '\0' != interfaceName[0]) strcpy(interface_name,interfaceName); return true; - } + } bool HasListener() {return (socket.HasListener());} + const char* GetInterface() + { + return (('\0' != interface_name[0]) ? + interface_name : NULL); + } private: protected: @@ -235,7 +244,9 @@ class MgenSocketTransport : public MgenTransport unsigned char tos; unsigned int tx_buffer; unsigned int rx_buffer; - unsigned char ttl; // multicast time-to-live + unsigned char multicast_ttl; // multicast time-to-live + unsigned char unicast_ttl; // multicast time-to-live + FragmentationStatus df; // df/fragmentation char interface_name[16]; ProtoSocket socket; @@ -261,7 +272,7 @@ class MgenUdpTransport : public MgenSocketTransport bool LeaveGroup(const ProtoAddress& theAddress, const ProtoAddress& sourceAddress, const char* interfaceName = NULL); - bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); + MessageStatus SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); bool Listen(UINT16 port,ProtoAddress::Type addrType, bool bindOnOpen); unsigned int GroupCount() {return group_count;} @@ -328,7 +339,7 @@ class MgenTcpTransport : public MgenSocketTransport bool IsConnecting() {return socket.IsConnecting();} bool IsListening() {return socket.IsListening();} void OnRecvMsg(unsigned int numBytes,unsigned int bufferIndex,const char* buffer); - bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); + MessageStatus SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); bool GetNextTxBuffer(unsigned int numBytes); void SetupNextTxBuffer(); UINT16 GetNextTxFragment(); @@ -392,6 +403,7 @@ class MgenSinkTransport : public MgenTransport // MgenSinkTransport implementation static MgenSinkTransport* Create(Mgen& theMgen, Protocol theProtocol); // SINK or SOURCE bool IsOpen() {return true;} + const char* GetInterface() {return NULL;} void Close() {return;} bool HasListener() {return true;} void SetPath(char* theSinkPath) { @@ -452,8 +464,8 @@ class MgenAppSinkTransport : public MgenSinkTransport, public ProtoChannel // source open bool Open(); bool OnOutputReady(); - bool Write(char* buffer, unsigned int* nbytes); - bool SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer); + bool Write(char* buffer, unsigned int* nbytes); + MessageStatus 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 8a10b3e5..a47aad32 100644 --- a/include/mgenVersion.h +++ b/include/mgenVersion.h @@ -1,6 +1,6 @@ #ifndef _MGEN_VERSION -#define MGEN_VERSION "5.02b" +#define MGEN_VERSION "5.02c" #endif // _MGEN_VERSION diff --git a/makefiles/Makefile.common b/makefiles/Makefile.common index f0fd26b2..3e93554f 100644 --- a/makefiles/Makefile.common +++ b/makefiles/Makefile.common @@ -8,6 +8,7 @@ SHELL=/bin/sh PROTOLIB = ../protolib COMMON = ../src/common +PYTHON = ../src/python INCLUDE = ../include UNIX = ../makefiles @@ -65,6 +66,16 @@ P2M_OBJ = $(P2M_SRC:.cpp=.o) pcap2mgen: $(P2M_OBJ) $(MGEN_OBJ) $(LIBPROTO) $(CC) -g $(CFLAGS) -o $@ $(P2M_OBJ) $(MGEN_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) +# gpsPub is a python extension module +GPSPUB_SRC = $(COMMON)/gpsPub.cpp $(PYTHON)/gpsPub_wrap.c +GPSPUB_OBJ = gpsPub.o gpsPub_wrap.o + +#Change the python directory as appropriate for your system +PYTHONLIB = /usr/include/python2.7 +gpsPub: $(GPSPUB_SRC) $(PYTHONLIB) + $(CC) -fpic -I$(INCLUDE) -I$(PYTHONLIB) -c $(GPSPUB_SRC) + $(CC) -shared $(GPSPUB_OBJ) -o _gpsPub.so + MPM_SRC = $(COMMON)/mgenPayloadMgr.cpp MPM_OBJ = $(MPM_SRC:.cpp=.o) @@ -83,7 +94,7 @@ mgenBlast: $(MM_OBJ) $(MGEN_OBJ) $(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; + rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/mgen $(UNIX)/*.so $(UNIX)/mpmgr $(NS)/*.o; $(MAKE) -C $(PROTOLIB)/makefiles -f Makefile.$(SYSTEM) clean distclean: clean diff --git a/makefiles/Makefile.linux b/makefiles/Makefile.linux index 6217bb2e..d0d23c47 100644 --- a/makefiles/Makefile.linux +++ b/makefiles/Makefile.linux @@ -35,8 +35,7 @@ SYSTEM_LIBS = -ldl -lpthread -lpcap # (We export these for other Makefiles as needed) # -SYSTEM_HAVES = -DLINUX -DHAVE_PSELECT -DHAVE_SCHED -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF -DHAVE_DIRFD \ --DHAVE_ASSERT $(NETSEC) -D_FILE_OFFSET_BITS=64 +SYSTEM_HAVES = -DLINUX -DHAVE_SCHED -DHAVE_GETLOGIN -DHAVE_LOCKF -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC) -D_FILE_OFFSET_BITS=64 -DUNIX -DUSE_SELECT -DUSE_TIMERFD -DHAVE_PSELECT -DHAVE_IPV6 SYSTEM = linux CC = g++ diff --git a/makefiles/README.TXT b/makefiles/README.TXT index 02f0abe9..93968fe8 100644 --- a/makefiles/README.TXT +++ b/makefiles/README.TXT @@ -1,4 +1,4 @@ - MGEN 4.x for UNIX + MGEN 5.x for UNIX This directory contains Makefiles for Unix platforms and any Unix-specific source code files. Build instructions are given @@ -53,10 +53,19 @@ NOTES: 6) Feel free to email us with questions. +BUILD gpsPub.so INSTRUCTIONS: + +gpsPub.so will be built by setup.py. Manual instructions follow: + +swig -python gpsPub.i +g++ -fpic -I/usr/include/python2.7 -c gpsPub.cpp gpsPub_wrap.c +g++ -shared gpsPub.o gpsPub_wrap.o -o _gpsPub.so + +You must regenerate gpsPub_wrap.c via swig if gpsPub.cpp changes. + ------------- Brian Adamson adamson@itd.nrl.navy.mil -Hal Greenwald hgreenwald@itd.nrl.navy.mil -5 September 2002 +19 May 2015 diff --git a/makefiles/android/change_target.sh b/makefiles/android/change_target.sh new file mode 100755 index 00000000..3709f877 --- /dev/null +++ b/makefiles/android/change_target.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +while getopts ":r:" opt; do + case $opt in + r) + RELVER=$OPTARG + if [ $RELVER -ne 23 -a $RELVER -ne 14 ] ; then + echo "Only supported versions are Android 14 and 23" + exit 1 + fi + ;; + \?) + echo "Usage $0 -r " >&2 + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + exit 1 + ;; + esac +done + +if [ ! -f jni/Application.mk.r$RELVER ] ; then + echo "Android version $RELVER is not supperted." + exit 1 +else + cd jni + ln -sf Application.mk.r$RELVER Application.mk + cd .. +fi + +if [ -f project.properties.r$RELVER ] ; then + ln -sf project.properties.r$RELVER project.properties +fi diff --git a/makefiles/android/jni/Application.mk b/makefiles/android/jni/Application.mk deleted file mode 100644 index 5c358d08..00000000 --- a/makefiles/android/jni/Application.mk +++ /dev/null @@ -1,3 +0,0 @@ -APP_ABI := all -APP_PLATFORM := android-8 -NDK_MODULE_PATH := ../..:../../protolib/ diff --git a/makefiles/android/jni/Application.mk b/makefiles/android/jni/Application.mk new file mode 120000 index 00000000..8e844e3f --- /dev/null +++ b/makefiles/android/jni/Application.mk @@ -0,0 +1 @@ +Application.mk.r23 \ No newline at end of file diff --git a/makefiles/android/jni/Application.mk.r14 b/makefiles/android/jni/Application.mk.r14 new file mode 100644 index 00000000..43cd7a97 --- /dev/null +++ b/makefiles/android/jni/Application.mk.r14 @@ -0,0 +1,3 @@ +APP_ABI := all +APP_PLATFORM := android-14 +NDK_MODULE_PATH := ../..:../../protolib/ diff --git a/makefiles/android/jni/Application.mk.r23 b/makefiles/android/jni/Application.mk.r23 new file mode 100644 index 00000000..db48c170 --- /dev/null +++ b/makefiles/android/jni/Application.mk.r23 @@ -0,0 +1,4 @@ +APP_ABI := all +APP_PLATFORM := android-23 +APP_PIE := true +NDK_MODULE_PATH := ../..:../../protolib/ diff --git a/makefiles/android/project.properties b/makefiles/android/project.properties deleted file mode 100644 index cd0ca122..00000000 --- a/makefiles/android/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# 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/android/project.properties b/makefiles/android/project.properties new file mode 120000 index 00000000..fbcc682d --- /dev/null +++ b/makefiles/android/project.properties @@ -0,0 +1 @@ +project.properties.r23 \ No newline at end of file diff --git a/makefiles/android/project.properties.r14 b/makefiles/android/project.properties.r14 new file mode 100644 index 00000000..1d35d2d8 --- /dev/null +++ b/makefiles/android/project.properties.r14 @@ -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-14 diff --git a/makefiles/android/project.properties.r23 b/makefiles/android/project.properties.r23 new file mode 100644 index 00000000..def83b4e --- /dev/null +++ b/makefiles/android/project.properties.r23 @@ -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-23 diff --git a/makefiles/gpsPub.i b/makefiles/gpsPub.i new file mode 100644 index 00000000..13b0d3f3 --- /dev/null +++ b/makefiles/gpsPub.i @@ -0,0 +1,9 @@ +/* python gpsPub */ +%module "gpsPub" + +%{ +#define SWIG_FILE_WITH_INIT +#include "gpsPub.h" +%} + +%include "gpsPub.h" diff --git a/makefiles/win32/mgen.sln b/makefiles/win32/mgen.sln index a8eb40b4..b5c380f1 100755 --- a/makefiles/win32/mgen.sln +++ b/makefiles/win32/mgen.sln @@ -1,24 +1,26 @@  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 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Protokit", "..\..\protolib\makefiles\win32\Protokit.vcxproj", "{DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgen", "mgen.vcxproj", "{992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}" +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 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/makefiles/win32/mgen.vcxproj b/makefiles/win32/mgen.vcxproj new file mode 100755 index 00000000..517d22ea --- /dev/null +++ b/makefiles/win32/mgen.vcxproj @@ -0,0 +1,168 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84} + mgen + + + + Application + v120 + false + MultiByte + + + Application + v120 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + .\Debug\ + .\Debug\ + false + + + .\Release\ + .\Release\ + false + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/mgen.tlb + + + + /vmg /GZ %(AdditionalOptions) + Disabled + ..\..\include;..\..\protolib\include;..\..\protolib\win32;%(AdditionalIncludeDirectories) + _DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_USE_32BIT_TIME_T;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + .\Debug/mgen.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Iphlpapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + .\Debug/mgen.exe + true + true + .\Debug/mgen.pdb + Windows + false + + MachineX86 + true + true + + + true + .\Debug/mgen.bsc + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/mgen.tlb + + + + /vmg %(AdditionalOptions) + MaxSpeed + OnlyExplicitInline + ..\..\include;..\..\protolib\include;..\..\protolib\win32;%(AdditionalIncludeDirectories) + _USE_32BIT_TIME_T;NDEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/mgen.pch + .\Release/ + .\Release/ + .\Release/ + Level4 + true + ProgramDatabase + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Iphlpapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + .\Release/mgen.exe + true + .\Release/mgen.pdb + Windows + false + + MachineX86 + false + + + true + .\Release/mgen.bsc + + + + + + + + + + + + + + + + + {de94f096-a09b-44b6-8efe-c7bf1f65c4c9} + false + + + + + + \ No newline at end of file diff --git a/makefiles/win64/mgen.sln b/makefiles/win64/mgen.sln index 75d68d7a..1dddd6f9 100755 --- a/makefiles/win64/mgen.sln +++ b/makefiles/win64/mgen.sln @@ -1,27 +1,32 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C++ Express 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 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 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 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}.Debug|x64.ActiveCfg = Debug|Win32 {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Release|Win32.ActiveCfg = Release|Win32 {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Release|Win32.Build.0 = Release|Win32 + {992F1B16-C3A2-48E1-ADA7-C660A1E3DE84}.Release|x64.ActiveCfg = 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}.Debug|x64.ActiveCfg = Debug|Win32 {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.ActiveCfg = Release|Win32 {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|Win32.Build.0 = Release|Win32 + {DE94F096-A09B-44B6-8EFE-C7BF1F65C4C9}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/setup.py b/setup.py index d13ba38f..a68e823e 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,22 @@ -from distutils.core import setup +import platform +from distutils.core import setup, Extension # 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. +PYTHON = "src/python/" +COMMON = "src/common/" + +srcFiles = [COMMON + 'gpsPub.cpp', PYTHON + 'gpsPub_wrap.c'] +sys_libs = ['_gpsPub'] + +system = platform.system().lower() +sys_macros = [('HAVE_ASSERT',None), ('HAVE_IPV6',None), ('PROTO_DEBUG', None)] + +if system == 'darwin': + sys_libs.append('resolv') # TBD - invoke the "protolib/setup.py" automatically? # (good intern task to do this the right way) @@ -15,3 +27,11 @@ py_modules=['mgen'] ) +setup(name='gpsPub', + version='1.0', + ext_modules = [Extension('_gpsPub', + srcFiles, + include_dirs = ['./include'], + define_macros=sys_macros, +# libraries = sys_libs, + library_dirs = ['./lib'])]) diff --git a/src/common/gpsPub.cpp b/src/common/gpsPub.cpp index fe867abe..b5608df3 100644 --- a/src/common/gpsPub.cpp +++ b/src/common/gpsPub.cpp @@ -161,7 +161,7 @@ extern "C" GPSHandle GPSSubscribe(const char* keyFile) else { //fprintf(stderr, "GPSSubscribe(): Error opening %s.\n", keyFile); - //perror("GPSSubscribe(): fopen() error"); + perror("GPSSubscribe(): fopen() error"); return NULL; } } // end GPSSubscribe() @@ -173,6 +173,25 @@ extern "C" void GPSUnsubscribe(GPSHandle gpsHandle) perror("GPSUnsubscribe() shmdt() error"); } // end GPSUnsubscribe() +extern "C" void GPSPublishPos(GPSHandle gpsHandle, double x, double y, double z) +{ + GPSPosition pos; + pos.x = x; + pos.y = y; + pos.z = z; + pos.xyvalid = true; + pos.zvalid = true; + pos.tvalid = true; + pos.stale = false; + // Update time + struct timeval time; + gettimeofday(&time, 0); + memcpy(&pos.gps_time, &time, sizeof(struct timeval)); + memcpy(&pos.sys_time, &time, sizeof(struct timeval)); + + memcpy((char*)gpsHandle, &pos, sizeof(GPSPosition)); +} + extern "C" void GPSPublishUpdate(GPSHandle gpsHandle, const GPSPosition* currentPosition) { memcpy((char*)gpsHandle, (char*)currentPosition, sizeof(GPSPosition)); diff --git a/src/common/mgen.cpp b/src/common/mgen.cpp index d2985921..b439a739 100644 --- a/src/common/mgen.cpp +++ b/src/common/mgen.cpp @@ -54,9 +54,13 @@ Mgen::Mgen(ProtoTimerMgr& timerMgr, default_flow_label(0), default_label_lock(false), default_tx_buffer(0), default_rx_buffer(0), default_broadcast(true), default_tos(0), - default_ttl(3), default_queue_limit(0), + default_multicast_ttl(1), default_unicast_ttl(255), + default_df(DF_DEFAULT), + default_queue_limit(0), default_broadcast_lock(false), - default_tos_lock(false), default_ttl_lock(false), + default_tos_lock(false), default_multicast_ttl_lock(false), + default_unicast_ttl_lock(false), + default_df_lock(false), default_tx_buffer_lock(false), default_rx_buffer_lock(false), default_interface_lock(false), default_queue_limit_lock(false), sink_non_blocking(true), @@ -161,6 +165,7 @@ bool Mgen::Start() timePtr = gmtime((time_t*)¤tTime.tv_sec); #endif // if/else _WIN32_WCE + Mgen::Log(log_file, "%02d:%02d:%02d.%06lu START Mgen Version %s\n", timePtr->tm_hour, timePtr->tm_min, timePtr->tm_sec, (UINT32)currentTime.tv_usec,MGEN_VERSION); @@ -273,7 +278,7 @@ MgenTransport* Mgen::JoinGroup(const ProtoAddress& groupAddress, { // Create new "dummy" socket for group joins only ProtoAddress tmpAddress; - if (!(mgenTransport = GetMgenTransport(UDP,thePort,tmpAddress,true))) + if (!(mgenTransport = GetMgenTransport(UDP,thePort,tmpAddress,interfaceName,true))) { DMSG(0, "Mgen::JoinGroup() memory allocation error: %s\n", GetErrorString()); @@ -328,7 +333,8 @@ MgenTransport* Mgen::FindMgenTransport(Protocol theProtocol, UINT16 srcPort, const ProtoAddress& dstAddress, bool closedOnly, - MgenTransport* mgenTransport) + MgenTransport* mgenTransport, + const char* interfaceName) { MgenTransport* next; if (!mgenTransport) {next = transport_list.head;} @@ -337,23 +343,28 @@ MgenTransport* Mgen::FindMgenTransport(Protocol theProtocol, while (next) { // Same protocol and srcPort? - if ((next->GetProtocol() == theProtocol) && - (srcPort == 0 || next->srcPort == srcPort) && - - // ignore events && unconnected udp sockets - // have invalid addrs and should match - (((!dstAddress.IsValid() && - !next->dstAddress.IsValid()) && theProtocol == UDP) - || - // For tcp ignore events we want to close the - // listening socket too which won't have a dst address - (theProtocol == TCP && !dstAddress.IsValid()) - || - (dstAddress.IsValid() && - next->dstAddress.IsEqual(dstAddress))) - - // We should only have one sink - || ((next->GetProtocol() == SINK && theProtocol == SINK))) + if ( + (next->GetProtocol() == theProtocol) + && + (srcPort == 0 || next->srcPort == srcPort) + && + ((NULL == interfaceName ) || + (NULL != interfaceName && NULL != next->GetInterface() && !strcmp(interfaceName,next->GetInterface()))) + && + // ignore events && unconnected udp sockets + // have invalid addrs and should match + (((!dstAddress.IsValid() && !next->dstAddress.IsValid()) && theProtocol == UDP) + || + // For tcp ignore events we want to close the + // listening socket too which won't have a dst address + (theProtocol == TCP && !dstAddress.IsValid()) + || + (dstAddress.IsValid() && next->dstAddress.IsEqual(dstAddress))) + + // We should only have one sink + || + (next->GetProtocol() == SINK && theProtocol == SINK) + ) { if (!closedOnly) { return next; } if (!next->IsOpen()) { return next;} @@ -471,6 +482,7 @@ MgenTransport* Mgen::FindMgenTransportBySocket(const ProtoSocket& socket) MgenTransport* Mgen::GetMgenTransport(Protocol theProtocol, UINT16 srcPort, const ProtoAddress& dstAddress, + const char* theInterface, bool closedOnly, bool connect) { @@ -478,7 +490,7 @@ MgenTransport* Mgen::GetMgenTransport(Protocol theProtocol, if (connect || theProtocol == TCP ) tmpAddress = dstAddress;// ignore events have invalid addrs - MgenTransport* theTransport = FindMgenTransport(theProtocol,srcPort,tmpAddress,closedOnly,NULL); + MgenTransport* theTransport = FindMgenTransport(theProtocol,srcPort,tmpAddress,closedOnly,NULL,theInterface); if (theTransport) return theTransport; @@ -769,7 +781,7 @@ void Mgen::ProcessDrecEvent(const DrecEvent& event) { ProtoAddress tmpAddress; - MgenTransport* theMgenTransport = GetMgenTransport(event.GetProtocol(),port[i],tmpAddress); + MgenTransport* theMgenTransport = GetMgenTransport(event.GetProtocol(),port[i],tmpAddress,event.GetInterface()); if (theMgenTransport) { @@ -822,7 +834,7 @@ void Mgen::ProcessDrecEvent(const DrecEvent& event) MgenTransport* mgenTransport; MgenTransport* next = NULL; ProtoAddress tmpAddress; - while ((mgenTransport = FindMgenTransport(theProtocol, port[i],tmpAddress,false,next))) + while ((mgenTransport = FindMgenTransport(theProtocol, port[i],tmpAddress,false,next,event.GetInterface()))) { if (mgenTransport->HasListener()) { @@ -1265,6 +1277,8 @@ const StringMapper Mgen::COMMAND_LIST[] = {"+BROADCAST", BROADCAST}, {"+TOS", TOS}, {"+TTL", TTL}, + {"+UNICAST_TTL", UNICAST_TTL}, + {"+DF", DF}, {"+INTERFACE", INTERFACE}, {"-CHECKSUM", CHECKSUM}, {"-TXCHECKSUM", TXCHECKSUM}, @@ -1488,7 +1502,30 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) case INTERFACE: SetDefaultMulticastInterface(arg, override); break; - + + case DF: + { + FragmentationStatus df = DF_DEFAULT; + 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)) + df = DF_ON; + else if (!strncmp("OFF", temp, len)) + df = DF_OFF; + else + { + DMSG(0,"Mgen::OnCommand() Error: wrong argument to DF: %s\n",arg); + return false; + } + SetDefaultDF(df, override); + break; + } + // For backwards compatability TTL refers to multicast ttl case TTL: { int ttlTemp; @@ -1499,7 +1536,20 @@ bool Mgen::OnCommand(Mgen::Command cmd, const char* arg, bool override) return false; } - SetDefaultTtl(ttlTemp, override); + SetDefaultMulticastTtl(ttlTemp, override); + break; + } + case UNICAST_TTL: + { + int ttlTemp; + int result = sscanf(arg, "%i", &ttlTemp); + if ((1 != result) || (ttlTemp < 0) || (ttlTemp > 255)) + { + DMSG(0, "Mgen::OnCommand() - invalid ttl value"); + return false; + } + + SetDefaultUnicastTtl(ttlTemp, override); break; } diff --git a/src/common/mgenApp.cpp b/src/common/mgenApp.cpp index b9806c24..431c0c0b 100644 --- a/src/common/mgenApp.cpp +++ b/src/common/mgenApp.cpp @@ -39,21 +39,24 @@ MgenApp::~MgenApp() void MgenApp::Usage() { fprintf(stderr, "mgen [ipv4][ipv6][input ][save ]\n" - " [output ][log ][hostAddr {on|off}\n" - " [logData {on|off}][logGpsData {on|off}]\n" - " [binary][txlog][nolog][flush]\n" - " [event \"\"][port ]\n" - " [instance ][command ]\n" - " [sink ][block][source ]\n" - " [interface ][ttl ]\n" - " [tos ][label ]\n" - " [txbuffer ][rxbuffer ]\n" - " [start [GMT]][offset ]\n" - " [precise {on|off}][ifinfo ]\n" - " [txcheck][rxcheck][check]\n" - " [queue ][broadcast {on|off}]\n" - " [convert ][debug ]\n" - " [boost] [reuse {on|off}]\n"); + " [output ][log ][hostAddr {on|off}\n" + " [logData {on|off}][logGpsData {on|off}]\n" + " [binary][txlog][nolog][flush]\n" + " [event \"\"][port ]\n" + " [instance ][command ]\n" + " [sink ][block][source ]\n" + " [interface ][ttl ]\n" + " [unicast_ttl ]\n" + " [df ]\n" + " [tos ][label ]\n" + " [txbuffer ][rxbuffer ]\n" + " [start [GMT]][offset ]\n" + " [precise {on|off}][ifinfo ]\n" + " [txcheck][rxcheck][check]\n" + " [queue ][broadcast {on|off}]\n" + " [convert ][debug ]\n" + " [gpskey ]\n" + " [boost] [reuse {on|off}]\n"); } // end MgenApp::Usage() @@ -74,6 +77,7 @@ const char* const MgenApp::CMD_LIST[] = "+hostaddr", // turn "host" field on/off in sent messages "-boost", // boost process priority "-help", // print usage and exit + "+gpskey", // Override default gps shared memory location "+logdata", // log optional data attribute? default ON "+loggpsdata", // log gps data? default ON NULL @@ -272,12 +276,12 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) else if (!strncmp("ipv6", lowerCmd, len)) { #ifdef HAVE_IPV6 - ProtoSocket::SetHostIPv6Capable(); if (ProtoSocket::HostIsIPv6Capable()) mgen.SetDefaultSocketType(ProtoAddress::IPv6); else #endif // HAVE_IPV6 DMSG(0, "MgenApp::ProcessCommand(ipv6) Warning: system not IPv6 capable?\n"); + } else if (!strncmp("background", lowerCmd, len)) { @@ -300,7 +304,7 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) { mgen.SetSourcePath(val); ProtoAddress tmpAddress; - MgenTransport* theMgenTransport = mgen.GetMgenTransport(SOURCE,0,tmpAddress,true,false); + MgenTransport* theMgenTransport = mgen.GetMgenTransport(SOURCE,0,tmpAddress,NULL,true,false); if (!theMgenTransport) { DMSG(0,"MgenApp::OnCommand() Error getting MgenAppSinkTransport.\n"); @@ -390,6 +394,14 @@ bool MgenApp::OnCommand(const char* cmd, const char* val) } } } +#ifdef HAVE_GPS + else if (!strncmp("gpskey", lowerCmd, len)) + { + gps_handle = GPSSubscribe(val); + if (gps_handle) + mgen.SetPositionCallback(MgenApp::GetPosition, gps_handle); + } +#endif //HAVE_GPS else if (!strncmp("logdata", lowerCmd, len)) { char status[4]; // valid status is "on" or "off" @@ -453,20 +465,15 @@ bool MgenApp::OnStartup(int argc, const char*const* argv) mgen.SetLogFile(stdout); // log to stdout by default -#ifdef HAVE_IPV6 - - if (ProtoSocket::HostIsIPv6Capable()) - mgen.SetDefaultSocketType(ProtoAddress::IPv6); - -#endif // HAVE_IPV6 - #ifdef HAVE_GPS gps_handle = GPSSubscribe(NULL); if (gps_handle) mgen.SetPositionCallback(MgenApp::GetPosition, gps_handle); + // This payload stuff shouldn't be here! payload_handle = GPSSubscribe("/tmp/mgenPayloadKey"); - mgen.SetPayloadHandle(payload_handle); + if (payload_handle) + mgen.SetPayloadHandle(payload_handle); #endif // HAVE_GPS diff --git a/src/common/mgenAppSinkTransport.cpp b/src/common/mgenAppSinkTransport.cpp index da141a1d..1ff5c8f6 100644 --- a/src/common/mgenAppSinkTransport.cpp +++ b/src/common/mgenAppSinkTransport.cpp @@ -1,5 +1,6 @@ #include "mgen.h" #include "mgenTransport.h" +#include "mgenGlobals.h" #include #include @@ -157,7 +158,7 @@ bool MgenAppSinkTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) } // end MgenAppSinkTransport::Open -bool MgenAppSinkTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) +MessageStatus MgenAppSinkTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) { UINT32 txChecksum = 0; @@ -167,11 +168,12 @@ bool MgenAppSinkTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_a len = theMsg.Pack(txBuffer,theMsg.GetMsgLen(),mgen.GetChecksumEnable(),txChecksum); if (len == 0) - return false; // no room - + { + return MSG_SEND_FAILED; // no room + } if (mgen.GetChecksumEnable() && theMsg.FlagIsSet(MgenMsg::CHECKSUM)) theMsg.WriteChecksum(txChecksum,(unsigned char*)txBuffer,(UINT32)len); - + if (msg_index >= msg_length) { // Copy txBuffer to msg_buffer @@ -180,18 +182,20 @@ bool MgenAppSinkTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_a msg_length = len; msg_index = 0; if (!OnOutputReady()) // and rename this function - return false; + { + return MSG_SEND_BLOCKED; + } } else { PLOG(PL_WARN, "MgenAppSinkTransport::SendMessage() message sink buffer overflow\n"); - return false; + return MSG_SEND_BLOCKED; } struct timeval currentTime; ProtoSystemTime(currentTime); LogEvent(SEND_EVENT,&theMsg,currentTime,txBuffer); messages_sent++; - return true; + return MSG_SEND_OK; } // end MgenAppSinkTransport::SendMessage diff --git a/src/common/mgenEvent.cpp b/src/common/mgenEvent.cpp index 627f90d4..8242692b 100644 --- a/src/common/mgenEvent.cpp +++ b/src/common/mgenEvent.cpp @@ -15,7 +15,7 @@ MgenBaseEvent::MgenBaseEvent(Category theCategory) MgenEvent::MgenEvent() : MgenBaseEvent(MGEN), flow_id(0), event_type(INVALID_TYPE), src_port(0), - payload(0), count(-1),protocol(INVALID_PROTOCOL), tos(0), ttl(255),option_mask(0), + payload(0), count(-1),protocol(INVALID_PROTOCOL), tos(0), ttl(255),option_mask(0),df(DF_DEFAULT), queue(0),connect(false) { interface_name[0] = '\0'; @@ -131,6 +131,7 @@ const StringMapper MgenEvent::OPTION_LIST[] = {"RSVP", RSVP}, {"INTERFACE", INTERFACE}, {"TTL", TTL}, + {"DF",DF}, {"SEQUENCE", SEQUENCE}, {"LABEL",LABEL}, {"TXBUFFER",TXBUFFER}, @@ -442,6 +443,35 @@ bool MgenEvent::InitFromString(const char* string) while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; break; } + case DF: // df/fragmentation on or off + { + if (1 != sscanf(ptr, "%s", fieldBuffer)) + { + DMSG(0, "MgenEvent::InitFromString() DF Error: missing {on|off}\n"); + return false; + } + FragmentationStatus dfValue; + unsigned int len = strlen(fieldBuffer); + unsigned int i; + for (i = 0 ; i < len; i++) + fieldBuffer[i] = toupper(fieldBuffer[i]); + fieldBuffer[i] = '\0'; + if(!strncmp("ON", fieldBuffer, len)) + dfValue = DF_ON; + else if(!strncmp("OFF", fieldBuffer, len)) + dfValue = DF_OFF; + else + { + DMSG(0, "MgenEvent::InitFromString() DF Error: %s is neither on nor off\n", fieldBuffer); + return false; + } + df = dfValue; + // Set ptr to next field, skipping any white space + ptr += strlen(fieldBuffer); + while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; + break; + } // df + case TOS: // tos spec { if (1 != sscanf(ptr, "%s", fieldBuffer)) @@ -528,7 +558,7 @@ bool MgenEvent::InitFromString(const char* string) while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; break; - case TTL: // multicast ttl value + case TTL: // ttl value { if (1 != sscanf(ptr, "%s", fieldBuffer)) { @@ -543,7 +573,7 @@ bool MgenEvent::InitFromString(const char* string) } if (ttlValue > 255) { - DMSG(0, "MgenEvent::InitFromString() Error: invalid \n"); + DMSG(0, "MgenEvent::InitFromString() Error: invalid \n"); return false; } ttl = ttlValue; @@ -552,7 +582,6 @@ bool MgenEvent::InitFromString(const char* string) while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; break; } - case SEQUENCE: // sequence number initialization { if (1 != sscanf(ptr, "%s", fieldBuffer)) diff --git a/src/common/mgenFlow.cpp b/src/common/mgenFlow.cpp index 4bd99955..9987a65a 100644 --- a/src/common/mgenFlow.cpp +++ b/src/common/mgenFlow.cpp @@ -1,6 +1,7 @@ #include "mgenFlow.h" #include "mgenMsg.h" #include "mgen.h" +#include "mgenGlobals.h" #include // for gmtime(), struct tm, etc #ifndef ENABLE_EVENT_VALIDATION @@ -19,7 +20,7 @@ MgenFlow::MgenFlow(unsigned int flowId, flow_transport(NULL), seq_num(0), pending_messages(0), next_event(NULL), - started(false), timer_mgr(timerMgr), + started(false), socket_error(false),timer_mgr(timerMgr), controller(theController), mgen(theMgen), pending_next(NULL), @@ -59,8 +60,9 @@ bool MgenFlow::InsertEvent(MgenEvent* theEvent, bool mgenStarted, double current if (ValidateEvent(theEvent)) { Update(theEvent); - // LJT event-test +#ifdef _VALIDATE_EVENTS_OFF event_list.Remove(theEvent); +#endif // _VALIDATE_EVENTS_OFF } else { @@ -116,7 +118,7 @@ bool MgenFlow::ValidateEvent(const MgenEvent* event) { #ifdef _VALIDATE_EVENTS_OFF return true; -#endif +#endif // _VALIDATE_EVENTS_OFF const MgenEvent* prevEvent = (MgenEvent*)event->Prev(); MgenEvent::Type prevType = prevEvent ? prevEvent->GetType() : MgenEvent::INVALID_TYPE; @@ -229,10 +231,20 @@ bool MgenFlow::DoOnEvent(const MgenEvent* event) // 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()); + + // Temporarily commenting this code out in order to reuse any + // existing sockets as having multiple sockets listening/sending + // to a common port is broken when we have socket errors (like + // no route). The listening socket will not get all packets from + // all sources when a sending socket is closed that is sending + // to the same port. We can not guarantee that all the messages + // are sent before the flow is turned off with this change as the + // transport keeps track of the message limit, not the flow. Not sure + // what the permanent solution is yet. + //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(),event->GetInterface(),false,event->GetConnect()); if (!flow_transport) { @@ -328,18 +340,22 @@ bool MgenFlow::DoModEvent(const MgenEvent* event) if (flow_transport != NULL) src_port = flow_transport->GetSrcPort(); ProtoAddress tmpDstAddr = dst_addr; - + if (event->OptionIsSet(MgenEvent::SRC)) {tmpSrcPort = event->GetSrcPort();} if (event->OptionIsSet(MgenEvent::DST)) {tmpDstAddr = event->GetDstAddr();} - // If we're not changing socket src/dst addr or - // connection status, return. + // If we're not changing socket src/dst addr + // connection status, or transport, return. if (((tmpSrcPort == src_port) && (dst_addr.IsEqual(tmpDstAddr))) - && ((event->OptionIsSet(MgenEvent::CONNECT) - && flow_transport->IsConnected()) - || - (!event->OptionIsSet(MgenEvent::CONNECT) - && !flow_transport->IsConnected()))) + && + ((event->OptionIsSet(MgenEvent::INTERFACE) + && !strcmp(event->GetInterface(), flow_transport->GetInterface()))) + && + ((event->OptionIsSet(MgenEvent::CONNECT) + && flow_transport->IsConnected()) + || + (!event->OptionIsSet(MgenEvent::CONNECT) + && !flow_transport->IsConnected()))) return true; @@ -408,6 +424,7 @@ bool MgenFlow::DoModEvent(const MgenEvent* event) // or numBytes read == 0) and we'll log the off/disconnect // event then if (old_transport && !old_transport->TransmittingFlow(flow_id)) + { if (old_transport->Shutdown()) { // Log shutdown event if we've shutdown the socket @@ -428,7 +445,7 @@ bool MgenFlow::DoModEvent(const MgenEvent* event) if (old_transport->IsOpen()) old_transport->Close(); old_transport = NULL; } - + } // If we're not changing the src port, get the transport // that matches the original src port as we want to retain @@ -440,6 +457,7 @@ bool MgenFlow::DoModEvent(const MgenEvent* event) flow_transport = mgen.GetMgenTransport(protocol, src_port, dst_addr, + event->GetInterface(), false, event->GetConnect()); if (!flow_transport) return false; @@ -507,7 +525,7 @@ bool MgenFlow::Update(const MgenEvent* event) { #ifndef _VALIDATE_EVENTS_OFF ASSERT(!tx_timer.IsActive()); -#endif +#endif // _VALIDATE_EVENTS_OFF if (!DoOnEvent(event)) return false; // Note the lack of "break" here is _intentional_ @@ -517,13 +535,11 @@ 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! @@ -580,17 +596,28 @@ bool MgenFlow::Update(const MgenEvent* event) // we've already handled the drec event off_pending = true; - flow_transport->AppendFlow(this); - flow_transport->StartOutputNotification(); - - if (tx_timer.IsActive()) tx_timer.Deactivate(); - break; + flow_transport->AppendFlow(this); + // If we had a socket error, we stopped output notification + // for the transport and turned on a tx_timer to check + // socket readiness. We only set socket_error for flows + // with unlimited transmission rates and checking output + // readiness for these sockets can overwhelm mgen, therefore + // don't restart it here! Let the flow notice the off_pending + // when it tries to send the next message. + if (!socket_error) + { + flow_transport->StartOutputNotification(); + + if (tx_timer.IsActive()) tx_timer.Deactivate(); + break; + } } // Inform rapr so it can reuse the flowid if (controller) { - char buffer [512]; + + char buffer [512]; sprintf(buffer, "offevent flow>%lu", (unsigned long)flow_id); unsigned int len = strlen(buffer); controller->OnOffEvent(buffer,len); @@ -685,14 +712,6 @@ void MgenFlow::StopFlow() 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; @@ -765,7 +784,7 @@ bool MgenFlow::SendMessage() return false; } - if (!flow_transport || message_limit > 0 && flow_transport->GetMessagesSent() >= 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 @@ -888,56 +907,82 @@ bool MgenFlow::SendMessage() // Send message, checking for error // (log only on success) char txBuffer[MAX_SIZE]; - bool success = false; - + MessageStatus result; // txbuffer only used by udp and sink transports if (flow_transport != NULL) - success = flow_transport->SendMessage(theMsg,dst_addr,txBuffer); + result = flow_transport->SendMessage(theMsg,dst_addr,txBuffer); else - success = 0; + result = MSG_SEND_FAILED; - if (!success) - { - // message was not sent, so sequence number is decremented back one + if (result == MSG_SEND_OK) + { + if (GetPending()) pending_messages--; + + // If we had a previous socket failure for flows with + // unlimited transmission we may have set a timer. If + // so deactivate it and let the flow be managed by + // socket output readiness + if (pattern.UnlimitedRate() && tx_timer.IsActive() && socket_error) + { + socket_error = false; + tx_timer.Deactivate(); + flow_transport->StartOutputNotification(); + } + return true; + } + + // message was not sent, so sequence number is decremented back one #ifndef _RAPR_JOURNAL - PLOG(PL_DEBUG, "MgenFlow::SendMessage() error sending message flow>%d seq>%d.\n",flow_id,(seq_num -1)); - seq_num--; + PLOG(PL_DEBUG, "MgenFlow::SendMessage() error sending message flow>%d seq>%d.\n",flow_id,(seq_num -1)); + seq_num--; #else - PLOG(PL_DEBUG, "MgenFlow::SendMessage() error sending message flow>%d seq>%d.\n",flow_id,MgenSequencer::GetSequence(flow_id)); - // rollback sequence number... - MgenSequencer::GetPrevSequence(flow_id); + PLOG(PL_DEBUG, "MgenFlow::SendMessage() error sending message flow>%d seq>%d.\n",flow_id,MgenSequencer::GetSequence(flow_id)); + // rollback sequence number... + MgenSequencer::GetPrevSequence(flow_id); #endif - - // Let the transport notify us when it's ready - // Note that we may have already shutdown the transport - // if the send failed due to a socket disconnect, and - // set flow_transport to NULL... + + // Let the transport notify us when it's ready + // Note that we may have already shutdown the transport + // if the send failed due to a socket disconnect, and + // set flow_transport to NULL... - if ((queue_limit != 0 || pattern.UnlimitedRate()) - && flow_transport && flow_transport->IsConnected()) - { - pending_messages++; - flow_transport->AppendFlow(this); - flow_transport->StartOutputNotification(); + if ((queue_limit != 0 || pattern.UnlimitedRate()) + && flow_transport && flow_transport->IsConnected()) + { + pending_messages++; + flow_transport->AppendFlow(this); + + if (queue_limit > 0 && pending_messages >= queue_limit) + if (tx_timer.IsActive()) tx_timer.Deactivate(); + + // We only want to start output notification if + // the socket was blocked (EWOULDBLOCK) + if (result == MSG_SEND_BLOCKED) + flow_transport->StartOutputNotification(); + + // If we have an unlimited transmission rate and socket + // failure, stop output notification. MgenFlow::OnTxTimeout + // will set a timer to test socket readiness at larger + // intervals that socket output notification uses + if ((result == MSG_SEND_FAILED) + && pattern.UnlimitedRate()) + { + flow_transport->StopOutputNotification(); + socket_error = true; + tx_timer.SetInterval(0.001); + if (!tx_timer.IsActive()) + timer_mgr.ActivateTimer(tx_timer); - if (queue_limit > 0 && pending_messages >= queue_limit) - if (tx_timer.IsActive()) tx_timer.Deactivate(); - } - } - else - { - if (GetPending()) pending_messages--; - } + } + } - return success; + return false; } // MgenFlow::SendMessage - bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) { - - if (!flow_transport || message_limit > 0 && flow_transport->GetMessagesSent() >= message_limit) + if (!flow_transport || (message_limit > 0 && flow_transport->GetMessagesSent() >= message_limit)) { // deactivate timer and stopMgenSequencer flow immediately rather than // waiting for an OFF_EVENT . @@ -989,10 +1034,15 @@ bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) return true; } // Don't process OFF event if we have pending messages - // or are still sending a message for this flow + // or are still sending a message for this flow. If we have + // a socket_error however, we are sending messages + // as fast as possible and have already stopped output + // notification and started a timer to keep mgen from + // thrashing - just go ahead and stop the flow at this point. if (off_pending) { - if (flow_transport->TransmittingFlow(flow_id) || GetPending() > 0) + if (flow_transport->TransmittingFlow(flow_id) || (!socket_error && GetPending() > 0)) + //if (flow_transport->TransmittingFlow(flow_id) || GetPending() > 0) { if (tx_timer.IsActive()) tx_timer.Deactivate(); flow_transport->AppendFlow(this); @@ -1032,32 +1082,39 @@ bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) } } - // If we have any pending flows, wait till they - // get serviced via output notification - if (flow_transport && flow_transport->HasPendingFlows()) - { - flow_transport->StartOutputNotification(); - - if (queue_limit > 0) - { - pending_messages++; - flow_transport->AppendFlow(this); - } - // If we've exceeded our queue limit, turn off the timer - // we'll restart it when the queue gets below the limit, - // unless we have an unlimited queue size (queue_limit -1) - // or we're sending packets as fast as possible - if ((queue_limit > 0 && pending_messages >= queue_limit) - && (!pattern.UnlimitedRate())) // ljt should we allow queue limits for unlimited rates? - { - if (tx_timer.IsActive()) tx_timer.Deactivate(); - return false; // don't want to fail twice! - } - else - { - return GetNextInterval(); - } - } + // If we have an unlimited rate and have had a socket + // error - try to send the message to test socket + // readiness. Otherwise service any pending flows + // the transport might have first using socket output + // notification to send as fast as possible + if ((flow_transport && flow_transport->HasPendingFlows()) + && (!pattern.UnlimitedRate() && !socket_error)) + + { + // If we have an unlimited transmission rate and have had + // a socket error don't start output notification in this + // case we will use a tx_timer to prevent thrashing until + // the condition is resolved + flow_transport->StartOutputNotification(); + + if (queue_limit > 0) + { + pending_messages++; + flow_transport->AppendFlow(this); + } + // If we've exceeded our queue limit, turn off the timer + // we'll restart it when the queue gets below the limit, + // unless we have an unlimited queue size (queue_limit -1) + // or we're sending packets as fast as possible + if ((queue_limit > 0 && pending_messages >= queue_limit) + && (!pattern.UnlimitedRate())) // ljt should we allow queue limits for unlimited rates? + { + if (tx_timer.IsActive()) tx_timer.Deactivate(); + return false; // don't want to fail twice! + } + else + return GetNextInterval(); + } if (!flow_transport) { @@ -1069,7 +1126,7 @@ bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) // If we have an unlimited rate, turn off the transmission // timer. If we add it to the pending queue the transport send // functions will send messages as fast as possible. - if (pattern.UnlimitedRate()) + if (pattern.UnlimitedRate() && !socket_error) { flow_transport->AppendFlow(this); flow_transport->StartOutputNotification(); @@ -1077,7 +1134,19 @@ bool MgenFlow::OnTxTimeout(ProtoTimer& /*theTimer*/) return false; } else - return GetNextInterval(); + // else if we have an unlimited rate and a socket_error + // schedule a transmission timer at 100 milliseconds + // to prevent thrashing + if (pattern.UnlimitedRate() && socket_error) + { + tx_timer.SetInterval(0.001); + if (!tx_timer.IsActive()) + timer_mgr.ActivateTimer(tx_timer); + return true; + } + else + return GetNextInterval(); + } // end MgenFlow::OnTxTimeout() @@ -1127,8 +1196,9 @@ bool MgenFlow::OnEventTimeout(ProtoTimer& /*theTimer*/) // 1) Update flow as needed using "next_event" Update(next_event); - // ljt event test +#ifdef _VALIDATE_EVENTS_OFF MgenEvent* processedEvent = next_event; +#endif // _VALIDATE_EVENTS_OFF // 2) Set (or kill) event_timer according to "next_event->next" double currentTime = next_event->GetTime(); @@ -1138,8 +1208,9 @@ 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 +#ifdef _VALIDATE_EVENTS_OFF event_list.Remove(processedEvent); +#endif // _VALIDATE_EVENTS_OFF return true; } else @@ -1148,8 +1219,9 @@ bool MgenFlow::OnEventTimeout(ProtoTimer& /*theTimer*/) if (event_timer.IsActive()) #endif // _VALIDATE_EVENTS_OFF event_timer.Deactivate(); - // ljt event test +#ifdef _VALIDATE_EVENTS_OFF event_list.Remove(processedEvent); +#endif // _VALIDATE_EVENTS_OFF return false; } } // end MgenFlow::OnEventTimeout() diff --git a/src/common/mgenPattern.cpp b/src/common/mgenPattern.cpp index 36f70cdf..7b976ae2 100644 --- a/src/common/mgenPattern.cpp +++ b/src/common/mgenPattern.cpp @@ -197,7 +197,7 @@ MgenPattern::FileType MgenPattern::GetFileTypeFromString(const char* string) } // end MgenPattern::GetFileTypeFromString() #endif //_HAVE_PCAP -bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string,Protocol protocol) +bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string, Protocol protocol) { type = theType; switch (type) @@ -207,11 +207,36 @@ bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string,P { double aveRate; - if (2 != sscanf(string, "%lf %u\n", &aveRate, &pkt_size)) + char sizeText[256]; + if (2 != sscanf(string, "%lf %256s", &aveRate, sizeText)) { DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid parameters.\n"); return false; } + // Look for colon delimiter to indicate variable packet size + if (NULL != strchr(sizeText, ':')) + { + if (2 != sscanf(sizeText, "%u:%u", &pkt_size_min, &pkt_size_max)) + { + DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid variable parameter.\n"); + return false; + } + else if (pkt_size_min > pkt_size_max) + { + unsigned int temp = pkt_size_min; + pkt_size_min = pkt_size_max; + pkt_size_max = temp; + } + } + else if (1 != sscanf(sizeText, "%u", &pkt_size_min)) + { + DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid parameter.\n"); + return false; + } + else + { + pkt_size_max = pkt_size_min; + } if (aveRate < 0.0) { if (-1.0 != aveRate) @@ -221,8 +246,8 @@ bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string,P } else { - unlimitedRate = true; - interval_ave = 0.0; + unlimitedRate = true; + interval_ave = 0.0; } } else if (aveRate > 0.0) @@ -231,35 +256,62 @@ bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string,P } else { - interval_ave = -1.0; + interval_ave = -1.0; } - if (protocol == TCP) - { - // unlimited message size for TCP?? - if ((pkt_size < MIN_FRAG_SIZE)) - { - DMSG(0,"MgenPattern::InitFromString(PERIODIC/POISSON) error: packet size must be greater than the minimum fragment size: %d.\n",MIN_FRAG_SIZE); - return false; - } - } - else { - if ((pkt_size > MAX_SIZE) || (pkt_size < MIN_SIZE)) + if (UDP != protocol) { - DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid message size.\n"); - return false; + // unlimited message size for non-UDP protocols + if ((pkt_size_min < MIN_FRAG_SIZE)) + { + DMSG(0,"MgenPattern::InitFromString(PERIODIC/POISSON) error: packet size must be greater than the minimum fragment size: %d.\n",MIN_FRAG_SIZE); + return false; + } + } + else + { + // Typically operating systems limit UDP datagrams to 8192 byte payloads? + if ((pkt_size_max > MAX_SIZE) || (pkt_size_min < MIN_SIZE)) + { + DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid message size.\n"); + return false; + } } - } break; } - case JITTER: + case JITTER: // form " " { double aveRate, jitterFraction; interval_remainder = 0.0; - if (3 != sscanf(string, "%lf %u %lf\n", &aveRate, &pkt_size, &jitterFraction)) + char sizeText[256]; + if (3 != sscanf(string, "%lf %256s %lf", &aveRate, sizeText, &jitterFraction)) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid parameters.\n"); return false; } + // Look for colon delimiter to indicate variable packet size + if (NULL != strchr(sizeText, ':')) + { + if (2 != sscanf(sizeText, "%u:%u", &pkt_size_min, &pkt_size_max)) + { + DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid variable parameter.\n"); + return false; + } + else if (pkt_size_min > pkt_size_max) + { + unsigned int temp = pkt_size_min; + pkt_size_min = pkt_size_max; + pkt_size_max = temp; + } + } + else if (1 != sscanf(sizeText, "%u", &pkt_size_min)) + { + DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid parameter.\n"); + return false; + } + else + { + pkt_size_max = pkt_size_min; + } if ((jitterFraction < 0.0) || (jitterFraction > 0.5)) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid jitter fraction.\n"); @@ -294,11 +346,24 @@ bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string,P { jitter_min = jitter_max = interval_ave; } - if ((pkt_size > MAX_SIZE) || (pkt_size < MIN_SIZE)) + if (UDP != protocol) + { + // unlimited message size for non-UDP protocols + if ((pkt_size_min < MIN_FRAG_SIZE)) + { + DMSG(0,"MgenPattern::InitFromString(JITTER) error: packet size must be greater than the minimum fragment size: %d.\n",MIN_FRAG_SIZE); + return false; + } + } + else { - DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid message size.\n"); - return false; - } + // Typically operating systems limit UDP datagrams to 8192 byte payloads? + if ((pkt_size_max > MAX_SIZE) || (pkt_size_min < MIN_SIZE)) + { + DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid message size.\n"); + return false; + } + } break; } @@ -518,15 +583,15 @@ bool MgenPattern::OpenPcapDevice() double MgenPattern::RestartPcapRead(double& prevTime) { - struct pcap_pkthdr header; - const u_char *packet = NULL; + struct pcap_pkthdr header; + const u_char *packet = NULL; - if (!OpenPcapDevice()) - return -1; // open failed + if (!OpenPcapDevice()) + return -1; // open failed - // Get interval between 1st & 2nd pkts (A). Schedule 2nd packet - // in file to be sent (A) seconds after the last pkt in the file - if (pcap_next(pcap_device,&header)) // Get 1st pkt in file + // Get interval between 1st & 2nd pkts (A). Schedule 2nd packet + // in file to be sent (A) seconds after the last pkt in the file + if (pcap_next(pcap_device,&header)) // Get 1st pkt in file { // Save the time as a double for interval calculation prevTime = (header.ts.tv_sec * 1.0 + header.ts.tv_usec * 1.0e-6); @@ -534,10 +599,10 @@ double MgenPattern::RestartPcapRead(double& prevTime) packet = pcap_next(pcap_device,&header); // Get 2nd pkt in file } - if (packet) + if (packet) { // force minimum mgen length. (check for ipv6 ultimately) - pkt_size = (header.len - 42) > 28 ? (header.len -42) : 28;; + pkt_size_min = pkt_size_max = (header.len - 42) > 28 ? (header.len - 42) : 28;; // calculate interval (A) double interval = ((header.ts.tv_sec * 1.0 + header.ts.tv_usec * 1.0e-6) - prevTime); @@ -656,7 +721,7 @@ double MgenPattern::GetPktInterval() if (packet) { // force minimum mgen length. (check for ipv6 ultimately) - pkt_size = (header.len - 42) > 28 ? (header.len -42) : 28;; + pkt_size_min = pkt_size_max = (header.len - 42) > 28 ? (header.len -42) : 28;; if (firstPacket) firstPacket = false; @@ -696,9 +761,9 @@ double MgenPattern::GetPktInterval() break; } #endif //_HAVE_PCAP - case INVALID_TYPE: - ASSERT(0); - break; + case INVALID_TYPE: + ASSERT(0); + break; } // end switch(type) return -1.0; } // end MgenPattern::GetPktInterval() @@ -709,15 +774,19 @@ unsigned int MgenPattern::GetPktSize() { case PERIODIC: case POISSON: + case JITTER: + if (pkt_size_min != pkt_size_max) + return UniformRandUnsigned(pkt_size_min, pkt_size_max); + else + return pkt_size_min; + break; + #ifdef _HAVE_PCAP case CLONE: #endif //_HAVE_PCAP - return pkt_size; - return pkt_size; + return pkt_size_min; case BURST: return burst_pattern->GetPktSize(); - case JITTER: - return pkt_size; case INVALID_TYPE: ASSERT(0); break; diff --git a/src/common/mgenPayloadMgrApp.cpp b/src/common/mgenPayloadMgrApp.cpp index bda59438..20bee1cf 100644 --- a/src/common/mgenPayloadMgrApp.cpp +++ b/src/common/mgenPayloadMgrApp.cpp @@ -65,11 +65,6 @@ 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"); diff --git a/src/common/mgenTransport.cpp b/src/common/mgenTransport.cpp index b6bbd0e8..d8ca261c 100644 --- a/src/common/mgenTransport.cpp +++ b/src/common/mgenTransport.cpp @@ -3,6 +3,7 @@ #include "mgenMsg.h" #include "protoSocket.h" #include "protoChannel.h" +#include "mgenGlobals.h" #ifndef _WIN32_WCE // JPH 6/8/06 #include // for EAGAIN @@ -152,9 +153,8 @@ void MgenTransport::AppendFlow(MgenFlow* const theFlow) void MgenTransport::RemoveFlow(MgenFlow* theFlow) { // ljt rewrite? - MgenFlow *next,*prev,*pendingCurrent; + MgenFlow *next,*prev; prev = NULL; - pendingCurrent = pending_current; for (next = pending_head; next != NULL; prev = next, next = next->GetPendingNext()) { if (next == theFlow) @@ -214,55 +214,57 @@ bool MgenTransport::SendPendingMessage() while (IsOpen() && !IsTransmitting() && pending_current) { - if ((pending_current->GetPending() > 0) || - pending_current->UnlimitedRate()) - if (!pending_current->SendMessage()) return false; - - // Restart flow timer if we're below the queue limit - if ((pending_current->QueueLimit() > 0 && - (pending_current->GetPending() < pending_current->QueueLimit())) - || - (pending_current->QueueLimit() < 0 && - !(pending_current->GetPending() > 0)) // ljt don't think we need - // this anymore if we're - // just restarting the timer? - || - pending_current->QueueLimit() == 0) // Tcp finally connected? - + if ((pending_current->GetPending() > 0) || + pending_current->UnlimitedRate()) + { + if (!pending_current->SendMessage()) return false; + } + + // Restart flow timer if we're below the queue limit + if ((pending_current->QueueLimit() > 0 && + (pending_current->GetPending() < pending_current->QueueLimit())) + || + (pending_current->QueueLimit() < 0 && + !(pending_current->GetPending() > 0)) // ljt don't think we need + // this anymore if we're + // just restarting the timer? + || + pending_current->QueueLimit() == 0) // Tcp finally connected? + { - // Don't restart the timer if our rate is unlimited... + // Don't restart the timer if our rate is unlimited... if (!pending_current->UnlimitedRate()) - - pending_current->RestartTimer(); + + pending_current->RestartTimer(); } - - // If we've sent all pending messages, - // remove flow from pending list. - if (!pending_current->GetPending() && - !pending_current->UnlimitedRate()) + + // If we've sent all pending messages, + // remove flow from pending list. + if (!pending_current->GetPending() && + !pending_current->UnlimitedRate()) { - RemoveFromPendingList(); //ljt remove this function - // or replace remove flow - // why istn' this getting called?? - //RemoveFlow(pending_current); - continue; + RemoveFromPendingList(); //ljt remove this function + // or replace remove flow + // why istn' this getting called?? + //RemoveFlow(pending_current); + continue; } - pending_current = pending_current->GetPendingNext(); - - // cycle back to head of queue if we - // reached the end. - if (!pending_current && pending_head) - pending_current = pending_head; - + pending_current = pending_current->GetPendingNext(); + + // cycle back to head of queue if we + // reached the end. + if (!pending_current && pending_head) + pending_current = pending_head; + } // Resume normal operations if (!IsTransmitting() && !HasPendingFlows()) - { + { StopOutputNotification(); - } - + } + return true; - + } // end MgenTransport::SendPendingMessage() void MgenTransport::RemoveFromPendingList() @@ -439,7 +441,8 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, UINT16 thePort) : MgenTransport(theMgen,theProtocol,thePort), broadcast(false), - tos(0), tx_buffer(0), rx_buffer(0),ttl(0), + tos(0), tx_buffer(0), rx_buffer(0),multicast_ttl(0),unicast_ttl(0), + df(DF_DEFAULT), socket(GetSocketProtocol(theProtocol)) { interface_name[0] = '\0'; @@ -447,7 +450,9 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, // set defaults SetBroadcast(theMgen.GetDefaultBroadcast()); - SetTTL(theMgen.GetDefaultTtl()); + SetMulticastTTL(theMgen.GetDefaultMulticastTtl()); + SetUnicastTTL(theMgen.GetDefaultUnicastTtl()); + SetDF(theMgen.GetDefaultDF()); SetTOS(theMgen.GetDefaultTos()); SetTxBufferSize(theMgen.GetDefaultTxBuffer()); SetRxBufferSize(theMgen.GetDefaultRxBuffer()); @@ -460,7 +465,8 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, const ProtoAddress& theDstAddress) : MgenTransport(theMgen,theProtocol,thePort,theDstAddress), broadcast(false), - tos(0), tx_buffer(0), rx_buffer(0),ttl(0), + tos(0), tx_buffer(0), rx_buffer(0),multicast_ttl(0),unicast_ttl(0), + df(DF_DEFAULT), socket(GetSocketProtocol(theProtocol)) { interface_name[0] = '\0'; @@ -468,7 +474,9 @@ MgenSocketTransport::MgenSocketTransport(Mgen& theMgen, // set defaults SetBroadcast(theMgen.GetDefaultBroadcast()); - SetTTL(theMgen.GetDefaultTtl()); + SetMulticastTTL(theMgen.GetDefaultMulticastTtl()); + SetUnicastTTL(theMgen.GetDefaultUnicastTtl()); + SetDF(theMgen.GetDefaultDF()); SetTOS(theMgen.GetDefaultTos()); SetTxBufferSize(theMgen.GetDefaultTxBuffer()); SetRxBufferSize(theMgen.GetDefaultRxBuffer()); @@ -496,10 +504,24 @@ void MgenSocketTransport::SetEventOptions(const MgenEvent* event) if (!SetTOS(event->GetTOS())) DMSG(0, "MgenFlow::Update() error setting socket TOS value\n"); } + if (event->OptionIsSet(MgenEvent::DF)) + { + if (!SetDF(event->GetDF())) + DMSG(0,"MgenFlow::Update() error setting DF value\n"); + } if (event->OptionIsSet(MgenEvent::TTL)) { - if (!SetTTL(event->GetTTL())) - DMSG(0, "MgenFlow::Update() error setting socket TTL\n"); + + if (event->GetDstAddr().IsMulticast()) + { + if (!SetMulticastTTL(event->GetTTL())) + DMSG(0, "MgenFlow::Update() error setting socket multicast TTL\n"); + } + else + { + if (!SetUnicastTTL(event->GetTTL())) + DMSG(0, "MgenFlow::Update() error setting socket unicast TTL\n"); + } } if (event->OptionIsSet(MgenEvent::INTERFACE) && GetProtocol() == UDP) { @@ -509,10 +531,10 @@ void MgenSocketTransport::SetEventOptions(const MgenEvent* event) } // end MgenSocketTransport::SetEventOptions -bool MgenSocketTransport::SetTTL(unsigned char ttlValue) +bool MgenSocketTransport::SetMulticastTTL(unsigned char ttlValue) { - ttl = ttlValue; + multicast_ttl = ttlValue; if (protocol == TCP) return true; @@ -524,6 +546,32 @@ bool MgenSocketTransport::SetTTL(unsigned char ttlValue) return true; } // end MgenSocketTransport::SetTTL() +bool MgenSocketTransport::SetUnicastTTL(unsigned char ttlValue) +{ + + unicast_ttl = ttlValue; + if (protocol == TCP) + return true; + + if (socket.IsOpen()) + { + if (!socket.SetUnicastTTL(ttlValue)) + return false; + } + return true; +} // end MgenSocketTransport::SetTTL() + +bool MgenSocketTransport::SetDF(FragmentationStatus dfValue) +{ + df = dfValue; + if (socket.IsOpen()) + { + if (!socket.SetFragmentation(dfValue)) + return false; + } + return true; +} // MgenSocketTransport::SetDF() + bool MgenSocketTransport::SetTOS(unsigned char tosValue) { if (socket.IsOpen()) @@ -622,9 +670,15 @@ bool MgenSocketTransport::Open(ProtoAddress::Type addrType, bool bindOnOpen) if (tos) socket.SetTOS(tos); - if (ttl >= 0) - socket.SetTTL(ttl); + if (socket.GetProtocol() != ProtoSocket::TCP && multicast_ttl >= 0) + socket.SetTTL(multicast_ttl); + + if (unicast_ttl >= 0) + socket.SetUnicastTTL(unicast_ttl); + if (df != DF_DEFAULT) + socket.SetFragmentation(df); + if ('\0' != interface_name[0]) socket.SetMulticastInterface(interface_name); @@ -641,7 +695,7 @@ bool MgenSocketTransport::Listen(UINT16 port,ProtoAddress::Type addrType, bool b { if (!socket.Bind(port)) { - DMSG(0,"MgenTransportList;:MgenSocketTransport::Listen() Error: socket bind error on port %hu\n"); + DMSG(0,"MgenTransportList;:MgenSocketTransport::Listen() Error: socket bind error on port %hu\n",port); return false; } } @@ -902,7 +956,7 @@ void MgenUdpTransport::OnEvent(ProtoSocket& theSocket, ProtoSocket::Event theEve } } // end MgenUdpTransport::OnEvent() -bool MgenUdpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) +MessageStatus MgenUdpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) { // Udp packets are single shot and larger than @@ -916,27 +970,34 @@ bool MgenUdpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, unsigned int len = theMsg.Pack(txBuffer,theMsg.GetMsgLen(),mgen.GetChecksumEnable(),txChecksum); if (len == 0) - return false; // no room + return MSG_SEND_FAILED; // no room if (mgen.GetChecksumEnable() && theMsg.FlagIsSet(MgenMsg::CHECKSUM)) theMsg.WriteChecksum(txChecksum,(unsigned char*)txBuffer,(UINT32)len); - if (!socket.SendTo(txBuffer,len,dst_addr)) - { + bool result = socket.SendTo(txBuffer,len,dst_addr); + + // If result is true but numBytes == 0 + // we had an EWOULDBLOCK condition + if (result && len == 0) + return MSG_SEND_BLOCKED; + + // We had some other socket failure + if (!result) + { #ifndef _WIN32_WCE - if ((EAGAIN != errno) && (ENOBUFS != errno)) - DMSG(PL_WARN, "MgenUdpTransport::SendMessage() socket.SendTo() error: %s\n", GetErrorString()); - else + if ((EAGAIN != errno) && (ENOBUFS != errno)) + DMSG(PL_WARN,"MgenUdpTransport::SendMessage() socket.SendTo() error: %s\n", GetErrorString()); + else #endif // !_WIN32_WCE - DMSG(PL_WARN, "MgenUdpTransport::SendMessage() socket.SendTo() error: %s\n", GetErrorString()); - return false; - } + DMSG(PL_WARN,"MgenUdpTransport::SendMessage() socket.SendTo() error: %s\n", GetErrorString()); + return MSG_SEND_FAILED; + } - /* 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; + return MSG_SEND_OK; + } // end MgenUdpTransport::SendMessage bool MgenUdpTransport::Listen(UINT16 port,ProtoAddress::Type addrType, bool bindOnOpen) @@ -1062,7 +1123,7 @@ void MgenTcpTransport::OnEvent(ProtoSocket& theSocket,ProtoSocket::Event theEven // Get a transport with a closed socket since we need to have // transport with a different socket to hold the accepted connection - MgenTransport* newMgenTransport = mgen.GetMgenTransport(TCP,theSocket.GetPort(),theSocket.GetDestination(),true); + MgenTransport* newMgenTransport = mgen.GetMgenTransport(TCP,theSocket.GetPort(),theSocket.GetDestination(),GetInterface(),true); if (!newMgenTransport) return; @@ -1131,11 +1192,11 @@ void MgenTcpTransport::OnEvent(ProtoSocket& theSocket,ProtoSocket::Event theEven * function.) */ -bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) +MessageStatus MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr,char* txBuffer) { // But not if the transport is transmitting anything... if (tx_msg_offset != 0) - return false; + return MSG_SEND_BLOCKED; // Set the transport's tx_msg to the loaded msg tx_msg = theMsg; @@ -1145,10 +1206,10 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, 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 fragment pending!\n"); + return MSG_SEND_FAILED; + } // Send message, checking for error (log only on success) @@ -1162,7 +1223,7 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, if (tx_buffer_pending != 0 && numBytes == 0) { StartOutputNotification(); - return true; + return MSG_SEND_BLOCKED; } // Otherwise keep track of what we've sent @@ -1207,7 +1268,7 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, messages_sent++; StopOutputNotification(); // ljt 0516 - check if we need this? // we may still have pending stuff! - return true; + return MSG_SEND_OK; } continue; } // other socket failure @@ -1216,12 +1277,12 @@ bool MgenTcpTransport::SendMessage(MgenMsg& theMsg,const ProtoAddress& dst_addr, 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; + ResetTxMsgState(); + StopOutputNotification(); // ljt 0516 delete me? + return MSG_SEND_FAILED; } } - return false; // shouldn't fall thru! + return MSG_SEND_FAILED; // shouldn't fall thru! } // end MgenTcpTransport::SendMessage /** @@ -1238,8 +1299,8 @@ void MgenTcpTransport::ShutdownTransport(LogEventType eventType) ProtoSystemTime(currentTime); tx_msg.GetSrcAddr().SetPort(GetSrcPort()); LogEvent(eventType,&tx_msg,currentTime); - Shutdown(); - if (IsOpen()) Close(); + Shutdown(); + if (IsOpen()) Close(); } else { @@ -1445,6 +1506,7 @@ bool MgenTcpTransport::Accept(ProtoSocket& theSocket) if (tx_buffer) socket.SetTxBufferSize(tx_buffer); if (rx_buffer) socket.SetRxBufferSize(rx_buffer); if (tos) socket.SetTOS(tos); + if (df != DF_DEFAULT) socket.SetFragmentation(df); // no ttl or multicast interface for tcp sockets reference_count++; SetDstAddr(socket.GetDestination()); diff --git a/src/python/gpsFaker.py b/src/python/gpsFaker.py new file mode 100644 index 00000000..85d21787 --- /dev/null +++ b/src/python/gpsFaker.py @@ -0,0 +1,85 @@ +import _gpsPub as gpsPub +import argparse +import ctypes +import datetime +import random +import math +import threading +import time + +class timeval(): + def __init__(self,tv_sec=0.0,tv_usec=0.0): + self.tv_sec = tv_sec + self.tv_usec = tv_usec + _fields_ = [("tv_sec", ctypes.c_long),("tv_usec", ctypes.c_long)] + +class GPSPosition(): + def __init__(self,x,y,z,gps_time_sec=0,gps_time=0,sys_time=0,xyvalid=True,zvalid=True,tvalid=True,stale=False): + self.x = x + self.y = y + self.z = z + self.gps_time = gps_time + self.sys_time = sys_time + self.xyvalid = xyvalid + self.zvalid = zvalid + self.tvalid = tvalid + self.stale = stale + + _fields_ = [("x",ctypes.c_double),("y",ctypes.c_double),("z",ctypes.c_double),("gpsTime",timeval),("sysTime",timeval),("xyvalid",ctypes.c_int),("zvalid",ctypes.c_int),("tvalid",ctypes.c_int),("stale",ctypes.c_int)] + + +def publish_random_updates(handle,lon,lat,alt,interval,radius): + # Convert radius from meters to degrees + radiusInDegrees = radius / 111000.0 + + u = random.uniform(1,100) + v = random.uniform(1,100) + w = radiusInDegrees * math.sqrt(u) + t = 2 * math.pi * v + x = w * math.cos(t) + y = w * math.sin(t) + + # Adjust the x-coor for the shrinking of the east-west distances + # aren't we fancy + new_x = x / math.cos(lat) + + new_lon = new_x + lon + new_lat = y + lat + + print "lat %f lon %f " %(new_lat,new_lon) + + gpsPub.GPSPublishPos(handle,new_lat,new_lon,alt) + +def main(): + usagestr = "usage: %prog [-h] [options] [args]" + parser = argparse.ArgumentParser() + + parser.add_argument("-f",default="/tmp/gpskey",dest="gpsFile",type=str,help="Location of gps shared memory file") + parser.add_argument("--lat",default="38.828533",dest="lat",type=str,help="lat") + parser.add_argument("--lon",default="-77.028633",dest="lon",type=str,help="lon") + parser.add_argument("--alt",default="0.0",dest="alt",type=str,help="alt") + parser.add_argument("-r","--random",dest="random",action='store_true',help="Publish random gps reports. Enter lat,lon,alt to offset random reports from given location.") + parser.add_argument("-i","--interval",default="1",dest="interval",type=float,help="Publish interval") + parser.add_argument("--radius",default="200",dest="radius",type=int,help="Radius of gps reports from origin") + args = parser.parse_args() + + print args.gpsFile + lat = float(args.lat) + lon = float(args.lon) + alt = float(args.alt) + + handle = gpsPub.GPSPublishInit(args.gpsFile) + + if args.random is True: + while True: + publish_random_updates(handle,lon,lat,alt,args.interval,args.radius) + time.sleep(args.interval) + else: + gpsPub.GPSPublishPos(handle,lat,lon,alt) + + gpsPub.GPSPublishShutdown(handle,args.gpsFile) + +if __name__ == "__main__": + main() + + diff --git a/src/python/gpsPub_wrap.c b/src/python/gpsPub_wrap.c new file mode 100644 index 00000000..638d0dea --- /dev/null +++ b/src/python/gpsPub_wrap.c @@ -0,0 +1,4975 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.4 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_DIRECTOR_NO_VTABLE + +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIG_MSC_UNSUPPRESS_4505 +# if defined(_MSC_VER) +# pragma warning(disable : 4505) /* unreferenced local function has been removed */ +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic C API SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the SWIG runtime code. + In 99.9% of the cases, SWIG just needs to declare them as 'static'. + + But only do this if strictly necessary, ie, if you have problems + with your compiler or suchlike. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The SWIG conversion methods, as ConvertPtr, return an integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old versions of SWIG, code such as the following was usually written: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + which is the same really, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + also requires SWIG_ConvertPtr to return new result values, such as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + SWIG errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() +*/ + +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (strcmp(iter->type->name, c) == 0) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (iter->type == from) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + +/* Compatibility macros for Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + +#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) +#define PyInt_Check(x) PyLong_Check(x) +#define PyInt_AsLong(x) PyLong_AsLong(x) +#define PyInt_FromLong(x) PyLong_FromLong(x) +#define PyString_Check(name) PyBytes_Check(name) +#define PyString_FromString(x) PyUnicode_FromString(x) +#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) +#define PyString_AsString(str) PyBytes_AsString(str) +#define PyString_Size(str) PyBytes_Size(str) +#define PyString_InternFromString(key) PyUnicode_InternFromString(key) +#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE +#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x) +#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x) + +#endif + +#ifndef Py_TYPE +# define Py_TYPE(op) ((op)->ob_type) +#endif + +/* SWIG APIs for compatibility of both Python 2 & 3 */ + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_FromFormat PyUnicode_FromFormat +#else +# define SWIG_Python_str_FromFormat PyString_FromFormat +#endif + + +/* Warning: This function will allocate a new string in Python 3, + * so please call SWIG_Python_str_DelForPy3(x) to free the space. + */ +SWIGINTERN char* +SWIG_Python_str_AsChar(PyObject *str) +{ +#if PY_VERSION_HEX >= 0x03000000 + char *cstr; + char *newstr; + Py_ssize_t len; + str = PyUnicode_AsUTF8String(str); + PyBytes_AsStringAndSize(str, &cstr, &len); + newstr = (char *) malloc(len+1); + memcpy(newstr, cstr, len+1); + Py_XDECREF(str); + return newstr; +#else + return PyString_AsString(str); +#endif +} + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) +#else +# define SWIG_Python_str_DelForPy3(x) +#endif + + +SWIGINTERN PyObject* +SWIG_Python_str_FromChar(const char *c) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromString(c); +#else + return PyString_FromString(c); +#endif +} + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif + +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +typedef inquiry lenfunc; +typedef intargfunc ssizeargfunc; +typedef intintargfunc ssizessizeargfunc; +typedef intobjargproc ssizeobjargproc; +typedef intintobjargproc ssizessizeobjargproc; +typedef getreadbufferproc readbufferproc; +typedef getwritebufferproc writebufferproc; +typedef getsegcountproc segcountproc; +typedef getcharbufferproc charbufferproc; +static long PyNumber_AsSsize_t (PyObject *x, void *SWIGUNUSEDPARM(exc)) +{ + long result = 0; + PyObject *i = PyNumber_Int(x); + if (i) { + result = PyInt_AsLong(i); + Py_DECREF(i); + } + return result; +} +#endif + +#if PY_VERSION_HEX < 0x02040000 +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) +#endif + +#if PY_VERSION_HEX < 0x02030000 +typedef struct { + PyTypeObject type; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; + PyBufferProcs as_buffer; + PyObject *name, *slots; +} PyHeapTypeObject; +#endif + +#if PY_VERSION_HEX < 0x02030000 +typedef destructor freefunc; +#endif + +#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \ + (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \ + (PY_MAJOR_VERSION > 3)) +# define SWIGPY_USE_CAPSULE +# define SWIGPY_CAPSULE_NAME ((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME) +#endif + +#if PY_VERSION_HEX < 0x03020000 +#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) +#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + char *tmp; + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + + +/* ----------------------------------------------------------------------------- + * Wrapper of PyInstanceMethod_New() used in Python 3 + * It is exported to the generated module, used for -fastproxy + * ----------------------------------------------------------------------------- */ +#if PY_VERSION_HEX >= 0x03000000 +SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *func) +{ + return PyInstanceMethod_New(func); +} +#else +SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(func)) +{ + return NULL; +} +#endif + +#ifdef __cplusplus +} +#endif + + +/* ----------------------------------------------------------------------------- + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) + +#ifdef SWIGPYTHON_BUILTIN +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags) +#else +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) +#endif + +#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) + +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) SwigPyClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +#if defined(SWIGPYTHON_BUILTIN) + +SWIGINTERN void +SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) { + PyObject *s = PyString_InternFromString(key); + PyList_Append(seq, s); + Py_DECREF(s); +} + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char *)name, obj); + Py_DECREF(obj); + if (public_interface) + SwigPyBuiltin_AddPublicSymbol(public_interface, name); +} + +#else + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char *)name, obj); + Py_DECREF(obj); +} + +#endif + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + if (min <= 1 && max >= 1) { + register int i; + objs[0] = args; + for (i = 1; i < max; ++i) { + objs[i] = 0; + } + return 2; + } + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) +#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) + +#ifdef __cplusplus +extern "C" { +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* SwigPyClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; + PyTypeObject *pytype; +} SwigPyClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + SwigPyClientData *data = (SwigPyClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME SwigPyClientData * +SwigPyClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + data->pytype = 0; + return data; + } +} + +SWIGRUNTIME void +SwigPyClientData_Del(SwigPyClientData *data) { + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== SwigPyObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +#ifdef SWIGPYTHON_BUILTIN + PyObject *dict; +#endif +} SwigPyObject; + +SWIGRUNTIME PyObject * +SwigPyObject_long(SwigPyObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +SwigPyObject_format(const char* fmt, SwigPyObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { + PyObject *ofmt = SWIG_Python_str_FromChar(fmt); + if (ofmt) { +#if PY_VERSION_HEX >= 0x03000000 + res = PyUnicode_Format(ofmt,args); +#else + res = PyString_Format(ofmt,args); +#endif + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +SwigPyObject_oct(SwigPyObject *v) +{ + return SwigPyObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +SwigPyObject_hex(SwigPyObject *v) +{ + return SwigPyObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +SwigPyObject_repr(SwigPyObject *v) +#else +SwigPyObject_repr(SwigPyObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *repr = SWIG_Python_str_FromFormat("", name, (void *)v); + if (v->next) { +# ifdef METH_NOARGS + PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); +# else + PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next, args); +# endif +# if PY_VERSION_HEX >= 0x03000000 + PyObject *joined = PyUnicode_Concat(repr, nrep); + Py_DecRef(repr); + Py_DecRef(nrep); + repr = joined; +# else + PyString_ConcatAndDel(&repr,nrep); +# endif + } + return repr; +} + +SWIGRUNTIME int +SwigPyObject_print(SwigPyObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char *str; +#ifdef METH_NOARGS + PyObject *repr = SwigPyObject_repr(v); +#else + PyObject *repr = SwigPyObject_repr(v, NULL); +#endif + if (repr) { + str = SWIG_Python_str_AsChar(repr); + fputs(str, fp); + SWIG_Python_str_DelForPy3(str); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +SwigPyObject_str(SwigPyObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + SWIG_Python_str_FromChar(result) : 0; +} + +SWIGRUNTIME int +SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +/* Added for Python 3.x, would it also be useful for Python 2.x? */ +SWIGRUNTIME PyObject* +SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) +{ + PyObject* res; + if( op != Py_EQ && op != Py_NE ) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0); + return res; +} + + +SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void); + +#ifdef SWIGPYTHON_BUILTIN +static swig_type_info *SwigPyObject_stype = 0; +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + SwigPyClientData *cd; + assert(SwigPyObject_stype); + cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; + assert(cd); + assert(cd->pytype); + return cd->pytype; +} +#else +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce(); + return type; +} +#endif + +SWIGRUNTIMEINLINE int +SwigPyObject_Check(PyObject *op) { +#ifdef SWIGPYTHON_BUILTIN + PyTypeObject *target_tp = SwigPyObject_type(); + if (PyType_IsSubtype(op->ob_type, target_tp)) + return 1; + return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0); +#else + return (Py_TYPE(op) == SwigPyObject_type()) + || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0); +#endif +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +SwigPyObject_dealloc(PyObject *v) +{ + SwigPyObject *sobj = (SwigPyObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporary object to carry the destroy operation */ + PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +SwigPyObject_append(PyObject* v, PyObject* next) +{ + SwigPyObject *sobj = (SwigPyObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!SwigPyObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +SwigPyObject_next(PyObject* v) +#else +SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +SwigPyObject_disown(PyObject *v) +#else +SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +SwigPyObject_acquire(PyObject *v) +#else +SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +SwigPyObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + SwigPyObject *sobj = (SwigPyObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + SwigPyObject_acquire(v); + } else { + SwigPyObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + SwigPyObject_acquire(v,args); + } else { + SwigPyObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)SwigPyObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)SwigPyObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)SwigPyObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)SwigPyObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +SwigPyObject_getattr(SwigPyObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +SwigPyObject_TypeOnce(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods SwigPyObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + /* nb_divide removed in Python 3 */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc)0, /*nb_divide*/ +#endif + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ +#if PY_VERSION_HEX < 0x03000000 + 0, /*nb_coerce*/ +#endif + (unaryfunc)SwigPyObject_long, /*nb_int*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_long, /*nb_long*/ +#else + 0, /*nb_reserved*/ +#endif + (unaryfunc)0, /*nb_float*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_oct, /*nb_oct*/ + (unaryfunc)SwigPyObject_hex, /*nb_hex*/ +#endif +#if PY_VERSION_HEX >= 0x03000000 /* 3.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ +#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject swigpyobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"SwigPyObject", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyObject_dealloc, /* tp_dealloc */ + (printfunc)SwigPyObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)SwigPyObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ +#else + (cmpfunc)SwigPyObject_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyObject_repr, /* tp_repr */ + &SwigPyObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)SwigPyObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + swigpyobject_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + swigpyobject_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&swigpyobject_type) < 0) + return NULL; +#endif + } + return &swigpyobject_type; +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own) +{ + SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} SwigPyPacked; + +SWIGRUNTIME int +SwigPyPacked_print(SwigPyPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +SwigPyPacked_repr(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return SWIG_Python_str_FromFormat("", result, v->ty->name); + } else { + return SWIG_Python_str_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +SwigPyPacked_str(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); + } else { + return SWIG_Python_str_FromChar(v->ty->name); + } +} + +SWIGRUNTIME int +SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void); + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce(); + return type; +} + +SWIGRUNTIMEINLINE int +SwigPyPacked_Check(PyObject *op) { + return ((op)->ob_type == SwigPyPacked_TypeOnce()) + || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0); +} + +SWIGRUNTIME void +SwigPyPacked_dealloc(PyObject *v) +{ + if (SwigPyPacked_Check(v)) { + SwigPyPacked *sobj = (SwigPyPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_TypeOnce(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject swigpypacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX>=0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"SwigPyPacked", /* tp_name */ + sizeof(SwigPyPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyPacked_dealloc, /* tp_dealloc */ + (printfunc)SwigPyPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX>=0x03000000 + 0, /* tp_reserved in 3.0.1 */ +#else + (cmpfunc)SwigPyPacked_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)SwigPyPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + swigpypacked_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + swigpypacked_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&swigpypacked_type) < 0) + return NULL; +#endif + } + return &swigpypacked_type; +} + +SWIGRUNTIME PyObject * +SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (SwigPyPacked_Check(obj)) { + SwigPyPacked *sobj = (SwigPyPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return SWIG_Python_str_FromChar("this"); +} + +static PyObject *swig_this = NULL; + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + if (swig_this == NULL) + swig_this = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +/* TODO: I don't know how to implement the fast getset in Python 3 right now */ +#if PY_VERSION_HEX>=0x03000000 +#define SWIG_PYTHON_SLOW_GETSET_THIS +#endif + +SWIGRUNTIME SwigPyObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + PyObject *obj; + + if (SwigPyObject_Check(pyobj)) + return (SwigPyObject *) pyobj; + +#ifdef SWIGPYTHON_BUILTIN + (void)obj; +# ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + pyobj = PyWeakref_GET_OBJECT(pyobj); + if (pyobj && SwigPyObject_Check(pyobj)) + return (SwigPyObject*) pyobj; + } +# endif + return NULL; +#else + + obj = 0; + +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !SwigPyObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + SwigPyObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (SwigPyObject *)obj; +#endif +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + int res; + SwigPyObject *sobj; + + if (!obj) + return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) + *ptr = 0; + return SWIG_OK; + } + + res = SWIG_ERROR; + + sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (SwigPyObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + res = SWIG_OK; + } else { + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + } + return res; +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) + return SWIG_ERROR; + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, without calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { +#if PY_VERSION_HEX >= 0x03000000 + inst = PyBaseObject_Type.tp_new((PyTypeObject*) data->newargs, Py_None, Py_None); + PyObject_SetAttr(inst, SWIG_This(), swig_this); + Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; +#else + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); +#endif + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + SwigPyObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) { + SwigPyClientData *clientdata; + PyObject * robj; + int own; + + if (!ptr) + return SWIG_Py_Void(); + + clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0; + own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + if (clientdata && clientdata->pytype) { + SwigPyObject *newobj; + if (flags & SWIG_BUILTIN_TP_INIT) { + newobj = (SwigPyObject*) self; + if (newobj->ptr) { + PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0); + while (newobj->next) + newobj = (SwigPyObject *) newobj->next; + newobj->next = next_self; + newobj = (SwigPyObject *)next_self; + } + } else { + newobj = PyObject_New(SwigPyObject, clientdata->pytype); + } + if (newobj) { + newobj->ptr = ptr; + newobj->ty = type; + newobj->own = own; + newobj->next = 0; +#ifdef SWIGPYTHON_BUILTIN + newobj->dict = 0; +#endif + return (PyObject*) newobj; + } + return SWIG_Py_Void(); + } + + assert(!(flags & SWIG_BUILTIN_TP_INIT)); + + robj = SwigPyObject_New(ptr, type, own); + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else +# ifdef SWIGPY_USE_CAPSULE + type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0); +# else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); +# endif + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +#ifdef SWIGPY_USE_CAPSULE +SWIG_Python_DestroyModule(PyObject *obj) +#else +SWIG_Python_DestroyModule(void *vptr) +#endif +{ +#ifdef SWIGPY_USE_CAPSULE + swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME); +#else + swig_module_info *swig_module = (swig_module_info *) vptr; +#endif + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; + if (data) SwigPyClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); + swig_this = NULL; +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { +#if PY_VERSION_HEX >= 0x03000000 + /* Add a dummy module object into sys.modules */ + PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION); +#else + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */ + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); +#endif +#ifdef SWIGPY_USE_CAPSULE + PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +#else + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +#endif +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = SWIG_Python_str_FromChar(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { +#ifdef SWIGPY_USE_CAPSULE + descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL); +#else + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); +#endif + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { +#ifdef SWIGPY_USE_CAPSULE + obj = PyCapsule_New((void*) descriptor, NULL, NULL); +#else + obj = PyCObject_FromVoidPtr(descriptor, NULL); +#endif + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + char *tmp; + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str)); + } else { + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); + } + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +SwigPyObject_GetDesc(PyObject *self) +{ + SwigPyObject *v = (SwigPyObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && SwigPyObject_Check(obj)) { + const char *otype = (const char *) SwigPyObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + SWIG_Python_str_DelForPy3(cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); +#if SWIG_POINTER_EXCEPTION + if (flags) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } +#endif + } + return result; +} + +SWIGRUNTIME int +SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) { + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + PyObject *encoded_name; + descrsetfunc f; + int res; + +#ifdef Py_USING_UNICODE + if (PyString_Check(name)) { + name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL); + if (!name) + return -1; + } else if (!PyUnicode_Check(name)) +#else + if (!PyString_Check(name)) +#endif + { + PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name); + return -1; + } else { + Py_INCREF(name); + } + + if (!tp->tp_dict) { + if (PyType_Ready(tp) < 0) + goto done; + } + + res = -1; + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL) + f = descr->ob_type->tp_descr_set; + if (!f) { + if (PyString_Check(name)) { + encoded_name = name; + Py_INCREF(name); + } else { + encoded_name = PyUnicode_AsUTF8String(name); + } + PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); + Py_DECREF(encoded_name); + } else { + res = f(descr, obj, value); + } + + done: + Py_DECREF(name); + return res; +} + + +#ifdef __cplusplus +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_GPSPosition swig_types[0] +#define SWIGTYPE_p_char swig_types[1] +#define SWIGTYPE_p_timeval swig_types[2] +#define SWIGTYPE_p_void swig_types[3] +static swig_type_info *swig_types[5]; +static swig_module_info swig_module = {swig_types, 4, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif + +/*----------------------------------------------- + @(target):= _gpsPub.so + ------------------------------------------------*/ +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_init PyInit__gpsPub + +#else +# define SWIG_init init_gpsPub + +#endif +#define SWIG_name "_gpsPub" + +#define SWIGVERSION 0x020004 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#define SWIG_FILE_WITH_INIT +#include "gpsPub.h" + + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + + #define SWIG_From_double PyFloat_FromDouble + + +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +#include + + +#include + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_long (PyObject *obj, long* val) +{ + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int (PyObject * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ +#if PY_VERSION_HEX>=0x03000000 + if (PyUnicode_Check(obj)) +#else + if (PyString_Check(obj)) +#endif + { + char *cstr; Py_ssize_t len; +#if PY_VERSION_HEX>=0x03000000 + if (!alloc && cptr) { + /* We can't allow converting without allocation, since the internal + representation of string in Python 3 is UCS-2/UCS-4 but we require + a UTF-8 representation. + TODO(bhy) More detailed explanation */ + return SWIG_RuntimeError; + } + obj = PyUnicode_AsUTF8String(obj); + PyBytes_AsStringAndSize(obj, &cstr, &len); + if(alloc) *alloc = SWIG_NEWOBJ; +#else + PyString_AsStringAndSize(obj, &cstr, &len); +#endif + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + #if PY_VERSION_HEX>=0x03000000 + assert(0); /* Should never reach here in Python 3 */ + #endif + *cptr = SWIG_Python_str_AsChar(obj); + } + } + if (psize) *psize = len + 1; +#if PY_VERSION_HEX>=0x03000000 + Py_XDECREF(obj); +#endif + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) +{ + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v > UINT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (unsigned int)(v); + } + } + return res; +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_InternalNewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(carray, (int)(size)); +#else + return PyString_FromStringAndSize(carray, (int)(size)); +#endif + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long (unsigned long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value)); +} + + +SWIGINTERNINLINE PyObject * +SWIG_From_unsigned_SS_int (unsigned int value) +{ + return SWIG_From_unsigned_SS_long (value); +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_GPSPosition_x_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + double arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_x_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_x_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_x_set" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + if (arg1) (arg1)->x = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_x_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + double result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_x_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_x_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (double) ((arg1)->x); + resultobj = SWIG_From_double((double)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_y_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + double arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_y_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_y_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_y_set" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + if (arg1) (arg1)->y = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_y_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + double result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_y_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_y_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (double) ((arg1)->y); + resultobj = SWIG_From_double((double)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_z_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + double arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_z_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_z_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_z_set" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + if (arg1) (arg1)->z = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_z_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + double result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_z_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_z_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (double) ((arg1)->z); + resultobj = SWIG_From_double((double)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_gps_time_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + struct timeval arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_gps_time_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_gps_time_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + { + res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_timeval, 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GPSPosition_gps_time_set" "', argument " "2"" of type '" "struct timeval""'"); + } + if (!argp2) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "GPSPosition_gps_time_set" "', argument " "2"" of type '" "struct timeval""'"); + } else { + arg2 = *((struct timeval *)(argp2)); + } + } + if (arg1) (arg1)->gps_time = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_gps_time_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + struct timeval result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_gps_time_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_gps_time_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = ((arg1)->gps_time); + resultobj = SWIG_NewPointerObj((struct timeval *)memcpy((struct timeval *)malloc(sizeof(struct timeval)),&result,sizeof(struct timeval)), SWIGTYPE_p_timeval, SWIG_POINTER_OWN | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_sys_time_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + struct timeval arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_sys_time_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_sys_time_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + { + res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_timeval, 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GPSPosition_sys_time_set" "', argument " "2"" of type '" "struct timeval""'"); + } + if (!argp2) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "GPSPosition_sys_time_set" "', argument " "2"" of type '" "struct timeval""'"); + } else { + arg2 = *((struct timeval *)(argp2)); + } + } + if (arg1) (arg1)->sys_time = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_sys_time_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + struct timeval result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_sys_time_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_sys_time_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = ((arg1)->sys_time); + resultobj = SWIG_NewPointerObj((struct timeval *)memcpy((struct timeval *)malloc(sizeof(struct timeval)),&result,sizeof(struct timeval)), SWIGTYPE_p_timeval, SWIG_POINTER_OWN | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_xyvalid_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_xyvalid_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_xyvalid_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_xyvalid_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->xyvalid = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_xyvalid_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_xyvalid_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_xyvalid_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (int) ((arg1)->xyvalid); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_zvalid_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_zvalid_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_zvalid_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_zvalid_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->zvalid = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_zvalid_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_zvalid_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_zvalid_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (int) ((arg1)->zvalid); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_tvalid_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_tvalid_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_tvalid_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_tvalid_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->tvalid = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_tvalid_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_tvalid_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_tvalid_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (int) ((arg1)->tvalid); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_stale_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPosition_stale_set",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_stale_set" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPosition_stale_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->stale = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPosition_stale_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPosition_stale_get",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPosition_stale_get" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + result = (int) ((arg1)->stale); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_GPSPosition(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *result = 0 ; + + if (!PyArg_ParseTuple(args,(char *)":new_GPSPosition")) SWIG_fail; + result = (GPSPosition *)calloc(1, sizeof(GPSPosition)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GPSPosition, SWIG_POINTER_NEW | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_GPSPosition(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSPosition *arg1 = (GPSPosition *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"O:delete_GPSPosition",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GPSPosition, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_GPSPosition" "', argument " "1"" of type '" "GPSPosition *""'"); + } + arg1 = (GPSPosition *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *GPSPosition_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_GPSPosition, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *_wrap_GPSMemoryInit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + unsigned int arg2 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + unsigned int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char *result = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSMemoryInit",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSMemoryInit" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSMemoryInit" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + result = (char *)GPSMemoryInit((char const *)arg1,arg2); + resultobj = SWIG_FromCharPtr((const char *)result); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPublishInit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + GPSHandle result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSPublishInit",&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPublishInit" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (GPSHandle)GPSPublishInit((char const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPublishUpdate(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + GPSPosition *arg2 = (GPSPosition *) 0 ; + int res1 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPublishUpdate",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPublishUpdate" "', argument " "1"" of type '" "GPSHandle""'"); + } + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GPSPublishUpdate" "', argument " "2"" of type '" "GPSPosition const *""'"); + } + arg2 = (GPSPosition *)(argp2); + GPSPublishUpdate((void const *)arg1,(struct GPSPosition const *)arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPublishPos(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + double arg2 ; + double arg3 ; + double arg4 ; + int res1 ; + double val2 ; + int ecode2 = 0 ; + double val3 ; + int ecode3 = 0 ; + double val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OOOO:GPSPublishPos",&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPublishPos" "', argument " "1"" of type '" "GPSHandle""'"); + } + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSPublishPos" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + ecode3 = SWIG_AsVal_double(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "GPSPublishPos" "', argument " "3"" of type '" "double""'"); + } + arg3 = (double)(val3); + ecode4 = SWIG_AsVal_double(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GPSPublishPos" "', argument " "4"" of type '" "double""'"); + } + arg4 = (double)(val4); + GPSPublishPos((void const *)arg1,arg2,arg3,arg4); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSPublishShutdown(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + char *arg2 = (char *) 0 ; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSPublishShutdown",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSPublishShutdown" "', argument " "1"" of type '" "GPSHandle""'"); + } + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GPSPublishShutdown" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + GPSPublishShutdown((void const *)arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSSubscribe(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + GPSHandle result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSSubscribe",&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSSubscribe" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (GPSHandle)GPSSubscribe((char const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSGetCurrentPosition(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + GPSPosition *arg2 = (GPSPosition *) 0 ; + int res1 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSGetCurrentPosition",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSGetCurrentPosition" "', argument " "1"" of type '" "GPSHandle""'"); + } + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_GPSPosition, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GPSGetCurrentPosition" "', argument " "2"" of type '" "GPSPosition *""'"); + } + arg2 = (GPSPosition *)(argp2); + GPSGetCurrentPosition((void const *)arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSUnsubscribe(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + int res1 ; + PyObject * obj0 = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSUnsubscribe",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSUnsubscribe" "', argument " "1"" of type '" "GPSHandle""'"); + } + GPSUnsubscribe((void const *)arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSSetMemory(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + unsigned int arg2 ; + char *arg3 = (char *) 0 ; + unsigned int arg4 ; + int res1 ; + unsigned int val2 ; + int ecode2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + unsigned int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + unsigned int result; + + if (!PyArg_ParseTuple(args,(char *)"OOOO:GPSSetMemory",&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSSetMemory" "', argument " "1"" of type '" "GPSHandle""'"); + } + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSSetMemory" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "GPSSetMemory" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + ecode4 = SWIG_AsVal_unsigned_SS_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GPSSetMemory" "', argument " "4"" of type '" "unsigned int""'"); + } + arg4 = (unsigned int)(val4); + result = (unsigned int)GPSSetMemory((void const *)arg1,arg2,(char const *)arg3,arg4); + resultobj = SWIG_From_unsigned_SS_int((unsigned int)(result)); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSGetMemorySize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + int res1 ; + PyObject * obj0 = 0 ; + unsigned int result; + + if (!PyArg_ParseTuple(args,(char *)"O:GPSGetMemorySize",&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSGetMemorySize" "', argument " "1"" of type '" "GPSHandle""'"); + } + result = (unsigned int)GPSGetMemorySize((void const *)arg1); + resultobj = SWIG_From_unsigned_SS_int((unsigned int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSGetMemoryPtr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + unsigned int arg2 ; + int res1 ; + unsigned int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char *result = 0 ; + + if (!PyArg_ParseTuple(args,(char *)"OO:GPSGetMemoryPtr",&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSGetMemoryPtr" "', argument " "1"" of type '" "GPSHandle""'"); + } + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSGetMemoryPtr" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + result = (char *)GPSGetMemoryPtr((void const *)arg1,arg2); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_GPSGetMemory(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + GPSHandle arg1 = (GPSHandle) 0 ; + unsigned int arg2 ; + char *arg3 = (char *) 0 ; + unsigned int arg4 ; + int res1 ; + unsigned int val2 ; + int ecode2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + unsigned int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + unsigned int result; + + if (!PyArg_ParseTuple(args,(char *)"OOOO:GPSGetMemory",&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GPSGetMemory" "', argument " "1"" of type '" "GPSHandle""'"); + } + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GPSGetMemory" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "GPSGetMemory" "', argument " "3"" of type '" "char *""'"); + } + arg3 = (char *)(buf3); + ecode4 = SWIG_AsVal_unsigned_SS_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GPSGetMemory" "', argument " "4"" of type '" "unsigned int""'"); + } + arg4 = (unsigned int)(val4); + result = (unsigned int)GPSGetMemory((void const *)arg1,arg2,arg3,arg4); + resultobj = SWIG_From_unsigned_SS_int((unsigned int)(result)); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"SWIG_PyInstanceMethod_New", (PyCFunction)SWIG_PyInstanceMethod_New, METH_O, NULL}, + { (char *)"GPSPosition_x_set", _wrap_GPSPosition_x_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_x_get", _wrap_GPSPosition_x_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_y_set", _wrap_GPSPosition_y_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_y_get", _wrap_GPSPosition_y_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_z_set", _wrap_GPSPosition_z_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_z_get", _wrap_GPSPosition_z_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_gps_time_set", _wrap_GPSPosition_gps_time_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_gps_time_get", _wrap_GPSPosition_gps_time_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_sys_time_set", _wrap_GPSPosition_sys_time_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_sys_time_get", _wrap_GPSPosition_sys_time_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_xyvalid_set", _wrap_GPSPosition_xyvalid_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_xyvalid_get", _wrap_GPSPosition_xyvalid_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_zvalid_set", _wrap_GPSPosition_zvalid_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_zvalid_get", _wrap_GPSPosition_zvalid_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_tvalid_set", _wrap_GPSPosition_tvalid_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_tvalid_get", _wrap_GPSPosition_tvalid_get, METH_VARARGS, NULL}, + { (char *)"GPSPosition_stale_set", _wrap_GPSPosition_stale_set, METH_VARARGS, NULL}, + { (char *)"GPSPosition_stale_get", _wrap_GPSPosition_stale_get, METH_VARARGS, NULL}, + { (char *)"new_GPSPosition", _wrap_new_GPSPosition, METH_VARARGS, NULL}, + { (char *)"delete_GPSPosition", _wrap_delete_GPSPosition, METH_VARARGS, NULL}, + { (char *)"GPSPosition_swigregister", GPSPosition_swigregister, METH_VARARGS, NULL}, + { (char *)"GPSMemoryInit", _wrap_GPSMemoryInit, METH_VARARGS, NULL}, + { (char *)"GPSPublishInit", _wrap_GPSPublishInit, METH_VARARGS, NULL}, + { (char *)"GPSPublishUpdate", _wrap_GPSPublishUpdate, METH_VARARGS, NULL}, + { (char *)"GPSPublishPos", _wrap_GPSPublishPos, METH_VARARGS, NULL}, + { (char *)"GPSPublishShutdown", _wrap_GPSPublishShutdown, METH_VARARGS, NULL}, + { (char *)"GPSSubscribe", _wrap_GPSSubscribe, METH_VARARGS, NULL}, + { (char *)"GPSGetCurrentPosition", _wrap_GPSGetCurrentPosition, METH_VARARGS, NULL}, + { (char *)"GPSUnsubscribe", _wrap_GPSUnsubscribe, METH_VARARGS, NULL}, + { (char *)"GPSSetMemory", _wrap_GPSSetMemory, METH_VARARGS, NULL}, + { (char *)"GPSGetMemorySize", _wrap_GPSGetMemorySize, METH_VARARGS, NULL}, + { (char *)"GPSGetMemoryPtr", _wrap_GPSGetMemoryPtr, METH_VARARGS, NULL}, + { (char *)"GPSGetMemory", _wrap_GPSGetMemory, METH_VARARGS, NULL}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_GPSPosition = {"_p_GPSPosition", "struct GPSPosition *|GPSPosition *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_timeval = {"_p_timeval", "struct timeval *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_void = {"_p_void", "GPSHandle|void *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_GPSPosition, + &_swigt__p_char, + &_swigt__p_timeval, + &_swigt__p_void, +}; + +static swig_cast_info _swigc__p_GPSPosition[] = { {&_swigt__p_GPSPosition, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_timeval[] = { {&_swigt__p_timeval, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_void[] = { {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_GPSPosition, + _swigc__p_char, + _swigc__p_timeval, + _swigc__p_void, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString(""); +#else + return PyString_FromString(""); +#endif + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { +#if PY_VERSION_HEX >= 0x03000000 + PyObject *str = PyUnicode_InternFromString("("); + PyObject *tail; + PyObject *joined; + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + tail = PyUnicode_FromString(var->name); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + if (var->next) { + tail = PyUnicode_InternFromString(", "); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + } + } + tail = PyUnicode_InternFromString(")"); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; +#else + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); +#endif + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + char *tmp; + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str)); + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"swigvarlink", /* tp_name */ + sizeof(swig_varlinkobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) swig_varlink_dealloc, /* tp_dealloc */ + (printfunc) swig_varlink_print, /* tp_print */ + (getattrfunc) swig_varlink_getattr, /* tp_getattr */ + (setattrfunc) swig_varlink_setattr, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + varlink_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&varlink_type) < 0) + return NULL; +#endif + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_InternalNewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif + +SWIGEXPORT +#if PY_VERSION_HEX >= 0x03000000 +PyObject* +#else +void +#endif +SWIG_init(void) { + PyObject *m, *d, *md; +#if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef SWIG_module = { +# if PY_VERSION_HEX >= 0x03020000 + PyModuleDef_HEAD_INIT, +# else + { + PyObject_HEAD_INIT(NULL) + NULL, /* m_init */ + 0, /* m_index */ + NULL, /* m_copy */ + }, +# endif + (char *) SWIG_name, + NULL, + -1, + SwigMethods, + NULL, + NULL, + NULL, + NULL + }; +#endif + +#if defined(SWIGPYTHON_BUILTIN) + static SwigPyClientData SwigPyObject_clientdata = { + 0, 0, 0, 0, 0, 0, 0 + }; + static PyGetSetDef this_getset_def = { + (char *)"this", &SwigPyBuiltin_ThisClosure, NULL, NULL, NULL + }; + static SwigPyGetSet thisown_getset_closure = { + (PyCFunction) SwigPyObject_own, + (PyCFunction) SwigPyObject_own + }; + static PyGetSetDef thisown_getset_def = { + (char *)"thisown", SwigPyBuiltin_GetterClosure, SwigPyBuiltin_SetterClosure, NULL, &thisown_getset_closure + }; + PyObject *metatype_args; + PyTypeObject *builtin_pytype; + int builtin_base_count; + swig_type_info *builtin_basetype; + PyObject *tuple; + PyGetSetDescrObject *static_getset; + PyTypeObject *metatype; + SwigPyClientData *cd; + PyObject *public_interface, *public_symbol; + PyObject *this_descr; + PyObject *thisown_descr; + int i; + + (void)builtin_pytype; + (void)builtin_base_count; + (void)builtin_basetype; + (void)tuple; + (void)static_getset; + + /* metatype is used to implement static member variables. */ + metatype_args = Py_BuildValue("(s(O){})", "SwigPyObjectType", &PyType_Type); + assert(metatype_args); + metatype = (PyTypeObject *) PyType_Type.tp_call((PyObject *) &PyType_Type, metatype_args, NULL); + assert(metatype); + Py_DECREF(metatype_args); + metatype->tp_setattro = (setattrofunc) &SwigPyObjectType_setattro; + assert(PyType_Ready(metatype) >= 0); +#endif + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + +#if PY_VERSION_HEX >= 0x03000000 + m = PyModule_Create(&SWIG_module); +#else + m = Py_InitModule((char *) SWIG_name, SwigMethods); +#endif + md = d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + +#ifdef SWIGPYTHON_BUILTIN + SwigPyObject_stype = SWIG_MangledTypeQuery("_p_SwigPyObject"); + assert(SwigPyObject_stype); + cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; + if (!cd) { + SwigPyObject_stype->clientdata = &SwigPyObject_clientdata; + SwigPyObject_clientdata.pytype = SwigPyObject_TypeOnce(); + } else if (SwigPyObject_TypeOnce()->tp_basicsize != cd->pytype->tp_basicsize) { + PyErr_SetString(PyExc_RuntimeError, "Import error: attempted to load two incompatible swig-generated modules."); +# if PY_VERSION_HEX >= 0x03000000 + return NULL; +# else + return; +# endif + } + + /* All objects have a 'this' attribute */ + this_descr = PyDescr_NewGetSet(SwigPyObject_type(), &this_getset_def); + (void)this_descr; + + /* All objects have a 'thisown' attribute */ + thisown_descr = PyDescr_NewGetSet(SwigPyObject_type(), &thisown_getset_def); + (void)thisown_descr; + + public_interface = PyList_New(0); + public_symbol = 0; + (void)public_symbol; + + PyDict_SetItemString(md, "__all__", public_interface); + Py_DECREF(public_interface); + for (i = 0; SwigMethods[i].ml_name != NULL; ++i) + SwigPyBuiltin_AddPublicSymbol(public_interface, SwigMethods[i].ml_name); + for (i = 0; swig_const_table[i].name != 0; ++i) + SwigPyBuiltin_AddPublicSymbol(public_interface, swig_const_table[i].name); +#endif + + SWIG_InstallConstants(d,swig_const_table); + + SWIG_Python_SetConstant(d, "NULL",SWIG_From_int((int)(0))); +#if PY_VERSION_HEX >= 0x03000000 + return m; +#else + return; +#endif +} + diff --git a/src/python/mgen.py b/src/python/mgen.py index 24f5a53a..b3a3368e 100644 --- a/src/python/mgen.py +++ b/src/python/mgen.py @@ -89,14 +89,20 @@ def __init__(self, flowId, controller = None): self.dst_port = None self.pattern = None self.src_port = None + self.interface = None self.count = None self.sequence = None + self.tos = None + self.ttl = None self.data = None self.data_length = 0 self.controller = None if controller is not None: controller.add_flow(self) self.active = False + + #def __del__(self): + #print "flow DTOR" def is_valid(self): """Checks that the minimum parameters for a valid flow are set""" @@ -123,10 +129,16 @@ def start(self, delay=0.0): cmd += " " + str(self.pattern) if self.src_port is not None: cmd += " src " + str(self.src_port) + if self.interface is not None: + cmd += " interface " + self.interface if self.count is not None: cmd += " count " + str(self.count) if self.sequence is not None: cmd += " sequence " + str(self.sequence) + if self.tos is not None: + cmd += " tos " + str(self.tos) + if self.ttl is not None: + cmd += " ttl " + str(self.ttl) if self.data is not None: cmd += " data [" + self.data + "]" self.controller.send_event(cmd) @@ -171,6 +183,18 @@ def set_destination(self, addr, port): cmd = "mod %d dst %s/%d" % (self.flow_id, addr, port) self.controller.send_event(cmd) + def set_interface(self, iface): + self.interface = iface + if self.active: + cmd = "mod %d interface %s" % (self.flow_id, interface) + self.controller.send_event(cmd) + + def set_source(self, srcPort): + self.src_port = srcPort + if self.active: + cmd = "mod %d src %d" % (self.flow_id, srcPort) + self.controller.send_event(cmd) + def set_pattern(self, pattern): self.pattern = pattern if self.active: @@ -189,6 +213,18 @@ def set_sequence(self, sequence): cmd = "mod %d sequence %d" % (self.flow_id, self.sequence) self.controller.send_event(cmd) + def set_tos(self, tos): + self.tos = tos + if self.active: + cmd = "mod %d tos %s" % (self.flow_id, self.tos) + self.controller.send_event(cmd) + + def set_ttl(self, ttl): + self.ttl = ttl + if self.active: + cmd = "mod %d ttl %s" % (self.flow_id, self.ttl) + 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): @@ -197,6 +233,12 @@ def set_text_payload(self, text): cmd = "mod %d data [%s]" % (self.flow_id, self.data) self.controller.send_event(cmd) + def get_text_payload(self): + if self.data: + return self.data.decode('hex','strict') + else: + return None + def set_binary_payload(self, buf): self.data = binasci.hexlify(buf) if self.active: @@ -209,9 +251,6 @@ def set_struct_payload(self, theStruct, *args): 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 @@ -321,7 +360,7 @@ def InitFromString(self, text): return self.init_from_string(text) class Controller: - def __init__(self, instance=None): + def __init__(self, instance=None, gpsKey=None): """Instantiate an mgen.Controller The 'instance' name is optional. If it is _not_ given, an mgen instance named "mgen--" where the is the process id of the Python @@ -331,39 +370,58 @@ def __init__(self, instance=None): instance is created. Note that the mgen output can be monitored only for the mgen instance the controller creates, if applicable. """ - args = ['mgen', 'flush', 'instance'] + self.flow_dict = {} + self.sink_proc = None + self.gpsKey = gpsKey + args = ['mgen', 'flush'] if instance is None: pidHex = "%x" % os.getpid() idHex = "%x" % id(self) self.instance_name = 'mgen-' + pidHex + '-' + idHex else: self.instance_name = instance + + if self.gpsKey is not None: + args.append('gpskey') + args.append(self.gpsKey) + + args.append('instance') + args.append(self.instance_name) + # TBD - should we try to connect to the instance_name to # see if it already exists instead of always creating a # child process??? #print "mgen instance name " + self.instance_name - args.append(self.instance_name) - fp = open(os.devnull, 'w') ;# redirect stderr to /dev/null to hide - self.proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=fp) - fp.close() - # Read the mgen stdout and find the "START event to confirm it - # has launched successfully before trying to connect to it - # (TBD - parse and save START event info for first readline() output) - for line in self: - field = line.split() - if (len(field) > 1) and (field[1] == "START"): - break - # Connect a ProtoPipe to the mgen instance to be able to control - # the mgen instance as needed in the future self.mgen_pipe = protokit.Pipe("MESSAGE") - self.mgen_pipe.Connect(self.instance_name) - self.flow_dict = {} - self.sink_proc = None + try: + self.mgen_pipe.Connect(self.instance_name) + self.proc = None + except: + fp = open(os.devnull, 'w') ;# redirect stderr to /dev/null to hide + self.proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=fp) + fp.close() + # Read the mgen stdout and find the "START event to confirm it + # has launched successfully before trying to connect to it + # (TBD - parse and save START event info for first readline() output) + for line in self: + field = line.split() + if (len(field) > 1) and (field[1] == "START"): + break + # Connect a ProtoPipe to the mgen instance to be able to control + # the mgen instance as needed in the future + self.mgen_pipe.Connect(self.instance_name) + + def __del__(self): + self.shutdown() + + def shutdown(self): self.mgen_pipe.Close() - self.proc.terminate() - self.proc.wait() + if self.proc is not None: + self.proc.terminate() + self.proc.wait() + self.proc = None if self.sink_proc is not None: self.sink_proc.terminate() self.sink_proc.wait() @@ -472,6 +530,6 @@ def get_flow(self, flowId): def remove_flow(self, flow): if flow.active: flow.stop() - del self.flow_dist[flow.flow_id] + del self.flow_dict[flow.flow_id] flow.controller = None diff --git a/src/python/mgenBasicActor.py b/src/python/mgenBasicActor.py index e8923193..7175bc2f 100755 --- a/src/python/mgenBasicActor.py +++ b/src/python/mgenBasicActor.py @@ -1,35 +1,104 @@ #! /usr/bin/env python -# A basic mgen actor that can be instantiated as a zerorpc server for remote mgen control -# This relies on installing the mgen controller within the local python environment and a importable module -# See mgen install instructions and setup.py with mgen distribution -# Requires Zerorpc and optparse modules -# Joe Macker Jan 2015 + +'''This module provides a basic mgen actor that can be instantiated as a zerorpc server for remote mgen control. + +This relies on installing the mgen controller within the local python environment and a importable module. See mgen install instructions and setup.py with mgen distribution. This module requires zerorpc and argparse modules''' + +__author__ = "Joe Macker" +__copyright__ = "" import zerorpc import mgen -import optparse, sys, os, datetime, signal +import argparse, sys, os, datetime, signal + +global _HAVE_GPSPUB +try: + __import__('imp').find_module('_gpsPub') + import _gpsPub as gpsPub + _HAVE_GPSPUB = True + # Make things with supposed existing module +except ImportError: + _HAVE_GPSPUB = False + pass # Setup an actor response class with various methods class MgenActor(object): - - def __init__(self, name): + """This class is the basic Mgen Actor class object + + :param name: required and provides the basic name of the actor + :param hasGps: sets whether to use Gps shared memory approach + :type name: string + :type hasGps: boolean + + - and to provide sections such as **Example** using the double commas syntax:: + + :Example: + + followed by a blank line ! + + which appears as follow: + + :Example: + + s = zerorpc.Server(MgenActor(args.name)) + s.bind(server_url) + s.run() + + .. seealso:: + MGEN Reference and Users guide + http://downloads.pf.itd.nrl.navy.mil/docs/mgen/mgen.html + + .. note:: + mgen.py module is required from an mgen install. + + """ + def __init__(self, name, hasGps=True): self.name = name - self.sender = mgen.Controller(name) + if _HAVE_GPSPUB is False: + # Disable gps regardless of our init flag if + # the gps module is not available + hasGps = False + self.hasGps = hasGps + if self.hasGps: + self.gpsKey = os.getcwd() + '/gpsKey' + self.gpsHandle = gpsPub.GPSPublishInit(self.gpsKey) + self.sender = mgen.Controller(name,self.gpsKey) + self.gpsLat=None + self.gpsLon=None + self.gpsAlt=None + else: + self.sender = mgen.Controller(name) - def send_sensor_payload(self, sensor_data, ip_addr, ip_port, interface,max_mgen=1400): - ''' Sends binary based sensor payload + # TODO: add a python context manager so we can shutdown? + # gpsPub.GPSPublishShutdown(self.gpsHandle,self.gpsKey) + + def send_sensor_payload(self, sensor_data, ip_addr, ip_port, interface): + ''' Send a binary-based sensor payload using MGEN RPC call to construct and send an mgen message with a binary byte-based sensor payload as a python structure of some sort - (e.g., list of seq,sample) + (e.g., list of seq,sample, dict) Required input: - - send_sensor_payload(sensor_data,ip_addr,ip_port,interface,max_mgen=1400) - + + :param sensor_data: hexified sensor data for mgen packet data field + :param ip_addr: ip destination address + :param ip_port: ip destination port + :param interface: network interface name to use as source + :param max_mgen: maximum mgen packet size to use + :type sensor_data: str + :type ip_addr: str + :type ip_port: int + :type interface: str + :type max_mgen: int + :returns: MGEN event line that was invoked by agent + :rtype: str + + ..warning:: Because of mgen payload limits if length is longer the max_mgen it will truncate. Packet size will be autocalculated using the following ipv4_mgen_header = 54 + payload length (bytes) ''' + max_mgen=1400 if len(sensor_data) > max_mgen: sensor_data = sensor_data[:max_mgen] size = max_mgen + 54 @@ -45,18 +114,31 @@ def send_sensor_payload(self, sensor_data, ip_addr, ip_port, interface,max_mgen= print "Executed MGEN send !!" return mgenevent - def send_text_payload(self, text, ip_addr, ip_port, interface, max_mgen=1400): - ''' Sends text string as mgen payload + def send_text_payload(self, text, ip_addr, ip_port, interface, flowid): + ''' Send a text-based payload using MGEN - RPC call to construct and send an mgen message with a text data payload + RPC call to construct and send an mgen message with a text payload Required input: - send_text_payload(text,ip_addr,ip_port,interface) - - Because of mgen payload limits if length is longer the 255 it + :param text: text for mgen packet data field + :param ip_addr: ip destination address + :param ip_port: ip destination port + :param interface: network interface name to use as source + :param max_mgen: maximum mgen packet size to use + :type sensor_data: str + :type ip_addr: str + :type ip_port: int + :type interface: str + :type flowid: int + :returns: MGEN event line that was invoked by agent + :rtype: str + + ..warning:: + Because of mgen payload limits if length is longer the max_mgen it will truncate. Packet size will be autocalculated using the following ipv4_mgen_header = 54 + payload length (bytes) ''' + max_mgen=1400 if len(text) > max_mgen: sensor_data = text[:max_mgen] size = max_mgen + 54 @@ -64,7 +146,7 @@ def send_text_payload(self, text, ip_addr, ip_port, interface, max_mgen=1400): size = len(text) + 54 mgen_size = " per [1 {0}]" .format(unicode(str(size),'utf-8')) - mgenevent = "on 1 udp dst " + str(ip_addr) + "/" + str(ip_port)\ + mgenevent = "on " + str(flowid) + " udp dst " + str(ip_addr) + "/" + str(ip_port)\ + mgen_size\ + " count 1 interface " + str(interface)\ + " data [{0}]" .format(text.encode('hex','strict').rstrip()) @@ -76,17 +158,33 @@ def send_text_payload(self, text, ip_addr, ip_port, interface, max_mgen=1400): def send_event (self, mgen_event): ''' Send a raw mgen event - Send Raw mgen event commands over the zerorpc connection + Function to send a raw mgen event conformant with + MGEN Reference and Users Guide. + + :param mgen_event: MGEN event + :returns: MGEN event line that was invoked by agent + :rtype: str + + ..note: + Refer to MGEN Reference and Users Guide. ''' - + self.sender.send_event(mgen_event) print "Executed MGEN send !!" return mgen_event def send_mgen_cmd(self, mgen_cmd): - ''' Send a raw mgen event + ''' Send an mgen command - Send Raw mgen event commands over the zerorpc connection + Function to send an mgen command conformant with + MGEN Reference and Users Guide. + + :param mgen_cmd: MGEN command + :returns: MGEN command line that was invoked by agent + :rtype: str + + ..note: + Refer to MGEN Reference and Users Guide. ''' self.sender.send_command(mgen_cmd) @@ -94,30 +192,80 @@ def send_mgen_cmd(self, mgen_cmd): return mgen_cmd def my_name(self): - ''' Returns name of controller instance''' + ''' Function to return name of actor to remote RPC client + + :returns: name of Actor Class instance + :rtype: str + + ''' return self.name + def has_gps(self): + ''' Function to return whether has_gps is enabled + + has_gps is a state variable that determines whether + gps reading and writing is supported for an mgen Actor instance + + :returns: has_gps + :rtype: boolean + + ''' + return self.hasGps + + def publish_gps_pos(self,lat,lon,alt): + ''' Helper function to write lat,lon,alt to shared memory location + + :returns: N/A + + ''' + if self.hasGps: + try: + self.gpsLat = float(lat) + self.gpsLon = float(lon) + self.gpsAlt = float(alt) + except ValueError: + print "publish_gps_pos() error converting values" + return + gpsPub.GPSPublishPos(self.gpsHandle,self.gpsLat, self.gpsLon, self.gpsAlt) + else: + print "publish_gps_pos() gps not enabled." + return + + def get_gps_pos(self): + ''' Helper function to return lat,lon,alt from shared memory location + + :returns: gpsLat,gpsLon,gpsAlt + + ''' + if not self.hasGps: + print "get_gps_pos() gps not enabled." + return False + else: + return self.gpsLat,self.gpsLon,self.gpsAlt + def shutdown(*args): print "Shutting down" sys.exit(0) def main(): - usagestr = "usage: %prog [-h] [options] [args]" - parser = optparse.OptionParser(usage = usagestr) - - parser.set_defaults(addr = "127.0.0.1") - parser.set_defaults(port = 5555) - parser.set_defaults(name = "mgenActor") - parser.add_option("-a", "--addr", dest = "addr", type = str, - help = "addr to bind zerorpc server; default = %s" % - parser.defaults["addr"]) - parser.add_option("-p", "--port", dest = "port", type = int, - help = "port for zerorpc server; default = %s" % - parser.defaults["port"]) - parser.add_option("-n", "--name", dest = "name", type = str, - help = "name for mgen controller; default = %s" % - parser.defaults["name"]) + parser = argparse.ArgumentParser() + parser.add_argument("-a", "--addr", + type = str, + default = "127.0.0.1", + help = "addr to bind zerorpc server") + parser.add_argument("-p", "--port", + dest = "port", + type = int, + default=10101, + help = "port for zerorpc server") + parser.add_argument("-n", "--name", + dest = "name", + type = str, + default = "mgenActor", + help = "name for mgen controller") + parser.add_argument("-d", "--disableGps", dest = "hasGps", action='store_false', + help = "disable gps for this actor; gps is enabled by default") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: @@ -129,16 +277,20 @@ def usage(msg = None, err = 0): signal.signal(signal.SIGTERM, shutdown) # parse command line options - (options, args) = parser.parse_args() + args = parser.parse_args() - if options.port < 2000 or options.port > 100000: - usage("invalid port: %s" % options.port) + if args.port < 2000 or args.port > 100000: + usage("invalid port: %s" % args.port) - port=options.port - server_url = "tcp://" + options.addr + ":%s" % str(port) + port=args.port + server_url = "tcp://" + args.addr + ":%s" % str(port) print server_url - s = zerorpc.Server(MgenActor(options.name)) + hasGps = args.hasGps + if _HAVE_GPSPUB is False: + hasGps = False + print "_gpsPub not installed on this system, disabling gps support" + s = zerorpc.Server(MgenActor(args.name,hasGps)) s.bind(server_url) s.run() diff --git a/src/python/mgenExample.py b/src/python/mgenExample.py index ec900302..7009ae50 100644 --- a/src/python/mgenExample.py +++ b/src/python/mgenExample.py @@ -2,7 +2,8 @@ # Create an MgenController instance # (an underlying "mgen" process is instantiated) -receiver = mgen.Controller() +# Note the instance name passed in is completely _optional_ +receiver = mgen.Controller("receiver") # Send a global command receiver.send_command("ipv4") @@ -34,6 +35,7 @@ # alternatively with no size validation sender.send_event("6.0 mod 1 data [%s]" % "Flow 1 modified payload".encode('hex','strict').rstrip()) + # Monitor mgen receiver's output for events updateCount = 1 for line in receiver: