home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / sockspx / sockspx.c < prev    next >
C/C++ Source or Header  |  1997-10-08  |  24KB  |  1,123 lines

  1. /******************************************************************************\
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright 1996-1997 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. \******************************************************************************/
  10.  
  11.  
  12. /*
  13. Module Name:
  14.  
  15.     sockspx.c
  16.  
  17. Abstract:
  18.  
  19.     This module illustrates the Win32 Winsock APIs over IPX/SPX protocol
  20.     sequence.
  21.  
  22.     This example implements a client and a server. This example can use IPX,
  23.     SPX as well as SPXII protocol sequences. The example has a number command
  24.     line options. For example,
  25.  
  26.     -s To run the example as a server.
  27.     
  28.     -c To run the example as a client.
  29.     
  30.     -e <Endpoint> To specify an end point of your choice. This is a mandatory
  31.     parameter. Servers use this as the socket number to listen on, clients use
  32.     it as the socket number to connect to, on a specified host.
  33.  
  34.     -n <ServerIpxAddress> To specify the server's IPX address. This is used by
  35.     clients. The address must be spcified as <NetworkNumber.NodeNumber> 
  36.     format, for example AABBCCDD.AABBCCDDEEFF.
  37.     
  38.     -l <LocalIpxAddress> To specify the local IPX address. This is used by
  39.     clients and servers. The address must be spcified as <NetworkNumber.
  40.     NodeNumber> format, for example AABBCCDD.AABBCCDDEEFF. If an IPX address
  41.     is not specified the created sockets are bound to the default interface,
  42.     00000000.000000000000.
  43.  
  44.     -p <d or s or p> To specify the protocol sequence to be used. 
  45.     'd' - datagram support, in this case IPX protocol sequence is used. 
  46.     's' - SOCK_STREAM/SPXII protocol sequence is used(default protocol).
  47.     'p' - SOCK_SEQPACKET/SPXII protocol sequence isused.
  48.        
  49.     -m To Enumerate Local Addresses. This example can be used only to 
  50.     enumerate the local IPX adapters. This may be important before running the
  51.     client to know the server's IPX address.
  52.        
  53.     To run the application as a server, the following command line can be 
  54.     specified:
  55.     
  56.     sockspx -s -e 8000 -p s
  57.     
  58.     To run the application to act as a client, the following command line can be
  59.     specified:
  60.     
  61.     sockspx -c -n AABBCCDD.AABBCCDDEEFF -e 8000 -p s
  62.     
  63.     To enumerate the local IPX adapters, the following command line will have
  64.     to be specified:
  65.     
  66.     sockspx -m
  67.       
  68.     
  69. Author:
  70.  
  71.     Rajesh Dadhia (rajeshd) 05-Mar-96
  72.  
  73. Revision History:
  74.  
  75. */
  76.  
  77. #include <stdio.h>
  78. #include <windows.h>
  79. #include <winsock.h>
  80. #include <wsipx.h>
  81. #include <wsnwlink.h> 
  82.  
  83. #define MAX_DATA_LEN 80
  84.  
  85. BOOL __stdcall
  86. CtrlCHandler (
  87.     DWORD dwEvent
  88.     );
  89.  
  90. void __stdcall
  91. EnumerateAdapters ( void );
  92.  
  93. void  __stdcall
  94. DoServer ( void );
  95.  
  96. void __stdcall 
  97. DoClient ( void );
  98.  
  99. void __stdcall
  100. DoStartup ( void );
  101.  
  102. void __stdcall
  103. CreateSocket ( void );
  104.  
  105. void __stdcall
  106. BindSocket ( 
  107.     SOCKADDR_IPX *psa, 
  108.     LPSTR lpsAddress,
  109.     LPSTR lpsEndpoint
  110.     );
  111.  
  112. void _stdcall
  113. FillIpxAddress ( 
  114.     SOCKADDR_IPX *psa, 
  115.     LPSTR lpsAddress,
  116.     LPSTR lpsEndpoint
  117.     );
  118.  
  119. INT __stdcall 
  120. SendData (
  121.     SOCKET s, 
  122.     CHAR *pchBuffer 
  123.     );
  124.  
  125. INT __stdcall
  126. ReceiveData (
  127.     SOCKET s, 
  128.     CHAR *pchBuffer
  129.     );
  130.  
  131. INT __stdcall
  132. SendDatagram (
  133.     SOCKET s, 
  134.     CHAR *pchBuffer, 
  135.     SOCKADDR_IPX *psa
  136.     );
  137.  
  138. INT __stdcall
  139. ReceiveDatagarm (
  140.     SOCKET s, 
  141.     CHAR *pchBuffer, 
  142.     SOCKADDR_IPX *psa, 
  143.     INT *pcb );
  144.  
  145. void __stdcall
  146. DoCleanup ( void );
  147.  
  148. void __stdcall
  149. CheckParameters (
  150.     INT argc, 
  151.     CHAR **argv
  152.     );
  153.  
  154. BOOL __stdcall
  155. CheckProtocol(
  156.     CHAR chProtocol
  157.     );
  158.  
  159. void __stdcall
  160. Usage (
  161.     CHAR *pszProgramName
  162.     );
  163.  
  164. void __stdcall 
  165. PrintError (
  166.     CHAR *lpszRoutine,
  167.     CHAR *lpszCallName,
  168.     DWORD dwError
  169.     );
  170.  
  171. void __stdcall
  172. PrintIpxAddress(
  173.     CHAR *lpsNetnum,
  174.     CHAR *lpsNodenum
  175.     );
  176.  
  177. void __stdcall
  178. AtoH(
  179.     CHAR *szDest, 
  180.     CHAR *szSource,
  181.     INT iCount
  182.     );
  183.  
  184. UCHAR __stdcall
  185. BtoH(
  186.     CHAR ch
  187.     );
  188.  
  189. //
  190. // Global Variables
  191. //
  192.  
  193. // Role of the Application 
  194. BOOL fServer = TRUE,
  195.  
  196. // Enumerate the Local Adapters 
  197.      fEnumerate = FALSE,
  198.  
  199. // WSAStartup () was sucessfull 
  200.      fStarted = FALSE;
  201.  
  202. // Global socket handles 
  203. SOCKET sock = INVALID_SOCKET,
  204.        newsock = INVALID_SOCKET;
  205.  
  206. // Server's IPX address string
  207. CHAR *pszServerAddress,
  208.  
  209. // Local IPX address string 
  210.      *pszLocalAddress,
  211.  
  212. // Server's Endpoint(socket) string 
  213.      *pszServerEndpoint,
  214.  
  215. // Protocol type (Datagram, Stream, Sequenced Packet)
  216.      chProtocol = 's';
  217.  
  218. void __cdecl
  219. main (
  220.     INT argc,
  221.     CHAR **argv
  222.     )
  223. {
  224.     
  225.     //
  226.     // Install the CTRL+BREAK Handler
  227.     //
  228.     if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler,
  229.                       TRUE 
  230.                       ) ) 
  231.     {
  232.     PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) );
  233.     }
  234.     
  235.     //
  236.     // Parse the command line parameters
  237.     //
  238.     CheckParameters ( argc, argv );
  239.  
  240.     //
  241.     // Check to see if the role of the application is to enumerate local 
  242.     // adapters
  243.     //
  244.     if ( TRUE == fEnumerate )
  245.     {
  246.     EnumerateAdapters ( );
  247.     return;
  248.     }
  249.  
  250.     //
  251.     // Act as a server
  252.     //
  253.     if( TRUE == fServer )
  254.     {
  255.     DoServer ( );
  256.     return;
  257.     }
  258.     
  259.     //
  260.     // Act as client
  261.     //
  262.     else
  263.     {
  264.     DoClient ( );
  265.     return;
  266.     }                                                       
  267. }
  268.  
  269. //
  270. // CtrlCHandler () intercepts the CTRL+BREAK or CTRL+C events and calls the
  271. // cleanup routines
  272. //
  273. BOOL __stdcall
  274. CtrlCHandler (
  275.     DWORD dwEvent
  276.     )
  277. {
  278.   
  279.     if ( ( CTRL_C_EVENT == dwEvent ) || ( CTRL_BREAK_EVENT == dwEvent ) )
  280.     {
  281.     DoCleanup ( );    
  282.     }
  283.  
  284.     return FALSE;
  285. }
  286.   
  287. //
  288. // EnumerateAdapters () will enumerate the available IPX adapters and print
  289. // the addresses
  290. //
  291. void __stdcall
  292. EnumerateAdapters ( void )
  293. {
  294.   SOCKADDR_IPX sa_ipx;
  295.   IPX_ADDRESS_DATA ipx_data;
  296.   INT iRetVal, cb, nAdapters, i=0;
  297.     
  298.     //        
  299.     // Initialize the Winsock 1.1 DLL
  300.     //
  301.     DoStartup ( );
  302.  
  303.     //
  304.     // Create a local socket
  305.     //
  306.     chProtocol = 'd';
  307.     CreateSocket ( );
  308.     
  309.     //
  310.     // Bind to a local address and endpoint
  311.     //
  312.     BindSocket ( &sa_ipx, NULL, NULL );
  313.     
  314.     //
  315.     // Call getsockopt() see the total number of adapters
  316.     //
  317.     cb = sizeof ( nAdapters );
  318.     iRetVal = getsockopt ( sock, 
  319.                NSPROTO_IPX, 
  320.                IPX_MAX_ADAPTER_NUM,
  321.                (CHAR *) &nAdapters,
  322.                &cb 
  323.                );
  324.     
  325.     if ( SOCKET_ERROR == iRetVal )
  326.     {
  327.     PrintError ( "EnumerateAdapters", 
  328.              "getsockopt", 
  329.              WSAGetLastError ( ) 
  330.              );
  331.     }
  332.     fprintf ( stdout, "Total number of adapters -> %d\n", nAdapters );
  333.  
  334.     //
  335.     // Get the address of each adapter
  336.     //
  337.     while ( nAdapters > 0 )
  338.     {                                                
  339.     memset ( &ipx_data, 0, sizeof ( ipx_data ) );
  340.     ipx_data.adapternum = (nAdapters -1);
  341.     cb = sizeof ( ipx_data );
  342.             
  343.     iRetVal = getsockopt ( sock,
  344.                    NSPROTO_IPX,
  345.                    IPX_ADDRESS,
  346.                    (CHAR *) &ipx_data,
  347.                    &cb 
  348.                    );
  349.  
  350.     if ( SOCKET_ERROR == iRetVal )
  351.     {
  352.         PrintError ( "EnumerateAdapters", 
  353.              "getsockopt", 
  354.              WSAGetLastError ( ) 
  355.              );
  356.     }
  357.         
  358.     //   
  359.     // Print each address
  360.     //
  361.     PrintIpxAddress ( ipx_data.netnum, ipx_data.nodenum );
  362.     nAdapters--;                                                         
  363.     }
  364.     
  365.     //
  366.     // Call the cleanup routine
  367.     //
  368.     DoCleanup ( );
  369.     return;
  370. }
  371.  
  372. //
  373. // DoServer () performs the connection-less/connection-oriented server
  374. // related tasks
  375. //
  376. void  __stdcall
  377. DoServer ( void )
  378. {                        
  379.   // Address structures for the client and the server
  380.   SOCKADDR_IPX sa_ipx, sa_ipx_client;     
  381.  
  382.   // Buffer for the received/sent data
  383.   CHAR chBuffer[MAX_DATA_LEN];
  384.  
  385.   INT iRetVal, cb;
  386.     
  387.     DoStartup ( );
  388.    
  389.     CreateSocket ( );
  390.  
  391.     //
  392.     // Bind to a local address and endpoint
  393.     //
  394.     BindSocket ( &sa_ipx, pszLocalAddress, pszServerEndpoint);
  395.  
  396.     //
  397.     // Check the Specified protocol. Call listen(), accept() if a connection 
  398.     // oriented protocol is specified
  399.     //
  400.     if ( 'd' != chProtocol   )
  401.     {
  402.     iRetVal = listen ( sock, 5 );
  403.     
  404.     if ( SOCKET_ERROR == iRetVal )
  405.     {
  406.         PrintError ( "DoServer", "listen", WSAGetLastError ( ) );
  407.     }
  408.         
  409.     fprintf ( stdout, "Waiting for a Connection...\n");
  410.     fprintf ( stdout, "Press <CTRL+C> or <CTRL+BREAK> to exit\n");
  411.     //
  412.     // Wait for a connection
  413.     //
  414.     cb = sizeof ( sa_ipx_client );
  415.     newsock = accept ( sock, 
  416.                (SOCKADDR *) &sa_ipx_client, 
  417.                &cb 
  418.                );
  419.     
  420.     if ( INVALID_SOCKET == newsock )
  421.     {
  422.         PrintError ( "DoServer", "accept", WSAGetLastError ( ) );
  423.     }
  424.         
  425.     //
  426.     // Print the address of connected client
  427.     //
  428.     fprintf ( stdout, "Connected to Client Address - " );
  429.     PrintIpxAddress ( sa_ipx_client.sa_netnum, sa_ipx_client.sa_nodenum );
  430.  
  431.     //
  432.     // Receive data on newly created socket
  433.     //
  434.     iRetVal = ReceiveData ( newsock, chBuffer );
  435.         
  436.     //
  437.     // Print the contents of received data
  438.     //
  439.     chBuffer[iRetVal] = '\0';
  440.     fprintf ( stdout,"%d bytes of data received->%s\n",iRetVal, chBuffer );
  441.     strcpy ( chBuffer, "Hello SPX Client" ); 
  442.     
  443.     //
  444.     // Send data on newly created socket
  445.     //
  446.     iRetVal = SendData ( newsock, chBuffer );
  447.     fprintf ( stdout, "%d bytes of data sent\n", iRetVal );
  448.     }
  449.     //
  450.     // Server will receive and send datagrams
  451.     //
  452.     else 
  453.     {
  454.     //
  455.     // Receive a datagram on the bound socket
  456.     //
  457.     cb = sizeof ( sa_ipx_client );
  458.     iRetVal = ReceiveDatagarm ( sock, chBuffer, &sa_ipx_client, &cb );
  459.  
  460.     //
  461.     // Print the contents of received datagram and the senders address
  462.     //
  463.     fprintf ( stdout, "Message Received from Client Address - " );
  464.     PrintIpxAddress( sa_ipx_client.sa_netnum, sa_ipx_client.sa_nodenum );
  465.     chBuffer[iRetVal] = '\0';
  466.     fprintf( stdout, "Data Received->%s\n", chBuffer );
  467.     fprintf( stdout,"%d bytes of data received->%s\n",iRetVal, chBuffer );
  468.     
  469.     //
  470.     // Send a datagram on the bound socket to the client
  471.     //
  472.     strcpy ( chBuffer, "Hello IPX Client" ); 
  473.     iRetVal = SendDatagram (sock, chBuffer, &sa_ipx_client );
  474.     fprintf( stdout, "%d bytes of data sent\n", iRetVal );
  475.     }
  476.  
  477.     // 
  478.     // Call the cleanup routine
  479.     //
  480.     DoCleanup ( );
  481.     return;
  482. }
  483.  
  484. //
  485. // DoClient () performs the connection-less/connection-oriented client
  486. // related tasks
  487. //
  488. void __stdcall 
  489. DoClient ( void )
  490. {                                                
  491.   // Address structures for the client and the server
  492.   SOCKADDR_IPX sa_ipx, sa_ipx_server;     
  493.     
  494.   // Buffer for the received/sent data
  495.   CHAR chBuffer[MAX_DATA_LEN];            
  496.          
  497.   INT iRetVal, cb;
  498.     
  499.     DoStartup ( ) ;
  500.     
  501.     CreateSocket ( );
  502.     
  503.     //
  504.     // Bind to a local address and endpoint
  505.     //
  506.     BindSocket ( &sa_ipx, pszLocalAddress, NULL);
  507.  
  508.     
  509.     if ( NULL == pszServerEndpoint )
  510.     {
  511.     fprintf ( stdout, "Server Endpoint must be specified....Exiting\n");
  512.     DoCleanup ( );
  513.     exit ( 1 );
  514.     }
  515.  
  516.     //
  517.     // Fill the sa_ipx_server address address with server address and endpoint
  518.     //
  519.     if ( NULL != pszServerAddress )
  520.     {
  521.     FillIpxAddress ( &sa_ipx_server, pszServerAddress, pszServerEndpoint );
  522.     }
  523.     else
  524.     {
  525.     fprintf ( stdout, "Server Address must be specified....Exiting\n");
  526.     DoCleanup ( );
  527.     exit ( 1 );
  528.     }
  529.     
  530.     //
  531.     // Check the Specified protocol. Call connect() if a connection oriented 
  532.     // protocol is specified
  533.     //
  534.     if ( chProtocol != 'd' )
  535.     {
  536.     fprintf(stdout, "Connecting to Server -");
  537.     PrintIpxAddress ( sa_ipx_server.sa_netnum, sa_ipx_server.sa_nodenum );
  538.         
  539.     //
  540.     // Connect to the server
  541.     //
  542.     iRetVal = connect ( sock, 
  543.                 (SOCKADDR *) &sa_ipx_server,
  544.                 sizeof sa_ipx_server
  545.                 );
  546.     
  547.     if ( SOCKET_ERROR == iRetVal )
  548.     {
  549.         PrintError ( "DoClient", "connect", WSAGetLastError ( ) );
  550.     }
  551.            
  552.     fprintf ( stdout, "Connected to Server Address - " );
  553.     PrintIpxAddress( sa_ipx_server.sa_netnum, sa_ipx_server.sa_nodenum );
  554.  
  555.     //
  556.     // Send data to the specfied server
  557.     //
  558.     strcpy ( chBuffer, "Hello SPX Server" ); 
  559.     iRetVal = SendData ( sock, chBuffer );
  560.     fprintf( stdout, "%d bytes of data sent\n", iRetVal );
  561.         
  562.     //
  563.     // Receive data from the server
  564.     //
  565.     iRetVal = ReceiveData ( sock, chBuffer );
  566.         
  567.     //
  568.     // Print the contents of received data
  569.     //
  570.     chBuffer[iRetVal] = '\0';
  571.     fprintf( stdout, "%d bytes of data received->%s\n", iRetVal,chBuffer);
  572.     }
  573.     else
  574.     {
  575.     //
  576.     // Send a datagram to the specified server
  577.     //
  578.     strcpy ( chBuffer, "Hello IPX Server" ); 
  579.     iRetVal = SendDatagram ( sock, chBuffer, &sa_ipx_server );
  580.     fprintf ( stdout, "%d bytes of data sent\n", iRetVal );
  581.  
  582.     //
  583.     // Receive a datagram from the server
  584.     //
  585.     cb = sizeof sa_ipx_server;
  586.     iRetVal = ReceiveDatagarm ( sock, chBuffer, &sa_ipx_server, &cb );
  587.         
  588.     //
  589.     // Print the contents of received data
  590.     //
  591.     chBuffer[iRetVal] = '\0';
  592.     fprintf ( stdout, "%d bytes of data received->%s\n",iRetVal,chBuffer);
  593.     }
  594.     
  595.     //
  596.     // Call the cleanup routine
  597.     //
  598.     DoCleanup ( );
  599.  
  600.     return;
  601. }
  602.  
  603. //
  604. // DoStartup() initializes the Winsock DLL with Winsock version 1.1
  605. //
  606. void __stdcall
  607. DoStartup ( void )
  608. {
  609.   WSADATA wsaData;
  610.   INT iRetVal;
  611.  
  612.     iRetVal = WSAStartup ( MAKEWORD ( 1,1 ), &wsaData );
  613.     
  614.     if ( 0 != iRetVal)
  615.     {
  616.         PrintError ( "DoStartup", "WSAStartup", iRetVal );
  617.     }
  618.     
  619.     /* Set the global flag */
  620.     fStarted = TRUE;
  621.  
  622.     return;
  623. }
  624.  
  625. //
  626. // CreateSocket() creates an endpoint (socket) and assigns the returned value
  627. // from socket() to the global socket descriptor 'sock'. The actual protocol
  628. // specified on the command line is checked, in order to make the socket()
  629. // call correctly.
  630. //
  631. void __stdcall
  632. CreateSocket ( void )
  633. {
  634.     sock = socket ( AF_IPX,
  635.             chProtocol == 'd' ? SOCK_DGRAM : 
  636.             ( chProtocol == 's'  ? SOCK_STREAM : SOCK_SEQPACKET),
  637.             chProtocol == 'd' ? NSPROTO_IPX : NSPROTO_SPXII
  638.             );
  639.     
  640.     if ( INVALID_SOCKET == sock )
  641.     {
  642.     PrintError ( "CreateSocket", "socket", WSAGetLastError ( ) );
  643.     }
  644.     
  645.     return;
  646. }
  647.  
  648. //
  649. // BindSocket() binds the global socket descriptor 'sock' to the specified
  650. // address. If an endpoint is specified it uses that or it binds to a system 
  651. // assigned port.
  652. //
  653. void __stdcall
  654. BindSocket ( 
  655.     SOCKADDR_IPX *psa, 
  656.     LPSTR lpsAddress,
  657.     LPSTR lpsEndpoint
  658.     )
  659. {
  660.   INT iRetVal;
  661.  
  662.     //
  663.     // Fill the givenSOCKADDR_IPX structure
  664.     //
  665.     FillIpxAddress ( psa, lpsAddress, lpsEndpoint );
  666.  
  667.     iRetVal = bind ( sock, 
  668.              (SOCKADDR *) psa, 
  669.              sizeof (SOCKADDR_IPX) 
  670.              );
  671.     
  672.     if ( SOCKET_ERROR == iRetVal )
  673.     {
  674.     PrintError ( "BindSocket", "bind", WSAGetLastError ( ) );
  675.     }
  676.  
  677.     // 
  678.     // Print the address we are bound to. If a particular interface is not
  679.     // mentioned in the BindSocket() call, this may print the address as
  680.     // 00000000.0000000000000000. This is because of the fact that an 
  681.     // interface is picked only when the actual connection establishment 
  682.     // occurs, in case of connection oriented socket.
  683.     //
  684.     fprintf ( stdout, "Bound to Local Address - " );
  685.     PrintIpxAddress( psa->sa_netnum, psa->sa_nodenum );
  686.     
  687.     return;
  688. }
  689.  
  690. //
  691. // FillIpxAddress() fills a structure of type SOCKADDR_IPX with relevant
  692. // address-family, network number, node number and socket (endpoint)
  693. // parameters.
  694. //
  695. void _stdcall
  696. FillIpxAddress ( 
  697.     SOCKADDR_IPX *psa, 
  698.     LPSTR lpsAddress,
  699.     LPSTR lpsEndpoint
  700.     )
  701. {
  702.   // Location of the separator
  703.   LPSTR pszPoint;                 
  704.   
  705.     ZeroMemory ( psa, sizeof ( SOCKADDR_IPX ) );
  706.     
  707.     psa->sa_family = AF_IPX;
  708.     
  709.     //
  710.     // Check if an address is specified
  711.     //
  712.     if ( NULL != lpsAddress )
  713.     {
  714.     //
  715.     // Get the offset for node number/network number separator
  716.     //
  717.     pszPoint = strchr ( lpsAddress, '.' );
  718.  
  719.     if ( NULL == pszPoint )
  720.     {
  721.         fprintf ( stderr, "IPX Address does not have a separator\n");
  722.         DoCleanup ( );
  723.         exit ( 1 );
  724.     }
  725.  
  726.     //
  727.     // covert the address in the  string format to binary format
  728.     //
  729.     AtoH ( (CHAR *) psa->sa_netnum, lpsAddress, 4 );
  730.     AtoH ( (CHAR *) psa->sa_nodenum, pszPoint + 1, 6 );
  731.     
  732.     }
  733.     
  734.     if ( NULL != lpsEndpoint )
  735.     {
  736.         psa->sa_socket = (USHORT) atoi ( lpsEndpoint );
  737.     }
  738.     
  739.     return;
  740. }
  741.  
  742. //
  743. // SendData() is generic rotuine to send some data over a 
  744. // connection-oriented IPX socket.
  745. //
  746. INT __stdcall 
  747. SendData (
  748.     SOCKET s, 
  749.     CHAR *pchBuffer 
  750.     )
  751. {
  752.   INT iRetVal;
  753.     
  754.     iRetVal = send ( s, 
  755.              pchBuffer,  
  756.              strlen ( pchBuffer ), 
  757.              0
  758.              );
  759.     
  760.     if ( SOCKET_ERROR == iRetVal )
  761.     {
  762.     PrintError ( "SendData", "send", WSAGetLastError ( ) );
  763.     }
  764.     
  765.     //
  766.     // return the total number of bytes sent
  767.     //
  768.     return iRetVal;
  769. }
  770.  
  771. //
  772. // ReceiveData() is generic rotuine to receive some data over a 
  773. // connection-oriented IPX socket.
  774. //
  775. INT __stdcall
  776. ReceiveData (
  777.     SOCKET s, 
  778.     CHAR *pchBuffer
  779.     )
  780. {
  781.   INT iRetVal;
  782.         
  783.     iRetVal = recv ( s, 
  784.              pchBuffer, 
  785.              MAX_DATA_LEN, 
  786.              0
  787.              );
  788.     
  789.     if ( SOCKET_ERROR == iRetVal )
  790.     {
  791.     PrintError ( "ReceiveData", "recv", WSAGetLastError ( ) );
  792.     }
  793.     
  794.     //
  795.     // return the total number of bytes received
  796.     //
  797.     return iRetVal;
  798. }
  799.  
  800. //
  801. // SendDatagram() is generic rotuine to send a datagram to a
  802. // specifid host.
  803. //
  804. INT __stdcall
  805. SendDatagram (
  806.     SOCKET s, 
  807.     CHAR *pchBuffer, 
  808.     SOCKADDR_IPX *psa
  809.     )
  810. {
  811.   INT iRetVal;
  812.  
  813.     iRetVal = sendto ( s, 
  814.                pchBuffer,  
  815.                strlen ( pchBuffer ), 
  816.                0,
  817.                (SOCKADDR *) psa,
  818.                sizeof ( SOCKADDR_IPX )
  819.                );
  820.  
  821.     if ( SOCKET_ERROR == iRetVal )
  822.     {
  823.         PrintError ( "SendDatagram", "sendto", WSAGetLastError ( ) );
  824.     }
  825.     
  826.     /* return the total number of bytes sent in the datagram */
  827.     return iRetVal;     
  828.  }
  829.  
  830. //
  831. // ReceiveDatagram() is generic rotuine to receive a datagram from a
  832. // specifid host.
  833. //
  834. INT __stdcall
  835. ReceiveDatagarm (
  836.     SOCKET s, 
  837.     CHAR *pchBuffer, 
  838.     SOCKADDR_IPX *psa, 
  839.     INT *pcb )
  840. {
  841.   INT iRetVal;
  842.     
  843.     iRetVal = recvfrom ( s, 
  844.              pchBuffer, 
  845.              MAX_DATA_LEN, 
  846.              0,
  847.              (SOCKADDR *) psa,
  848.              pcb
  849.              );
  850.     
  851.     if ( SOCKET_ERROR == iRetVal )
  852.     {
  853.         PrintError ( "ReceiveDatagram", "recvfrom", WSAGetLastError ( ) );
  854.     }
  855.     
  856.     //
  857.     // return the total number of bytes received in the datagram
  858.     //
  859.     return iRetVal;
  860. }
  861.              
  862. //
  863. // DoCleanup () will close the sockets which were opened successfully using 
  864. // a call to socket (). Additionally, it will call WSACleanup (), if a call
  865. // to WSAStartup () was made successfully.
  866. //
  867. void __stdcall
  868. DoCleanup ( void )
  869. {
  870.     if ( INVALID_SOCKET != sock )
  871.     {
  872.         closesocket ( sock );
  873.     }
  874.  
  875.     if ( INVALID_SOCKET != newsock )
  876.     {
  877.         closesocket ( sock );
  878.     }
  879.  
  880.     if ( TRUE == fStarted )
  881.     {
  882.         WSACleanup ( );
  883.     }
  884.  
  885.     fprintf ( stdout, "DONE\n");
  886.  
  887.     return;
  888. }
  889.  
  890. //
  891. // CheckParameters() parses the command line parametrs.
  892. //
  893. void __stdcall
  894. CheckParameters (
  895.     INT argc, 
  896.     CHAR **argv
  897.     )
  898. {
  899.     INT i;
  900.     
  901.     for ( i = 1; i < argc; i++ ) 
  902.     {
  903.     if ( ( *argv[i] == '-') || ( *argv[i] == '/' ) ) 
  904.     {
  905.         switch ( tolower ( *( argv[i]+1 ) ) ) 
  906.         {
  907.         
  908.         //
  909.         // Role of the application - server
  910.         //
  911.         case 's':                            
  912.             fServer = TRUE;
  913.             break;
  914.         
  915.         //
  916.         // Role of the application - client
  917.         //
  918.         case 'c':                            
  919.             fServer = FALSE;
  920.             break;
  921.         
  922.         //
  923.         // Store a pointer to the server endpoint
  924.         //
  925.         case 'e':
  926.             pszServerEndpoint = argv[++i];   
  927.             break;
  928.         
  929.         //
  930.         // Store a pointer to the server address
  931.         //
  932.         case 'n':
  933.             pszServerAddress = argv[++i];    
  934.             break;
  935.                          
  936.         //
  937.         // Store a pointer to the local address
  938.         //
  939.         case 'l':
  940.             pszLocalAddress = argv[++i];     
  941.             break;
  942.  
  943.         
  944.         //
  945.         // Set the flag to indicate enumeration of local adapters
  946.         //
  947.         case 'm':
  948.             fEnumerate = TRUE;               
  949.             break;
  950.  
  951.         //
  952.         // Read and validate the protocol specified
  953.         //
  954.         case 'p':
  955.             chProtocol = tolower ( *argv[++i] );
  956.             if ( FALSE == CheckProtocol ( chProtocol ) )
  957.             {
  958.             fprintf ( stderr, "UnKnown protcol specified\n\n");
  959.             Usage ( argv[0] );
  960.             }
  961.             break;
  962.         //
  963.         // Help
  964.         //
  965.         case 'h':
  966.         case '?':
  967.         default:
  968.         Usage ( argv[0] );
  969.         }
  970.     }
  971.     //
  972.     // Help
  973.     //
  974.     else
  975.         Usage ( argv[0] );
  976.     }    
  977.     return;
  978. }
  979.  
  980. //
  981. // CheckProtocol() checks if a valid protocol is specified on the command
  982. // line.
  983. //
  984. BOOL __stdcall
  985. CheckProtocol(
  986.     CHAR chProtocol
  987.     )
  988. {
  989.     if ( 'd' != chProtocol && 's' != chProtocol && 'p' != chProtocol )
  990.     {
  991.     return FALSE;
  992.     }
  993.  
  994.     return TRUE;
  995. }
  996.  
  997. //
  998. // Display the usage of command line parameters.
  999. //
  1000. void __stdcall
  1001. Usage (
  1002.     CHAR *pszProgramName
  1003.     )
  1004. {
  1005.     fprintf ( stderr,"Usage:  %s\n", pszProgramName );
  1006.     fprintf ( stderr, 
  1007.         "\t-s or -c (s - server, c - client, default - server)\n" );
  1008.     fprintf ( stderr, "\t-e <Endpoint>\n" );
  1009.     fprintf ( stderr, "\t-n <ServerIpxAddress>\n" );    
  1010.     fprintf ( stderr, "\t-l <LocalIpxAddress>\n" );    
  1011.     fprintf ( stderr,
  1012.     "\t-p <d or s or p> ( d - datagram, s - stream, p - sequenced packet)\n" );
  1013.     fprintf ( stderr, "\t-m To Enumerate Local Addresses\n" );
  1014.        
  1015.     exit ( 1 );
  1016. }
  1017.  
  1018. //
  1019. // PrintError () is a generic routine to print the Winsock or Win32 
  1020. // error codes for the errors occurred during relevant calls.
  1021. // If an error occurs, the error code is printed, cleanup routine is 
  1022. // called and the application exits.
  1023. //
  1024. void __stdcall 
  1025. PrintError (
  1026.     CHAR *lpszRoutine,
  1027.     CHAR *lpszCallName,
  1028.     DWORD dwError
  1029.     )
  1030. {
  1031.     fprintf ( stderr,
  1032.           "The Call to %s() in the Routine %s() failed with Error %d\n",
  1033.           lpszCallName, 
  1034.           lpszRoutine, 
  1035.           dwError
  1036.           );
  1037.  
  1038.     DoCleanup ( );
  1039.     exit ( 1 );
  1040. }
  1041.  
  1042. //
  1043. // Print an IPX address.
  1044. // 
  1045. void __stdcall
  1046. PrintIpxAddress(
  1047.     CHAR *lpsNetnum,
  1048.     CHAR *lpsNodenum
  1049.     )
  1050. {
  1051.   INT i;
  1052.     
  1053.     for ( i = 0; i < 4; i++ )
  1054.     {
  1055.     fprintf ( stdout, "%02X", (UCHAR) lpsNetnum[i] );
  1056.     }
  1057.     
  1058.     fprintf ( stdout, "." );
  1059.     
  1060.     for ( i = 0; i < 6; i++ )
  1061.     {
  1062.     fprintf ( stdout, "%02X", (UCHAR) lpsNodenum[i] );
  1063.     }
  1064.  
  1065.     fprintf ( stdout, "\n" );
  1066.  
  1067.     return;
  1068. }
  1069.  
  1070. //
  1071. // AtoH () coverts the IPX address specified in the string(ascii) format to 
  1072. // the binary(hexadecimal) format.
  1073. //
  1074. void __stdcall
  1075. AtoH(
  1076.     CHAR *szDest, 
  1077.     CHAR *szSource,
  1078.     INT iCount
  1079.     )
  1080. {
  1081.     while (iCount--)
  1082.     {
  1083.     *szDest++ = ( BtoH ( *szSource++ ) << 4 ) + BtoH ( *szSource++ );
  1084.     }
  1085.     return;
  1086. }
  1087.  
  1088. //
  1089. // BtoH () returns the equivalent binary value for an individual
  1090. // character specified in the ascii format.
  1091. //
  1092. UCHAR __stdcall
  1093. BtoH(
  1094.     CHAR ch
  1095.     )
  1096. {
  1097.  
  1098.     if ( ch >= '0' && ch <= '9' )
  1099.     {
  1100.         return ( ch - '0' );
  1101.     }
  1102.  
  1103.     if ( ch >= 'A' && ch <= 'F' )
  1104.     {
  1105.         return ( ch - 'A' + 0xA );
  1106.     }
  1107.  
  1108.     if (ch >= 'a' && ch <= 'f' )
  1109.     {
  1110.         return ( ch - 'a' + 0xA );
  1111.     }
  1112.     
  1113.     //
  1114.     // Illegal values in the IPX address will not be excepted
  1115.     //
  1116.     fprintf( stderr, 
  1117.     "Illegal value specified in  one of the IPX Addresses-BtoH Failed\n" );
  1118.     
  1119.     DoCleanup ( );
  1120.  
  1121.     exit ( 1 );
  1122. }
  1123.