31
31
32
32
#define MAX_PRINTF_LEN 64
33
33
34
- size_t webSocketSendFrameWindow (AsyncClient *client){
34
+ #define MAX_HEADER_SIZE 8
35
+
36
+ // Return a guess at the maximum packet size we can send
37
+ static size_t webSocketSendFrameWindow (AsyncClient *client){
35
38
if (!client->canSend ())
36
39
return 0 ;
37
40
size_t space = client->space ();
38
- if (space < 9 )
41
+ if (space <= MAX_HEADER_SIZE )
39
42
return 0 ;
40
- return space - 8 ;
43
+ // TODO - consider if we have enough contiguous RAM to allocate
44
+ return space - MAX_HEADER_SIZE;
45
+ }
46
+
47
+ static size_t webSocketHeaderLength (bool mask, size_t len) {
48
+ return ((len < 126 )?2 :4 ) + (mask * 4 );
41
49
}
42
50
43
- size_t webSocketSendFrame (AsyncClient *client, bool final , uint8_t opcode, bool mask, uint8_t *data , size_t len){
51
+ static size_t webSocketSendFrameHeader (AsyncClient *client, bool final , uint8_t opcode, uint8_t mask_buf[ 4 ] , size_t len){
44
52
if (!client->canSend ())
45
53
return 0 ;
46
- size_t space = client->space ();
47
- if (space < 2 )
48
- return 0 ;
49
- uint8_t mbuf[4 ] = {0 ,0 ,0 ,0 };
50
- uint8_t headLen = 2 ;
51
- if (len && mask){
52
- headLen += 4 ;
53
- mbuf[0 ] = rand () % 0xFF ;
54
- mbuf[1 ] = rand () % 0xFF ;
55
- mbuf[2 ] = rand () % 0xFF ;
56
- mbuf[3 ] = rand () % 0xFF ;
57
- }
58
- if (len > 125 )
59
- headLen += 2 ;
60
- if (space < headLen)
61
- return 0 ;
62
- space -= headLen;
63
54
64
- if (len > space) len = space;
55
+ uint8_t buf[8 ]; // header buffer
56
+ uint8_t headLen = webSocketHeaderLength (mask_buf != nullptr , len);
65
57
66
- uint8_t *buf = (uint8_t *)malloc (headLen);
67
- if (buf == NULL ){
68
- // os_printf("could not malloc %u bytes for frame header\n", headLen);
58
+ if (client->space () < headLen)
69
59
return 0 ;
70
- }
71
60
72
61
buf[0 ] = opcode & 0x0F ;
73
62
if (final )
@@ -79,33 +68,41 @@ size_t webSocketSendFrame(AsyncClient *client, bool final, uint8_t opcode, bool
79
68
buf[2 ] = (uint8_t )((len >> 8 ) & 0xFF );
80
69
buf[3 ] = (uint8_t )(len & 0xFF );
81
70
}
82
- if (len && mask ){
71
+ if (len && mask_buf ){
83
72
buf[1 ] |= 0x80 ;
84
- memcpy (buf + (headLen - 4 ), mbuf, 4 );
73
+
74
+ for (int i = 0 ; i < 4 ; ++i) {
75
+ buf[headLen-4 +i] = mask_buf[i] = rand () % 0xFF ;
76
+ }
85
77
}
86
- if (client->add ((const char *)buf, headLen) != headLen){
78
+
79
+ size_t sent = client->add ((const char *)buf, headLen);
80
+ if (sent != headLen){
87
81
// os_printf("error adding %lu header bytes\n", headLen);
88
- free (buf);
82
+ // we are in BIG trouble as we don't cache the headers...!
83
+ // TODO: might be better to close the connection here
84
+ }
85
+ return sent;
86
+ }
87
+
88
+ static size_t webSocketSendFrame (AsyncClient *client, bool final , uint8_t opcode, bool mask, uint8_t *data, size_t len){
89
+ uint8_t mbuf[4 ];
90
+ if (webSocketSendFrameHeader (client, final , opcode, mask ? mbuf : nullptr , len) == 0 ) {
89
91
return 0 ;
90
92
}
91
- free (buf);
92
93
94
+ size_t added = 0 ;
93
95
if (len){
96
+ // Apply the mask
94
97
if (len && mask){
95
98
size_t i;
96
99
for (i=0 ;i<len;i++)
97
100
data[i] = data[i] ^ mbuf[i%4 ];
98
- }
99
- if (client->add ((const char *)data, len) != len){
100
- // os_printf("error adding %lu data bytes\n", len);
101
- return 0 ;
102
- }
101
+ }
102
+ added = client->add ((const char *)data, len);
103
103
}
104
- if (!client->send ()){
105
- // os_printf("error sending frame: %lu\n", headLen+len);
106
- return 0 ;
107
- }
108
- return len;
104
+ client->send ();
105
+ return added;
109
106
}
110
107
111
108
@@ -159,6 +156,7 @@ class AsyncWebSocketControl {
159
156
160
157
AsyncWebSocketBasicMessage::AsyncWebSocketBasicMessage (const char * data, size_t len, uint8_t opcode, bool mask)
161
158
:_len(len)
159
+ ,_attempted(0 )
162
160
,_sent(0 )
163
161
,_ack(0 )
164
162
,_acked(0 )
@@ -177,6 +175,7 @@ AsyncWebSocketBasicMessage::AsyncWebSocketBasicMessage(const char * data, size_t
177
175
}
178
176
AsyncWebSocketBasicMessage::AsyncWebSocketBasicMessage (uint8_t opcode, bool mask)
179
177
:_len(0 )
178
+ ,_attempted(0 )
180
179
,_sent(0 )
181
180
,_ack(0 )
182
181
,_acked(0 )
@@ -215,6 +214,13 @@ AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() {
215
214
_status = WS_MSG_ERROR;
216
215
return 0 ;
217
216
}
217
+ if (_sent < _attempted) {
218
+ // Frame was truncated
219
+ size_t sent = client->write ((const char *)(_data + _sent), _attempted - _sent);
220
+ _ack += sent;
221
+ _sent += sent;
222
+ return sent;
223
+ }
218
224
219
225
size_t toSend = _len - _sent;
220
226
size_t window = webSocketSendFrameWindow (client);
@@ -223,8 +229,9 @@ AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() {
223
229
toSend = window;
224
230
}
225
231
232
+ _attempted += toSend;
226
233
_sent += toSend;
227
- _ack += toSend + ((toSend < 126 )? 2 : 4 ) + ( _mask * 4 );
234
+ _ack += toSend + webSocketHeaderLength ( _mask, toSend );
228
235
229
236
bool final = (_sent == _len);
230
237
uint8_t * dPtr = (uint8_t *)(_data + (_sent - toSend));
@@ -233,8 +240,9 @@ AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() {
233
240
size_t sent = webSocketSendFrame (client, final , opCode, _mask, dPtr, toSend);
234
241
_status = WS_MSG_SENDING;
235
242
if (toSend && sent != toSend){
236
- _sent -= (toSend - sent);
243
+ _attempted -= (toSend - sent);
237
244
_ack -= (toSend - sent);
245
+ // TODO - what if header never sent
238
246
}
239
247
return sent;
240
248
}
@@ -259,7 +267,8 @@ AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() {
259
267
260
268
261
269
AsyncWebSocketMultiMessage::AsyncWebSocketMultiMessage (AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask)
262
- :_sent(0 )
270
+ :_attempted(0 )
271
+ ,_sent(0 )
263
272
,_ack(0 )
264
273
,_acked(0 )
265
274
,_WSbuffer(std::move(buffer))
@@ -302,6 +311,13 @@ AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() {
302
311
// ets_printf("E: %u > %u\n", _sent, _len);
303
312
return 0 ;
304
313
}
314
+ if (_sent < _attempted) {
315
+ // Frame was truncated
316
+ size_t sent = client->write (_WSbuffer.data () + _sent, _attempted - _sent);
317
+ _ack += sent;
318
+ _sent += sent;
319
+ return sent;
320
+ }
305
321
306
322
size_t toSend = _WSbuffer.size () - _sent;
307
323
size_t window = webSocketSendFrameWindow (client);
@@ -310,8 +326,9 @@ AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() {
310
326
toSend = window;
311
327
}
312
328
329
+ _attempted += toSend;
313
330
_sent += toSend;
314
- _ack += toSend + ((toSend < 126 )? 2 : 4 ) + ( _mask * 4 );
331
+ _ack += toSend + webSocketHeaderLength ( _mask, toSend );
315
332
316
333
// ets_printf("W: %u %u\n", _sent - toSend, toSend);
317
334
@@ -325,6 +342,7 @@ AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() {
325
342
// ets_printf("E: %u != %u\n", toSend, sent);
326
343
_sent -= (toSend - sent);
327
344
_ack -= (toSend - sent);
345
+ // TODO - what if header never sent
328
346
}
329
347
// ets_printf("S: %u %u\n", _sent, sent);
330
348
return sent;
0 commit comments