VR-Link API Documentation for DIS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DIS Netdump Example

Table of Contents

The DIS Netdump example is a simple program that prints all received PDUs to a console.

VR-Link includes this as a tool that can be used to monitor the information sent over the network. It particularly comes in handy as a debug tool, allowing users to see if packets are sent correctly, if there's anything flooding the network, and more.

Usage

  1. Launch 2 Command Windows from your VR-Link install's bin64 directory.
  2. Start a netdumpDIS application in one window.
  3. In the other window, start another application such as the f18DIS example.
  4. Observe the netdumpDIS console window populate with PDUs containing interactions and object updates.

Main Application

/****************************************************************************
* Copyright (c) 2015 MAK Technologies, Inc
* All rights reserved.
****************************************************************************/
#if DtDIS
#include <vlutil/vlTime.h>
#include <vl/unknownPdu.h>
#include <vcPdu.h>
#include <signal.h>
#include <stdio.h>
#include <iostream>
#include <vector>
// Reads and prints a PDU. Returns 0 if there were none to be read.
int readAndProcess( DtInetUdpSocket* skt );
// Globals
char* vb = 0;
char* clearScreen = (char *)"";
int numBetweenStdinChecks = 100;
#if defined(_WIN32) || defined(__solaris__)
unsigned int defaultReceiveBufferSize(DtInetUtils::getMaxPacketBufferSize());
#else
unsigned int defaultReceiveBufferSize(UINT_MAX);
#endif
DtCmdLine::ValueArg<DtString> destAddrString("A","destAddrString", "DIS Destination Address String", false, "0.0.0.0", "IP Address");
DtCmdLine::ValueArg<DtString> netmaskString("N","netmaskString", "DIS Net Mask Address String", false, "0.0.0.0", "IP Address");
DtCmdLine::ValueArg<DtString> deviceAddrString("","deviceAddress", "DIS Device Address String", false, "0.0.0.0", "IP Address");
DtCmdLine::ValueArg<int> disPort("P", "disPort", "DIS Port", false, 3000, "integer");
DtCmdLine::SwitchArg verbose("", "verbose", "Enable Verbose Output", false);
DtCmdLine::SwitchArg useIpv6("", "useIpv6", "Use IPv6", false);
DtCmdLine::SwitchArg errorChecking("", "errorChecking", "Enable Error Checking", false);
DtCmdLine::SwitchArg clearScreenFlag("c", "clrScreen", "Clear Screen Between PDUs", false);
DtCmdLine::ValueArg<int> receiveBufferSize("", "receiveBufferSize", "Receive Buffer Size", false, defaultReceiveBufferSize, "integer");
DtCmdLine::MultiArg<DtString> mcastAddrs("S", "mcastAddr", "Multicast Address", false, "IP Address");
DtCmdLine::SwitchArg printRaw("r", "raw", "Print Raw Data", false);
DtPduFactory* pduFactory;
DtClock* vrClock = new DtClock();
#if VXWORKS
#define main realMain
DT_VXWORKS_APP( netdump )
#endif
int main( int argc, char* argv[] )
{
// Used for error handling
DtINIT_MINIDUMPER( "DIS-Netdump" );
signal( SIGFPE, SIG_IGN );
DtInfo << "Using VR-Link version " << VR_LINK_VERSION_STRING << std::endl;
DtInfo << "Built on " << DtOperatingSystem() << " with " << DtCompiler() << " - " <<
#if defined( DT_HAVE_64BIT_LONGS ) || defined( _WIN64 )
"64bit"
#else
"32bit"
#endif
<< std::endl;
#ifndef _GT_
/* this increases speed of output, since dumpPdu will fflush */
setvbuf( stdout, NULL, _IOFBF, BUFSIZ );
#endif
DtCmdLine::CmdLine cmdLine("DIS Netdump", ' ', DtExerciseConn::vrlinkVersion().c_str());
cmdLine.add(destAddrString);
cmdLine.add(netmaskString);
cmdLine.add(deviceAddrString);
cmdLine.add(disPort);
cmdLine.add(verbose);
cmdLine.add(useIpv6);
cmdLine.add(errorChecking);
cmdLine.add(receiveBufferSize);
cmdLine.add(clearScreenFlag);
cmdLine.add(mcastAddrs);
cmdLine.add(printRaw);
cmdLine.parse(argc, argv);
if (clearScreenFlag)
{
clearScreen = (char *)"\033[H\033[2J";
}
// Initialize the socket
DtInetDevice* netDeviceToUse = 0;
DtInetDevice netDevice(DtInetAddr(deviceAddrString.getValue()));
if (deviceAddrString.isSet())
{
if (netDevice.isOk())
{
netDeviceToUse = &netDevice;
}
else
{
DtWarn << "Invalid device address: \"" << deviceAddrString.getValue()
<< "\" Using default." << std::endl;
}
}
DtInetEndpoint endpoint;
endpoint.setPort(disPort);
DtInetAddr destAddr(destAddrString.getValue());
if (netmaskString.isSet())
{
destAddr = DtInetAddr(destAddrString.getValue(), netmaskString.getValue());
}
if (destAddrString.isSet())
{
// The user set a destination address, use it.
endpoint.setAddress(destAddr);
}
else
{
// Use the primary broadcast address
if (bcastAddr)
{
endpoint.setAddress(*bcastAddr);
}
else
{
DtFatalError("Cannot obtain primary broadcast address.\n");
}
DtDELETE(bcastAddr);
}
DtInetUdpSocket* skt = new DtDisSocket(endpoint, 0, netDeviceToUse);
if (skt->isOk())
{
DtWarn << "Netdump socket OK to: " << skt->destination().toDtString() << std::endl;
}
else
{
DtFatalError("Cannot construct a socket to: %s\n",
}
if (receiveBufferSize.isSet())
{
// User changed the receive buffer size.
if (receiveBufferSize <= 0)
{
DtWarn << "Invalid receive buffer size: " << receiveBufferSize.getValue() << " must be > 0." << std::endl;
DtWarn << "Using default: " << skt->getReceiveBufferSize() << std::endl;
}
else
{
skt->setReceiveBufferSize(receiveBufferSize);
}
}
std::vector <DtString>::const_iterator pos = mcastAddrs.getValue().begin();
for (; pos != mcastAddrs.getValue().end(); ++pos)
{
}
pduFactory = &fact;
pduFactory->DtADD_PDU_CREATOR(ViewControl);
fflush( stdout );
if ( verbose )
{
vb =(char *)"************************************************************\n";
}
else
{
vb = (char *)"";
}
int forever = 1; // to keep cfront quiet
while( forever )
{
// Keep reading and processing as long as there is stuff to read.
// Check for keyboard input every numBetweenStdinChecks reads.
int numBeforeStdinCheck = 0;
do
{
if ( numBeforeStdinCheck == 0 )
{
numBeforeStdinCheck = numBetweenStdinChecks;
if ( input.keybrdTick() == -1 )
{
return 0;
}
}
else
{
--numBeforeStdinCheck;
}
} while( readAndProcess( skt ) );
}
return 0;
}
int readAndProcess( DtInetUdpSocket* skt )
{
static int n = 1;
char packet[15000];
DtInetEndpoint fromAddress;
DtInetSockRcvStatus status = skt->recvFrom((caddr_t)packet, 15000, fromAddress);
int size = status;
if ( !status )
{
return 0;
}
int pktSize = ( (DtNetPduHeader*)packet )->DtLength;
unsigned int pktVersion = ( (DtNetPduHeader*)packet )->version;
bool isCoupling = ((DtU8)((DtNetPduHeader*)packet)->pduStatus) & 0x8;
DtU8 pduVersion = (DtU8)((DtNetPduHeader*)packet)->version;
DtNetU8 pduStatus = (DtU8)((DtNetPduHeader*)packet)->pduStatus;
if ( size != pktSize && pktVersion >= 7 && !isCoupling)
{
DtWarn << "#### WARNING: Size mismatch: Received("<< size
<<"), DIS Header(" << pktSize << ") ####\n";
if ( errorChecking )
{
DtWarn << " Will not attempt to print this PDU." << std::endl;
return 1;
}
}
if ( printRaw )
{
DtInfo( "%s%s******** PDU #%-6d \t\t %13.3f secs ********\n%s",
clearScreen, vb, n++, vrClock->elapsedRealTime(), vb );
DtUnknownPdu unkPdu( (DtNetPacket*)packet, (DtBufferPtr)packet );
unkPdu.printHeader();
int pduSize = unkPdu.length();
for ( int k = 0; k < pduSize; k += 4 )
{
DtInfo("%04x\t%08x\n", k, *(DtU32 *)(unkPdu.netRep() + k));
}
DtInfo << std::endl;
}
if ( (((pduStatus >> 3) & 0x1) == 0x1))
{
// This is an error check to ensure there is sufficient space for the Attribute PDU
unsigned int couplingPadding = alignedPadding(pktSize, 8);
unsigned int minimumSizeForAttibutePdu = pktSize + couplingPadding + sizeof(DtNetAttributePdu);
if (!(size >= minimumSizeForAttibutePdu))
{
// There is not enough room for the minimum size of the Attribute PDU
// We will change it so the Coupled Extension Indicator is off
DtWarn << "Turning off Coupled Extension Indicator in Bad PDU due to packet having insufficient space" << std::endl;
DtU8 val = pduStatus;
// When Not Coupled, set bit to 0
DtPDU_STATUS_SET_INDICATOR_ONE_BIT(CoupledExtensionIndicator, NotCoupled);
((DtNetPduHeader*)packet)->pduStatus = val;
isCoupling = false;
}
else
{
// This is the common case, where a PDU has the coupled extension PDU indicator on, and there is sufficient room in the packet
}
}
DtPdu* pdu;
int version = ( (DtNetPduHeader*)packet )->version;
if ( version >= DtProtocolVersionToRecvMin &&
{
pdu = pduFactory->createPdu( (DtNetPacket*)packet, (DtBufferPtr)packet );
}
else
{
pdu = new DtUnknownPdu( (DtNetPacket*)packet, (DtBufferPtr)packet );
}
//METOC PDUs need access tot he standardVariableRecordFactory to decode the various METOC Layer Records.
//So we set the standardVariableRecordFactory on incoming PDUs here before they are printed.
DtPduWithAttributeRecordSets* pduWithAttrRecSet = dynamic_cast<DtPduWithAttributeRecordSets*>(pdu);
if (pduWithAttrRecSet)
{
}
if ( pdu )
{
if ( !printRaw )
{
DtInfo( "%s%s******** PDU #%-6d \t\t %13.3f secs ********\n%s",
clearScreen, vb, n++, vrClock->elapsedRealTime(), vb );
DtInfo("SourceInetAddr:\t %s\n", fromAddress.address().toDtString().c_str());
pdu->print();
DtInfo << std::endl;
}
DtDELETE( pdu );
}
if (isCoupling && !printRaw)
{
unsigned int couplingPadding = alignedPadding(pktSize, 8);
char* coupledPduPtr = packet + pktSize + couplingPadding;
pdu = pduFactory->createPdu((DtNetPacket*)coupledPduPtr, (DtBufferPtr)coupledPduPtr);
if (pdu)
{
DtInfo("%s%s******** PDU #%-6d \t\t %13.3f secs ********\n%s",
clearScreen, vb, n++, vrClock->elapsedRealTime(), vb);
DtInfo("SourceInetAddr:\t %s\n", fromAddress.address().toDtString().c_str());
pdu->print();
DtInfo << std::endl;
DtDELETE(pdu);
}
}
return 1;
}
#endif

Document ID: Generated on Wed Mar 27 02:04:30 EDT 2024 from SVN revision 264570
Copyright © 2005-2024 MAK Technologies. All Rights Reserved (www.mak.com)