version 1.30, 2005/02/25 06:39:52
|
version 1.31, 2005/02/25 06:47:29
|
|
|
} | } |
#endif | #endif |
| |
// clients threads to create |
/* clients threads to create */ |
#define NUM_CLIENTS 64 | #define NUM_CLIENTS 64 |
| |
// amount of data to transfer from each client to server |
/* amount of data to transfer from each client to server */ |
#define TEST_DATA_SIZE 145243 | #define TEST_DATA_SIZE 145243 |
| |
// max time (seconds) to run test. |
/* max time (seconds) to run test. |
// On a 650 Mhz Linux system with tcpdump running, it takes 8 seconds. |
On a 650 Mhz Linux system with tcpdump running, it takes 8 seconds. */ |
#define TEST_TIMEOUT 20 | #define TEST_TIMEOUT 20 |
| |
// we often pass this size by reference |
/* we often pass this size by reference */ |
int sizeofSOCKADDR_IN = sizeof(SOCKADDR_IN); | int sizeofSOCKADDR_IN = sizeof(SOCKADDR_IN); |
| |
// global test data; server sends it to client, then client verifies it |
/* global test data; server sends it to client, then client verifies it */ |
char *gTestData; | char *gTestData; |
| |
struct ThreadInfo { | struct ThreadInfo { |
|
|
| |
struct BlockingServerConnection { | struct BlockingServerConnection { |
struct ThreadInfo serverThread; | struct ThreadInfo serverThread; |
SOCKET connectedSocket; // socket to communicate with client |
SOCKET connectedSocket; /* socket to communicate with client */ |
SOCKADDR_IN clientAddr; // client info |
SOCKADDR_IN clientAddr; /* client info */ |
}; | }; |
| |
static void test_Startup(void); | static void test_Startup(void); |
|
|
int memSame; | int memSame; |
char buf[1001]; | char buf[1001]; |
| |
// create socket |
/* create socket */ |
sock = socket(AF_INET, SOCK_STREAM, 0); | sock = socket(AF_INET, SOCK_STREAM, 0); |
ok( sock != INVALID_SOCKET , "Error in socket()\n"); | ok( sock != INVALID_SOCKET , "Error in socket()\n"); |
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { |
|
|
server.sin_addr = *(struct in_addr *) hp->h_addr; | server.sin_addr = *(struct in_addr *) hp->h_addr; |
server.sin_port = *serverPort; | server.sin_port = *serverPort; |
| |
// connect to server |
/* connect to server */ |
connectError = connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)); | connectError = connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)); |
ok( !connectError , "client cannot connect to host\n"); | ok( !connectError , "client cannot connect to host\n"); |
if(connectError) { | if(connectError) { |
|
|
exit(0); | exit(0); |
} | } |
| |
// start receiving data from server |
/* start receiving data from server */ |
while( totCharsReceived < TEST_DATA_SIZE ) { | while( totCharsReceived < TEST_DATA_SIZE ) { |
numCharsReceived = recv(sock, buf, 1000, 0); | numCharsReceived = recv(sock, buf, 1000, 0); |
ok( numCharsReceived > 0, "socket was closed unexpectedly\n" ); | ok( numCharsReceived > 0, "socket was closed unexpectedly\n" ); |
| |
// check received data againt global test data |
/* check received data againt global test data */ |
memSame = ! memcmp(buf,gTestData+totCharsReceived,numCharsReceived); | memSame = ! memcmp(buf,gTestData+totCharsReceived,numCharsReceived); |
ok( memSame, "data integrity lost during transfer\n" ); | ok( memSame, "data integrity lost during transfer\n" ); |
totCharsReceived += numCharsReceived; | totCharsReceived += numCharsReceived; |
|
|
| |
static int BlockingServer_Init(int type, SOCKET *sock, SOCKADDR_IN *addr) | static int BlockingServer_Init(int type, SOCKET *sock, SOCKADDR_IN *addr) |
{ | { |
// BlockingServer_Init creates socket sock of type type and returns assigned port number in addr. |
/* BlockingServer_Init creates socket sock of type type and returns assigned port number in addr. |
// returns server port number |
returns server port number */ |
| |
SOCKADDR_IN tmpAddr; | SOCKADDR_IN tmpAddr; |
int bindOK; | int bindOK; |
int listenReturn; | int listenReturn; |
| |
// create socket |
/* create socket */ |
*sock = socket(AF_INET, type, 0); | *sock = socket(AF_INET, type, 0); |
ok( *sock != INVALID_SOCKET , "Error in socket()\n"); | ok( *sock != INVALID_SOCKET , "Error in socket()\n"); |
if (*sock == INVALID_SOCKET) { | if (*sock == INVALID_SOCKET) { |
|
|
addr->sin_addr.s_addr = INADDR_ANY; | addr->sin_addr.s_addr = INADDR_ANY; |
addr->sin_port = htons(0); | addr->sin_port = htons(0); |
| |
// bind socket to port |
/* bind socket to port */ |
bindOK = !bind(*sock, (const SOCKADDR *) addr, sizeofSOCKADDR_IN); | bindOK = !bind(*sock, (const SOCKADDR *) addr, sizeofSOCKADDR_IN); |
ok( bindOK , "Error binding client to socket\n"); | ok( bindOK , "Error binding client to socket\n"); |
if( !bindOK ) { | if( !bindOK ) { |
|
|
exit(0); | exit(0); |
} | } |
| |
// get port number |
/* get port number */ |
getsockname(*sock, (SOCKADDR *) &tmpAddr, &sizeofSOCKADDR_IN); | getsockname(*sock, (SOCKADDR *) &tmpAddr, &sizeofSOCKADDR_IN); |
addr->sin_port = tmpAddr.sin_port; | addr->sin_port = tmpAddr.sin_port; |
| |
// listen on port |
/* listen on port */ |
listenReturn = listen(*sock, NUM_CLIENTS); | listenReturn = listen(*sock, NUM_CLIENTS); |
ok(listenReturn != SOCKET_ERROR, "error listening on socket\n"); | ok(listenReturn != SOCKET_ERROR, "error listening on socket\n"); |
| |
return addr->sin_port; | return addr->sin_port; |
} | } |
| |
static void BlockingServer(SOCKET *sock) // listens for incoming connections and accepts up to NUM_CLIENTS connections at once |
static void BlockingServer(SOCKET *sock) |
{ | { |
|
/* listens for incoming connections and accepts up to NUM_CLIENTS connections at once */ |
struct BlockingServerConnection *connections[NUM_CLIENTS]; | struct BlockingServerConnection *connections[NUM_CLIENTS]; |
int connIndex = 0; | int connIndex = 0; |
SOCKET tmpSock; | SOCKET tmpSock; |
SOCKADDR_IN tmpSockAddr; | SOCKADDR_IN tmpSockAddr; |
| |
// we require one connection from each client thread |
/* we require one connection from each client thread */ |
for (connIndex = 0; connIndex < NUM_CLIENTS; connIndex++) { | for (connIndex = 0; connIndex < NUM_CLIENTS; connIndex++) { |
// accept connection |
/* accept connection */ |
tmpSock = accept(*sock, (SOCKADDR *) &tmpSockAddr, &sizeofSOCKADDR_IN); | tmpSock = accept(*sock, (SOCKADDR *) &tmpSockAddr, &sizeofSOCKADDR_IN); |
ok(tmpSock != INVALID_SOCKET, "error accepting socket\n"); | ok(tmpSock != INVALID_SOCKET, "error accepting socket\n"); |
| |
// handle new connection |
/* handle new connection */ |
connections[connIndex] = BlockingServerConnection_New(tmpSock, tmpSockAddr); | connections[connIndex] = BlockingServerConnection_New(tmpSock, tmpSockAddr); |
} | } |
| |
// clean up connections |
/* clean up connections */ |
for(connIndex = 0; connIndex < NUM_CLIENTS; connIndex++) { | for(connIndex = 0; connIndex < NUM_CLIENTS; connIndex++) { |
BlockingServerConnection_Delete(connections[connIndex]); | BlockingServerConnection_Delete(connections[connIndex]); |
} | } |
|
|
connection->connectedSocket = sock; | connection->connectedSocket = sock; |
connection->clientAddr = clientAddr; | connection->clientAddr = clientAddr; |
| |
// spawn thread to handle sending data |
/* spawn thread to handle sending data */ |
connection->serverThread.Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &BlockingServerConnection_Run, connection, 0, &connection->serverThread.ID); | connection->serverThread.Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &BlockingServerConnection_Run, connection, 0, &connection->serverThread.ID); |
| |
return connection; | return connection; |
|
|
| |
static void BlockingServerConnection_Run(struct BlockingServerConnection *connection) | static void BlockingServerConnection_Run(struct BlockingServerConnection *connection) |
{ | { |
// this will handle all connections to the server, it's in its own function to allow for multithreading |
/* BlockingServerConnection_Run handles data transfer */ |
int bClosed; | int bClosed; |
int totCharsSent = 0; | int totCharsSent = 0; |
int numCharsSent; | int numCharsSent; |
const int charsPerSend = 2000; | const int charsPerSend = 2000; |
| |
// loop and send data |
/* loop and send data */ |
while( totCharsSent < TEST_DATA_SIZE ) { | while( totCharsSent < TEST_DATA_SIZE ) { |
numCharsSent = send(connection->connectedSocket, gTestData+totCharsSent, (totCharsSent + charsPerSend <= TEST_DATA_SIZE) ? charsPerSend : TEST_DATA_SIZE - totCharsSent, 0); | numCharsSent = send(connection->connectedSocket, gTestData+totCharsSent, (totCharsSent + charsPerSend <= TEST_DATA_SIZE) ? charsPerSend : TEST_DATA_SIZE - totCharsSent, 0); |
ok( numCharsSent != SOCKET_ERROR, "socket error\n" ); | ok( numCharsSent != SOCKET_ERROR, "socket error\n" ); |
| |
// pass if send buffer is full |
/* pass if send buffer is full */ |
if(numCharsSent == 0) { | if(numCharsSent == 0) { |
Sleep(100); | Sleep(100); |
} | } |
|
|
| |
static void BlockingServerConnection_Delete(struct BlockingServerConnection *c) | static void BlockingServerConnection_Delete(struct BlockingServerConnection *c) |
{ | { |
// wait for client to receive data before cleaning up |
/* wait for client to receive data before cleaning up */ |
WaitForSingleObject(c->serverThread.Handle, INFINITE); | WaitForSingleObject(c->serverThread.Handle, INFINITE); |
| |
free(c); | free(c); |
|
|
int serverPort; | int serverPort; |
int threadIndex = 0; | int threadIndex = 0; |
| |
// create socket, bind server and start listening |
/* create socket, bind server and start listening */ |
serverPort = BlockingServer_Init(SOCK_STREAM, &sock, &server); | serverPort = BlockingServer_Init(SOCK_STREAM, &sock, &server); |
| |
// start server thread |
/* start server thread */ |
trace("starting server thread\n"); | trace("starting server thread\n"); |
serverThread.Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &BlockingServer, &sock, 0, &serverThread.ID); | serverThread.Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &BlockingServer, &sock, 0, &serverThread.ID); |
| |
// start client threads |
/* start client threads */ |
clientThreads = malloc(sizeof(struct ThreadInfo) * NUM_CLIENTS); | clientThreads = malloc(sizeof(struct ThreadInfo) * NUM_CLIENTS); |
memset(clientThreads, 0, sizeof(struct ThreadInfo) * NUM_CLIENTS); | memset(clientThreads, 0, sizeof(struct ThreadInfo) * NUM_CLIENTS); |
| |
|
|
} | } |
trace("%d clients started\n", NUM_CLIENTS); | trace("%d clients started\n", NUM_CLIENTS); |
| |
// server thread needs to end before cleaning up |
/* server thread needs to end before cleaning up */ |
waitStatus = WaitForSingleObject(serverThread.Handle, TEST_TIMEOUT * 1000); | waitStatus = WaitForSingleObject(serverThread.Handle, TEST_TIMEOUT * 1000); |
ok( waitStatus != WAIT_TIMEOUT, "test did not complete in time\n" ); | ok( waitStatus != WAIT_TIMEOUT, "test did not complete in time\n" ); |
| |
// wait for all clients to receive data before cleaning up |
/* wait for all clients to receive data before cleaning up */ |
for(threadIndex = 0; threadIndex < NUM_CLIENTS; threadIndex++) { | for(threadIndex = 0; threadIndex < NUM_CLIENTS; threadIndex++) { |
WaitForSingleObject(clientThreads[threadIndex].Handle, INFINITE); | WaitForSingleObject(clientThreads[threadIndex].Handle, INFINITE); |
} | } |
|
|
| |
static void test_Startup(void) | static void test_Startup(void) |
{ | { |
// initialize application |
/* initialize application */ |
WSADATA wsaData; | WSADATA wsaData; |
int wsastartup_result; | int wsastartup_result; |
int versionOK; | int versionOK; |
| |
// check for compatible winsock version |
/* check for compatible winsock version */ |
wsastartup_result = WSAStartup(MAKEWORD(1,1), &wsaData); | wsastartup_result = WSAStartup(MAKEWORD(1,1), &wsaData); |
versionOK = (LOBYTE(wsaData.wVersion) == 1) && (HIBYTE(wsaData.wVersion) == 1); | versionOK = (LOBYTE(wsaData.wVersion) == 1) && (HIBYTE(wsaData.wVersion) == 1); |
| |