// broadcasting.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int main(int argc, char* argv[])
{
	return 0;
}





















***************************
/******************************************************************************\
*       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
    )
{

    //
    // Install the CTRL+BREAK Handler
    //
    if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler,
					  TRUE 
					  ) ) 
    {
	PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) );
    }  
  
    //
    // Initialize the global socket descriptor.
    //
    sock = socket ( AF_INET, SOCK_DGRAM, 0 );

    if ( INVALID_SOCKET ==  sock)
    {
	PrintError ( "DoUdp", "socket", WSAGetLastError() );
    }
    
    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;
}
