|
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 ); |
| | |