# DAST library

### NLANR applications support
http://dast.nlanr.net/
<dast@nlanr.net>

#### Mark Gates
Alex Warshavsky

## Introduction

In developing Iperf and other network programs, a number of C++ classes, C utilities, and autoconf macros were developed that are generic. The C++ classes are intended to be similar in design to the corresponding Java classes. These are packaged in the lib directory, and may be included in other projects, subject to the UI license.

(This page is slightly out of date. Refer to the source files for some new functions.)

## Socket class

The socket class represents a socket end point of a TCP or UDP connection. It has wrappers around the common socket functions to create a socket connection. Typically I have Server, Listener, and Client sub-classes of Socket.

Functions:

Socket( short inPort, bool inUDP = false )
  Constructor. Stores the port number and whether this will be a UDP (true) or TCP (false) socket.

virtual ~Socket()
  Destructor. Closes the socket if it has not been closed yet.

void Listen( const char *inLocalhost = NULL )
  Creates a socket, binds it to a local address and port, and starts listening on it. If inLocalhost is null, the socket is bound to the wildcard address, so the socket will listen for connections on any interface. If inLocalhost is not null, that address is DNS resolved and used to bind the socket, to specify the local interface to listen on.

int Accept( void )
  Accept is a wrapper around the socket accept call. It provides the additional facilty of restarting an accept call if it interupted. Assumes the socket is setup with Listen() first.

void Connect( const char *inHostname, const char *inLocalhost = NULL )
  Connects the socket to the server. inHostname is DNS resolved to get the server's IP address. If inLocalhost is not null, it is also DNS resolved and used to bind the socket to a local interface, which specifies the outgoing interface to use.

void Close( void )
  Closes the socket

virtual void SetSocketOptions( void )
  A virtual function that subclasses may override to set socket options at the appropriate time. Several socket options, including TCP window sizes, must be set before calling the socket connect() or listen() calls. SetSocketOptions is called in the Listen() and Connect() functions. The default implementation is empty.

## Queue class

The queue class stores arbitrary pointers in a queue, and provides functions to make the queue thread-safe using pthreads.

Queue( int inSize )
  Constructor. Creates a queue with space allocated for inSize pointers. Note that an array of inSize+1 is allocated; one space is unusable.

~Queue()
  Destructor. Deletes the array of pointers. Does nothing with the pointers themselves; the caller is responsible for removing and deleting all pointers before deleting the queue.

bool Enqueue( void* inItem )
  Stores a pointer into the queue. Returns true if the operation was successful. If the queue is full, returns false and does not store the pointer.

void* Dequeue( void )
  Removes and returns the front pointer from the queue. If the queue is empty, returns null and does not change the queue.

void* Front( void )
  Returns (but does not remove) the front pointer from the queue. If the queue is empty, returns null and does not change the queue.

int Size( void )
  Returns the number of items in the queue.

bool IsEmpty( void )
  Returns true if the queue is empty.

bool IsFull( void )
  Returns true if the queue is full.

void BlockUntilSignal( time_t inAbsTimeout = 0 )
  Blocks the calling thread until a condition signal is sent. The condition signal is sent whenever the queue is unlocked, and usually indicates the queue has been changed.

void Lock( void )
  Puts a mutual exclusion lock (pthread mutex) on the queue.

void Unlock( void )
  Releases a mutual exclusion lock (pthread mutex) on the queue and sends a condition signal to wake up any threads blocked in BlockUntilSignal().

## Thread class

Used to create and run a new thread. Currently this implementation uses pthreads.

Thread( void )
  Constructor. Initializes the thread class. Does not actually create a new thread.

virtual ~Thread()
  Destructor. Immediately exits the thread if it is still running.

void Start( void )
  Create a new thread and call its Run() function.

void Stop( void )
  Immediately stop the thread. The thread itself may call this to call pthread_exit. Other threads may call this to call pthread_cancel.

virtual void Run( void ) = 0;
  Pure virtual function which subclasses must implement. This is called by Start() and should be the main loop for the thread.

void Join( void )
  Wait for the thread to exit.

static void Joinall( void )
  Wait for all threads (which are created by the Thread class) to exit.

void DeleteSelfAfterRun( void )
  Sets a flag so the Thread object will delete itself when it exits. The caller no longer has responsibility for deleting the Thread object.

static void* Run_Wrapper( void* objectPtr )
  Lov level function which starts the new thread. This is necesary because pthread_create is a C library function and does not understand C++ classes. A pointer the the Thread object is passed in as the argument in pthread_create.

## Timestamp class

The timestamp class is a wrapper around the unix gettimeofday second/microsecond time. (TODO how to implement on Windows?) This is intended as a platform-independant API. It offers both integer second/microsecond access and floating point access. All functions are inlined for optimal performance.

Timestamp( void )
  Create a timestamp, with the current time in it.

Timestamp( unsigned long sec, unsigned long usec )
  Create a timestamp, with the given seconds/microseconds.

Timestamp( double sec )
  Create a timestamp, with the given seconds.

void setnow( void
  Set timestamp to current time.

void set( unsigned long sec, unsigned long usec )
  Set timestamp to the given seconds/microseconds.

void set( double sec )
  Set timestamp to the given seconds.

unsigned long getSecs( void )
  Return seconds portion of timestamp.

unsigned long getUsecs( void )
  Return microseconds portion of timestamp.

double get( void )
  Return timestamp as a floating point seconds.

unsigned long subUsec( Timestamp right )
  Subtract the right timestamp from my timestamp. Return the difference in microseconds.

double subSec( Timestamp right )
  Subtract the right timestamp from my timestamp. Return the difference in seconds as a floating point.

void add( Timestamp right )
  Add the right timestamp to my timestamp.

void add( double sec )
  Add the seconds to my timestamp.

bool before( Timestamp right )
  Return true if my timestamp is before the right timestamp.

bool after( Timestamp right )
  Return true if my timestamp is after the right timestamp.

## C utilities

These are a number of utility functions of varying usefulness for other applications. All are declared in util.h, but the implementations are defined in a variety of C source files.

void ntoh( void *buffer, int len, int inSizeof )
void hton( void *buffer, int len, int inSizeof )
  Convert the endian-ness of an entire array of elements, each of size inSizeof, between network byte order and the host's native byte order. ntoh translates from network byte order, hton translates to network byte order. (Actually, it is the same translation, the names are merely descriptive.) On big-endian hosts, these are null macros. On little endian hosts, each takes O(n) time.

int setsock_tcp_windowsize( int inSock, int inTCPWin )
  Set the send and receive TCP window size for a socket. This handles verifying the TCP window size was set correctly, and prints a warning on stderr if the OS did not accept the exact specified window size. If the window size is zero (0), nothing is done. Has special code for UNICOS and AIX.

int getsock_tcp_windowsize( int inSock )
  Returns the TCP window size, as specified by the send buffer size, for the given socket. If inSock is invalid (inSock < 0), a new TCP socket is created and the OS's default TCP window size is returned.

void setsock_tcp_mss( int inSock, int inTCPWin )
  Set the TCP maximum segment size. The MTU is the MSS + 40 bytes for the IP header. Many OSes do not support setting this option, and the MSS may only be lowered, not raised, since the MTU is a physical characteristic of the network interface. This handles verifying the TCP mss was set correctly, and prints a warning on stderr if the OS did not accept the specified mss.

int getsock_tcp_mss( int inSock )
  Returns the TCP maximum segment size for the given socket. Usually this will not be valid until after the socket has been connected, since before that the interface is unspecified.

ssize_t readn( int inSock, void *outBuf, size_t inLen )
  Read a complete buffer, rather than returning prematurely with the buffer only partially filled as socket read call usually does. This code is from Stevens, 1998, section 3.9.

ssize_t writen( int inSock, const void *inBuf, size_t inLen )
  Write a complete buffer, rather than returning prematurely with only part of the buffer written. The socket write call never returns before writing the complete buffer, but nothing in the specification disallows that behaviour, so this is for our safety. This code is from Stevens, 1998, section 3.9.

unsigned long delay_loop( unsigned long usecs )
  An (more) accurate microsecond delay function. With very small values, usleep often sleeps for much more time than requested, since it gives up time to the OS. delay_loop iterates a very small loop, so it often is much more accurate for small values. Similar to the linux BogoMips code. For best accuracy, delay_loop_calibrate should be called first. This is a new implementation since Iperf 1.0.

void delay_loop_calibrate( void )
  Calibrates the delay_loop() function for this processor. It samples the delay_loop for various times, and corrects for the function call and other overhead.

typedef void Sigfunc( int)
SigfuncPtr my_signal( int inSigno, SigfuncPtr inFunc )
  Exactly the same as signal(), but internally uses sigaction which has a POSIX standard and so is more likely to be portable.

void die( const char *inMessage, const char *inFile, int inLine )
  Print the message on stderr and call exit(1). If compiled without defining NDEBUG, also prints out the filename and line number where it was called from.

void die_errno( const char *inMessage, const char *inFile, int inLine )
  Print the message, errno and its strerror description, and call exit(1). If compiled without defining NDEBUG, also prints out the filename and line number where it was called from.

FAIL( cond, msg ) [macro]
  Calls die if the condition is true.

FAIL_errno( cond, msg ) [macro]
  Calls die_errno if the condition is true.

void pattern( char *outBuf, int inBytes )
  Fill a character buffer with some data. Currently the data is the digits 0 through 9 repeated.

void replace( char *position, int poslen, const char *replacement )
  Starting at position, remove poslen number of characters and insert the replacement string. Characters after poslen are shifted to fit after the replacement string. TODO this assumes position is allocated long enough to fit the replacement string.

char *concat( char *dest, int len, const char *src )
  Append the src string to the dest string, without overwriting the allocated length, len, of the dest string and ensuring a null terminating character is always stored.

double byte_atof( const char *inString )
  Given a string of form #x where # is a number and x is a format character listed below, this returns the interpreted floating point number. Gg, Mm, Kk are giga, mega, kilo-bytes respectively. (Iperf v1.0 had a byte_atoi function, but the atof is more general.)

void byte_printf( double inNum, char inFormat )
  Given a number in bytes and a format, converts the number and prints it out with a bits or bytes label.
  B, K, M, G, A for Byte, Kbyte, Mbyte, Gbyte, adaptive byte
  b, k, m, g, a for bit, Kbit, Mbit, Gbit, adaptive bit
  adaptive picks the "best" one based on the number.

DELETE( ptr ) [macro]
  If ptr is not null, delete it and set it to null. This prevents deleting the same object twice, at least using that pointer.

## autoconf macros

DAST_CHECK_BOOL
  Checks if bool, true, and false are defined. Defines bool as int, true as 1, false as 0 if not defined. Often it is helpful to call for just C++ code:

  AC_LANG_SAVE
  AC_LANG_CPLUSPLUS
  DAST_CHECK_BOOL
  AC_LANG_RESTORE

DAST_CHECK_TYPE( type, includes )
  Does a similar check to AC_CHECK_TYPE( type, default ), but if type isn't defined it doesn't define it. Also you may specify what header files to include. Default includes are <sys/types>, <stdlib.h>, or <stddef.h>. This defines HAVE_<type>. For example, DAST_CHECK_TYPE( int32_t ) will define HAVE_INT32_T on machines with int32_t defined. This is useful if there is no single default value to use; in the case of int32_t it depends on what integer type has sizeof == 4.

DAST_ASK( message, variable, default )
  Prompts the user for input, with a default value in square brackets, and reads the result into the given variable.

DAST_PROG_CC
DAST_PROG_CXX
  These two prompt the user for what compiler to use. Define the CFLAGS and CXXFLAGS to be 2nd level optimization (-O2 or similar). If the compiler is gcc, also add -Wall. Currently recognizes HP-UX and SunOS special cases for the optimization flags. Does not include the -g debug flag as AC_PROG_CC and AC_PROG_CXX do.

DAST_CHECK_PTHREAD
  Check for pthreads in either -lpthread or -lpthreads. If found, add -lpthread(s) to LIBS and -D_REENTRANT to CFLAGS and CXXFLAGS.

DAST_CHECK_LIB
  Similar to AC_CHECK_LIB, but try to link the code without the library first. Some OSes include functions in a library (like socket in -lsocket) but do not require explicitly compiling with that library.

## Bugs and Comments

While these functions have been extensively tested, there may be bugs in this code; if any arise, or if unexpected behaviour results, please contact us at <dast@nlanr.net>. There are also a number of issues this code does not yet consider. We would like to implement these as they become important to our users, so please send in requests for features. If these do not work on a particular platform or host, we can probably help solve those issues.

Copyright 1999
The Board of Trustees of the University of Illinois
All rights reserved
See UI License for complete details.

dast@nlanr.net Last modified: Jan 10, 2000
NLANR || applications support || engineering support || measurement and operations