/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 1998 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;
}