version 1.1, 2005/03/10 11:34:15
|
version 1.4, 2005/03/16 14:30:36
|
|
|
struct sockaddr_in peer; | struct sockaddr_in peer; |
char *buf; | char *buf; |
int nread; | int nread; |
|
int nsent; |
} sock_info; | } sock_info; |
| |
/* Test parameters for both server & client */ | /* Test parameters for both server & client */ |
|
|
typedef struct async_param_t | typedef struct async_param_t |
{ | { |
server_params *svc_params; | server_params *svc_params; |
int numClients; |
server_memory *mem; |
char *fileBuf; |
HWND hwnd; |
} async_param_t; | } async_param_t; |
| |
/**************** Static variables ***************/ | /**************** Static variables ***************/ |
|
|
mem->sock[i].s = INVALID_SOCKET; | mem->sock[i].s = INVALID_SOCKET; |
mem->sock[i].buf = (LPVOID) LocalAlloc ( LPTR, gen->n_chunks * gen->chunk_size ); | mem->sock[i].buf = (LPVOID) LocalAlloc ( LPTR, gen->n_chunks * gen->chunk_size ); |
mem->sock[i].nread = 0; | mem->sock[i].nread = 0; |
|
mem->sock[i].nsent = 0; |
} | } |
| |
if ( gen->sock_type == SOCK_STREAM ) | if ( gen->sock_type == SOCK_STREAM ) |
|
|
ExitThread ( GetCurrentThreadId () ); | ExitThread ( GetCurrentThreadId () ); |
} | } |
| |
|
/* This function takes in server_memory struct of the running server |
|
and looks for the first existence of sockToFind socket in sock[] array. */ |
|
static sock_info* GetClientSockInfo( server_memory* servMem, SOCKET sockToFind ) |
|
{ |
|
|
|
/* Looping through all the possible clients */ |
|
int clientNum; |
|
for( clientNum = 0; clientNum < MAX_CLIENTS; clientNum++ ){ |
|
|
|
/* When the match is found, return the pointer to that sock_info struct */ |
|
if( servMem->sock[clientNum].s == sockToFind ){ |
|
|
|
return &(servMem->sock[clientNum]); |
|
|
|
} |
|
|
|
} |
|
|
|
/* Did not find a match. */ |
|
return NULL; |
|
|
|
} |
|
|
|
/* This function takes in server_memory structure of the running |
|
server and finds the first socket that is available */ |
|
static sock_info* GetNextOpenSock( server_memory* servMem ) |
|
{ |
|
|
|
/* Loop through sock array of servMem */ |
|
int clientNum; |
|
for( clientNum = 0; clientNum < MAX_CLIENTS; clientNum++ ){ |
|
|
|
/* when an open slot is found, return */ |
|
if( servMem->sock[clientNum].s == INVALID_SOCKET ) |
|
return &(servMem->sock[clientNum]); |
|
|
|
} |
|
|
|
/* When there is no more open socket, return NULL */ |
|
return NULL; |
|
|
|
} |
|
|
|
/* this function returns TRUE if all sockets in servMem are INVALID_SOCKET */ |
|
static BOOL noOpenSock( server_memory* servMem ) |
|
{ |
|
|
|
/* Loop through sock array of servMem */ |
|
int clientNum; |
|
for( clientNum = 0; clientNum < MAX_CLIENTS; clientNum++ ){ |
|
|
|
/* if any socket != INVALID_SOCKET, there is an open socket */ |
|
if( servMem->sock[clientNum].s != INVALID_SOCKET ) |
|
return FALSE; |
|
|
|
} |
|
|
|
/* no open sockets */ |
|
return TRUE; |
|
|
|
} |
|
|
|
/* This function takes in pointer to sock_info structure of a client |
|
and attempts to send all the data that hasn't been sent back yet. */ |
|
static void try_send_all_buf( sock_info* sockInfo, int servBufLen ) |
|
{ |
|
int n_sent = 0, sendLen, err; |
|
int id = GetCurrentThreadId(); |
|
|
|
/* send any data that hasn't been sent yet */ |
|
while( sockInfo->nsent < sockInfo->nread ){ |
|
|
|
/* find out the buffer length to send */ |
|
sendLen = min( sockInfo->nread - sockInfo->nsent, servBufLen ); |
|
|
|
/* send the data */ |
|
n_sent = send( sockInfo->s, sockInfo->buf + sockInfo->nsent, sendLen, 0 ); |
|
|
|
/* If there was an error, break */ |
|
if( n_sent == SOCKET_ERROR ) |
|
break; |
|
|
|
/* update the number bytes sent */ |
|
sockInfo->nsent += n_sent; |
|
|
|
} |
|
|
|
/* check the error */ |
|
if( n_sent == SOCKET_ERROR && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK ) |
|
ok( 0, "async_server (%x): send error: %d\n", id, err ); |
|
|
|
} |
|
|
/**************** Client utilitiy functions ***************/ | /**************** Client utilitiy functions ***************/ |
| |
static void client_start ( client_params *par ) | static void client_start ( client_params *par ) |
|
|
*/ | */ |
static LRESULT CALLBACK async_server_proc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) | static LRESULT CALLBACK async_server_proc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
{ | { |
SOCKET socket = (SOCKET) wParam; |
|
server_memory* mem = TlsGetValue( tls ); |
server_memory* mem = async_params.mem; |
|
SOCKET clientSock = (SOCKET) wParam; |
|
test_params* gen = (async_params.svc_params)->general; |
|
char* inetAddr = (char*)gen->inet_addr; |
|
|
|
sock_info* sockInfo; |
struct sockaddr_in peer; | struct sockaddr_in peer; |
char *file_buf = async_params.fileBuf; |
int addrLen = sizeof( peer ); |
char *inetAddr = (char*)((async_params.svc_params)->general)->inet_addr; |
int eventCode, err, id = GetCurrentThreadId(); |
int n_recvd, n_sent, addrLen, id = GetCurrentThreadId(); |
int servBufLen = (async_params.svc_params)->buflen; |
int eventCode, packet_len = (async_params.svc_params)->buflen;; |
int n_recvd = 0, n_expected; |
|
char *p; |
| |
switch( msg ){ |
switch( msg ) |
|
{ |
| |
case ASYNC_EVENT: | case ASYNC_EVENT: |
| |
eventCode = WSAGETSELECTEVENT( lParam ); | eventCode = WSAGETSELECTEVENT( lParam ); |
switch( eventCode ){ |
switch( eventCode ) |
|
{ |
| |
case FD_ACCEPT: | case FD_ACCEPT: |
| |
// accept connection |
|
trace( "async_server (%x): accept event\n", id ); | trace( "async_server (%x): accept event\n", id ); |
addrLen = sizeof ( peer ); |
|
socket = accept( mem->s, (struct sockaddr*) &peer, &addrLen ); |
|
wsa_ok( socket, INVALID_SOCKET !=, "async_server (%lx): accept failed: %d\n" ); |
|
| |
if( socket == INVALID_SOCKET ){ |
/* Find the next available socket */ |
|
sockInfo = GetNextOpenSock( mem ); |
|
ok( sockInfo != NULL, "async_server (%x): no more open socket\n", id ); |
|
|
|
/* accept connection */ |
|
sockInfo->s = accept( mem->s, (struct sockaddr*) &peer, &addrLen ); |
|
wsa_ok( sockInfo->s, INVALID_SOCKET !=, "async_server (%lx): accept failed: %d\n" ); |
| |
trace( "async_server (%x): exiting\n", id ); |
/* check the address retrieved from accept() is valid */ |
server_stop(); |
ok( peer.sin_addr.s_addr == inet_addr( inetAddr ), "async_server (%x): strange peer address\n", id ); |
| |
} |
/* make this newly accepted socket asynchronous */ |
|
err = WSAAsyncSelect( sockInfo->s, async_params.hwnd, ASYNC_EVENT, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE ); |
|
wsa_ok( err, SOCKET_ERROR !=, "async_server (%lx): WSAAsyncSelect failed: %d\n" ); |
| |
ok( peer.sin_addr.s_addr == inet_addr ( inetAddr ), |
|
"async_server (%x): strange peer address\n", id ); |
|
break; | break; |
| |
case FD_READ: |
case FD_WRITE: |
|
|
// server has data waiting to be read |
|
n_recvd = recv( socket, file_buf, packet_len, 0 ); |
|
wsa_ok( n_recvd, SOCKET_ERROR !=, "recv (%lx): error %d:\n" ); |
|
| |
if( n_recvd == SOCKET_ERROR ){ |
/* get the sock_info* of this client socket */ |
|
sockInfo = GetClientSockInfo( mem, clientSock ); |
|
ok( sockInfo != NULL, "async_server (%x): socket to write to is not open\n", id ); |
| |
trace( "async_server (%x) exiting\n", id ); |
/* try sending any remaining data */ |
server_stop(); |
try_send_all_buf( sockInfo, servBufLen ); |
|
break; |
} |
|
|
|
// Send the packet back |
|
n_sent = send( socket, file_buf, n_recvd, 0 ); |
|
wsa_ok( n_sent, SOCKET_ERROR !=, "send (%lx): error %d:\n" ); |
|
| |
if( n_sent == SOCKET_ERROR ){ |
case FD_READ: |
| |
trace( "async_server (%x) exiting\n", id ); |
/* get the sock_info* of this client socket */ |
server_stop(); |
sockInfo = GetClientSockInfo( mem, clientSock ); |
|
ok( sockInfo != NULL, "async_server (%x): socket to read from is not open\n", id ); |
|
|
|
/* retrieve the data */ |
|
n_recvd = recv( sockInfo->s, sockInfo->buf + sockInfo->nread, servBufLen, 0 ); |
|
if( n_recvd == SOCKET_ERROR && ( err = WSAGetLastError () ) != WSAEWOULDBLOCK ) |
|
ok( 0, "async_server (%x): recv error: %d\n", id, err ); |
|
|
|
/* record number of bytes read so far */ |
|
if( n_recvd != SOCKET_ERROR ) |
|
sockInfo->nread += n_recvd; |
| |
} |
/* send the remaining data */ |
|
try_send_all_buf( sockInfo, servBufLen ); |
break; | break; |
| |
case FD_CLOSE: | case FD_CLOSE: |
| |
// Close the client socket and then close the server |
/* Client closed connection - close the connection with this server. */ |
// when all clients are done. |
|
trace( "async_server (%x): close event\n", id ); | trace( "async_server (%x): close event\n", id ); |
closesocket( socket ); |
sockInfo = GetClientSockInfo( mem, clientSock ); |
|
ok( sockInfo != NULL, "async_server (%x): socket to close is not open\n", id ); |
| |
if( --async_params.numClients == 0 ){ |
/* Check the data it received */ |
|
n_expected = gen->n_chunks * gen->chunk_size; |
|
ok( sockInfo->nread == n_expected, |
|
"async_server (%x): received less data than expected: %d of %d\n", id, sockInfo->nread, n_expected ); |
|
|
|
p = test_buffer( sockInfo->buf, gen->chunk_size, gen->n_chunks ); |
|
ok( p == NULL, "async_server (%x): test pattern error: %d\n", id, p - sockInfo->buf); |
|
|
|
/* clean up */ |
|
wsa_ok( closesocket( sockInfo->s ), 0 ==, "async_server (%lx): closesocket error: %d\n" ); |
|
sockInfo->s = INVALID_SOCKET; |
|
|
|
/* If all sockets are closed, kill the server */ |
|
if( noOpenSock( mem ) ){ |
| |
trace( "async_server (%x) exiting\n", id ); | trace( "async_server (%x) exiting\n", id ); |
server_stop(); | server_stop(); |
|
|
*/ | */ |
static void WINAPI async_server( server_params *par ) | static void WINAPI async_server( server_params *par ) |
{ | { |
int id = GetCurrentThreadId(), err; |
int id = GetCurrentThreadId(); |
test_params* gen = par->general; |
|
|
|
// set up async_params structure |
|
memset( &async_params, 0, sizeof( async_params ) ); |
|
async_params.svc_params = par; |
|
async_params.numClients = gen->n_clients; |
|
async_params.fileBuf = (LPVOID) LocalAlloc( LPTR, gen->n_chunks * gen->chunk_size ); |
|
| |
trace( "async_server (%x) starting\n", id ); | trace( "async_server (%x) starting\n", id ); |
set_so_opentype( FALSE ); /* non-overlapped */ | set_so_opentype( FALSE ); /* non-overlapped */ |
server_start( par ); | server_start( par ); |
server_memory *mem = TlsGetValue( tls ); |
|
| |
wsa_ok( listen ( mem->s, SOMAXCONN ), 0 ==, "async_server (%lx): listen failed: %d\n"); |
/* set up async_params structure */ |
|
memset( &async_params, 0, sizeof( async_params ) ); |
|
async_params.svc_params = par; |
|
async_params.mem = TlsGetValue( tls ); |
| |
// Get the current instance |
wsa_ok( listen ( (async_params.mem)->s, SOMAXCONN ), 0 ==, "async_server (%lx): listen failed: %d\n"); |
|
|
|
/* Get the current instance */ |
HINSTANCE instance = GetModuleHandle( NULL ); | HINSTANCE instance = GetModuleHandle( NULL ); |
ok( instance != NULL, "async_server (%x):GetModuleHandle error %ld\n", id, GetLastError() ); | ok( instance != NULL, "async_server (%x):GetModuleHandle error %ld\n", id, GetLastError() ); |
if( instance == NULL ){ |
|
| |
trace( "async_server (%x) exiting\n", id ); |
/* Create a hiddent window to handle async events */ |
server_stop(); |
|
|
|
} |
|
|
|
// Create a hiddent window to handle async events |
|
WNDCLASS windowClass; | WNDCLASS windowClass; |
windowClass.lpszClassName = "Hidden_Winsock_Window"; | windowClass.lpszClassName = "Hidden_Winsock_Window"; |
windowClass.style = CS_HREDRAW | CS_VREDRAW; | windowClass.style = CS_HREDRAW | CS_VREDRAW; |
|
|
windowClass.lpszMenuName = NULL; | windowClass.lpszMenuName = NULL; |
ATOM classAtom = RegisterClass( &windowClass ); | ATOM classAtom = RegisterClass( &windowClass ); |
ok( classAtom != 0, "async_server (%x): RegisterClass error %ld\n", id, GetLastError() ); | ok( classAtom != 0, "async_server (%x): RegisterClass error %ld\n", id, GetLastError() ); |
if( classAtom == 0 ){ |
|
|
|
trace( "async_server (%x) exiting\n", id ); |
|
server_stop(); |
|
|
|
} |
|
| |
HWND hwnd = CreateWindow( "Hidden_Winsock_Window", | HWND hwnd = CreateWindow( "Hidden_Winsock_Window", |
"Winsock Window", | "Winsock Window", |
|
|
NULL, | NULL, |
instance, | instance, |
NULL ); | NULL ); |
|
|
ok( hwnd != NULL, "async_server (%x): CreateWindowd error %ld\n", id, GetLastError() ); | ok( hwnd != NULL, "async_server (%x): CreateWindowd error %ld\n", id, GetLastError() ); |
if( hwnd == NULL ){ |
|
|
|
trace ( "async_server (%x) exiting\n", id ); |
|
server_stop(); |
|
| |
} |
/* save hwnd */ |
|
async_params.hwnd = hwnd; |
| |
/* make the socket asynchronous */ | /* make the socket asynchronous */ |
err = WSAAsyncSelect( mem->s, hwnd, ASYNC_EVENT, FD_ACCEPT | FD_READ | FD_CLOSE ); |
int err; |
|
err = WSAAsyncSelect( (async_params.mem)->s, hwnd, ASYNC_EVENT, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE ); |
wsa_ok( err, SOCKET_ERROR !=, "async_server (%lx): WSAAsyncSelect failed: %d\n" ); | wsa_ok( err, SOCKET_ERROR !=, "async_server (%lx): WSAAsyncSelect failed: %d\n" ); |
if( err == SOCKET_ERROR ){ |
|
|
|
trace( "async_server (%x) exiting\n", id ); |
|
server_stop(); |
|
|
|
} |
|
| |
trace( "async_server (%x) ready\n", id ); | trace( "async_server (%x) ready\n", id ); |
SetEvent( server_ready ); /* notify clients */ | SetEvent( server_ready ); /* notify clients */ |
|
|
ok( retVal != -1, "async_server (%x): GetMessage error %ld\n", id, GetLastError() ); | ok( retVal != -1, "async_server (%x): GetMessage error %ld\n", id, GetLastError() ); |
if( retVal == -1 ){ | if( retVal == -1 ){ |
| |
// error: exit |
/* exit so that the server won't block */ |
trace( "async_server (%x) exiting\n", id ); |
trace( "async_server (%x): exiting\n", id ); |
server_stop(); | server_stop(); |
| |
} | } |
| |
// Translate and dispatch the message |
/* Translate and dispatch the message */ |
TranslateMessage( &msg ); | TranslateMessage( &msg ); |
DispatchMessage( &msg ); | DispatchMessage( &msg ); |
| |