www.pudn.com > bcast.zip > BCAST.C, change:1997-10-08,size:26555b


/******************************************************************************\ 
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright 1996-1997 Microsoft Corporation. 
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation. 
*       See these sources for detailed information regarding the 
*       Microsoft samples programs. 
\******************************************************************************/ 
 
/* 
Module Name: 
 
    bcast.c 
 
Abstract: 
 
    This module illustrates the Win32 Winsock and Mailslot APIs to do a generic 
    broadcast over IPX, UDP and Mailslot protocols. 
 
    This example implements a client and a server. The example has a number of 
    command line options. For example, 
 
    -s To run the example as a server(default role). 
	 
	-c To run the example as a client. 
    
	-p <i or m or u> To specify the protocol to be used. 
	 i - IPX. 
	 m - Mailslots. 
	 u - UDP(default protocol). 
	 
    -e <Endpoint> To specify an end point of your choice. This is a mandatory 
	parameter. Servers create this endpoint and read broadcast messages. An  
	endpoint in case Mailslot protocol is a Mailslot name.(default is 5005).  
	 
    -d <DomainName> - To specify a domain name or a workgroup name. This is  
	useful for Mailslot clients, only. 
 
	To run the application as a server, the following command lines can be  
	specified: 
     
	bcast -s -e 8000 -p u 
	bcast -s -e 8000 -p i 
	bcast -s -e MAILSLOT1 -p m 
 
	To run the application as a client, the following command lines can be 
	specified: 
	 
	bcast -c -e 8000 -p u 
	bcast -c -e 8000 -p i 
	bcast -c -e MAILSLOT1 -p m -d DOMAIN1 
	bcast -c -e MAILSLOT1 -p m -d WORKGROUP1 
 
Author: 
 
    Rajesh Dadhia (rajeshd) 02-Mar-96 
 
Revision History: 
 
*/ 
 
#include <stdio.h> 
#include <time.h> 
#include <windows.h> 
#include <winsock.h> 
#include <wsipx.h> 
#include <wsnwlink.h> 
 
#define MAX_MSGLEN 80 
#define MAX_ADDLEN 80 
#define MAX_MSLOTNAME 80 
 
typedef enum _MODE { CLIENT=0, SERVER } MODE; 
typedef enum _PROTOCOL { UDP=0, IPX, MAILSLOT } PROTOCOL; 
 
BOOL __stdcall 
CtrlCHandler ( 
    DWORD dwEvent 
    ); 
 
void __stdcall 
DoMailSlot ( 
    MODE mRole, 
    LPSTR lpsEndPoint, 
    LPSTR lpsDomainName 
    ); 
 
void __stdcall 
DoIpx ( 
    MODE mRole, 
    USHORT usEndPoint 
    ); 
 
void __stdcall 
DoUdp ( 
    MODE mRole, 
    USHORT usEndPoint 
    ); 
 
void __stdcall 
DoMailSlotServer ( 
    LPSTR lpsEndPoint 
    ); 
 
void __stdcall 
DoMailSlotClient ( 
    LPSTR lpsEndPoint, 
    LPSTR lpsDomainName 
    ); 
 
void __stdcall 
DoUdpServer ( 
    USHORT usEndPoint 
    ); 
 
void __stdcall 
DoUdpClient ( 
    USHORT usEndPoint 
    ); 
 
void __stdcall  
DoIpxServer ( 
    USHORT usEndPoint 
    ); 
 
void __stdcall 
DoIpxClient ( 
    USHORT usEndPoint 
    ); 
 
void __stdcall 
Usage ( 
    CHAR *pszProgramName 
    ); 
 
void __stdcall 
PrintError ( 
    LPSTR lpszRoutine, 
    LPSTR lpszCallName, 
    DWORD dwError 
    ); 
 
CHAR * __stdcall 
IpxnetAddr ( 
    CHAR *lpBuffer, 
	CHAR *lpsNetnum,  
	CHAR *lpsNodenum  
	); 
 
void __stdcall 
DoStartup ( void ); 
 
void __stdcall 
DoCleanup ( void ); 
 
// 
// Global Variables 
// 
 
// If Startup was successful, fStarted is used to keep track. 
BOOL fStarted = FALSE; 
 
// Global socket descriptor 
SOCKET sock = INVALID_SOCKET; 
 
void __cdecl 
main ( 
    INT argc, 
    CHAR **argv 
    ) 
{ 
 
  // Default role of the application is SERVER, which means receiver of 
  // the broadcast messages. 
  MODE mRole = SERVER; 
   
  // Deafult protocol used is UDP. 
  PROTOCOL pProto = UDP; 
   
  // Default Endpoint. 
  USHORT usEndPoint = 5005; 
   
  // Strings pointing to Endpoint and DomainName(necessary for Mailslots). 
  LPSTR lpsEndPoint, lpsDomainName; 
  INT  i; 
  CHAR chProto; 
 
    // 
    // Install the CTRL+BREAK Handler 
    // 
    if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler, 
					  TRUE  
					  ) )  
    { 
	PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) ); 
    }   
   
    // 
    // allow the user to override settings with command line switches 
    // 
    for ( i = 1; i < argc; i++ )  
    { 
	if ( ( *argv[i] == '-' ) || ( *argv[i] == '/' ) )  
	{ 
	    switch ( tolower ( *( argv[i]+1 ) ) )  
	    { 
		// 
		// Role of the application (Client - Sender of broadcasts). 
		// 
		case 'c':   
		    mRole = CLIENT; 
		    break; 
 
		// 
		// Role of the application (Server - Receiver of broadcasts) 
		// 
		case 's':   
		    mRole = SERVER; 
		    break; 
 
		// 
		// Network protocol (Mailslots, IPX or UDP). 
		// 
		case 'p': 
		    chProto = tolower ( *argv[++i] ); 
		    if ( 'm' == chProto ) 
		    { 
			pProto = MAILSLOT; 
		    } 
		    else if ( 'i' == chProto ) 
		    { 
			pProto = IPX; 
		    } 
		    else 
			pProto = UDP; 
		    break; 
		 
		// 
		// EndPoint. 
		// 
		case 'e':  
		    lpsEndPoint = argv[++i]; 
		    break; 
		 
		// 
		// DomainName (Important for Mailslot broadcasts, only). 
		// 
		case 'd': 
		    lpsDomainName = argv[++i]; 
		    break; 
 
		// 
		// Help. 
		// 
		case 'h': 
		case '?': 
		default: 
		    Usage ( argv[0] ); 
	    } 
	} 
	else 
	    // 
	    // Help. 
	    // 
	    Usage ( argv[0] ); 
    } 
 
     
    // 
    // If the protocol specified is not MAILSLOT, convert the endpoint 
    // information to integer format from the string format. 
    // 
    if ( MAILSLOT != pProto ) 
    { 
	usEndPoint = atoi ( lpsEndPoint ); 
    } 
 
    // 
    // Print a Summary of the switches specfied  
    // Helpful for debugging 
    // 
    fprintf ( stdout, "SUMMARY:\n" ); 
    fprintf ( stdout, "\tRole-> %s\n", (CLIENT == mRole)?"Client":"Server" ); 
    fprintf ( stdout, "\tProtocol-> %s\n",  
		      ( MAILSLOT == pProto ) ? "MAILSLOT" :  
		      ( IPX == pProto ) ? "IPX" : "UDP" ); 
    fprintf ( stdout, "\tEndpoint-> %s\n", lpsEndPoint ); 
     
    // 
    // Check the protocol specified. 
    // Call the appropriate handler rouine. By default the protocol 
    // is UDP. 
    // 
    switch ( pProto ) 
    { 
	case MAILSLOT : 
	    DoMailSlot ( mRole, lpsEndPoint, lpsDomainName ); 
	    break; 
 
	case IPX: 
	    DoStartup ( ); 
	    DoIpx ( mRole, usEndPoint ); 
	    break; 
 
	default: 
	    DoStartup ( ); 
	    DoUdp ( mRole, usEndPoint ); 
	    break; 
    } 
	 
    return; 
} 
 
// 
// CtrlCHandler () intercepts the CTRL+BREAK or CTRL+C events and calls the 
// cleanup routines. 
// 
BOOL __stdcall 
CtrlCHandler ( 
    DWORD dwEvent 
	) 
{ 
    if ( ( CTRL_C_EVENT == dwEvent ) || ( CTRL_BREAK_EVENT == dwEvent ) ) 
    { 
	DoCleanup ( );     
    } 
 
    return FALSE; 
} 
 
// 
// DoMailSlot () function calls appropriate handler function (client/server), 
// if protocol=MAILSLOT is specified. By default, the role of the application 
// is - SERVER. 
// 
void __stdcall 
DoMailSlot ( 
    MODE mRole, 
    LPSTR lpsEndPoint, 
    LPSTR lpsDomainName 
    ) 
{ 
    switch ( mRole ) 
    { 
	case CLIENT: 
	    DoMailSlotClient ( lpsEndPoint, lpsDomainName ); 
	    break; 
 
	default: 
	    DoMailSlotServer ( lpsEndPoint ); 
    } 
	return; 
} 
 
// 
// DoIpx () function calls appropriate handler function (client/server), 
// if protocol=IPX  is specified. By default, the role of the application 
// is - SERVER. 
// 
void __stdcall 
DoIpx ( 
    MODE mRole, 
    USHORT usEndPoint 
    ) 
{ 
    // 
    // Initialize the global socket descriptor. 
    // 
    sock = socket ( AF_IPX, SOCK_DGRAM, NSPROTO_IPX ); 
 
    if ( INVALID_SOCKET ==  sock ) 
    { 
	PrintError( "DoIpx", "socket", WSAGetLastError ( ) ); 
    } 
 
    switch ( mRole ) 
    { 
	case CLIENT: 
	    DoIpxClient ( usEndPoint ); 
	    break; 
 
	default: 
	    DoIpxServer ( usEndPoint ); 
    } 
	return; 
} 
 
 
// 
// DoUdp () function calls appropriate handler function (client/server), 
// if protocol=UDP  is specified. By default, the role of the application 
// is - SERVER. 
// 
void __stdcall 
DoUdp ( 
    MODE mRole, 
    USHORT usEndPoint 
    ) 
{ 
    // 
    // Initialize the global socket descriptor. 
    // 
    sock = socket ( AF_INET, SOCK_DGRAM, 0 ); 
 
    if ( INVALID_SOCKET ==  sock) 
    { 
	PrintError ( "DoUdp", "socket", WSAGetLastError() ); 
    } 
     
    switch ( mRole ) 
    { 
	case CLIENT: 
	    DoUdpClient ( usEndPoint ); 
	    break; 
 
	default: 
	    DoUdpServer ( usEndPoint ); 
    } 
    return; 
} 
 
// 
// DoMailSlotServer () function receives a mailslot message on a particular 
// mailslot. The function creates a mailslot, posts a ReadFile () to receive 
// the message. The function then checks the first four bytes of the message 
// for the message ID, and discards all the messages with same ID, in future. 
// 
void __stdcall 
DoMailSlotServer ( 
    LPSTR lpsEndPoint 
    ) 
{ 
  HANDLE hSlot; 
    
  // Variables that store MessageID, previous messageID, number of bytes to  
  // read/read, size of next available message and the number of messages. 
  DWORD dwMessageID, 
	dwPrevID, 
	cbMessage, 
	cbRead,  
	cbToRead,  
	nMessages; 
   
  BOOL fResult; 
   
  CHAR achMailSlotName[MAX_MSLOTNAME],  
       achBuffer[MAX_MSGLEN + sizeof ( DWORD )]; 
   
  // Variable that points past the message ID part in the message. 
  LPSTR lpsMessage; 
 
    // 
    // Create a string for the mailslot name. 
    // 
    wsprintf ( achMailSlotName, "\\\\.\\mailslot\\%s", lpsEndPoint ); 
 
    // 
    // Create the mailslot. 
    // 
    hSlot = CreateMailslot ( achMailSlotName, 
			     0, 
			     MAILSLOT_WAIT_FOREVER, 
			     (LPSECURITY_ATTRIBUTES) NULL 
			     ); 
 
    if ( INVALID_HANDLE_VALUE == hSlot ) 
    { 
	PrintError ( "DoMailSlotServer",  "CreateMailSlot", GetLastError() ); 
    } 
 
    // 
    // Post ReadFile() and read a message. 
    // 
    cbToRead = MAX_MSGLEN + sizeof (DWORD); 
 
    fResult = ReadFile ( hSlot, 
			 achBuffer, 
			 cbToRead, 
			 &cbRead, 
			 (LPOVERLAPPED) NULL 
			 ); 
     
    if ( TRUE != fResult ) 
    { 
	PrintError ( "DoMailSlotServer", "ReadFile", GetLastError() ); 
    } 
	 
    achBuffer[cbRead] = '\0'; 
 
    // 
    // Get the message ID part from the message. 
    // 
    memcpy ( &dwMessageID, achBuffer, sizeof ( DWORD ) ); 
 
    // 
    // Adjust the actual message pointer. 
    // 
    lpsMessage = achBuffer + sizeof ( DWORD ); 
	     
    // 
    // Print the message 
    // 
    fprintf ( stdout,  
	      "A MailSlot Message of %d bytes received with ID %d\n",  
              strlen (lpsMessage ),  
              dwMessageID  
              ); 
 
    fprintf ( stdout, "MessageText->%s\n", lpsMessage ); 
 
    // 
    // Check for duplicate messages. 
    // 
    dwPrevID = dwMessageID; 
     
    while ( 1 ) 
    { 
	// 
	// get information on pending messages. 
	// 
	fResult = GetMailslotInfo ( hSlot, 
				    (LPDWORD) NULL, 
				    &cbMessage,  
				    &nMessages, 
				    (LPDWORD) NULL 
				    ); 
	if ( TRUE != fResult ) 
	{  
	    PrintError ( "DoMailSlotServer",  
			 "GetMailSlotInfo",  
			 GetLastError ( )  
			 ); 
	} 
									 
	// 
	// Break if no more messages. 
	// 
	if ( MAILSLOT_NO_MESSAGE == cbMessage ) 
		break; 
 
	// 
	// We now know how much to read. 
	// 
	cbToRead = cbMessage; 
	fResult = ReadFile ( hSlot, 
			     achBuffer, 
			     cbToRead, 
			     &cbRead, 
			     (LPOVERLAPPED) NULL 
			     ); 
 
	if ( TRUE != fResult ) 
	{ 
	    PrintError ( "DoMailSlotServer", 
			 "ReadFile",  
			 GetLastError ( )  
			 ); 
	} 
     
	achBuffer[cbRead] = '\0'; 
	memcpy ( &dwMessageID, achBuffer, sizeof (DWORD) ); 
 
	// 
	// print the message only if it is not a duplicate. 
	// 
	lpsMessage = achBuffer + sizeof (DWORD); 
	if ( dwMessageID != dwPrevID )     
	{ 
	    fprintf ( stdout,  
		      "A MailSlot Message of %d bytes received with ID %d\n",  
		      strlen (lpsMessage ),  
		      dwMessageID  
		      ); 
 
	    fprintf ( stdout, "MessageText->%s\n", achBuffer ); 
	} 
	 
	dwPrevID = dwMessageID; 
    } 
     
    // 
    // Close the handle to our mailslot. 
    // 
    fResult = CloseHandle ( hSlot ); 
 
    if ( TRUE != fResult ) 
    { 
	PrintError ( "DoMailSlotServer", "CloseHandle", GetLastError() ); 
    } 
    return; 
} 
 
// 
// DoMailSlotClient () function implements the broadcast routine for a 
// Mailslot client. The function opens handle to the mailslot using  
// CreateFile (). CreateFile will fail on Windows NT for local mailslots, 
// if the mailslot is not already created using CreateMailSlot () API.  
//   
// The function appends a message number to the message which the server uses 
// to discard duplicate messages. In the event of a client runnig on a system 
// with multiple transport protocols loaded, a mailsot message is sent over 
// each protocol. 
// 
// This routine broadcasts a mailslot message to everyone on a Windows NT 
// domain, it can also be used to send a mailslot message to a particular 
// host or a workgroup. 
// 
void __stdcall 
DoMailSlotClient ( 
    LPSTR lpsEndPoint, 
    LPSTR lpsDomainName 
    ) 
{ 
  HANDLE hFile; 
   
  // Variables that store MessageID, number of bytes to write/written. 
  DWORD dwMessageID,  
	cbWritten, 
	cbToWrite; 
   
  BOOL fResult; 
   
  CHAR achMailSlotName[MAX_MSLOTNAME], 
       achBuffer[MAX_MSGLEN + sizeof ( DWORD ) ]; 
  
    if ( NULL == lpsDomainName ) 
    { 
	fprintf ( stdout,  
		  "Domain/Workgroup name must be specified....Exiting\n" 
		  ); 
	exit ( 1 ); 
    } 
   
    // 
    // Create a string for the mailslot name. 
    // 
    wsprintf ( achMailSlotName, 
	       "\\\\%s\\mailslot\\%s", 
	       lpsDomainName, 
	       lpsEndPoint  
	       ); 
 
    // 
    // Open a handle to the mailslot. 
    // 
    hFile = CreateFile ( achMailSlotName, 
			 GENERIC_WRITE, 
			 FILE_SHARE_READ, 
			 (LPSECURITY_ATTRIBUTES) NULL, 
			 OPEN_EXISTING, 
			 FILE_ATTRIBUTE_NORMAL, 
			 (HANDLE) NULL  
			 ); 
     
    if ( INVALID_HANDLE_VALUE == hFile) 
    { 
	PrintError ( "DoMailSlotClient", "CreateFile", GetLastError ( ) ); 
    } 
     
    // 
    // Generate a Message ID. 
    // 
    srand ( (UINT) time ( NULL) ); 
    dwMessageID = rand ( ); 
 
    memcpy ( achBuffer, &dwMessageID, sizeof ( DWORD ) ); 
    lstrcpy ( achBuffer + sizeof (DWORD), "A MailSlot Broadcast Message" ); 
 
    // 
    // Total number of bytes to write. 
    // 
    cbToWrite = sizeof ( DWORD ) + strlen ( achBuffer + sizeof ( DWORD ) ); 
	 
    // 
    // Send a mailslot message. 
    // 
    fResult = WriteFile ( hFile, 
			  achBuffer, 
			  cbToWrite, 
			  &cbWritten, 
			  (LPOVERLAPPED) NULL 
			  ); 
 
    if ( TRUE != fResult ) 
    { 
	PrintError ( "DoMailSlotClient", "WriteFile", GetLastError ( ) ); 
    } 
 
    fprintf ( stdout,  
	      "%d bytes of MailSlot data broadcasted with ID %d\n",  
	      cbWritten,  
	      dwMessageID 
	      ); 
     
    // 
    // Close the mailslot handle. 
    // 
    fResult = CloseHandle ( hFile ); 
 
    if ( TRUE != fResult ) 
    { 
	PrintError ( "DoMailSlotClient", "CloseHandle", GetLastError() ); 
    } 
    return; 
} 
 
// 
// DoUdpServer () function receives the broadcast on a specified port. The 
// server will have to post a recv (), before the client sends the broadcast. 
//  
void __stdcall 
DoUdpServer ( 
    USHORT usEndPoint 
    ) 
{ 
   
  // IP address structures needed to bind to a local port and get the sender's 
  // information. 
  SOCKADDR_IN saUdpServ, saUdpCli; 
   
  INT err, nSize; 
   
  CHAR achBuffer[MAX_MSGLEN]; 
 
    // 
    // bind to the specified port. 
    // 
    saUdpServ.sin_family = AF_INET; 
    saUdpServ.sin_addr.s_addr = htonl ( INADDR_ANY ); 
    saUdpServ.sin_port = htons ( usEndPoint ); 
 
    err = bind ( sock, (SOCKADDR FAR *)&saUdpServ, sizeof ( SOCKADDR_IN ) ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoUdpServer", "bind", WSAGetLastError ( ) ); 
    } 
 
    // 
    // receive a datagram on the bound port number. 
    // 
    nSize = sizeof ( SOCKADDR_IN ); 
    err = recvfrom ( sock, 
		     achBuffer, 
		     MAX_MSGLEN, 
		     0, 
		     (SOCKADDR FAR *) &saUdpCli, 
		     &nSize 
		     ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoUdpServer", "recvfrom", WSAGetLastError ( ) ); 
    } 
      
    // 
    // print the sender's information. 
    // 
    achBuffer[err] = '\0'; 
    fprintf ( stdout, "A Udp Datagram of length %d bytes received from ", err ); 
    fprintf ( stdout, "\n\tIP Adress->%s ", inet_ntoa ( saUdpCli.sin_addr ) ); 
    fprintf ( stdout, "\n\tPort Number->%d\n", ntohs ( saUdpCli.sin_port ) ); 
    fprintf ( stdout, "MessageText->%s\n", achBuffer ); 
 
    // 
    // Call the cleanup routine 
    // 
    DoCleanup ( ); 
       
    return; 
} 
 
// 
// DoUdpClient () function implements the broadcast routine for an UDP 
// client. The function sets the SO_BROADCAST option with the global socket. 
// Calling this API is important. After binding to a local port, it sends an  
// UDP boradcasts to the IP address INADDR_BROADCAST, with a particular 
// port number. 
// 
void __stdcall 
DoUdpClient ( 
    USHORT usEndPoint 
    ) 
{ 
   
  // IP address structures needed to fill the source and destination  
  // addresses. 
  SOCKADDR_IN saUdpServ, saUdpCli; 
   
  INT err; 
   
  CHAR achMessage[MAX_MSGLEN]; 
   
  // Variable to set the broadcast option with setsockopt (). 
  BOOL fBroadcast = TRUE; 
 
     
    err = setsockopt ( sock,  
		       SOL_SOCKET, 
		       SO_BROADCAST, 
		       (CHAR *) &fBroadcast, 
		       sizeof ( BOOL ) 
		       ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoUdpClient", "setsockopt", WSAGetLastError ( )  ); 
    } 
 
    // 
    // bind to a local socket and an interface. 
    // 
    saUdpCli.sin_family = AF_INET; 
    saUdpCli.sin_addr.s_addr = htonl ( INADDR_ANY ); 
    saUdpCli.sin_port = htons ( 0 ); 
 
    err = bind ( sock, (SOCKADDR *) &saUdpCli, sizeof (SOCKADDR_IN) ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoUdpClient", "bind", WSAGetLastError ( ) ); 
    } 
 
    // 
    // Fill an IP address structure, to send an IP broadcast. The  
    // packet will be broadcasted to the specified port. 
    // 
    saUdpServ.sin_family = AF_INET; 
    saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST ); 
    saUdpServ.sin_port = htons ( usEndPoint ); 
 
    lstrcpy ( achMessage, "A Broadcast Datagram" ); 
   
    err = sendto ( sock, 
		   achMessage, 
		   lstrlen ( achMessage ), 
		   0, 
		   (SOCKADDR *) &saUdpServ, 
		   sizeof ( SOCKADDR_IN ) 
		   ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoUdpClient", "sendto", WSAGetLastError ( ) ); 
    } 
 
    fprintf ( stdout, "%d bytes of data broadcasted\n", err ); 
 
    // 
    // Call the cleanup routine. 
    // 
    DoCleanup ( ); 
 
    return; 
} 
 
 
// 
// DoIpxServer () function receives the broadcast on a specified socket. The 
// server will have to post a recv (), before the client sends the broadcast.  
// It is necessary call setsockopt () with SO_BROADCAST flag set, in order to 
// receive IPX broadcasts on Windows 95. 
// 
void __stdcall  
DoIpxServer ( 
    USHORT usEndPoint 
    ) 
{ 
    
  // IPX address structures needed to bind to a local socket and get the 
  // sender's information. 
  SOCKADDR_IPX saIpxServ, saIpxCli; 
   
  INT err, nSize; 
   
  CHAR achBuffer[MAX_MSGLEN],  
	   achAddress[MAX_ADDLEN]; 
   
  OSVERSIONINFO osVer; 
   
  // Variable to set the broadcast option with setsockopt (). 
  BOOL fResult, fBroadcast = TRUE; 
 
    // 
    // Check the platform. 
    // 
    osVer.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ); 
    fResult  = GetVersionEx ( &osVer); 
 
    if ( FALSE == fResult) 
    { 
        PrintError ( "DoIpxServer", "GetVersionEx", GetLastError ( ) ); 
    } 
 
    // 
    // If the platform is Windows 95, call setsockopt (). 
    // 
    if ( VER_PLATFORM_WIN32_WINDOWS == osVer.dwPlatformId ) 
    {    
	err = setsockopt ( sock,  
			   SOL_SOCKET,  
			   SO_BROADCAST,  
			   (CHAR *) &fBroadcast,  
			   sizeof ( BOOL )  
			   ); 
 
	if ( SOCKET_ERROR == err ) 
	{ 
	    PrintError ( "DoIpxServer", "setsockopt", WSAGetLastError() ); 
	} 
    } 
 
    // 
    // bind to the specified socket. 
    // 
    saIpxServ.sa_family = AF_IPX; 
    saIpxServ.sa_socket = usEndPoint; 
    memset ( saIpxServ.sa_netnum, 0, sizeof (saIpxServ.sa_netnum ) ); 
    memset ( saIpxServ.sa_nodenum, 0, sizeof (saIpxServ.sa_nodenum ) ); 
 
    err = bind ( sock, (SOCKADDR *) &saIpxServ, sizeof (SOCKADDR_IPX) ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoIpxServer", "bind", WSAGetLastError ( ) ); 
    } 
 
    // 
    // receive a datagram on the bound socket number. 
    // 
    nSize = sizeof ( SOCKADDR_IPX ); 
    err = recvfrom ( sock, 
		     achBuffer, 
		     MAX_MSGLEN, 
		     0, 
		     (SOCKADDR *) &saIpxCli, 
		     &nSize  
		     ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoIpxServer", "recvfrom", WSAGetLastError ( ) ); 
    } 
     
    // 
    // print the sender's information. 
    // 
    achBuffer[err] = '\0'; 
    fprintf ( stdout,  
	      "An Ipx Datagram of length %d bytes received from ",  
	      err ); 
    fprintf ( stdout,  
	      "\n\tIPX Adress->%s ",  
	      IpxnetAddr ( achAddress,  
			   saIpxCli.sa_netnum,  
			   saIpxCli.sa_nodenum  
			   )  
	      ); 
    fprintf ( stdout, "\n\tSocket Number->%d\n", saIpxCli.sa_socket ); 
    fprintf ( stdout, "MessageText->%s\n", achBuffer ); 
     
    // 
    // Call the cleanup routine. 
    // 
    DoCleanup ( ); 
    return;               
 
} 
 
// 
// DoIpxClient () function implements the broadcast routine for a an IPX 
// client. The fucntion sets the SO_BROADCAST option with the gloabal socket. 
// Calling this API is important. After binding to a local port, it sends an IPX 
// packet to the address with node number as all 1's and net number as all 0's, 
// with a particuler socket number. 
// 
void __stdcall 
DoIpxClient ( 
    USHORT usEndPoint 
	) 
{ 
    
  // IPX address structures needed to fill the source and destination  
  // addresses. 
  SOCKADDR_IPX saIpxServ, saIpxCli; 
   
  INT err; 
   
  CHAR achMessage[MAX_MSGLEN]; 
   
  // Variable to set the broadcast option with setsockopt (). 
  BOOL fBroadcast = TRUE; 
     
  err = setsockopt ( sock,  
		     SOL_SOCKET,  
		     SO_BROADCAST, 
		     (CHAR *) &fBroadcast,  
		     sizeof ( BOOL )  
		     ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoIpxClient", "setsockopt", WSAGetLastError ( ) ); 
    } 
 
    // 
    // bind to a local socket and an interface. 
    // 
    saIpxCli.sa_family = AF_IPX; 
    saIpxCli.sa_socket = (USHORT) 0; 
    memset ( saIpxCli.sa_netnum, 0, sizeof ( saIpxCli.sa_netnum ) ); 
    memset ( saIpxCli.sa_nodenum, 0, sizeof ( saIpxCli.sa_nodenum ) ); 
 
    err = bind ( sock, (SOCKADDR  *) &saIpxCli, sizeof ( SOCKADDR_IPX ) ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoIpxClient", "bind", WSAGetLastError() ); 
    } 
 
    // 
    // Fill an IPX address structure, to send an IPX broadcast. The  
    // packet will be broadcasted to the specified socket. 
    //  
    saIpxServ.sa_family = AF_IPX; 
    saIpxServ.sa_socket = usEndPoint; 
    memset ( saIpxServ.sa_netnum, 0, sizeof ( saIpxServ.sa_netnum ) ); 
    memset ( saIpxServ.sa_nodenum, 0xFF, sizeof ( saIpxServ.sa_nodenum ) ); 
 
    lstrcpy ( achMessage, "A Broadcast Datagram" ); 
   
    err = sendto ( sock, 
		   achMessage, 
		   lstrlen ( achMessage ), 
		   0, 
		   (SOCKADDR *) &saIpxServ, 
		   sizeof ( SOCKADDR_IPX ) 
		   ); 
 
    if ( SOCKET_ERROR == err ) 
    { 
	PrintError ( "DoIpxClient", "sendto", WSAGetLastError ( ) ); 
    } 
 
    fprintf ( stdout, "%d bytes of data broadcasted\n", err); 
 
    // 
    // Call the cleanup routine. 
    // 
    DoCleanup ( ); 
 
    return; 
} 
 
// 
// Usage () lists the available command line options. 
// 
void __stdcall 
Usage ( 
    CHAR *pszProgramName 
	) 
{ 
    fprintf ( stderr, "Usage:  %s\n", pszProgramName ); 
    fprintf ( stderr,  
	"\t-s or -c (s - server, c - client, default - server)\n" ); 
    fprintf ( stderr,  
	"\t-p <i or m or u> (i - IPX, m - Mailslots, u - UDP)\n" ); 
    fprintf ( stderr, "\t-e <Endpoint>\n" ); 
    fprintf ( stderr,  
		"\t-d <DomainName> - needed only for a Mailslot client\n" ); 
    fprintf ( stderr,  
	"\n\tDefault Values-> Role:Server, Protocol:UDP, EndPoint:5005\n" ); 
     
	exit ( 1 ); 
} 
 
 
// 
// PrintError () is a function available globally for printing the error and  
// doing the cleanup. 
// 
void __stdcall 
PrintError ( 
    LPSTR lpszRoutine, 
	LPSTR lpszCallName, 
	DWORD dwError 
	) 
{ 
 
    fprintf ( stderr,  
	      "The Call to %s() in routine() %s failed with error %d\n",  
	      lpszCallName,  
	      lpszRoutine, 
	      dwError  
	      ); 
 
    DoCleanup ( ); 
 
    exit ( 1 ); 
} 
 
// 
// IpxnetAddr () function converts an IPX address address in the binary form 
// to ascii format, it fills the input buffer with the address and returns a 
// pointer to it. 
// 
CHAR * __stdcall 
IpxnetAddr ( 
    CHAR *lpBuffer, 
    CHAR *lpsNetnum,  
    CHAR *lpsNodenum  
    ) 
{ 
    wsprintf ( lpBuffer,  
	       "%02X%02X%02X%02X.%02X%02X%02X%02X%02X%02X", 
	       (UCHAR) lpsNetnum[0], (UCHAR) lpsNetnum[1],  
	       (UCHAR) lpsNetnum[2], (UCHAR) lpsNetnum[3], 
	       (UCHAR) lpsNodenum[0], (UCHAR) lpsNodenum[1], 
	       (UCHAR) lpsNodenum[2], (UCHAR) lpsNodenum[3], 
	       (UCHAR) lpsNodenum[4], (USHORT) lpsNodenum[5] 
	       ); 
 
    return ( lpBuffer); 
} 
 
// 
// DoStartup () initializes the Winsock DLL with Winsock version 1.1 
// 
void __stdcall 
DoStartup ( void ) 
{ 
  WSADATA wsaData; 
   
  INT iRetVal; 
 
    iRetVal = WSAStartup ( MAKEWORD ( 1,1 ), &wsaData ); 
	 
    if ( 0 != iRetVal) 
    { 
	PrintError ( "DoStartup", "WSAStartup", iRetVal ); 
    } 
     
    // 
    // Set the global flag. 
    // 
    fStarted = TRUE; 
  
    return; 
} 
 
// 
// DoCleanup () will close the global socket which was opened successfully by 
// a call to socket (). Additionally, it will call WSACleanup (), if a call 
// to WSAStartup () was made successfully. 
// 
void __stdcall 
DoCleanup ( void ) 
{ 
    if ( INVALID_SOCKET != sock ) 
    { 
	closesocket ( sock ); 
    } 
 
    if ( TRUE == fStarted ) 
    { 
	WSACleanup ( ); 
    } 
 
    fprintf ( stdout, "DONE\n" ); 
 
    return; 
}