singrdk/base/Windows/gulp/gulp.c

422 lines
12 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))
_declspec (thread) void * MC_MyCS_StopEvent;
typedef struct args {
LPTSTR host;
int port;
} thread_args_t, *pthread_args_t;
static HANDLE endThreadEvent;
static HANDLE threadCountMutex;
static int doneThreads;
static int numThreads;
static int iterationCount;
static int g_totalBytesRead;
/*
* 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 (%d)", lpszTemp, errnum);
sprintf(lpszBuf, " error %d\n", 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, 10000) != 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 Gulp(SOCKET sockfd )
{
int totalBytes;
int numPackets;
int bytesRead;
char buffer[4096];
totalBytes = 0;
numPackets = 0;
do {
bytesRead = MC_Recv(sockfd, buffer, 4096);
if (bytesRead > 0 ) {
numPackets++;
totalBytes += bytesRead;
}
} while (bytesRead > 0) ;
//printf(" Read %d bytes in %d receives\n", totalBytes, numPackets);
return totalBytes;
}
static DWORD WINAPI
MC_DoFetchUrl(LPVOID lpParam)
{
struct hostent *hostelement;
struct sockaddr_in sock_addr;
DWORD tmp;
int server_status = 0;
int ret_count = 0;
SOCKET sockfd;
pthread_args_t args;
char retmsg[1024];
int size_retmsg;
int i;
struct linger lo;
int bytesRead;
args = (pthread_args_t) lpParam;
size_retmsg = 1024;
bytesRead = 0;
for (i=0; i < iterationCount; i++) {
memset((void *) &sock_addr, '\0', sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons((short) (args->port > 0 ? args->port : 80));
if ((sockfd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) {
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to create socket: ");
printf(retmsg);
//break;
}
if ((hostelement = gethostbyname(args->host)) == NULL) {
tmp = sprintf(retmsg, "Unable to resolve host name '%s':", args->host);
MC_GetLastErrorText(retmsg + tmp, size_retmsg - tmp, WSAGetLastError());
printf(retmsg);
break;
}
memcpy(&sock_addr.sin_addr, hostelement->h_addr, hostelement->h_length);
tmp = connect(sockfd, (struct sockaddr *) &sock_addr, sizeof(sock_addr));
if (tmp == SOCKET_ERROR) {
MC_ErrMsg(retmsg, size_retmsg, "500 Unable to connect to web server: ");
printf(retmsg);
//break;
}
lo.l_onoff = 1;
lo.l_linger = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
(char *) &lo, sizeof(lo)) < 0) {
printf("HTDoConnect: Can't set sockopt SO_LINGER (%d)\n", errno);
break;
}
bytesRead += Gulp(sockfd);
shutdown(sockfd, SD_BOTH);
closesocket(sockfd);
}
WaitForSingleObject(threadCountMutex,INFINITE);
g_totalBytesRead += bytesRead;
doneThreads++;
printf("Thread ending..count=%d\n",doneThreads);
SetEvent(endThreadEvent);
ReleaseMutex(threadCountMutex);
return 1;
}
/* 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;
}
void Usage()
{
printf(
"Usage:\n"
" gulp [options] \n"
"Options:\n"
" /p:N -- Port to connect to (default=5000)\n"
" /a:nnn.nnn.nnn -- address to connect to\n"
" /i:N -- number of iterations\n"
);
}
int main(int argc, char *argv[]) {
int arg;
pthread_args_t blee;
BOOL fNeedHelp = FALSE;
char *argn;
char *argp;
char *address;
DWORD dwPort;
BOOL bHaveAddress;
LARGE_INTEGER before;
LARGE_INTEGER after;
LARGE_INTEGER frequency;
double elapsed;
double rate;
double MBS;
double mbs;
int i;
DWORD dwThreadId;
HANDLE hThread;
InitChildLayer();
endThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
threadCountMutex = CreateMutex(NULL,FALSE,NULL);
doneThreads = 0;
if (endThreadEvent == NULL) {
printf("Unable to allocate event!\n");
exit(1);
}
numThreads = 1;
dwPort = 5000;
iterationCount = 10;
fNeedHelp = FALSE;
bHaveAddress = FALSE;
for (arg = 1; arg < argc && !fNeedHelp; arg++) {
if (argv[arg][0] == '-' || argv[arg][0] == '/') {
argn = argv[arg]+1; // Argument name
argp = argn; // Argument parameter
while (*argp && *argp != ':') {
argp++;
}
if (*argp == ':')
*argp++ = '\0';
switch (argn[0]) {
case '?': // Help
fNeedHelp = TRUE;
break;
case 'a': // address to connect to
case 'A':
address = argp;
printf("Address = '%s'\n", argp);
bHaveAddress = TRUE;
break;
case 'i': // iterations within thread
case 'I':
iterationCount = atoi(argp);
break;
case 'p': // port to attach to
case 'P':
dwPort = (DWORD)atoi(argp);
break;
case 't': // Number of threads to start
case 'T':
numThreads = atoi(argp);
break;
default:
printf("Unknown argument: %s\n", argv[arg]);
fNeedHelp = TRUE;
break;
}
}
else {
}
}
if (fNeedHelp | !bHaveAddress) {
Usage();
exit(1);
}
printf ("Connecting to %s on port %d. threads=%d iterations=%d..", address, dwPort, numThreads, iterationCount);
blee = malloc(sizeof(pthread_args_t));
blee->host = address;
blee->port = dwPort;
#if 1
for (i=0; i < numThreads; i++) {
hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
MC_DoFetchUrl, // thread function
blee, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
}
//for (i=0; i < numThreads; i++) {
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&before);
while(doneThreads != numThreads ) {
WaitForSingleObject(endThreadEvent,INFINITE);
printf ("received %d of %d events, done=%d\n", i+1, numThreads, doneThreads);
}
QueryPerformanceCounter(&after);
after.QuadPart -= before.QuadPart;
elapsed = (double)after.QuadPart / (double)frequency.QuadPart;
rate = (double) g_totalBytesRead / elapsed;
printf("bytes read =%d, time elapsed = %10.3f seconds rate = %10.3f \n", g_totalBytesRead, elapsed, rate);
MBS = rate / (double) (1024 *1024);
mbs = MBS * 8;
printf("MB/s = %10.3f, mb/s = %10.3f\n", MBS, mbs);
#else
MC_DoFetchUrl(blee);
#endif
WSACleanup( );
}