version 1.30, 2005/02/25 06:39:52
|
version 1.33, 2005/03/01 04:26:32
|
|
|
} | } |
#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 145244 |
| |
// 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 |
/* global test data; server sends it to client, then client verifies it */ |
int sizeofSOCKADDR_IN = sizeof(SOCKADDR_IN); |
|
|
|
// 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 server port number |
returns assigned port number in addr. */ |
| |
SOCKADDR_IN tmpAddr; | SOCKADDR_IN tmpAddr; |
int bindOK; | int bindOK; |
int listenReturn; | int listenReturn; |
|
int sizeofSOCKADDR_IN = sizeof(SOCKADDR_IN); |
| |
// 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, sizeof(SOCKADDR_IN)); |
ok( bindOK , "Error binding client to socket\n"); | ok( bindOK , "Error binding client to socket\n"); |
if( !bindOK ) { | if( !bindOK ) { |
WSACleanup(); | WSACleanup(); |
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; |
|
int sizeofSOCKADDR_IN = sizeof(SOCKADDR_IN); |
| |
// 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; |
|
int charsToSend; |
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); |
if (totCharsSent + charsPerSend <= TEST_DATA_SIZE) { |
|
charsToSend = charsPerSend; |
|
} else { |
|
charsToSend = TEST_DATA_SIZE - totCharsSent; |
|
} |
|
|
|
numCharsSent = send(connection->connectedSocket, &gTestData[totCharsSent], charsToSend, 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); |
| |
for(threadIndex = 0; threadIndex < NUM_CLIENTS; threadIndex++) { | for(threadIndex = 0; threadIndex < NUM_CLIENTS; threadIndex++) { |
clientThreads[threadIndex].Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &BlockingClient, (void *) &serverPort, 0, &clientThreads[threadIndex].ID); |
clientThreads[threadIndex].Handle = CreateThread(NULL, 0, |
|
(LPTHREAD_START_ROUTINE) &BlockingClient, (void *) &serverPort, 0, |
|
&clientThreads[threadIndex].ID); |
} | } |
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 |
/* generate test data and initialize application */ |
WSADATA wsaData; | WSADATA wsaData; |
int wsastartup_result; | int wsastartup_result; |
int versionOK; | int versionOK; |
|
int i; |
|
char testPattern[11] = { 'A', 'O', 'E', 'U', 'I', 'D', 0x00, 0x05, 0x10, 0x15, 0x20 }; |
| |
// check for compatible winsock version |
/* fill out test data */ |
|
gTestData = malloc(TEST_DATA_SIZE); |
|
for(i = 0; i < TEST_DATA_SIZE; i++) { |
|
gTestData[i] = testPattern[i%11]; |
|
} |
|
|
|
/* 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); |
ok((wsastartup_result == NO_ERROR), "Error in WSAStartup()\n"); |
| |
|
versionOK = (LOBYTE(wsaData.wVersion) == 1) && (HIBYTE(wsaData.wVersion) == 1); |
ok( versionOK , "WSAStartup returns an incompatible sockets version\n"); | ok( versionOK , "WSAStartup returns an incompatible sockets version\n"); |
if ( !versionOK ) { | if ( !versionOK ) { |
WSACleanup(); | WSACleanup(); |
exit(0); | exit(0); |
} | } |
| |
ok((wsastartup_result == NO_ERROR), "Error in WSAStartup()\n"); |
|
trace("startup ok\n"); | trace("startup ok\n"); |
} | } |
| |
|
|
int cleanupOK; | int cleanupOK; |
| |
cleanupOK = ! WSACleanup(); | cleanupOK = ! WSACleanup(); |
|
|
ok( cleanupOK , "error in WSACleanup()\n"); | ok( cleanupOK , "error in WSACleanup()\n"); |
|
|
|
free(gTestData); |
|
|
trace("cleanup ok\n"); | trace("cleanup ok\n"); |
} | } |
| |
START_TEST(wsock32_main) | START_TEST(wsock32_main) |
{ | { |
const int numTests = 3; |
static const int numTests = 3; |
gTestData = malloc(TEST_DATA_SIZE); |
|
| |
trace("test 1 of %d:\n", numTests); | trace("test 1 of %d:\n", numTests); |
test_Startup(); | test_Startup(); |
|
|
test_Cleanup(); | test_Cleanup(); |
| |
trace("all " __FILE__ " tests done\n"); | trace("all " __FILE__ " tests done\n"); |
|
|
free(gTestData); |
|
} | } |