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 / bcast / bcast.c next >
C/C++ Source or Header  |  1997-10-08  |  27KB  |  1,174 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. Module Name:
  13.  
  14.     bcast.c
  15.  
  16. Abstract:
  17.  
  18.     This module illustrates the Win32 Winsock and Mailslot APIs to do a generic
  19.     broadcast over IPX, UDP and Mailslot protocols.
  20.  
  21.     This example implements a client and a server. The example has a number of
  22.     command line options. For example,
  23.  
  24.     -s To run the example as a server(default role).
  25.     
  26.     -c To run the example as a client.
  27.    
  28.     -p <i or m or u> To specify the protocol to be used.
  29.      i - IPX.
  30.      m - Mailslots.
  31.      u - UDP(default protocol).
  32.     
  33.     -e <Endpoint> To specify an end point of your choice. This is a mandatory
  34.     parameter. Servers create this endpoint and read broadcast messages. An 
  35.     endpoint in case Mailslot protocol is a Mailslot name.(default is 5005). 
  36.     
  37.     -d <DomainName> - To specify a domain name or a workgroup name. This is 
  38.     useful for Mailslot clients, only.
  39.  
  40.     To run the application as a server, the following command lines can be 
  41.     specified:
  42.     
  43.     bcast -s -e 8000 -p u
  44.     bcast -s -e 8000 -p i
  45.     bcast -s -e MAILSLOT1 -p m
  46.  
  47.     To run the application as a client, the following command lines can be
  48.     specified:
  49.     
  50.     bcast -c -e 8000 -p u
  51.     bcast -c -e 8000 -p i
  52.     bcast -c -e MAILSLOT1 -p m -d DOMAIN1
  53.     bcast -c -e MAILSLOT1 -p m -d WORKGROUP1
  54.  
  55. Author:
  56.  
  57.     Rajesh Dadhia (rajeshd) 02-Mar-96
  58.  
  59. Revision History:
  60.  
  61. */
  62.  
  63. #include <stdio.h>
  64. #include <time.h>
  65. #include <windows.h>
  66. #include <winsock.h>
  67. #include <wsipx.h>
  68. #include <wsnwlink.h>
  69.  
  70. #define MAX_MSGLEN 80
  71. #define MAX_ADDLEN 80
  72. #define MAX_MSLOTNAME 80
  73.  
  74. typedef enum _MODE { CLIENT=0, SERVER } MODE;
  75. typedef enum _PROTOCOL { UDP=0, IPX, MAILSLOT } PROTOCOL;
  76.  
  77. BOOL __stdcall
  78. CtrlCHandler (
  79.     DWORD dwEvent
  80.     );
  81.  
  82. void __stdcall
  83. DoMailSlot (
  84.     MODE mRole,
  85.     LPSTR lpsEndPoint,
  86.     LPSTR lpsDomainName
  87.     );
  88.  
  89. void __stdcall
  90. DoIpx (
  91.     MODE mRole,
  92.     USHORT usEndPoint
  93.     );
  94.  
  95. void __stdcall
  96. DoUdp (
  97.     MODE mRole,
  98.     USHORT usEndPoint
  99.     );
  100.  
  101. void __stdcall
  102. DoMailSlotServer (
  103.     LPSTR lpsEndPoint
  104.     );
  105.  
  106. void __stdcall
  107. DoMailSlotClient (
  108.     LPSTR lpsEndPoint,
  109.     LPSTR lpsDomainName
  110.     );
  111.  
  112. void __stdcall
  113. DoUdpServer (
  114.     USHORT usEndPoint
  115.     );
  116.  
  117. void __stdcall
  118. DoUdpClient (
  119.     USHORT usEndPoint
  120.     );
  121.  
  122. void __stdcall 
  123. DoIpxServer (
  124.     USHORT usEndPoint
  125.     );
  126.  
  127. void __stdcall
  128. DoIpxClient (
  129.     USHORT usEndPoint
  130.     );
  131.  
  132. void __stdcall
  133. Usage (
  134.     CHAR *pszProgramName
  135.     );
  136.  
  137. void __stdcall
  138. PrintError (
  139.     LPSTR lpszRoutine,
  140.     LPSTR lpszCallName,
  141.     DWORD dwError
  142.     );
  143.  
  144. CHAR * __stdcall
  145. IpxnetAddr (
  146.     CHAR *lpBuffer,
  147.     CHAR *lpsNetnum, 
  148.     CHAR *lpsNodenum 
  149.     );
  150.  
  151. void __stdcall
  152. DoStartup ( void );
  153.  
  154. void __stdcall
  155. DoCleanup ( void );
  156.  
  157. //
  158. // Global Variables
  159. //
  160.  
  161. // If Startup was successful, fStarted is used to keep track.
  162. BOOL fStarted = FALSE;
  163.  
  164. // Global socket descriptor
  165. SOCKET sock = INVALID_SOCKET;
  166.  
  167. void __cdecl
  168. main (
  169.     INT argc,
  170.     CHAR **argv
  171.     )
  172. {
  173.  
  174.   // Default role of the application is SERVER, which means receiver of
  175.   // the broadcast messages.
  176.   MODE mRole = SERVER;
  177.   
  178.   // Deafult protocol used is UDP.
  179.   PROTOCOL pProto = UDP;
  180.   
  181.   // Default Endpoint.
  182.   USHORT usEndPoint = 5005;
  183.   
  184.   // Strings pointing to Endpoint and DomainName(necessary for Mailslots).
  185.   LPSTR lpsEndPoint, lpsDomainName;
  186.   INT  i;
  187.   CHAR chProto;
  188.  
  189.     //
  190.     // Install the CTRL+BREAK Handler
  191.     //
  192.     if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler,
  193.                       TRUE 
  194.                       ) ) 
  195.     {
  196.     PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) );
  197.     }  
  198.   
  199.     //
  200.     // allow the user to override settings with command line switches
  201.     //
  202.     for ( i = 1; i < argc; i++ ) 
  203.     {
  204.     if ( ( *argv[i] == '-' ) || ( *argv[i] == '/' ) ) 
  205.     {
  206.         switch ( tolower ( *( argv[i]+1 ) ) ) 
  207.         {
  208.         //
  209.         // Role of the application (Client - Sender of broadcasts).
  210.         //
  211.         case 'c':  
  212.             mRole = CLIENT;
  213.             break;
  214.  
  215.         //
  216.         // Role of the application (Server - Receiver of broadcasts)
  217.         //
  218.         case 's':  
  219.             mRole = SERVER;
  220.             break;
  221.  
  222.         //
  223.         // Network protocol (Mailslots, IPX or UDP).
  224.         //
  225.         case 'p':
  226.             chProto = tolower ( *argv[++i] );
  227.             if ( 'm' == chProto )
  228.             {
  229.             pProto = MAILSLOT;
  230.             }
  231.             else if ( 'i' == chProto )
  232.             {
  233.             pProto = IPX;
  234.             }
  235.             else
  236.             pProto = UDP;
  237.             break;
  238.         
  239.         //
  240.         // EndPoint.
  241.         //
  242.         case 'e': 
  243.             lpsEndPoint = argv[++i];
  244.             break;
  245.         
  246.         //
  247.         // DomainName (Important for Mailslot broadcasts, only).
  248.         //
  249.         case 'd':
  250.             lpsDomainName = argv[++i];
  251.             break;
  252.  
  253.         //
  254.         // Help.
  255.         //
  256.         case 'h':
  257.         case '?':
  258.         default:
  259.             Usage ( argv[0] );
  260.         }
  261.     }
  262.     else
  263.         //
  264.         // Help.
  265.         //
  266.         Usage ( argv[0] );
  267.     }
  268.  
  269.     
  270.     //
  271.     // If the protocol specified is not MAILSLOT, convert the endpoint
  272.     // information to integer format from the string format.
  273.     //
  274.     if ( MAILSLOT != pProto )
  275.     {
  276.     usEndPoint = atoi ( lpsEndPoint );
  277.     }
  278.  
  279.     //
  280.     // Print a Summary of the switches specfied 
  281.     // Helpful for debugging
  282.     //
  283.     fprintf ( stdout, "SUMMARY:\n" );
  284.     fprintf ( stdout, "\tRole-> %s\n", (CLIENT == mRole)?"Client":"Server" );
  285.     fprintf ( stdout, "\tProtocol-> %s\n", 
  286.               ( MAILSLOT == pProto ) ? "MAILSLOT" : 
  287.               ( IPX == pProto ) ? "IPX" : "UDP" );
  288.     fprintf ( stdout, "\tEndpoint-> %s\n", lpsEndPoint );
  289.     
  290.     //
  291.     // Check the protocol specified.
  292.     // Call the appropriate handler rouine. By default the protocol
  293.     // is UDP.
  294.     //
  295.     switch ( pProto )
  296.     {
  297.     case MAILSLOT :
  298.         DoMailSlot ( mRole, lpsEndPoint, lpsDomainName );
  299.         break;
  300.  
  301.     case IPX:
  302.         DoStartup ( );
  303.         DoIpx ( mRole, usEndPoint );
  304.         break;
  305.  
  306.     default:
  307.         DoStartup ( );
  308.         DoUdp ( mRole, usEndPoint );
  309.         break;
  310.     }
  311.     
  312.     return;
  313. }
  314.  
  315. //
  316. // CtrlCHandler () intercepts the CTRL+BREAK or CTRL+C events and calls the
  317. // cleanup routines.
  318. //
  319. BOOL __stdcall
  320. CtrlCHandler (
  321.     DWORD dwEvent
  322.     )
  323. {
  324.     if ( ( CTRL_C_EVENT == dwEvent ) || ( CTRL_BREAK_EVENT == dwEvent ) )
  325.     {
  326.     DoCleanup ( );    
  327.     }
  328.  
  329.     return FALSE;
  330. }
  331.  
  332. //
  333. // DoMailSlot () function calls appropriate handler function (client/server),
  334. // if protocol=MAILSLOT is specified. By default, the role of the application
  335. // is - SERVER.
  336. //
  337. void __stdcall
  338. DoMailSlot (
  339.     MODE mRole,
  340.     LPSTR lpsEndPoint,
  341.     LPSTR lpsDomainName
  342.     )
  343. {
  344.     switch ( mRole )
  345.     {
  346.     case CLIENT:
  347.         DoMailSlotClient ( lpsEndPoint, lpsDomainName );
  348.         break;
  349.  
  350.     default:
  351.         DoMailSlotServer ( lpsEndPoint );
  352.     }
  353.     return;
  354. }
  355.  
  356. //
  357. // DoIpx () function calls appropriate handler function (client/server),
  358. // if protocol=IPX  is specified. By default, the role of the application
  359. // is - SERVER.
  360. //
  361. void __stdcall
  362. DoIpx (
  363.     MODE mRole,
  364.     USHORT usEndPoint
  365.     )
  366. {
  367.     //
  368.     // Initialize the global socket descriptor.
  369.     //
  370.     sock = socket ( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  371.  
  372.     if ( INVALID_SOCKET ==  sock )
  373.     {
  374.     PrintError( "DoIpx", "socket", WSAGetLastError ( ) );
  375.     }
  376.  
  377.     switch ( mRole )
  378.     {
  379.     case CLIENT:
  380.         DoIpxClient ( usEndPoint );
  381.         break;
  382.  
  383.     default:
  384.         DoIpxServer ( usEndPoint );
  385.     }
  386.     return;
  387. }
  388.  
  389.  
  390. //
  391. // DoUdp () function calls appropriate handler function (client/server),
  392. // if protocol=UDP  is specified. By default, the role of the application
  393. // is - SERVER.
  394. //
  395. void __stdcall
  396. DoUdp (
  397.     MODE mRole,
  398.     USHORT usEndPoint
  399.     )
  400. {
  401.     //
  402.     // Initialize the global socket descriptor.
  403.     //
  404.     sock = socket ( AF_INET, SOCK_DGRAM, 0 );
  405.  
  406.     if ( INVALID_SOCKET ==  sock)
  407.     {
  408.     PrintError ( "DoUdp", "socket", WSAGetLastError() );
  409.     }
  410.     
  411.     switch ( mRole )
  412.     {
  413.     case CLIENT:
  414.         DoUdpClient ( usEndPoint );
  415.         break;
  416.  
  417.     default:
  418.         DoUdpServer ( usEndPoint );
  419.     }
  420.     return;
  421. }
  422.  
  423. //
  424. // DoMailSlotServer () function receives a mailslot message on a particular
  425. // mailslot. The function creates a mailslot, posts a ReadFile () to receive
  426. // the message. The function then checks the first four bytes of the message
  427. // for the message ID, and discards all the messages with same ID, in future.
  428. //
  429. void __stdcall
  430. DoMailSlotServer (
  431.     LPSTR lpsEndPoint
  432.     )
  433. {
  434.   HANDLE hSlot;
  435.    
  436.   // Variables that store MessageID, previous messageID, number of bytes to 
  437.   // read/read, size of next available message and the number of messages.
  438.   DWORD dwMessageID,
  439.     dwPrevID,
  440.     cbMessage,
  441.     cbRead, 
  442.     cbToRead, 
  443.     nMessages;
  444.   
  445.   BOOL fResult;
  446.   
  447.   CHAR achMailSlotName[MAX_MSLOTNAME], 
  448.        achBuffer[MAX_MSGLEN + sizeof ( DWORD )];
  449.   
  450.   // Variable that points past the message ID part in the message.
  451.   LPSTR lpsMessage;
  452.  
  453.     //
  454.     // Create a string for the mailslot name.
  455.     //
  456.     wsprintf ( achMailSlotName, "\\\\.\\mailslot\\%s", lpsEndPoint );
  457.  
  458.     //
  459.     // Create the mailslot.
  460.     //
  461.     hSlot = CreateMailslot ( achMailSlotName,
  462.                  0,
  463.                  MAILSLOT_WAIT_FOREVER,
  464.                  (LPSECURITY_ATTRIBUTES) NULL
  465.                  );
  466.  
  467.     if ( INVALID_HANDLE_VALUE == hSlot )
  468.     {
  469.     PrintError ( "DoMailSlotServer",  "CreateMailSlot", GetLastError() );
  470.     }
  471.  
  472.     //
  473.     // Post ReadFile() and read a message.
  474.     //
  475.     cbToRead = MAX_MSGLEN + sizeof (DWORD);
  476.  
  477.     fResult = ReadFile ( hSlot,
  478.              achBuffer,
  479.              cbToRead,
  480.              &cbRead,
  481.              (LPOVERLAPPED) NULL
  482.              );
  483.     
  484.     if ( TRUE != fResult )
  485.     {
  486.     PrintError ( "DoMailSlotServer", "ReadFile", GetLastError() );
  487.     }
  488.     
  489.     achBuffer[cbRead] = '\0';
  490.  
  491.     //
  492.     // Get the message ID part from the message.
  493.     //
  494.     memcpy ( &dwMessageID, achBuffer, sizeof ( DWORD ) );
  495.  
  496.     //
  497.     // Adjust the actual message pointer.
  498.     //
  499.     lpsMessage = achBuffer + sizeof ( DWORD );
  500.         
  501.     //
  502.     // Print the message
  503.     //
  504.     fprintf ( stdout, 
  505.           "A MailSlot Message of %d bytes received with ID %d\n", 
  506.               strlen (lpsMessage ), 
  507.               dwMessageID 
  508.               );
  509.  
  510.     fprintf ( stdout, "MessageText->%s\n", lpsMessage );
  511.  
  512.     //
  513.     // Check for duplicate messages.
  514.     //
  515.     dwPrevID = dwMessageID;
  516.     
  517.     while ( 1 )
  518.     {
  519.     //
  520.     // get information on pending messages.
  521.     //
  522.     fResult = GetMailslotInfo ( hSlot,
  523.                     (LPDWORD) NULL,
  524.                     &cbMessage, 
  525.                     &nMessages,
  526.                     (LPDWORD) NULL
  527.                     );
  528.     if ( TRUE != fResult )
  529.     { 
  530.         PrintError ( "DoMailSlotServer", 
  531.              "GetMailSlotInfo", 
  532.              GetLastError ( ) 
  533.              );
  534.     }
  535.                                     
  536.     //
  537.     // Break if no more messages.
  538.     //
  539.     if ( MAILSLOT_NO_MESSAGE == cbMessage )
  540.         break;
  541.  
  542.     //
  543.     // We now know how much to read.
  544.     //
  545.     cbToRead = cbMessage;
  546.     fResult = ReadFile ( hSlot,
  547.                  achBuffer,
  548.                  cbToRead,
  549.                  &cbRead,
  550.                  (LPOVERLAPPED) NULL
  551.                  );
  552.  
  553.     if ( TRUE != fResult )
  554.     {
  555.         PrintError ( "DoMailSlotServer",
  556.              "ReadFile", 
  557.              GetLastError ( ) 
  558.              );
  559.     }
  560.     
  561.     achBuffer[cbRead] = '\0';
  562.     memcpy ( &dwMessageID, achBuffer, sizeof (DWORD) );
  563.  
  564.     //
  565.     // print the message only if it is not a duplicate.
  566.     //
  567.     lpsMessage = achBuffer + sizeof (DWORD);
  568.     if ( dwMessageID != dwPrevID )    
  569.     {
  570.         fprintf ( stdout, 
  571.               "A MailSlot Message of %d bytes received with ID %d\n", 
  572.               strlen (lpsMessage ), 
  573.               dwMessageID 
  574.               );
  575.  
  576.         fprintf ( stdout, "MessageText->%s\n", achBuffer );
  577.     }
  578.     
  579.     dwPrevID = dwMessageID;
  580.     }
  581.     
  582.     //
  583.     // Close the handle to our mailslot.
  584.     //
  585.     fResult = CloseHandle ( hSlot );
  586.  
  587.     if ( TRUE != fResult )
  588.     {
  589.     PrintError ( "DoMailSlotServer", "CloseHandle", GetLastError() );
  590.     }
  591.     return;
  592. }
  593.  
  594. //
  595. // DoMailSlotClient () function implements the broadcast routine for a
  596. // Mailslot client. The function opens handle to the mailslot using 
  597. // CreateFile (). CreateFile will fail on Windows NT for local mailslots,
  598. // if the mailslot is not already created using CreateMailSlot () API. 
  599. //  
  600. // The function appends a message number to the message which the server uses
  601. // to discard duplicate messages. In the event of a client runnig on a system
  602. // with multiple transport protocols loaded, a mailsot message is sent over
  603. // each protocol.
  604. //
  605. // This routine broadcasts a mailslot message to everyone on a Windows NT
  606. // domain, it can also be used to send a mailslot message to a particular
  607. // host or a workgroup.
  608. //
  609. void __stdcall
  610. DoMailSlotClient (
  611.     LPSTR lpsEndPoint,
  612.     LPSTR lpsDomainName
  613.     )
  614. {
  615.   HANDLE hFile;
  616.   
  617.   // Variables that store MessageID, number of bytes to write/written.
  618.   DWORD dwMessageID, 
  619.     cbWritten,
  620.     cbToWrite;
  621.   
  622.   BOOL fResult;
  623.   
  624.   CHAR achMailSlotName[MAX_MSLOTNAME],
  625.        achBuffer[MAX_MSGLEN + sizeof ( DWORD ) ];
  626.  
  627.     if ( NULL == lpsDomainName )
  628.     {
  629.     fprintf ( stdout, 
  630.           "Domain/Workgroup name must be specified....Exiting\n"
  631.           );
  632.     exit ( 1 );
  633.     }
  634.   
  635.     //
  636.     // Create a string for the mailslot name.
  637.     //
  638.     wsprintf ( achMailSlotName,
  639.            "\\\\%s\\mailslot\\%s",
  640.            lpsDomainName,
  641.            lpsEndPoint 
  642.            );
  643.  
  644.     //
  645.     // Open a handle to the mailslot.
  646.     //
  647.     hFile = CreateFile ( achMailSlotName,
  648.              GENERIC_WRITE,
  649.              FILE_SHARE_READ,
  650.              (LPSECURITY_ATTRIBUTES) NULL,
  651.              OPEN_EXISTING,
  652.              FILE_ATTRIBUTE_NORMAL,
  653.              (HANDLE) NULL 
  654.              );
  655.     
  656.     if ( INVALID_HANDLE_VALUE == hFile)
  657.     {
  658.     PrintError ( "DoMailSlotClient", "CreateFile", GetLastError ( ) );
  659.     }
  660.     
  661.     //
  662.     // Generate a Message ID.
  663.     //
  664.     srand ( (UINT) time ( NULL) );
  665.     dwMessageID = rand ( );
  666.  
  667.     memcpy ( achBuffer, &dwMessageID, sizeof ( DWORD ) );
  668.     lstrcpy ( achBuffer + sizeof (DWORD), "A MailSlot Broadcast Message" );
  669.  
  670.     //
  671.     // Total number of bytes to write.
  672.     //
  673.     cbToWrite = sizeof ( DWORD ) + strlen ( achBuffer + sizeof ( DWORD ) );
  674.     
  675.     //
  676.     // Send a mailslot message.
  677.     //
  678.     fResult = WriteFile ( hFile,
  679.               achBuffer,
  680.               cbToWrite,
  681.               &cbWritten,
  682.               (LPOVERLAPPED) NULL
  683.               );
  684.  
  685.     if ( TRUE != fResult )
  686.     {
  687.     PrintError ( "DoMailSlotClient", "WriteFile", GetLastError ( ) );
  688.     }
  689.  
  690.     fprintf ( stdout, 
  691.           "%d bytes of MailSlot data broadcasted with ID %d\n", 
  692.           cbWritten, 
  693.           dwMessageID
  694.           );
  695.     
  696.     //
  697.     // Close the mailslot handle.
  698.     //
  699.     fResult = CloseHandle ( hFile );
  700.  
  701.     if ( TRUE != fResult )
  702.     {
  703.     PrintError ( "DoMailSlotClient", "CloseHandle", GetLastError() );
  704.     }
  705.     return;
  706. }
  707.  
  708. //
  709. // DoUdpServer () function receives the broadcast on a specified port. The
  710. // server will have to post a recv (), before the client sends the broadcast.
  711. // 
  712. void __stdcall
  713. DoUdpServer (
  714.     USHORT usEndPoint
  715.     )
  716. {
  717.   
  718.   // IP address structures needed to bind to a local port and get the sender's
  719.   // information.
  720.   SOCKADDR_IN saUdpServ, saUdpCli;
  721.   
  722.   INT err, nSize;
  723.   
  724.   CHAR achBuffer[MAX_MSGLEN];
  725.  
  726.     //
  727.     // bind to the specified port.
  728.     //
  729.     saUdpServ.sin_family = AF_INET;
  730.     saUdpServ.sin_addr.s_addr = htonl ( INADDR_ANY );
  731.     saUdpServ.sin_port = htons ( usEndPoint );
  732.  
  733.     err = bind ( sock, (SOCKADDR FAR *)&saUdpServ, sizeof ( SOCKADDR_IN ) );
  734.  
  735.     if ( SOCKET_ERROR == err )
  736.     {
  737.     PrintError ( "DoUdpServer", "bind", WSAGetLastError ( ) );
  738.     }
  739.  
  740.     //
  741.     // receive a datagram on the bound port number.
  742.     //
  743.     nSize = sizeof ( SOCKADDR_IN );
  744.     err = recvfrom ( sock,
  745.              achBuffer,
  746.              MAX_MSGLEN,
  747.              0,
  748.              (SOCKADDR FAR *) &saUdpCli,
  749.              &nSize
  750.              );
  751.  
  752.     if ( SOCKET_ERROR == err )
  753.     {
  754.     PrintError ( "DoUdpServer", "recvfrom", WSAGetLastError ( ) );
  755.     }
  756.      
  757.     //
  758.     // print the sender's information.
  759.     //
  760.     achBuffer[err] = '\0';
  761.     fprintf ( stdout, "A Udp Datagram of length %d bytes received from ", err );
  762.     fprintf ( stdout, "\n\tIP Adress->%s ", inet_ntoa ( saUdpCli.sin_addr ) );
  763.     fprintf ( stdout, "\n\tPort Number->%d\n", ntohs ( saUdpCli.sin_port ) );
  764.     fprintf ( stdout, "MessageText->%s\n", achBuffer );
  765.  
  766.     //
  767.     // Call the cleanup routine
  768.     //
  769.     DoCleanup ( );
  770.       
  771.     return;
  772. }
  773.  
  774. //
  775. // DoUdpClient () function implements the broadcast routine for an UDP
  776. // client. The function sets the SO_BROADCAST option with the global socket.
  777. // Calling this API is important. After binding to a local port, it sends an 
  778. // UDP boradcasts to the IP address INADDR_BROADCAST, with a particular
  779. // port number.
  780. //
  781. void __stdcall
  782. DoUdpClient (
  783.     USHORT usEndPoint
  784.     )
  785. {
  786.   
  787.   // IP address structures needed to fill the source and destination 
  788.   // addresses.
  789.   SOCKADDR_IN saUdpServ, saUdpCli;
  790.   
  791.   INT err;
  792.   
  793.   CHAR achMessage[MAX_MSGLEN];
  794.   
  795.   // Variable to set the broadcast option with setsockopt ().
  796.   BOOL fBroadcast = TRUE;
  797.  
  798.     
  799.     err = setsockopt ( sock, 
  800.                SOL_SOCKET,
  801.                SO_BROADCAST,
  802.                (CHAR *) &fBroadcast,
  803.                sizeof ( BOOL )
  804.                );
  805.  
  806.     if ( SOCKET_ERROR == err )
  807.     {
  808.     PrintError ( "DoUdpClient", "setsockopt", WSAGetLastError ( )  );
  809.     }
  810.  
  811.     //
  812.     // bind to a local socket and an interface.
  813.     //
  814.     saUdpCli.sin_family = AF_INET;
  815.     saUdpCli.sin_addr.s_addr = htonl ( INADDR_ANY );
  816.     saUdpCli.sin_port = htons ( 0 );
  817.  
  818.     err = bind ( sock, (SOCKADDR *) &saUdpCli, sizeof (SOCKADDR_IN) );
  819.  
  820.     if ( SOCKET_ERROR == err )
  821.     {
  822.     PrintError ( "DoUdpClient", "bind", WSAGetLastError ( ) );
  823.     }
  824.  
  825.     //
  826.     // Fill an IP address structure, to send an IP broadcast. The 
  827.     // packet will be broadcasted to the specified port.
  828.     //
  829.     saUdpServ.sin_family = AF_INET;
  830.     saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST );
  831.     saUdpServ.sin_port = htons ( usEndPoint );
  832.  
  833.     lstrcpy ( achMessage, "A Broadcast Datagram" );
  834.   
  835.     err = sendto ( sock,
  836.            achMessage,
  837.            lstrlen ( achMessage ),
  838.            0,
  839.            (SOCKADDR *) &saUdpServ,
  840.            sizeof ( SOCKADDR_IN )
  841.            );
  842.  
  843.     if ( SOCKET_ERROR == err )
  844.     {
  845.     PrintError ( "DoUdpClient", "sendto", WSAGetLastError ( ) );
  846.     }
  847.  
  848.     fprintf ( stdout, "%d bytes of data broadcasted\n", err );
  849.  
  850.     //
  851.     // Call the cleanup routine.
  852.     //
  853.     DoCleanup ( );
  854.  
  855.     return;
  856. }
  857.  
  858.  
  859. //
  860. // DoIpxServer () function receives the broadcast on a specified socket. The
  861. // server will have to post a recv (), before the client sends the broadcast. 
  862. // It is necessary call setsockopt () with SO_BROADCAST flag set, in order to
  863. // receive IPX broadcasts on Windows 95.
  864. //
  865. void __stdcall 
  866. DoIpxServer (
  867.     USHORT usEndPoint
  868.     )
  869. {
  870.    
  871.   // IPX address structures needed to bind to a local socket and get the
  872.   // sender's information.
  873.   SOCKADDR_IPX saIpxServ, saIpxCli;
  874.   
  875.   INT err, nSize;
  876.   
  877.   CHAR achBuffer[MAX_MSGLEN], 
  878.        achAddress[MAX_ADDLEN];
  879.   
  880.   OSVERSIONINFO osVer;
  881.   
  882.   // Variable to set the broadcast option with setsockopt ().
  883.   BOOL fResult, fBroadcast = TRUE;
  884.  
  885.     //
  886.     // Check the platform.
  887.     //
  888.     osVer.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );
  889.     fResult  = GetVersionEx ( &osVer);
  890.  
  891.     if ( FALSE == fResult)
  892.     {
  893.         PrintError ( "DoIpxServer", "GetVersionEx", GetLastError ( ) );
  894.     }
  895.  
  896.     //
  897.     // If the platform is Windows 95, call setsockopt ().
  898.     //
  899.     if ( VER_PLATFORM_WIN32_WINDOWS == osVer.dwPlatformId )
  900.     {   
  901.     err = setsockopt ( sock, 
  902.                SOL_SOCKET, 
  903.                SO_BROADCAST, 
  904.                (CHAR *) &fBroadcast, 
  905.                sizeof ( BOOL ) 
  906.                );
  907.  
  908.     if ( SOCKET_ERROR == err )
  909.     {
  910.         PrintError ( "DoIpxServer", "setsockopt", WSAGetLastError() );
  911.     }
  912.     }
  913.  
  914.     //
  915.     // bind to the specified socket.
  916.     //
  917.     saIpxServ.sa_family = AF_IPX;
  918.     saIpxServ.sa_socket = usEndPoint;
  919.     memset ( saIpxServ.sa_netnum, 0, sizeof (saIpxServ.sa_netnum ) );
  920.     memset ( saIpxServ.sa_nodenum, 0, sizeof (saIpxServ.sa_nodenum ) );
  921.  
  922.     err = bind ( sock, (SOCKADDR *) &saIpxServ, sizeof (SOCKADDR_IPX) );
  923.  
  924.     if ( SOCKET_ERROR == err )
  925.     {
  926.     PrintError ( "DoIpxServer", "bind", WSAGetLastError ( ) );
  927.     }
  928.  
  929.     //
  930.     // receive a datagram on the bound socket number.
  931.     //
  932.     nSize = sizeof ( SOCKADDR_IPX );
  933.     err = recvfrom ( sock,
  934.              achBuffer,
  935.              MAX_MSGLEN,
  936.              0,
  937.              (SOCKADDR *) &saIpxCli,
  938.              &nSize 
  939.              );
  940.  
  941.     if ( SOCKET_ERROR == err )
  942.     {
  943.     PrintError ( "DoIpxServer", "recvfrom", WSAGetLastError ( ) );
  944.     }
  945.     
  946.     //
  947.     // print the sender's information.
  948.     //
  949.     achBuffer[err] = '\0';
  950.     fprintf ( stdout, 
  951.           "An Ipx Datagram of length %d bytes received from ", 
  952.           err );
  953.     fprintf ( stdout, 
  954.           "\n\tIPX Adress->%s ", 
  955.           IpxnetAddr ( achAddress, 
  956.                saIpxCli.sa_netnum, 
  957.                saIpxCli.sa_nodenum 
  958.                ) 
  959.           );
  960.     fprintf ( stdout, "\n\tSocket Number->%d\n", saIpxCli.sa_socket );
  961.     fprintf ( stdout, "MessageText->%s\n", achBuffer );
  962.     
  963.     //
  964.     // Call the cleanup routine.
  965.     //
  966.     DoCleanup ( );
  967.     return;              
  968.  
  969. }
  970.  
  971. //
  972. // DoIpxClient () function implements the broadcast routine for a an IPX
  973. // client. The fucntion sets the SO_BROADCAST option with the gloabal socket.
  974. // Calling this API is important. After binding to a local port, it sends an IPX
  975. // packet to the address with node number as all 1's and net number as all 0's,
  976. // with a particuler socket number.
  977. //
  978. void __stdcall
  979. DoIpxClient (
  980.     USHORT usEndPoint
  981.     )
  982. {
  983.    
  984.   // IPX address structures needed to fill the source and destination 
  985.   // addresses.
  986.   SOCKADDR_IPX saIpxServ, saIpxCli;
  987.   
  988.   INT err;
  989.   
  990.   CHAR achMessage[MAX_MSGLEN];
  991.   
  992.   // Variable to set the broadcast option with setsockopt ().
  993.   BOOL fBroadcast = TRUE;
  994.     
  995.   err = setsockopt ( sock, 
  996.              SOL_SOCKET, 
  997.              SO_BROADCAST,
  998.              (CHAR *) &fBroadcast, 
  999.              sizeof ( BOOL ) 
  1000.              );
  1001.  
  1002.     if ( SOCKET_ERROR == err )
  1003.     {
  1004.     PrintError ( "DoIpxClient", "setsockopt", WSAGetLastError ( ) );
  1005.     }
  1006.  
  1007.     //
  1008.     // bind to a local socket and an interface.
  1009.     //
  1010.     saIpxCli.sa_family = AF_IPX;
  1011.     saIpxCli.sa_socket = (USHORT) 0;
  1012.     memset ( saIpxCli.sa_netnum, 0, sizeof ( saIpxCli.sa_netnum ) );
  1013.     memset ( saIpxCli.sa_nodenum, 0, sizeof ( saIpxCli.sa_nodenum ) );
  1014.  
  1015.     err = bind ( sock, (SOCKADDR  *) &saIpxCli, sizeof ( SOCKADDR_IPX ) );
  1016.  
  1017.     if ( SOCKET_ERROR == err )
  1018.     {
  1019.     PrintError ( "DoIpxClient", "bind", WSAGetLastError() );
  1020.     }
  1021.  
  1022.     //
  1023.     // Fill an IPX address structure, to send an IPX broadcast. The 
  1024.     // packet will be broadcasted to the specified socket.
  1025.     // 
  1026.     saIpxServ.sa_family = AF_IPX;
  1027.     saIpxServ.sa_socket = usEndPoint;
  1028.     memset ( saIpxServ.sa_netnum, 0, sizeof ( saIpxServ.sa_netnum ) );
  1029.     memset ( saIpxServ.sa_nodenum, 0xFF, sizeof ( saIpxServ.sa_nodenum ) );
  1030.  
  1031.     lstrcpy ( achMessage, "A Broadcast Datagram" );
  1032.   
  1033.     err = sendto ( sock,
  1034.            achMessage,
  1035.            lstrlen ( achMessage ),
  1036.            0,
  1037.            (SOCKADDR *) &saIpxServ,
  1038.            sizeof ( SOCKADDR_IPX )
  1039.            );
  1040.  
  1041.     if ( SOCKET_ERROR == err )
  1042.     {
  1043.     PrintError ( "DoIpxClient", "sendto", WSAGetLastError ( ) );
  1044.     }
  1045.  
  1046.     fprintf ( stdout, "%d bytes of data broadcasted\n", err);
  1047.  
  1048.     //
  1049.     // Call the cleanup routine.
  1050.     //
  1051.     DoCleanup ( );
  1052.  
  1053.     return;
  1054. }
  1055.  
  1056. //
  1057. // Usage () lists the available command line options.
  1058. //
  1059. void __stdcall
  1060. Usage (
  1061.     CHAR *pszProgramName
  1062.     )
  1063. {
  1064.     fprintf ( stderr, "Usage:  %s\n", pszProgramName );
  1065.     fprintf ( stderr, 
  1066.     "\t-s or -c (s - server, c - client, default - server)\n" );
  1067.     fprintf ( stderr, 
  1068.     "\t-p <i or m or u> (i - IPX, m - Mailslots, u - UDP)\n" );
  1069.     fprintf ( stderr, "\t-e <Endpoint>\n" );
  1070.     fprintf ( stderr, 
  1071.         "\t-d <DomainName> - needed only for a Mailslot client\n" );
  1072.     fprintf ( stderr, 
  1073.     "\n\tDefault Values-> Role:Server, Protocol:UDP, EndPoint:5005\n" );
  1074.     
  1075.     exit ( 1 );
  1076. }
  1077.  
  1078.  
  1079. //
  1080. // PrintError () is a function available globally for printing the error and 
  1081. // doing the cleanup.
  1082. //
  1083. void __stdcall
  1084. PrintError (
  1085.     LPSTR lpszRoutine,
  1086.     LPSTR lpszCallName,
  1087.     DWORD dwError
  1088.     )
  1089. {
  1090.  
  1091.     fprintf ( stderr, 
  1092.           "The Call to %s() in routine() %s failed with error %d\n", 
  1093.           lpszCallName, 
  1094.           lpszRoutine,
  1095.           dwError 
  1096.           );
  1097.  
  1098.     DoCleanup ( );
  1099.  
  1100.     exit ( 1 );
  1101. }
  1102.  
  1103. //
  1104. // IpxnetAddr () function converts an IPX address address in the binary form
  1105. // to ascii format, it fills the input buffer with the address and returns a
  1106. // pointer to it.
  1107. //
  1108. CHAR * __stdcall
  1109. IpxnetAddr (
  1110.     CHAR *lpBuffer,
  1111.     CHAR *lpsNetnum, 
  1112.     CHAR *lpsNodenum 
  1113.     )
  1114. {
  1115.     wsprintf ( lpBuffer, 
  1116.            "%02X%02X%02X%02X.%02X%02X%02X%02X%02X%02X",
  1117.            (UCHAR) lpsNetnum[0], (UCHAR) lpsNetnum[1], 
  1118.            (UCHAR) lpsNetnum[2], (UCHAR) lpsNetnum[3],
  1119.            (UCHAR) lpsNodenum[0], (UCHAR) lpsNodenum[1],
  1120.            (UCHAR) lpsNodenum[2], (UCHAR) lpsNodenum[3],
  1121.            (UCHAR) lpsNodenum[4], (USHORT) lpsNodenum[5]
  1122.            );
  1123.  
  1124.     return ( lpBuffer);
  1125. }
  1126.  
  1127. //
  1128. // DoStartup () initializes the Winsock DLL with Winsock version 1.1
  1129. //
  1130. void __stdcall
  1131. DoStartup ( void )
  1132. {
  1133.   WSADATA wsaData;
  1134.   
  1135.   INT iRetVal;
  1136.  
  1137.     iRetVal = WSAStartup ( MAKEWORD ( 1,1 ), &wsaData );
  1138.     
  1139.     if ( 0 != iRetVal)
  1140.     {
  1141.     PrintError ( "DoStartup", "WSAStartup", iRetVal );
  1142.     }
  1143.     
  1144.     //
  1145.     // Set the global flag.
  1146.     //
  1147.     fStarted = TRUE;
  1148.  
  1149.     return;
  1150. }
  1151.  
  1152. //
  1153. // DoCleanup () will close the global socket which was opened successfully by
  1154. // a call to socket (). Additionally, it will call WSACleanup (), if a call
  1155. // to WSAStartup () was made successfully.
  1156. //
  1157. void __stdcall
  1158. DoCleanup ( void )
  1159. {
  1160.     if ( INVALID_SOCKET != sock )
  1161.     {
  1162.     closesocket ( sock );
  1163.     }
  1164.  
  1165.     if ( TRUE == fStarted )
  1166.     {
  1167.     WSACleanup ( );
  1168.     }
  1169.  
  1170.     fprintf ( stdout, "DONE\n" );
  1171.  
  1172.     return;
  1173. }
  1174.