UDP Client/Server

The UDP Client/Server implements a minimum case server on both the local PC and on a Rabbit BL2100 Smartcat processor and a Client that talks to either of them.

Server.c

/**************************************************************************************
* Copyright (c) 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
**************************************************************************************/

/***************************************************************************************
*                                                                                      *
* Server.c implements a minimum case UDP command server on Port 50001 and is addressed *
* by the Client.c implementation.                                                      *
*                                                                                      *
* Valid Commands are:  Des, Rev, Man and Val                                           *
*                                                                                      *
* To compile from the command line:  "CL Server.c"                                     *
*                                                                                      *
***************************************************************************************/

#pragma warning ( disable : 4514 )                          /* "unreferenced inline function has been removed"                   */

#pragma warning ( push, 3 )                                 /* Suppress Warnings from WINDOWS.H and WINSOCK2.H                   */
#include <WINSOCK2.H>                                       /* Windows Sockets Version 2.0                                       */
#pragma warning ( pop )                                     /* Return to Normal Processing                                       */

#include <STDIO.H>                                          /* Standard I/O Prototypes and Defines                               */
#include <STDDEF.H>                                         /* Definitions/Declarations for Common Constants, Types, Variables   */
#include <STDLIB.H>                                         /* Definitions/Declarations for Commonly Used Library Routines       */

#pragma comment ( lib, "ws2_32.lib" )                       /* Include the Library to Link the Functions Defined in WINSOCK2.H   */

#define DEFAULT_PORT 50001U                                 /* The UDP Port Number                                               */

#define RANGE(SPECIFIED_VALUE,MIN_VALUE,MAX_VALUE) min ( max ( ( SPECIFIED_VALUE ), ( MIN_VALUE ) ), ( MAX_VALUE ) )

static const char g_szDesc[]     = "UDP Server Rev 1.0";    /* The UDP Server Description and Revision Number                    */
BOOL              g_fMan         = FALSE;                   /* TRUE = We are in Manual Mode, FALSE = We are in Automatic Mode    */
int               g_anVal [ 10 ] = { 0 };                   /* Array of Integer Values                                           */

/**************************************************************************************
* Detect and Honor all of the Normal Shutdown Events, Including Ctrl+C and Ctrl+Break *
**************************************************************************************/

BOOL g_fShutDownRequested = FALSE;

static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

   {

   switch ( dwCtrlType )
      {
      case CTRL_C_EVENT:               /* Ctrl+C at the Keyboard           */
      case CTRL_BREAK_EVENT:           /* Ctrl+Break at the Keyboard       */
      case CTRL_CLOSE_EVENT:           /* Close at System Menu or Button   */
      case CTRL_LOGOFF_EVENT:          /* User Logoff Event                */
      case CTRL_SHUTDOWN_EVENT:        /* System Shutdown Event            */

         g_fShutDownRequested = TRUE;  /* Set Shutdown Requested           */

         return TRUE;

      default:  return FALSE;
      }

   }  /* static BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) */

size_t ProcessCommands ( char * szRequest, char * szResponse, size_t cbResponse )

   {
   char  * pszCommand   = NULL;        /* Pointer to the Command String    */
   char  * pszValue     = NULL;        /* Pointer to the Value String      */
   char  * pszIndex     = NULL;        /* Pointer to the Index String      */

   int   nIndex         = 0;           /* Set to the Requested Array Index */

/*
 * Get the Command
 */
   if ( ( pszCommand = strtok ( szRequest, " " ) ) == NULL )
      pszCommand = szRequest;

/*
 * Process a "Des" Command
 */
   if ( strcmpi ( pszCommand, "Des" ) == 0 )
      {
      return _snprintf ( szResponse, cbResponse, g_szDesc );
      }

/*
 * Process a "Rev" Command
 */
   else if ( strcmpi ( pszCommand, "Rev" ) == 0 )
      {
      return _snprintf ( szResponse, cbResponse, strstr ( g_szDesc, "Rev" ) );
      }

/*
 * Process a "Man" Command - This is an Example of Setting a Boolean Value
 */
   else if ( strcmpi ( pszCommand, "Man" ) == 0 )
      {
      if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
         {
         g_fMan = RANGE ( atoi ( pszValue ), 0, 1 );
         }

      return _snprintf ( szResponse, cbResponse, "Man %d", g_fMan );
      }

/*
 * Process a "Val" Command - This is an Example of Setting an Element in an Array
 */
   else if ( strcmpi ( pszCommand, "Val" ) == 0 )
      {

   /*
    * "Val" with No Parameters Returns All Values
    */
      if ( ( pszIndex = strtok ( NULL, " " ) ) == NULL )
         {
         char  szValue  [  16 ]  = { 0 };       /* Area to Print the Value          */
         char  szBuffer [ 128 ]  = { 0 };       /* Area to Concatenate the Values   */

         strcpy ( szBuffer, "Val " );

         for ( nIndex = 0; nIndex < sizeof g_anVal / sizeof g_anVal [ 0 ]; nIndex++ )
            {
            sprintf ( szValue, "%d,", g_anVal [ nIndex ] ),
            strcat ( szBuffer, szValue );
            }

         szBuffer [ strlen ( szBuffer ) - 1 ] = '\0'; /* Remove the Trailing ',' */

         return _snprintf ( szResponse, cbResponse, "%s", szBuffer );
         }

   /*
    * "Val <index>" - Test for Legal Index
    */
      else
         {
         nIndex = atoi ( pszIndex );
         if ( nIndex < 0 || nIndex >= sizeof g_anVal / sizeof g_anVal [ 0 ] )
            {
            return _snprintf ( szResponse, cbResponse, "Val %d Illegal Index - Must Range Between 0 and %d", nIndex, sizeof g_anVal / sizeof g_anVal [ 0 ] - 1 );
            }
         }

   /*
    * "Val <index> <newvalue>"
    */
      if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
         {

      /*
       * Only Set to New Value if in Manual Mode
       */
         if ( ! g_fMan )
            {
            return _snprintf ( szResponse, cbResponse, "Must be in Manual Mode" );
            }

      /*
       * Set Value [ <index> ] to <NewValue> Within Range of 0 to 100
       */
         g_anVal [ nIndex ] = RANGE ( atoi ( pszValue ), 0, 100 );
         }

      return _snprintf ( szResponse, cbResponse, "Val %d %d", nIndex, g_anVal [ nIndex ] );
      }

/*
 * The Command is Invalid
 */
   else return _snprintf ( szResponse, cbResponse, "Valid Commands are:  Des, Rev, Man and Val" );

   }  /* size_t ProcessCommands ( char * szRequest, char * szResponse, size_t cbResponse ) */

int main ( int argc, char * argv [], char * envp [] )

   {
   WSADATA        stWSAData            = { 0U };                        /* Winsock Library Information               */

   SOCKET         uUDPSocket           = INVALID_SOCKET;                /* The UDP Socket                            */
   unsigned short usUDPPort            = DEFAULT_PORT;                  /* The Default UDP Port Number               */

   int            nTimeoutMS           = 100;                           /* The Socket Timeout Value in milliseconds  */

   SOCKADDR_IN    sinUDPServer         = { AF_INET, 0U, INADDR_ANY };   /* Incoming Socket Address                   */
   SOCKADDR_IN    sinUDPClient         = { 0 };                         /* Outgoing Socket Address                   */

   char           szRequest   [ 256 ]  = { 0 };                         /* Temporary Incoming Command Buffer         */
   char           szResponse  [ 256 ]  = { 0 };                         /* Temporary Incoming Command Buffer         */

   int            cbRecd               = 0;                             /* The Number of Bytes Received              */
   int            cbSent               = 0;                             /* The Number of Bytes Transmitted           */

   UNREFERENCED_PARAMETER ( argc );
   UNREFERENCED_PARAMETER ( argv );
   UNREFERENCED_PARAMETER ( envp );

/*
 * Initiate the Windows Sockets Version 2.1
 */
   if ( WSAStartup ( MAKEWORD ( 2, 1 ), &stWSAData ) != 0 )
      {
      int nErrorCode = WSAGetLastError(); /* i.e. WSASYSNOTREADY  */

      fprintf ( stderr, "main():  WSAStartup() returned %d!\n", nErrorCode );
      WSACleanup();

      return 1;
      }

/*
 * Set the Port Number
 */
   sinUDPServer.sin_port = htons ( usUDPPort );

/*
 * Create the Datagram (UDP) Socket
 */
   if ( ( uUDPSocket = socket ( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET )
      {
      int nErrorCode = WSAGetLastError();

      fprintf ( stderr, "main():  socket() returned %d!\n", nErrorCode );
      WSACleanup();

      return 2;
      }

/*
 * Set the Timeout to 100 ms
 */
   setsockopt ( uUDPSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &nTimeoutMS, sizeof ( nTimeoutMS ) );

/*
 * Connect the Socket to Our Address
 */
   if ( bind ( uUDPSocket, ( struct sockaddr * ) &sinUDPServer, sizeof sinUDPServer ) == SOCKET_ERROR)
      {
      int nErrorCode = WSAGetLastError(); // i.e. WSAEADDRINUSE (10048)

      fprintf ( stderr, "main():  bind() returned %d!\n", nErrorCode );
      WSACleanup();

      return 3;
      }

/*
 * Bump to the Maximum Process and Thread Priority for the Timings Below
 */
   if ( ! SetPriorityClass ( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) )
      {
      fprintf ( stderr, "SetPriorityClass() returned %d!\n\a", GetLastError() );
      return 4;
      }

   if ( ! SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ) )
      {
      fprintf ( stderr, "SetThreadPriority() returned %d!\n\a", GetLastError() );
      return 5;
      }

/*
 * Main Processing Loop
 */
   fprintf ( stdout, "UDP Port %u Online!\n", DEFAULT_PORT );

   SetConsoleCtrlHandler ( ControlHandler, TRUE );

   while ( ! g_fShutDownRequested )
      {
      int cbSinUDPClient = sizeof sinUDPClient;

   /*
    * Receive the Request
    */
      memset ( szRequest, 0, sizeof szRequest );

      while ( ! g_fShutDownRequested )
         {
         if ( ( cbRecd = recvfrom ( uUDPSocket, szRequest, sizeof szRequest, 0, ( struct sockaddr * ) &sinUDPClient, &cbSinUDPClient ) ) != SOCKET_ERROR ) break;
         if ( WSAGetLastError() == WSAETIMEDOUT ) continue;

         fprintf ( stderr, "recvfrom() returned %d!\n", WSAGetLastError() );
         continue;
         }

      if ( g_fShutDownRequested ) break;

   /*
    * Display the Request
    */
      printf ( "\r==>  %s\t\t\n", szRequest );

   /*
    * Process the Command
    */
      ProcessCommands ( szRequest, szResponse, sizeof szResponse );

   /*
    * Return the Results
    */
      printf ( "%s\t\t\n", szResponse );

      if ( ( cbSent = sendto ( uUDPSocket, ( const char * ) szResponse, strlen ( szResponse ), 0, ( struct sockaddr * ) &sinUDPClient, cbSinUDPClient ) ) == SOCKET_ERROR )
         {
         fprintf ( stderr, "SvrPutAESEncryptedUDPPacket():  sendto() returned %d!\n", WSAGetLastError() );
         return 0U;
         }

      }  /* End - while ( ! fShutDownRequested ) */

/*
 * Close the UDP Socket
 */
   closesocket ( uUDPSocket );

   uUDPSocket = INVALID_SOCKET;

/*
 * Cleanup and Terminate Windows Sockets Version 2.1
 */
   WSACleanup();

/*
 * Return Success!
 */
   fprintf ( stdout, "\nBye!\n" );

   return 0;

   }  /* int main ( int argc, char * argv [], char * envp [] ) */

Smartcat.c

/**************************************************************************************
* Copyright (c) 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
**************************************************************************************/

/******************************************************************************************
*                                                                                         *
* Smartcat.c implements a minimum case UDP command server on Port 50001 and is addressed  *
* by the Client.c implementation.                                                         *
*                                                                                         *
* Valid Commands are:  Des, Rev, Man and Val                                              *
*                                                                                         *
* This Smartcat version closely replicates the Server.c version.                          *
*                                                                                         *
******************************************************************************************/

#define USE_ETHERNET             1                 // New for DCRABBIT_9.21 Compiler

#define MY_IP_ADDRESS            "192.168.10.147"  // ZWorld Demo Address
#define MY_NETMASK               "255.255.255.0"

#define TCPCONFIG                0                 // Use the Address Information Defined Abouve

#define MAX_UDP_SOCKET_BUFFERS   1                 // We only need one UDP socket

#class auto

#memmap xmem

#use "dcrtcp.lib"

#define DEFAULT_PORT 50001U                                 /* The UDP Port Number                                               */

#define RANGE(SPECIFIED_VALUE,MIN_VALUE,MAX_VALUE) min ( max ( ( SPECIFIED_VALUE ), ( MIN_VALUE ) ), ( MAX_VALUE ) )

typedef int BOOL;

static const char g_szDesc[]     = "UDP Server Rev 1.0";    /* The UDP Server Description and Revision Number                    */
BOOL              g_fMan;                                   /* TRUE = We are in Manual Mode, FALSE = We are in Automatic Mode    */
int               g_anVal [ 10 ];                           /* Array of Integer Values                                           */

size_t ProcessCommands ( char * szRequest, char * szResponse, size_t cbResponse )

   {
   char  * pszCommand;                 /* Pointer to the Command String    */
   char  * pszValue;                   /* Pointer to the Value String      */
   char  * pszIndex;                   /* Pointer to the Index String      */

   int   nIndex;                       /* Set to the Requested Array Index */
   char  szValue  [  16 ];             /* Area to Print the Value          */
   char  szBuffer [ 128 ];             /* Area to Concatenate the Values   */

   pszCommand  = pszValue = pszIndex = NULL;

   nIndex      = 0;

/*
 * Get the Command
 */
   if ( ( pszCommand = strtok ( szRequest, " " ) ) == NULL )
      pszCommand = szRequest;

/*
 * Process a "Des" Command
 */
   if ( strcmpi ( pszCommand, "Des" ) == 0 )
      {
      return sprintf ( szResponse, g_szDesc );
      }

/*
 * Process a "Rev" Command
 */
   else if ( strcmpi ( pszCommand, "Rev" ) == 0 )
      {
      return sprintf ( szResponse, strstr ( g_szDesc, "Rev" ) );
      }

/*
 * Process a "Man" Command - This is an Example of Setting a Boolean Value
 */
   else if ( strcmpi ( pszCommand, "Man" ) == 0 )
      {
      if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
         {
         g_fMan = RANGE ( atoi ( pszValue ), 0, 1 );
         }

      return sprintf ( szResponse, "Man %d", g_fMan );
      }

/*
 * Process a "Val" Command - This is an Example of Setting an Element in an Array
 */
   else if ( strcmpi ( pszCommand, "Val" ) == 0 )
      {

   /*
    * "Val" with No Parameters Returns All Values
    */
      if ( ( pszIndex = strtok ( NULL, " " ) ) == NULL )
         {
         memset ( szValue, 0, sizeof szValue );
         memset ( szBuffer, 0, sizeof szBuffer );

         strcpy ( szBuffer, "Val " );

         for ( nIndex = 0; nIndex < sizeof g_anVal / sizeof g_anVal [ 0 ]; nIndex++ )
            {
            sprintf ( szValue, "%d,", g_anVal [ nIndex ] ),
            strcat ( szBuffer, szValue );
            }

         szBuffer [ strlen ( szBuffer ) - 1 ] = '\0'; /* Remove the Trailing ',' */

         return sprintf ( szResponse, "%s", szBuffer );
         }

   /*
    * "Val <index>" - Test for Legal Index
    */
      else
         {
         nIndex = atoi ( pszIndex );
         if ( nIndex < 0 || nIndex >= sizeof g_anVal / sizeof g_anVal [ 0 ] )
            {
            return sprintf ( szResponse, "Val %d Illegal Index - Must Range Between 0 and %d", nIndex, sizeof g_anVal / sizeof g_anVal [ 0 ] - 1 );
            }
         }

   /*
    * "Val <index> <newvalue>"
    */
      if ( ( pszValue = strtok ( NULL, " " ) ) != NULL )
         {

      /*
       * Only Set to New Value if in Manual Mode
       */
         if ( ! g_fMan )
            {
            return sprintf ( szResponse, "Must be in Manual Mode" );
            }

      /*
       * Set Value [ <index> ] to <NewValue> Within Range of 0 to 100
       */
         g_anVal [ nIndex ] = RANGE ( atoi ( pszValue ), 0, 100 );
         }

      return sprintf ( szResponse, "Val %d %d", nIndex, g_anVal [ nIndex ] );
      }

/*
 * The Command is Invalid
 */
   else return sprintf ( szResponse, "Valid Commands are:  Des, Rev, Man and Val" );

   }  /* size_t ProcessCommands ( char * szRequest, char * szResponse, size_t cbResponse ) */

void main()

   {
   udp_Socket  uUDPSocket;

   char        szRequest   [ 128 ];
   char        szResponse  [ 128 ];

   longword    ip;
   word        port;

   auto int    i;

   // Initialize Sockets

   while ( ( i = sock_init() ) != 0 )
      {
      printf ( "sock_init() returned %d\n\a\a\a", i );
      }

   // Print the TCP/IP Address Info

   ip_print_ifs();

   // Open the UDP Socket

   if ( ! udp_open ( &uUDPSocket, 50001, -1, 0, NULL ) )
      {
      printf ( "udp_open() failed!\n" );
      exit ( 0 );
      }

      g_fMan = FALSE;                        /* TRUE = We are in Manual Mode, FALSE = We are in Automatic Mode    */
      memset ( g_anVal, 0, sizeof g_anVal ); /* Array of Integer Values                                           */

   // Main Processing Loop

   for(;;)
      {

      tcp_tick ( NULL );

      // Receive the Packet and Return the Sending Address and Port Number

      memset ( szRequest,  0, sizeof ( szRequest   ) );
      memset ( szResponse, 0, sizeof ( szResponse  ) );

      if ( udp_recvfrom ( &uUDPSocket, szRequest, sizeof szRequest, &ip, &port ) == -1 )
         continue;

      // Print the Incoming Datagram

      printf ( "==>  %s\n", szRequest );

   /*
    * Process the Command
    */
      ProcessCommands ( szRequest, szResponse, sizeof szResponse );

   /*
    * Return the Results
    */
      printf ( "%s\t\t\n", szResponse );

      // Send the Response
      udp_sendto ( &uUDPSocket, szResponse, strlen ( szResponse ), ip, port );

      }  // End - Main Procesing Loop

   }  // void main()


Client.c

/***************************************************************************************
*                                                                                      *
* Client.c implements client for the minimum case UDP command server on Port 50001.    *
* by the Client.c implementation.                                                      *
*                                                                                      *
* Run as:  "Client [ <server> [ <port> ] ]"                                            *
*                                                                                      *
* You can process commands from an external file:  "Client < Commands"                 *
*                                                                                      *
* To compile from the command line:  "CL Client.c"                                     *
*                                                                                      *
***************************************************************************************/

/**************************************************************************************
* Copyright (c) 2010 David Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
**************************************************************************************/

#pragma warning ( disable : 4514 )     /* unreferenced inline function has been removed         */

#pragma warning ( push, 3 )            /* Suppress Warnings from WINDOWS.H and WINSOCK2.H       */
#include <WINSOCK2.H>                  /* Windows Sockets Version 2.0                           */
#pragma warning ( pop )                /* Return to Normal Processing                           */

#include <IO.H>                        /* _isatty ( _fileno ( stdin ) ) );                      */
#include <STDIO.H>                     /* Definitions/Declarations for Standard I/O Routines    */

#pragma comment ( lib, "ws2_32.lib" )  /* Functions Defined in WINSOCK2.H                       */

#ifndef QWORD_DEFINED
typedef unsigned __int64 QWORD;
#define QWORD_DEFINED
#endif   /* QWORD_DEFINED */

/**************************************************************************************
* Detect and Honor all of the Normal Shutdown Events, Including Ctrl+C and Ctrl+Break *
**************************************************************************************/

BOOL g_fShutDownRequested = FALSE;

static BOOL WINAPI ControlHandler ( DWORD dwCtrlType )

   {

   switch ( dwCtrlType )
      {
      case CTRL_C_EVENT:               /* Ctrl+C from Keyboard                                  */
      case CTRL_BREAK_EVENT:           /* Ctrl+Break from Keyboard                              */
      case CTRL_CLOSE_EVENT:           /* Close from System Menu or Button                      */
      case CTRL_SHUTDOWN_EVENT:        /* System Shutdown Event                                 */
      case CTRL_LOGOFF_EVENT:          /* User Logoff Event                                     */

         g_fShutDownRequested = TRUE;  /* Set Shutdown Requested                                */
         return TRUE;

      default:
         fprintf ( stdout, "ControlHandler() Received %lu\n\a", dwCtrlType );
         return FALSE;
      }

   }  /* static BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) */

BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress )

   {
   struct hostent       * lpHostEntry  = gethostbyname ( strComputerNameOrAddress );
   struct sockaddr_in   stDestAddr     = { 0 };
   char                 * pszHostName  = NULL;

   if ( lpHostEntry )
      {
      memcpy ( &stDestAddr.sin_addr, lpHostEntry->h_addr_list [ 0 ], min ( sizeof stDestAddr.sin_addr, lpHostEntry->h_length ) );
      stDestAddr.sin_family = lpHostEntry->h_addrtype;
      }
   else
      {
      unsigned long lnAddr = 0LU;

      if ( ( lnAddr = inet_addr ( strComputerNameOrAddress ) ) == INADDR_NONE )
         {
         strncpy ( szAddress, "???.???.???.???", cbAddress );
         return FALSE;
         }
      }

/*
 * Convert the Destination Address Into a Printable String
 */
   pszHostName = inet_ntoa ( stDestAddr.sin_addr );

   strncpy ( szAddress, pszHostName, cbAddress );

   return TRUE;

   }  /* BOOL GetUDPAddress ( LPCSTR strComputerNameOrAddress, char * szAddress, size_t cbAddress ) */

int main ( int argc, char * argv[], char * envp [] )

   {
   SOCKET         uUDPSocket           = INVALID_SOCKET;                   /* The UDP Communications Socket             */

   SOCKADDR_IN    sinUDP               = { AF_INET, 0U };                  /* The Socket Intput Address                 */

   int            nTimeout             = 100;                              /* Desired Timeout Value in Milliseconds     */
   int            nResult              = 0;                                /* Error Return                              */

   WSADATA        stWSAData            = { 0U };                           /* The Windows Sockets Implementation Data   */

   char           * szHost             = NULL;                             /* The Host Name Parameter                   */
   char           szUDPAddress [ 16 ]  = "";                               /* The UDP Address of the Specified Host     */

   BOOL           fRedirected          = ! _isatty ( _fileno ( stdin ) );  /* Are Commands Comming from a Piped File?   */

   int            cbSent               = 0;                                /* The Number of Bytes Transmitted           */
   int            cbRecd               = 0;                                /* The Number of Bytes Received              */

   char           * szDefaultHost      = "localhost";                      /* The UDP Server's Default UDP Address      */
   unsigned short usPortNumber         = 50001U;                           /* The UDP Socket Port Number                */

/*
 * Account for Unreferenced Parameters
 */
   UNREFERENCED_PARAMETER ( envp );

/*
 * Start Up a Windows Socket Application
 */
   if ( WSAStartup ( MAKEWORD ( 2, 1 ), &stWSAData ) != 0 )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "WSAStartup() returned %d!\n\a", nErrorCode );
      return 1;
      }

/*
 * Determine the UDP Address and Socket Number to Use
 */
   szHost = argc > 1 ? argv [ 1 ] : szDefaultHost;

   if ( ! GetUDPAddress ( szHost, szUDPAddress, sizeof szUDPAddress ) )
      {
      fprintf ( stderr, "Host %s not found!\n\a", szHost );
      WSACleanup();
      return 2;
      }

   if ( argc > 2 )
      usPortNumber = ( unsigned short ) atoi ( argv [ 2 ] );

   sinUDP.sin_port = htons ( usPortNumber );

/*
 * Open the UDP Socket
 */
   if ( ( uUDPSocket = socket ( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET )
      {
      int nErrorCode = WSAGetLastError();
      fprintf ( stderr, "socket() returned %d!\n\a", nErrorCode );
      WSACleanup();
      return 3;
      }

/*
 * Set the Send and Receive Timeouts
 */
   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_SNDTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );
   nResult = setsockopt ( uUDPSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &nTimeout, sizeof ( nTimeout ) );

/*
 * Get the Socket Address
 */
   sinUDP.sin_addr.S_un.S_addr = inet_addr ( szUDPAddress );

/*
 * Connect it to the Remote Socket
 */
   if ( connect ( uUDPSocket, ( PSOCKADDR ) &sinUDP, sizeof ( sinUDP ) ) == SOCKET_ERROR )
      {
      int nErrorCode = WSAGetLastError(); /* i.e. WSAECONNREFUSED or WSAEADDRNOTAVAIL */
      closesocket ( uUDPSocket );
      uUDPSocket = INVALID_SOCKET;
      WSACleanup();
      fprintf ( stderr, "connect() returned %d <%s>!\n\a", nErrorCode, nErrorCode == WSAECONNREFUSED ? "Connection Refused" : "<unknown>" );
      return 4;
      }

/*
 * Do Normal Processing Here
 */
   SetConsoleCtrlHandler ( ControlHandler, TRUE );

/*************************************
* Process the Request/Response Pairs *
*************************************/

   while ( ! g_fShutDownRequested )
      {
      char  szRequest   [ 1024 ] = { '\0' };
      char  szResponse  [ 1024 ] = { '\0' };

      int   i                    = 0;

   /*
    * Get and Trim the Command String
    */
      fprintf ( stdout, "==>  " );

      if ( ! fgets ( szRequest, sizeof szRequest, stdin ) )
         break;

   /*
    * Find the Terminating '\0'
    */
      for ( i = 0; szRequest [ i ]; i++ );

   /*
    * Delete Trailing Newlines and Carriage Returns
    */
      while ( i && ( szRequest [ i - 1 ] == '\r' || szRequest [ i - 1 ] == '\n' ) )
         szRequest [ --i ] = '\0';

      if ( fRedirected )
         fprintf ( stdout, "%s\n", szRequest );

   /*
    * Send the Request
    */

      if ( ( cbSent = send ( uUDPSocket, szRequest, strlen ( szRequest ), MSG_DONTROUTE ) ) == SOCKET_ERROR )
         {
         fprintf ( stderr, "send():  send() returned %d!\n", WSAGetLastError() );
         continue;
         }

   /*
    * Get the Response
    */
      if ( ( cbRecd = recv ( uUDPSocket, szResponse, sizeof szResponse, 0 ) ) == SOCKET_ERROR )
         {
         fprintf ( stderr, "recv():  recv() returned %d!\n", WSAGetLastError() );
         continue;
         }

   /*
    * Print the Results
    */
      fprintf ( stdout, "%s\n", szResponse );

      }  /* End - while ( ! g_fShutDownRequested ) */

/*
 * Close the Socket
 */
   closesocket ( uUDPSocket );
   uUDPSocket = INVALID_SOCKET;

/*
 * Cleanup and Terminate Windows Sockets
 */
   WSACleanup();

/*
 * Return Success!
 */
   fprintf ( stdout, "\n\nBye!\n" );

   return 0;

   }  /* int main ( int argc, char * argv [], char * envp [] ) */