Skip to content

Commit 148d27a

Browse files
committed
Bluewing Server update to build 34
• Fixed secure websocket hosting on Windows. After initial Lacewing messages (connect, implementation), no data would go through either way. The queue would hold the data indefinitely, breaking future SSL packets' decryptions. This has been fixed by disabling the queue functionality, more as a stop-gap than a proper fix. (Most of my Windows tests were checking HTML5 clients connected; the more complex tests were done on Unix servers, as those were more likely to go wrong, ironically.) • Fixed large WebSocket packets (>126 bytes) causing a disconnect - browsers have a habit of sending a large packet starting with a network packet containing just the WebSocket header, and the parser recognised the absence of data and declared the size invalid. Now, it will just say it processed nothing, so the header is sent back to the parser again (with more of the data attached). This is again not a proper fix; although a huge packet with >2 network packets will just loop to parser a 3rd time, it's not performant. But you shouldn't be sending huge packets over WebSocket anyway. So I'm not too fussed. In previous commits: • Fixed SSL/TLS error reporting from always_log to using the lw_server's error handler. This is better because the fake struct hack was removed. I moved SSL client type from lw_stream to lw_server_client to let it be passed to the error handler; I may have to revert the change partially later, if Lacewing C++ SSL clients turn out to use the SSL structs I thought were server-only. • Fixed Firefox HTML5 client compatibility - it would request "Connection: Keep-Alive, Upgrade", not straight "Upgrade", and fail the upgrade check.
1 parent 14081a1 commit 148d27a

File tree

11 files changed

+94
-66
lines changed

11 files changed

+94
-66
lines changed

Lacewing/Lacewing.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,7 +1700,7 @@ struct relayclientinternal;
17001700
struct relayclient
17011701
{
17021702
public:
1703-
const static int buildnum = 100;
1703+
const static int buildnum = 101;
17041704

17051705
void * internaltag = nullptr, *tag = nullptr;
17061706

@@ -1924,7 +1924,7 @@ struct codepointsallowlist {
19241924
struct relayserverinternal;
19251925
struct relayserver
19261926
{
1927-
static const int buildnum = 33;
1927+
static const int buildnum = 34;
19281928

19291929
void * internaltag, * tag = nullptr;
19301930

Lacewing/src/openssl/sslclient.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ struct _lwp_sslclient
3333

3434
void * tag;
3535
lwp_sslclient_on_handshook on_handshook;
36+
lw_server_client client;
37+
void (*on_error)(lw_server_client client, lw_error error);
3638

3739
#ifdef _lacewing_npn
3840
unsigned char npn [32];
@@ -47,7 +49,7 @@ extern lw_streamdef def_downstream;
4749

4850
static void pumpclient (lwp_sslclient);
4951

50-
lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_stream socket,
52+
lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_server_client socket,
5153
lwp_sslclient_on_handshook on_handshook,
5254
void * tag)
5355
{
@@ -87,10 +89,10 @@ lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_stream socket,
8789
lwp_retain (&ctx->downstream, "lwp_sslclient downstream");
8890

8991
lw_stream_add_filter_upstream
90-
(socket, &ctx->upstream, lw_false, lw_false);
92+
((lw_stream)socket, &ctx->upstream, lw_false, lw_false);
9193

9294
lw_stream_add_filter_downstream
93-
(socket, &ctx->downstream, lw_false, lw_false);
95+
((lw_stream)socket, &ctx->downstream, lw_false, lw_false);
9496

9597
pumpclient (ctx);
9698

@@ -151,7 +153,12 @@ static size_t downstream_sink_data (lw_stream downstream,
151153

152154
if (bytes < 0)
153155
{
154-
always_log ("SSL downstream write error!");
156+
lw_error err = lw_error_new();
157+
lw_error_addf(err, "SSL downstream write error %d", SSL_get_error(ctx->ssl, bytes));
158+
159+
if (ctx->on_error)
160+
ctx->on_error(ctx->client, err);
161+
lw_error_delete (err);
155162

156163
lw_stream_close (&ctx->downstream, lw_true);
157164

@@ -195,8 +202,15 @@ static size_t upstream_sink_data (lw_stream upstream,
195202
{
196203
if (error == SSL_ERROR_WANT_READ)
197204
ctx->write_condition = error;
205+
else
206+
{
207+
lw_error err = lw_error_new();
208+
lw_error_addf(err, "SSL upstream write error %d", error);
198209

199-
always_log ("SSL upstream write error!");
210+
if (ctx->on_error)
211+
ctx->on_error(ctx->client, err);
212+
lw_error_delete(err);
213+
}
200214

201215
return 0;
202216
}

Lacewing/src/openssl/sslclient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ typedef struct _lwp_sslclient * lwp_sslclient;
1515

1616
typedef void (* lwp_sslclient_on_handshook) (lwp_sslclient, void * tag);
1717

18-
lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_stream socket,
18+
lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_server_client socket,
1919
lwp_sslclient_on_handshook, void * tag);
2020

2121
void lwp_sslclient_delete (lwp_sslclient);

Lacewing/src/stream.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,36 @@ size_t lwp_stream_write (lw_stream ctx, const char * buffer, size_t size, int fl
380380
}
381381
else
382382
{
383-
queue_back (ctx, buffer + written, size - written);
383+
#if _WIN32
384+
// Phi note 6th Jan 2023: queue_back() was indefinitely queued and wouldn't advance
385+
// for secure websockets on Windows.
386+
// Initial data - that is, the lacewing connect and response, including implementation, would work.
387+
// But after that, no server-sent messages would go through, and received client messages
388+
// would be received, but due to not processing and decrypting all the data prior, could not decrypt
389+
// properly.
390+
// Note the SECBUFFER_EXTRA data, which is initial TLS non-handshake data that is returned back by
391+
// the handshake func, and is not yet decrypted, thus must be passed through to the encrypt func again;
392+
// this extra data triggers this if(), as not all data "written" to the TLS stream was passed through,
393+
// so written < size.
394+
// Since we were getting an infinite recursion where written == 0, I check written is > 0 first.
395+
// Fallback are queue_back(), which on Windows doesn't work and causes client to be kicked from timeout,
396+
// but is better than recurring to death.
397+
//
398+
399+
// loop around and pass again
400+
if (written > 0)
401+
{
402+
const size_t roundTwo = lwp_stream_write(ctx, buffer + written, size - written, flags);
403+
if (roundTwo < size - written)
404+
{
405+
always_log("Failed to loop around initial TLS data. Attempting to queue_back().");
406+
written -= roundTwo;
407+
queue_back(ctx, buffer + written, size - written);
408+
}
409+
}
410+
else // infinite loop of written == 0 is bad
411+
#endif // _WIN32
412+
queue_back(ctx, buffer + written, size - written);
384413
}
385414
}
386415

Lacewing/src/unix/server.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ struct _lw_server_client
7474
lw_server_client * elem;
7575
};
7676

77+
void on_ssl_error(lw_server_client client, lw_error error)
78+
{
79+
lw_error_addf(error, "SSL error");
80+
81+
if (client->server->on_error)
82+
client->server->on_error(client->server, error);
83+
84+
// SSL errors are generally unrecoverable
85+
lw_stream_close((lw_stream)client, lw_true);
86+
}
87+
7788
static lw_server_client lwp_server_client_new (lw_server ctx, lw_pump pump, int fd)
7889
{
7990
lw_server_client client = (lw_server_client)calloc (sizeof (*client), 1);
@@ -99,7 +110,7 @@ static lw_server_client lwp_server_client_new (lw_server ctx, lw_pump pump, int
99110

100111
if (ctx->ssl_context)
101112
{
102-
client->ssl = lwp_sslclient_new (ctx->ssl_context, (lw_stream) client,
113+
client->ssl = lwp_sslclient_new (ctx->ssl_context, client,
103114
on_ssl_handshook, client);
104115
}
105116

Lacewing/src/webserver/webserver.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,11 @@ size_t lw_webserver_sink_websocket(lw_ws webserver, lwp_ws_httpclient client, co
149149
// Packet is too small to necessitate a 2-byte size
150150
if (size < 2 + 4 + 126)
151151
{
152-
error = "message too small to be valid";
153-
errorCode = 1002;
154-
break;
152+
// Pretend we haven't read anything, so this header comes back, but with more data behind it
153+
// This is necessary due to Firefox sending big WS packets as one network packet with just WS header,
154+
// with next packet data.
155+
// TODO: Performance: WebSocket large packet processing will be faster if we actually store the read part here, like MessageReader does.
156+
return 0;
155157
}
156158

157159
packetLen = ntohs(*(unsigned short*)&data[0]);

Lacewing/src/windows/server.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,15 @@ void * lw_server_tag (lw_server ctx)
122122
{
123123
return ctx->tag;
124124
}
125-
void on_ssl_error (lw_server ctx, lw_stream client, lw_error error)
125+
void on_ssl_error (lw_server_client client, lw_error error)
126126
{
127-
lw_error_addf(error, "SSL client error");
128-
if (ctx->on_error)
129-
ctx->on_error(ctx, error);
127+
lw_error_addf(error, "SSL error");
128+
129+
if (client->server->on_error)
130+
client->server->on_error(client->server, error);
130131

131132
// SSL errors are generally unrecoverable
132-
lw_stream_close(client, lw_true);
133+
lw_stream_close((lw_stream)client, lw_true);
133134
}
134135

135136
lw_server_client lwp_server_client_new (lw_server ctx, SOCKET socket)
@@ -153,7 +154,6 @@ lw_server_client lwp_server_client_new (lw_server ctx, SOCKET socket)
153154
if (ctx->cert_loaded)
154155
{
155156
lwp_serverssl_init (&client->ssl, ctx->ssl_creds, client);
156-
client->ssl.ssl.server = ctx;
157157
client->ssl.ssl.handle_error = on_ssl_error;
158158
}
159159

Lacewing/src/windows/ssl/serverssl.c

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,6 @@
1313
#include "serverssl.h"
1414
#include "../fdstream.h"
1515

16-
// TODO: These fake structs are a hack to get around the otherwise opaque pointers, to get the error handler
17-
// Can't clone the handler's address, in case it's changed; can copy server, though, but can't get the handler from that
18-
// Maybe an extra internal function
19-
20-
struct _lw_server_fake
21-
{
22-
lwp_refcounted;
23-
24-
SOCKET socket;
25-
26-
lw_pump pump;
27-
lw_pump_watch pump_watch;
28-
29-
lw_server_hook_connect on_connect;
30-
lw_server_hook_disconnect on_disconnect;
31-
lw_server_hook_data on_data;
32-
lw_server_hook_error on_error;
33-
// ... not the real struct, which is defined in a .c file
34-
};
35-
struct _lw_server_client_fake
36-
{
37-
struct _lw_fdstream fdstream;
38-
39-
struct _lw_server_fake* server;
40-
// ... not the real struct, which is defined in a .c file
41-
};
4216
static size_t proc_handshake_data (lwp_ssl ssl, const char * buffer, size_t size);
4317

4418
void lwp_serverssl_init (lwp_serverssl ctx,
@@ -47,7 +21,7 @@ void lwp_serverssl_init (lwp_serverssl ctx,
4721
{
4822
ctx->server_creds = server_creds;
4923
ctx->socket = socket;
50-
lwp_ssl_init (&ctx->ssl, (lw_stream) socket);
24+
lwp_ssl_init (&ctx->ssl, socket);
5125

5226
ctx->ssl.proc_handshake_data = proc_handshake_data;
5327
}
@@ -124,13 +98,11 @@ size_t proc_handshake_data (lwp_ssl ssl, const char * buffer, size_t size)
12498
lw_error_add(error, GetLastError() );
12599
lw_error_addf(error, "Secure handshake failure");
126100

127-
struct _lw_server_client_fake* sock = (struct _lw_server_client_fake *)ctx->socket;
128-
if (sock->server->on_error)
129-
sock->server->on_error((lw_server)sock->server, error);
101+
if (ctx->ssl.handle_error)
102+
ctx->ssl.handle_error(ctx->socket, error);
130103

131104
lw_error_delete(error);
132105

133-
lw_stream_close(&sock->fdstream.stream, lw_false);
134106
return size;
135107
}
136108

Lacewing/src/windows/ssl/ssl.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static size_t def_upstream_sink_data (lw_stream upstream,
5555
lw_error_add(err, status);
5656
lw_error_addf(err, "Encrypting message failed");
5757
if (ctx->handle_error)
58-
ctx->handle_error(ctx->server, ctx->orig_stream, err);
58+
ctx->handle_error(ctx->client, err);
5959
lw_error_delete(err);
6060

6161
return size;
@@ -99,7 +99,7 @@ static size_t def_downstream_sink_data (lw_stream downstream,
9999
lw_error_add(err, ctx->status);
100100
lw_error_addf(err, "Secure handshake failure");
101101
if (ctx->handle_error)
102-
ctx->handle_error(ctx->server, ctx->orig_stream, err);
102+
ctx->handle_error(ctx->client, err);
103103
lw_error_delete(err);
104104
return size;
105105
}
@@ -142,7 +142,7 @@ size_t proc_message_data (lwp_ssl ctx, const char * buffer, size_t size)
142142
lw_error_add(err, ctx->status);
143143
lw_error_addf(err, "Secure content expired");
144144
if (ctx->handle_error)
145-
ctx->handle_error(ctx->server, ctx->orig_stream, err);
145+
ctx->handle_error(ctx->client, err);
146146
lw_error_delete(err);
147147
return size;
148148
}
@@ -173,7 +173,7 @@ size_t proc_message_data (lwp_ssl ctx, const char * buffer, size_t size)
173173
lw_error_add(err, ctx->status);
174174
lw_error_addf(err, "Error decrypting the message");
175175
if (ctx->handle_error)
176-
ctx->handle_error(ctx->server, ctx->orig_stream, err);
176+
ctx->handle_error(ctx->client, err);
177177
lw_error_delete(err);
178178
return size;
179179
}
@@ -231,7 +231,7 @@ const static lw_streamdef def_downstream =
231231
0 /* cleanup */
232232
};
233233

234-
void lwp_ssl_init (lwp_ssl ctx, lw_stream socket)
234+
void lwp_ssl_init (lwp_ssl ctx, lw_server_client socket)
235235
{
236236
memset (ctx, 0, sizeof (*ctx));
237237

Lacewing/src/windows/ssl/ssl.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
typedef struct _lwp_ssl
1717
{
1818
DWORD status;
19-
lw_server server;
20-
lw_stream orig_stream;
21-
void (*handle_error)(lw_server, lw_stream, lw_error);
19+
lw_server_client client;
20+
void (*handle_error)(lw_server_client, lw_error);
2221
lw_bool handshake_complete;
2322

2423
lw_bool got_context;
@@ -37,7 +36,7 @@ typedef struct _lwp_ssl
3736

3837
} * lwp_ssl;
3938

40-
void lwp_ssl_init (lwp_ssl, lw_stream socket);
39+
void lwp_ssl_init (lwp_ssl, lw_server_client socket);
4140
void lwp_ssl_cleanup (lwp_ssl);
4241

4342
#endif

0 commit comments

Comments
 (0)