singrdk/base/Windows/gulpserver/gulpserver.c

342 lines
9.6 KiB
C

/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#include "winlean.h"
#include "winsock2.h"
#include <stdlib.h>
#include <stdio.h>
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024
#define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s))
#define xfree(p) HeapFree (GetProcessHeap(), 0, (p))
/*
* This event is set when a control socket is closed before the end of a test.
* If the user kills the manager script then its end of the control socket will
* be closed. We catch that and use this event to notify any worker threads
* associated with that control socket to stop what they're doing.
*/
_declspec (thread) void * MC_MyCS_StopEvent;
/* print an error message and exit the program */
void die (char *format,...) {
va_list args;
char buffer[2048], *ptr=buffer;
va_start(args,format);
ptr += vsprintf (ptr, format, args);
va_end (args);
*(ptr++) = '\n';
*(ptr++) = '\0';
printf( buffer);
exit(1);
}
int InitChildLayer(void) {
WORD wVersionRequested;
WSADATA wsaData;
int err;
int major, minor;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we couldn't find a useable */
/* WinSock DLL. */
die ("Couldn't find a WinSock DLL!\n");
}
/* Confirm that the WinSock DLL supports 2.0. */
/* Note that if the DLL supports versions greater */
/* than 2.0 in addition to 2.0, it will still return */
/* 2.0 in wVersion since that is the version we */
/* requested. */
major = LOBYTE( wsaData.wVersion );
minor = LOBYTE( wsaData.wVersion );
if ( major < 1 || ( major == 1 && minor < 1 ) ) {
/* Tell the user that we couldn't find a useable */
/* WinSock DLL. */
WSACleanup( );
die ("Require at least WinSock 1.1, your version is %d.%d!\n",
major, minor);
}
return 0;
}
static USHORT
checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
cksum += *(UCHAR*)buffer; /* if there's an odd number of bytes */
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
/*
* MC_GetLastErrorText
*
* PURPOSE: copies error message text to string
*
* PARAMETERS:
* lpszBuf - destination buffer
* dwSize - size of buffer
*
* RETURN VALUE:
* destination buffer
*/
LPSTR
MC_GetLastErrorText(LPSTR lpszBuf, DWORD dwSize, DWORD errnum)
{
DWORD dwRet;
LPTSTR lpszTemp = NULL;
dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpszTemp,
0,
NULL );
if ( !dwRet)
sprintf(lpszBuf, "error number %d", errnum); /* no message so use errnum */
else
{
lpszTemp[lstrlen(lpszTemp)-2] = '\0'; /* remove cr and newline characters */
sprintf(lpszBuf, "%s (0x%x)", lpszTemp, errnum);
}
if (lpszTemp)
LocalFree((HLOCAL) lpszTemp );
return lpszBuf;
}
static void
MC_ErrMsg(LPSTR buf, DWORD bufsize, LPCSTR msg)
{
DWORD tmp;
tmp = strlen(strcpy(buf, msg));
MC_GetLastErrorText(buf + tmp, bufsize - tmp, WSAGetLastError());
}
/*
* FUNCTION: MC_Recv
*
* PURPOSE: A replacement for the Winsock recv() routine. This version uses
* overlapped I/O to look for data on a socket and also watch
* for the Stop event.
*
* PARAMETERS:
* sock - read from this socket.
* buffer - place incoming data into this buffer.
* nbytes - the amount of storage in the buffer.
*
* RETURN VALUE:
* -1 - error.
* 0 - the socket connection has been closed.
* >0 - the number of bytes read.
*/
int
MC_Recv(SOCKET sock, char *buffer, int nbytes)
{
DWORD bytesreceived;
DWORD flags = 0;
WSAOVERLAPPED ov;
WSABUF wsabuffer[1];
HANDLE ourevents[2];
ov.hEvent = NULL;
ov.Offset = ov.OffsetHigh = 0;
wsabuffer[0].buf = buffer;
wsabuffer[0].len = nbytes;
while(1)
{
if (WSARecv(sock, wsabuffer, 1, &bytesreceived, &flags, &ov, NULL) == SOCKET_ERROR)
{
switch (WSAGetLastError())
{
case WSAEWOULDBLOCK: continue; /* try again */
case WSAENETRESET:
case WSAECONNRESET:
case WSAEDISCON: return 0; /* connection closed */
//case WSA_IO_PENDING: break; /* okay */
default: return -1; /* unexpected error */
}
ourevents[0] = (HANDLE) sock;
ourevents[1] = MC_MyCS_StopEvent;
if (WaitForMultipleObjects(2, ourevents, FALSE, INFINITE) != WAIT_OBJECT_0)
{
printf("MC_Recv(): Stop event or WaitForMultipleObjects() error\n");
return -1; /* Stop event or error */
}
else if (!WSAGetOverlappedResult(sock, &ov, &bytesreceived, FALSE, &flags))
return -1; /* error */
}
return bytesreceived; /* if we got here its due to a successful read */
}
}
static DWORD WINAPI Gulp(LPVOID lpParam )
{
int totalBytes;
int numPackets;
int bytesRead;
char buffer[4096];
SOCKET sockfd;
INT64 startCounter, endCounter, frequency;
totalBytes = 0;
numPackets = 0;
sockfd = *(SOCKET *) lpParam;
QueryPerformanceCounter((PLARGE_INTEGER)&startCounter);
do {
bytesRead = MC_Recv(sockfd, buffer, 4096);
if (bytesRead > 0 ) {
numPackets++;
totalBytes += bytesRead;
}
} while (bytesRead > 0) ;
QueryPerformanceCounter((PLARGE_INTEGER)&endCounter);
QueryPerformanceFrequency((PLARGE_INTEGER)&frequency);
printf(" Read %d bytes / %d KB / %d MB in %d receives\n",
totalBytes, totalBytes / 1024, totalBytes / 1048576, numPackets);
if (endCounter != startCounter) {
double tau = (double)(endCounter - startCounter) / (double)frequency;
double bps = totalBytes * 8.0 / tau;
printf("Transferred in %.3e seconds => %.3e bps\n",
tau, bps);
}
else {
printf("Transfer too quick to measure with this clock\n");
}
return 1;
}
static DWORD listener (int port, LPSTR retmsg, DWORD size_retmsg)
{
struct sockaddr_in sock_addr;
DWORD tmp;
int server_status = 0;
int ret_count = 0;
SOCKET listenSockfd;
SOCKET sockfd;
HANDLE hThread;
DWORD dwThreadId;
memset((void *) &sock_addr, '\0', sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.S_un.S_addr = INADDR_ANY;
sock_addr.sin_port = htons((short) (port > 0 ? port : 80));
if ((listenSockfd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET)
{
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to create socket: ");
printf(retmsg);
return -1;
}
if ((listenSockfd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET)
{
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to create socket: ");
printf(retmsg);
return -1;
}
tmp = bind(listenSockfd, (struct sockaddr *) &sock_addr, sizeof(sock_addr));
if (tmp == SOCKET_ERROR)
{
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to bind to socket: ");
printf(retmsg);
return -1;
}
tmp = listen( listenSockfd,10);
if (tmp == SOCKET_ERROR)
{
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to listen on socket: ");
printf(retmsg);
return -1;
}
do {
printf("\n listening\n");
sockfd = accept(listenSockfd,0,0);
if (sockfd == SOCKET_ERROR)
{
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to accept on socket: ");
printf(retmsg);
return -1;
}
printf(" ...Accepted connection\n");
hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
Gulp, // thread function
&sockfd, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// Check the return value for success.
if (hThread == NULL)
{
printf("CreateThread failed." );
}
else
{
CloseHandle( hThread );
}
} while (TRUE);
}
int main(int argc, char *argv[]) {
char retmsg[1024];
int foo;
if (argc < 2 ) {
printf("gulpserver port\n");
printf(" listens on port for TCP blast client \n");
return -1;
}
foo = atoi(argv[1]);
InitChildLayer();
printf (" Listening on port %d ...",foo);
listener(foo, retmsg, 1024);
WSACleanup( );
}