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

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