SOCKSPX.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:23k
源码类别:

Windows编程

开发平台:

Visual C++

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