Skip to content

Commit

Permalink
Handle race condition between handling open and getting first event m…
Browse files Browse the repository at this point in the history
…essage.
  • Loading branch information
d3x0r committed Jan 23, 2025
1 parent 9484bf4 commit bbf8f65
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 21 deletions.
3 changes: 2 additions & 1 deletion src/netlib/html5.websocket/client/html5.websocket.client.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ static void CPROC WebSocketClientReceive( PCLIENT pc, POINTER buffer, size_t len
//lprintf( "reply is %d", result );
if( (int)result == 101 )
{
websock->input_state.flags.initial_handshake_done = 1;
websock->flags.connected = 1;
{
PTEXT content = GetHttpContent( websock->pHttpState );
Expand Down Expand Up @@ -355,7 +356,7 @@ static void WebSocketClose_( WebSocketClient wsc, int code, const char *reason )
}
if( websock->Magic == 0x20130912 ) { // struct html5_web_socket
struct html5_web_socket *serverSock = (struct html5_web_socket*)websock;
if( serverSock->flags.initial_handshake_done ) {
if( serverSock->input_state.flags.initial_handshake_done ) {
//lprintf( "Send server side close with no payload." );
SendWebSocketMessage( &serverSock->input_state, 8, 1, serverSock->input_state.flags.expect_masking, (const uint8_t*)buf, buflen );
serverSock->input_state.flags.closed = 1;
Expand Down
1 change: 1 addition & 0 deletions src/netlib/html5.websocket/html5.websocket.common.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ void ProcessWebSockProtocol( WebSocketInputState websock, const uint8_t* msg, si
/// single packet, final...
//LogBinary( websock->fragment_collection, websock->fragment_collection_length );
if( websock->on_event ) {
while( !websock->flags.initial_handshake_done || websock->flags.in_open_event ) Relinquish();
#ifndef __NO_WEBSOCK_COMPRESSION__
if( websock->flags.deflate && ( websock->RSV1 & 0x40 ) ) {
int r;
Expand Down
10 changes: 5 additions & 5 deletions src/netlib/html5.websocket/html5.websocket.common.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ struct web_socket_input_state
BIT_FIELD use_ssl : 1;
BIT_FIELD want_close : 1; // schedule to close (moved from client; client only)
BIT_FIELD pipe : 1;
} flags;
BIT_FIELD initial_handshake_done : 1;
BIT_FIELD in_open_event : 1;
} volatile flags;
uint32_t last_reception; // (last message tick) for automatic ping/keep alive/idle death

#ifndef __NO_WEBSOCK_COMPRESSION__
Expand Down Expand Up @@ -100,14 +102,12 @@ struct html5_web_socket {
uint32_t Magic; // this value must be 0x20130912
struct web_socket_flags
{
BIT_FIELD initial_handshake_done : 1;
BIT_FIELD rfc6455 : 1;
BIT_FIELD accepted : 1;
BIT_FIELD http_request_only : 1;
BIT_FIELD in_open_event : 1; // set when sent to client, which can write and close before return; no further read must be done.
BIT_FIELD closed : 1; // was already closed (during in_read_event)
BIT_FIELD skip_read : 1;
} flags;
} volatile flags;
HTTPState http_state;
PCLIENT pc;
POINTER buffer;
Expand All @@ -124,7 +124,7 @@ struct web_socket_client
{
BIT_FIELD connected : 1; // if not connected, then parse data as http, otherwise process as websock protocol.
//BIT_FIELD use_ssl : 1;
} flags;
} volatile flags;
PCLIENT pc;

CTEXTSTR host;
Expand Down
38 changes: 23 additions & 15 deletions src/netlib/html5.websocket/server/html5.websocket.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,14 @@ static void HandleData( HTML5WebSocket socket, CPOINTER buffer, size_t length )
void ResetWebsocketRequestHandler( PCLIENT pc ) {
HTML5WebSocket socket = (HTML5WebSocket)GetNetworkLong( pc, 0 );
if( !socket ) return; // closing/closed....
socket->flags.initial_handshake_done = 0;
socket->input_state.flags.initial_handshake_done = 0;
socket->flags.http_request_only = 0;
EndHttp( socket->http_state );
}

void ResetWebsocketPipeRequestHandler( HTML5WebSocket socket ) {
if( !socket ) return; // closing/closed....
socket->flags.initial_handshake_done = 0;
socket->input_state.flags.initial_handshake_done = 0;
socket->flags.http_request_only = 0;
EndHttp( socket->http_state );
}
Expand All @@ -223,7 +223,7 @@ uintptr_t WebSocketPipeGetServerData( HTML5WebSocket socket ) {

static void CPROC destroyHttpState( HTML5WebSocket socket, PCLIENT pc_client ) {
//HTML5WebSocket socket = (HTML5WebSocket)GetNetworkLong( pc_client, 0 );
if( socket->flags.in_open_event ) {
if( socket->input_state.flags.in_open_event ) {
socket->flags.closed = 1;
return;
}
Expand Down Expand Up @@ -269,24 +269,24 @@ static void CPROC read_complete_process_data( HTML5WebSocket socket ) {
|| !StrCaseStr( GetText( value ), "upgrade" )
|| !TextLike( value2, "websocket" ) ) {
//lprintf( "request is not an upgrade for websocket." );
socket->flags.initial_handshake_done = 1;
socket->input_state.flags.initial_handshake_done = 1;
socket->flags.http_request_only = 1;
socket->flags.in_open_event = 1;
socket->input_state.flags.in_open_event = 1;
if( socket->input_state.on_request ) {
if( socket->Magic == 0x20240310 )
socket->input_state.on_request( (PCLIENT)socket, socket->input_state.psv_on );
else
socket->input_state.on_request( socket->pc, socket->input_state.psv_on );
} else {
socket->flags.in_open_event = 0;
socket->input_state.flags.in_open_event = 0;
if( socket->pc )
RemoveClient( socket->pc );
else if( socket->input_state.do_close )
socket->input_state.do_close( socket->input_state.psvCloser );

return;
}
socket->flags.in_open_event = 0;
socket->input_state.flags.in_open_event = 0;
if( socket->flags.closed ) {
destroyHttpState( socket, NULL );
return;
Expand Down Expand Up @@ -488,7 +488,7 @@ static void CPROC read_complete_process_data( HTML5WebSocket socket ) {
SendTCP( socket->pc, GetText( value ), GetTextSize( value ) );
//lprintf( "Sent http reply." );
VarTextDestroy( &pvt_output );
socket->flags.in_open_event = 1;
socket->input_state.flags.in_open_event = 1;

if( socket->input_state.on_open ) {
if( socket->Magic == 0x20240310 ) {
Expand All @@ -497,7 +497,7 @@ static void CPROC read_complete_process_data( HTML5WebSocket socket ) {
socket->input_state.psv_open = socket->input_state.on_open( socket->pc, socket->input_state.psv_on );
}
}
socket->flags.in_open_event = 0;
socket->input_state.flags.in_open_event = 0;
if( socket->flags.closed ) {
destroyHttpState( socket, NULL );
return;
Expand All @@ -512,7 +512,7 @@ static void CPROC read_complete_process_data( HTML5WebSocket socket ) {
}
// keep this until close, application might want resource and/or headers from this.
//EndHttp( socket->http_state );
socket->flags.initial_handshake_done = 1;
socket->input_state.flags.initial_handshake_done = 1;
}
break;
}
Expand All @@ -527,8 +527,8 @@ void WebSocketWrite( HTML5WebSocket socket, CPOINTER buffer, size_t length )
if( buffer )
{
CTEXTSTR tmp = (CTEXTSTR)buffer;
if( !( socket->flags.initial_handshake_done
|| socket->flags.in_open_event )
if( !( socket->input_state.flags.initial_handshake_done
|| socket->input_state.flags.in_open_event )
|| socket->flags.http_request_only )
{
if( AddHttpData( socket->http_state, tmp, length ) )
Expand Down Expand Up @@ -608,7 +608,11 @@ static void CPROC connected( PCLIENT pc_server, PCLIENT pc_new )
MemSet( socket, 0, sizeof( struct html5_web_socket ) );
socket->Magic = 0x20130912;
socket->pc = pc_new;
#ifdef __cplusplus
MemCpy( &socket->input_state, &server_socket->input_state, sizeof( socket->input_state ) ); // clone callback methods and config flags )
#else
socket->input_state = server_socket->input_state; // clone callback methods and config flags
#endif
socket->input_state.close_code = 1006;
socket->input_state.close_reason = StrDup( "Because I don't Like You?");
socket->input_state.psvSender = (uintptr_t)pc_new;
Expand Down Expand Up @@ -670,7 +674,11 @@ HTML5WebSocket WebSocketPipeConnect( HTML5WebSocket pipe, uintptr_t psvNew ) {
MemSet( socket, 0, sizeof( struct html5_web_socket ) );
socket->Magic = 0x20240310;
socket->pc = NULL;
#ifdef __cplusplus
MemCpy( &socket->input_state, &server_socket->input_state, sizeof( socket->input_state ) ); // clone callback methods and config flags )
#else
socket->input_state = server_socket->input_state; // clone callback methods and config flags
#endif
socket->input_state.psvSender = psvNew;
// this new socket gets a http state.
socket->http_state = CreateHttpState( &socket->pc ); // start a new http state collector
Expand Down Expand Up @@ -881,7 +889,7 @@ void WebSocketPipeAccept( HTML5WebSocket socket, char *protocols, int yesno ) {
SendTCP( socket->pc, GetText( value ), GetTextSize( value ) );
//lprintf( "Sent http reply." );
VarTextDestroy( &pvt_output );
socket->flags.in_open_event = 1;
socket->input_state.flags.in_open_event = 1;

if( socket->input_state.on_open ) {
//lprintf( "Doing open event too (this will be in the self-JS thread)");
Expand All @@ -891,12 +899,12 @@ void WebSocketPipeAccept( HTML5WebSocket socket, char *protocols, int yesno ) {
socket->input_state.psv_open = socket->input_state.on_open( socket->pc, socket->input_state.psv_on );
}
}
socket->flags.in_open_event = 0;
socket->input_state.flags.in_open_event = 0;
if( socket->flags.closed ) {
destroyHttpState( socket, NULL );
return;
}
socket->flags.initial_handshake_done = 1;
socket->input_state.flags.initial_handshake_done = 1;
}
}

Expand Down

0 comments on commit bbf8f65

Please sign in to comment.