@@ -269,13 +269,13 @@ struct relayserverinternal
269269 if (std::find (clients.begin (), clients.end (), client) != clients.end ())
270270 {
271271 serverReadLock.lw_unlock ();
272- // auto clientWriteLock = clientsocket ->lock.createWriteLock();
272+ auto clientWriteLock = client ->lock .createWriteLock ();
273273 if (client->_readonly )
274274 continue ;
275275 client->_readonly = true ;
276276
277277 auto error = lacewing::error_new ();
278- error->add (" Disconnecting client ID %i due to ping timeout" , client->_id );
278+ error->add (" Disconnecting client ID %hu due to ping timeout" , client->_id );
279279 handlererror (this ->server , error);
280280 lacewing::error_delete (error);
281281
@@ -314,7 +314,8 @@ struct relayserverinternal
314314 if (std::find (clients.begin (), clients.end (), client) != clients.end ())
315315 {
316316 serverReadLock.lw_unlock ();
317- // auto clientWriteLock = clientsocket->lock.createWriteLock();
317+
318+ auto clientWriteLock = client->lock .createWriteLock ();
318319 if (client->_readonly )
319320 continue ;
320321
@@ -323,12 +324,14 @@ struct relayserverinternal
323324 impl.erase (impl.cend ());
324325
325326 auto error = lacewing::error_new ();
326- error->add (" Disconnecting client ID %i due to inactivity timeout; client impl \" %s\" ." , client->_id , impl.c_str ());
327+ error->add (" Disconnecting client ID %hu due to inactivity timeout; client impl \" %s\" ." , client->_id , impl.c_str ());
327328 handlererror (this ->server , error);
328329 lacewing::error_delete (error);
329330
331+ // Don't send warning to a client that hasn't even sent Lacewing handshake after connecting
330332 if (client->gotfirstbyte )
331333 client->send (0 , " You're being kicked for inactivity." , 0 );
334+
332335 if (client->socket ->is_websocket ())
333336 client->disconnect (1000 );
334337 else // Close nicely - if client has not got first byte, e.g. non-Lacewing, close immediately
@@ -1178,18 +1181,18 @@ void handlerwebserverget(lacewing::webserver webserver, lacewing::webserver_requ
11781181 char sha1[20 ];
11791182 lw_sha1 (sha1, webSocketKey.data (), webSocketKey.size ());
11801183 const std::string webSocketKeyResponse = b64encode (sha1, sizeof (sha1));
1181-
1182- auto c = ((struct _lw_ws_req *)req)->client ;
1183- c ->websocket = lw_true;
1184- c ->ws ->timeout = 0 ; // disable timeout - next used when server inits a disconnect and is waiting for WebSocket close packet back
1184+
1185+ lwp_ws_client reqClient = ((struct _lw_ws_req *)req)->client ;
1186+ reqClient ->websocket = lw_true;
1187+ reqClient ->ws ->timeout = 0 ; // disable timeout - next used when server inits a disconnect and is waiting for WebSocket close packet back
11851188
11861189 lw_server server;
1187- if (c->secure )
1188- server = ((lw_ws)webserver)->socket ;
1189- else
1190+ if (reqClient->secure )
11901191 server = ((lw_ws)webserver)->socket_secure ;
1191- lw_server_client_set_websocket (c->socket , lw_true);
1192- internal.generic_handlerconnect ((lacewing::server)server, (lacewing::server_client)c->socket );
1192+ else
1193+ server = ((lw_ws)webserver)->socket ;
1194+ lw_server_client_set_websocket (reqClient->socket , lw_true);
1195+ internal.generic_handlerconnect ((lacewing::server)server, (lacewing::server_client)reqClient->socket );
11931196
11941197 req->header (" Upgrade" , " WebSocket" );
11951198 req->header (" Connection" , " Upgrade" );
@@ -1268,9 +1271,9 @@ void handlerwebserverdisconnect(lacewing::webserver webserver, lacewing::webserv
12681271 return ; // not websocket - just some dumb client, don't pass to relayserver
12691272 lw_server server;
12701273 if (client->secure )
1271- server = ((lw_ws)webserver)->socket ;
1272- else
12731274 server = ((lw_ws)webserver)->socket_secure ;
1275+ else
1276+ server = ((lw_ws)webserver)->socket ;
12741277 internal.generic_handlerdisconnect ((lacewing::server)server, (lacewing::server_client)client->socket );
12751278}
12761279
@@ -1394,6 +1397,9 @@ void relayserver::host_websocket(lw_ui16 portNonSecure, lw_ui16 portSecure)
13941397 websocket->host_secure (portSecure);
13951398 assert (websocket->hosting_secure ());
13961399 }
1400+
1401+ relayserverinternal* serverInternal = (relayserverinternal*)internaltag;
1402+ serverInternal->pingtimer ->start (serverInternal->tcpPingMS );
13971403}
13981404void relayserver::host_websocket (lacewing::filter& filterNonSecure, lacewing::filter& filterSecure)
13991405{
@@ -1410,44 +1416,99 @@ void relayserver::host_websocket(lacewing::filter& filterNonSecure, lacewing::fi
14101416 websocket->host_secure (filterSecure);
14111417 assert (websocket->hosting_secure ());
14121418 }
1419+
1420+ relayserverinternal* serverInternal = (relayserverinternal*)internaltag;
1421+ serverInternal->pingtimer ->start (serverInternal->tcpPingMS );
14131422}
14141423
14151424void relayserver::unhost ()
14161425{
1417- socket->unhost ();
1418- udp->unhost ();
1419- websocket->unhost ();
1420- websocket->unhost_secure ();
1426+ // websocket and flash are unhosted explicitly only, as they're hosted explicitly
1427+ // flash only points to regular server, so it has no client list itself
14211428
14221429 relayserverinternal* serverInternal = (relayserverinternal*)internaltag;
1423- serverInternal->pingtimer ->stop ();
1430+ const bool isWebSocketActive = websocket->hosting () || websocket->hosting_secure ();
1431+ if (!isWebSocketActive)
1432+ serverInternal->pingtimer ->stop ();
14241433
14251434 // This will drop all clients, by doing so drop all channels
14261435 // and both of those will free the IDs
1427- // We'll set them all as readonly so peer leave messages aren't sent as the clients leave their channels
1428- for (auto &c : serverInternal->clients )
1429- c->_readonly = true ; // unhost() has already made clients inaccessible
1436+ // We'll set the leavers all as readonly before closing channels, so peer leave messages aren't sent to them
1437+ // as the clients leave their channels
1438+ for (auto & c : serverInternal->clients )
1439+ {
1440+ if (!c->socket ->is_websocket ())
1441+ c->_readonly = true ; // unhost() has already made clients inaccessible
1442+ }
14301443
14311444 // Prevent the channel_close handler from being run
1432- const auto handler = serverInternal->handlerchannel_close ;
1433- serverInternal->handlerchannel_close = nullptr ;
1445+ // const auto handler = serverInternal->handlerchannel_close;
1446+ // serverInternal->handlerchannel_close = nullptr;
1447+
1448+ // disconnect handlers check server that ran them is still hosting
1449+ socket->unhost ();
1450+ udp->unhost ();
1451+
1452+ // Reinstate for next host() call
1453+ // serverInternal->handlerchannel_close = handler;
1454+ }
1455+ void relayserver::unhost_websocket (bool insecure, bool secure)
1456+ {
1457+ // Turn off parameters for servers that aren't hosting
1458+ insecure &= websocket->hosting ();
1459+ secure &= websocket->hosting_secure ();
1460+
1461+ if (!insecure && !secure)
1462+ return ;
14341463
1435- while (!serverInternal->clients .empty ())
1464+ // disconnect handlers check server that ran them is still hosting
1465+ relayserverinternal* serverInternal = (relayserverinternal*)internaltag;
1466+ // If we've got a different server up (and we're not about to unhost it here), then keep ping timer running
1467+ const bool isOtherHosting = socket->hosting () || (!insecure && websocket->hosting ()) || (!secure && websocket->hosting_secure ());
1468+ if (!isOtherHosting)
1469+ serverInternal->pingtimer ->stop ();
1470+
1471+ // We'll set the leavers all as readonly before closing channels, so peer leave messages aren't sent to leavers
1472+ // as the clients leave their channels
1473+ // (they're still sent to clients on still-hosting servers, obviously)
1474+ if (insecure)
14361475 {
1437- auto & c = serverInternal->clients .back ();
1438- serverInternal->close_client (c);
1476+ for (auto c = lw_server_client_first (((lw_ws)websocket)->socket ); c; c = lw_server_client_next (c))
1477+ {
1478+ relayserver::client* client = (relayserver::client*)lw_server_client_get_relay_tag (c);
1479+ if (client)
1480+ client->_readonly = true ;
1481+ }
14391482 }
1440-
1441- // any with autoclose on
1442- while (!serverInternal->channels .empty ())
1483+ if (secure)
14431484 {
1444- auto & c = serverInternal->channels .back ();
1445- c->_readonly = true ;
1446- serverInternal->close_channel (c);
1485+ for (auto c = lw_server_client_first (((lw_ws)websocket)->socket_secure ); c; c = lw_server_client_next (c))
1486+ {
1487+ relayserver::client* client = (relayserver::client*)lw_server_client_get_relay_tag (c);
1488+ if (client)
1489+ client->_readonly = true ;
1490+ }
14471491 }
14481492
1449- // Reinstate for next host() call
1450- serverInternal->handlerchannel_close = handler;
1493+ // Prevent the channel_close handler from being run
1494+ // const auto handler = server->handlerchannel_close;
1495+ // serverInternal->handlerchannel_close = nullptr;
1496+
1497+ // This will drop clients, by doing so drop all channels and both of those will free the IDs
1498+ //
1499+ // The lower-level handler (lacewing::handlerdisconnect) will be triggered, but will not call the RelayServer disconnect handler,
1500+ // as that will check server is hosting before calling it
1501+ // note: unhost calls handlerdisconnect, which:
1502+ // expects client still in server list
1503+ // calls close_client
1504+ // resets relay tag to null
1505+ if (insecure)
1506+ websocket->unhost ();
1507+ if (secure)
1508+ websocket->unhost_secure ();
1509+
1510+ // Resume close handler
1511+ // serverInternal->handlerchannel_close = handler;
14511512}
14521513
14531514bool relayserver::hosting ()
@@ -2438,7 +2499,7 @@ bool relayserverinternal::client_messagehandler(std::shared_ptr<relayserver::cli
24382499 case 10 : /* implementation response */
24392500 {
24402501 const std::string_view impl = reader.get (reader.bytesleft ());
2441- if (reader.failed || impl.empty ())
2502+ if (reader.failed || impl.empty () || ! lw_u8str_validate (impl) )
24422503 {
24432504 errStr << " Failed to read implementation response" sv;
24442505 trustedClient = false ;
@@ -2462,14 +2523,17 @@ bool relayserverinternal::client_messagehandler(std::shared_ptr<relayserver::cli
24622523 }
24632524 else if (impl.find (" Android" sv) != std::string_view::npos)
24642525 client->clientImpl = relayserver::client::clientimpl::Android;
2465- else if (impl.find (" Flash" sv) != std::string_view::npos)
2466- client->clientImpl = relayserver::client::clientimpl::Flash;
24672526 else if (impl.find (" iOS" sv) != std::string_view::npos)
24682527 client->clientImpl = relayserver::client::clientimpl::iOS;
2469- else if (impl.find (" Macintosh" sv) != std::string_view::npos)
2470- client->clientImpl = relayserver::client::clientimpl::Macintosh;
2528+ // First test in client build 99, first release as build 100
24712529 else if (impl.find (" HTML5" sv) != std::string_view::npos)
24722530 client->clientImpl = relayserver::client::clientimpl::HTML5;
2531+ // While supported, Blue Flash never existed, and Relay Flash won't return a implementation response
2532+ else if (impl.find (" Flash" sv) != std::string_view::npos)
2533+ client->clientImpl = relayserver::client::clientimpl::Flash;
2534+ // While supported, not created yet
2535+ else if (impl.find (" Macintosh" sv) != std::string_view::npos)
2536+ client->clientImpl = relayserver::client::clientimpl::Macintosh;
24732537 else
24742538 {
24752539 errStr << " Failed to recognise platform of implementation \" " sv << impl << " \" . Leaving it as Unknown." sv;
@@ -3004,9 +3068,11 @@ void relayserver::connect_response(
30043068
30053069 framebuilder builder (true );
30063070
3007- // Force a connect refusal if not hosting serevr
3071+ // Force a connect refusal if not hosting server
3072+ // TODO: Is this necessary? Client should've been d/c'd on unhost
3073+ // If it is necessary, the HTML5 server hosting check is borked, client could be on the other server
30083074 std::string_view denyReason = passedDenyReason;
3009- if (denyReason.empty () && ! hosting ())
3075+ if (denyReason.empty () && (client-> socket -> is_websocket () ? !websocket-> hosting () && !websocket-> hosting_secure () : ! hosting () ))
30103076 denyReason = " Server has shut down." sv;
30113077
30123078 // Connect request denied
@@ -3026,7 +3092,7 @@ void relayserver::connect_response(
30263092
30273093 // Connect request accepted
30283094
3029- lw_trace (" Connect request accepted in relayserver::connectresponse" );
3095+ lwp_trace (" Connect request accepted in relayserver::connectresponse" );
30303096 client->connectRequestApproved = true ;
30313097 client->connectRequestApprovedTime = decltype (client->connectRequestApprovedTime )::clock::now ();
30323098 client->clientImpl = relayserver::client::clientimpl::Unknown;
0 commit comments