2025-11-28 00:35:46 +09:00

347 lines
12 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
// Module:
// atmevent.cpp
//
// Abstract:
// This application demonstrates a very simple-minded Winsock application
// that uses the native ATM Winsock 2 service provider. The specific
// ATM protocol addressing demonstrated by this application is AAL5. This
// application makes no attempt to do anything useful per se, but concentrates
// how setting up a connection using AAL5 and sending some data. Additionally,
// this application demonstrates several Winsock2-specific APIs and techniques
// that are useful whether or not your main interest is ATM or not.
//
// Commandline parameters determine whether this application functions as
// either a sender (-n), a receiver (-i), or simply allows ATM interfaces to
// be enumerated. When specifying the ATM interface to bind to (on the receiver)
// or the remote ATM interface to connect to on the sender the interface
// is a 40 character NSAP address, with the last 2 hex digits (0 - 255 decimal)
// representing the port. The commandline switch (-a) can be used to enumerate
// all ATM interface on the local machine - note the last 2 digits will be 00.
//
// Use the -? commandline switch to determine available options.
//
// This application simply sends a buffer of data when acting as the sender,
// to an instance of itself acting as a receiver. Any number of senders (up
// to MAXCLIENTS) can be started to interact with one instance of a receiver.
// The size of the data buffer (-b), its contents (-d), and the number of
// times to send (-l) this buffer are controllable via commandline switches.
// A repeat value of 0 implies continuous sending. A delay
// commandline switch (-s:#), measured in milliseconds can be specified for the
// sender to insure the total transfer spans a measured unit of time. Additionally,
// the commandline switch (-s2:#) is available to delay closing the connection,
// measured in milliseconds, to allow the receiver time to pick up the data. This
// is important because neither AAL5 nor this application has any handshake
// mechanism to determine when the receiver has received all the data - AAL5
// does not support a graceful connection closure.
//
// Entry Points:
// main - this is where it all starts
//
// Usage:
// Enumerate ATM interfaces
// atmevent -a
// Act as a sender and send buffer 10 times
// and wait 2 seconds before closing the connection
// atmevent -n:receiver_atm_interface -l:10 -c:2000
// Act as a receiver
// atmevent -i:local_atm_interface
//
// Build:
// Use the headers and libs from the May99 Platform SDK or later.
// Link with ws2_32.lib
//
//
#define ATMEVENT_MAIN
#include "atmevent.h"
static BOOL ValidOptions(int argc, char **argv, OPTIONS *pOptions);
static VOID PrintOptions(OPTIONS *pOptions);
static VOID Usage(CHAR *szProgramname, OPTIONS *pOptions);
static BOOL FindATMServiceProvider(WSAPROTOCOL_INFO *pProtocolInfo);
int __cdecl main(int argc, char **argv)
{
int n = 0;
OPTIONS options;
WSADATA WSAData;
if (!ValidOptions(argc, argv, &options))
return 1;
if (0 != (n = WSAStartup(MAKEWORD(2,2), &WSAData)))
{
printf("WSAStartup failed w/%d\n", n);
return 1;
}
if (!FindATMServiceProvider(&options.protocolInfo))
{
printf("No matching service provider found\n");
} else
{
PrintOptions(&options);
if (CMD_RECEIVER == options.cmd)
Receiver(&options);
else if (CMD_SENDER == options.cmd)
Sender(&options);
else // enumerate ATM interfaces
Enumerator(&options);
}
if (options.buf) Free(options.buf);
WSACleanup();
return 0;
}
// Abstract:
// Verify options passed in and set options structure accordingly.
//
BOOL ValidOptions(int argc, char **argv, OPTIONS *pOptions)
{
OPTIONS default_options;
HRESULT hRet;
size_t dwSize;
pOptions->buf = NULL;
pOptions->cmd = CMD_RECEIVER;
pOptions->dwSleep = 0;
pOptions->dwSleepClose = 1000;
pOptions->dwTotalClients = 0;
pOptions->fillchar = 'c';
pOptions->nBufSize = 4096;
pOptions->nRepeat = 1;
pOptions->szLocalInterface[0] = '\0';
pOptions->szRemoteInterface[0] = '\0';
ZeroMemory(&pOptions->protocolInfo, sizeof(pOptions->protocolInfo));
default_options = *pOptions;
for (int i=1; i<argc; i++)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/') )
{
switch (tolower(argv[i][1]))
{
case 'a' :
pOptions->cmd = CMD_ENUMERATOR;
break;
case 'b' :
if (strlen(argv[i]) > 3)
pOptions->nBufSize = 1024*atoi(&argv[i][3]);
break;
case 'c' :
if (strlen(argv[i]) > 3)
pOptions->dwSleepClose = atoi(&argv[i][3]);
break;
case 'd' :
if (strlen(argv[i]) > 3)
pOptions->fillchar = argv[i][3];
break;
case 'i' :
pOptions->cmd = CMD_RECEIVER;
if (strlen(argv[i]) > 3)
{
hRet = StringCbLength(&argv[i][3],sizeof(pOptions->szLocalInterface),&dwSize);
hRet = StringCbCopyN(pOptions->szLocalInterface,sizeof(pOptions->szLocalInterface),&argv[i][3],dwSize);
}
break;
case 'l' :
if (strlen(argv[i]) > 3)
pOptions->nRepeat = atoi(&argv[i][3]);
break;
case 'n' :
pOptions->cmd = CMD_SENDER;
if (strlen(argv[i]) > 3)
{
hRet = StringCbLength(&argv[i][3],sizeof(pOptions->szRemoteInterface),&dwSize);
hRet = StringCbCopyN(pOptions->szRemoteInterface,sizeof(pOptions->szRemoteInterface),&argv[i][3],dwSize);
}
break;
case 's' :
if (strlen(argv[i]) > 3)
pOptions->dwSleep = atoi(&argv[i][3]);
break;
case '?' :
Usage(argv[0], &default_options);
return FALSE;
break;
default:
printf(" unknown options flag %s\n", argv[i]);
Usage(argv[0], &default_options);
return FALSE;
break;
}
} else
{
printf(" unknown option %s\n", argv[i]);
Usage(argv[0], &default_options);
return FALSE;
}
}
if (CMD_RECEIVER == pOptions->cmd)
pOptions->fillchar = 0;
pOptions->buf = (char*)Malloc(pOptions->nBufSize);
if (!pOptions->buf)
return FALSE;
else
{
FillMemory(pOptions->buf, pOptions->nBufSize, pOptions->fillchar);
return TRUE;
}
}
// Abstract:
// Just print the options to be used for this run.
//
static VOID PrintOptions(OPTIONS *pOptions)
{
printf("Options\n");
if (CMD_ENUMERATOR == pOptions->cmd)
printf(" Enumerate ATM interfaces\n");
else if (CMD_RECEIVER == pOptions->cmd)
printf(" Act as Receiver and bind to local interface <%s>\n",
pOptions->szLocalInterface);
else
{
printf(" Act as sender and send to remote interface <%s>\n", pOptions->szRemoteInterface);
printf(" Sleep %d milliseconds between sends\n", pOptions->dwSleep);
printf(" Fill buffer with <%c>\n", pOptions->fillchar);
if (pOptions->nRepeat)
printf(" Repeat sending the buffer %d times\n", pOptions->nRepeat);
else
printf(" Repeat sending the buffer continually\n");
}
printf(" Bufsize %d (bytes)\n", pOptions->nBufSize);
printf("\n");
return;
}
// Abstract:
// Print out usage table for the program
//
VOID Usage(CHAR *szProgramname, OPTIONS *pOptions)
{
printf("usage:\n %s -?\n\n", szProgramname);
printf(" %s [-a | -i:interface | -n:interface] [-b:#] [-d:c] [-l:#] [-s:#]\n\n",
szProgramname);
printf(" -?\t\tDisplay this help\n");
printf("\n");
printf(" -a\t\tPrint out all ATM interfaces on this machine\n");
printf(" -i:interface\tAct as receiver and bind to interface\n");
printf(" -n:interface\tAct as sender and connect to remote interface\n");
printf("\n");
printf(" -b:bufsize\tSize of send/recv buffer; in 1K increments (Def:%d)\n",
pOptions->nBufSize);
printf(" -c:#\t\tSleep # milliseconds before closing socket (def: 2000)\n");
printf(" -d:c\t\tCharacter used to fill buffer (Def:%c)\n",
pOptions->fillchar);
printf(" -l:loop\tLoop count for sending buffer (Def:continuous)\n");
printf(" -s:#\t\tSleep # milliseconds between sends (def: 0)\n");
printf("\n");
return;
}
// Abstract:
// Look for an ATM service provider.
//
// Notice that actual service provider names are different on NT and Win9x
// when searching for a service provider, you should not use the service provider
// name, but instead use the various flags in the protocol structure.
//
BOOL FindATMServiceProvider(
WSAPROTOCOL_INFO *pProtocolInfo
)
{
int nRet = 0;
WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
DWORD dwBufLen = 0;
DWORD dwErr = 0;
BOOL bProtocolFound = FALSE;
// first have WSAEnumProtocols tell us how big a buffer is needed
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
if (SOCKET_ERROR != nRet)
{
printf("WSAEnumProtocols: should not have suceeded\n");
} else if (WSAENOBUFS != (dwErr = WSAGetLastError()))
{
// WSAEnumProtocols failed for some reason not relating to buffer size
printf("WSAEnumProtocols(1): %d\n", WSAGetLastError());
} else
{
// WSAEnumProtocols failed for the "expected" reason, allocate a buffer
// of the needed size
lpProtocolBuf = (WSAPROTOCOL_INFO *)Malloc(dwBufLen);
if (lpProtocolBuf)
{
// now we can call WSAEnumProtocols again with the expectation it will
// succeed because we have allocated a big enough buffer.
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
if (SOCKET_ERROR == nRet)
{
printf("WSAEnumProtocols(3): %d\n", WSAGetLastError());
} else
{
// loop thru protocols, looking for a matching service provider
for (int i=0; i<nRet; i++)
{
printf(" sp <%s>\n", lpProtocolBuf[i].szProtocol);
if (AF_ATM == lpProtocolBuf[i].iAddressFamily &&
ATMPROTO_AAL5 == lpProtocolBuf[i].iProtocol &&
SOCK_RAW == lpProtocolBuf[i].iSocketType)
{
*pProtocolInfo = lpProtocolBuf[i];
bProtocolFound = TRUE;
break;
}
}
}
if (lpProtocolBuf) Free(lpProtocolBuf);
}
}
if (bProtocolFound)
printf(" Using service provider <%s>\n\n", pProtocolInfo->szProtocol);
return bProtocolFound;
}