Skip to content

Commit ad3fcd1

Browse files
committed
Fixed issue with WebSocket receive lock
1 parent 6647fec commit ad3fcd1

File tree

3 files changed

+139
-126
lines changed

3 files changed

+139
-126
lines changed

source/NetCoreServer/FileCache.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class FileCache
3434
/// <returns>'true' if the cache value was added, 'false' if the given key was not added</returns>
3535
public bool Add(string key, byte[] value, TimeSpan timeout = new TimeSpan())
3636
{
37-
lock(_lock)
37+
lock (_lock)
3838
{
3939
// Try to find and remove the previous key
4040
RemoveInternal(key);
@@ -90,7 +90,7 @@ public class FileCache
9090
/// <returns>'true' and cache value if the cache value was found, 'false' if the given key was not found</returns>
9191
public Tuple<bool, byte[]> Find(string key)
9292
{
93-
lock(_lock)
93+
lock (_lock)
9494
{
9595
// Try to find the given key
9696
if (!_entriesByKey.TryGetValue(key, out var cacheValue))
@@ -129,8 +129,10 @@ public Tuple<bool, byte[]> Find(string key, out DateTime timeout)
129129
/// <returns>'true' if the cache value was removed, 'false' if the given key was not found</returns>
130130
public bool Remove(string key)
131131
{
132-
lock(_lock)
132+
lock (_lock)
133+
{
133134
return RemoveInternal(key);
135+
}
134136
}
135137

136138
/// <summary>
@@ -152,7 +154,7 @@ public bool Remove(string key)
152154
if (!InsertPathInternal(path, prefix, timeout, handler))
153155
return false;
154156

155-
lock(_lock)
157+
lock (_lock)
156158
{
157159
// Update the cache entry
158160
if (timeout.Ticks > 0)
@@ -220,7 +222,7 @@ public bool RemovePath(string path)
220222
/// </summary>
221223
public void Clear()
222224
{
223-
lock(_lock)
225+
lock (_lock)
224226
{
225227
// Clear all cache entries
226228
_entriesByKey.Clear();
@@ -378,7 +380,7 @@ private bool InsertPathInternal(string path, string prefix, TimeSpan timeout, In
378380

379381
private bool RemovePathInternal(string path)
380382
{
381-
lock(_lock)
383+
lock (_lock)
382384
{
383385
// Try to find the given path
384386
if (!_pathsByKey.TryGetValue(path, out var cacheValue))

source/NetCoreServer/WebSocket.cs

Lines changed: 130 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public bool PerformClientUpgrade(HttpResponse response, Guid id)
108108
accept = true;
109109
}
110110
}
111-
111+
112112
// Failed to perform WebSocket handshake
113113
if (!accept || !connection || !upgrade)
114114
{
@@ -303,20 +303,10 @@ public void PrepareSendFrame(byte opcode, bool mask, byte[] buffer, long offset,
303303
/// <param name="size">Buffer size</param>
304304
public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
305305
{
306-
var index = 0;
307-
308-
// Clear received data after WebSocket frame was processed
309-
if (WsReceived)
306+
lock (WsReceiveLock)
310307
{
311-
WsReceived = false;
312-
WsHeaderSize = 0;
313-
WsPayloadSize = 0;
314-
WsReceiveBuffer.Clear();
315-
Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length);
316-
}
308+
var index = 0;
317309

318-
while (size > 0)
319-
{
320310
// Clear received data after WebSocket frame was processed
321311
if (WsReceived)
322312
{
@@ -327,32 +317,20 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
327317
Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length);
328318
}
329319

330-
// Prepare WebSocket frame opcode and mask flag
331-
if (WsReceiveBuffer.Count < 2)
320+
while (size > 0)
332321
{
333-
for (int i = 0; i < 2; ++i, ++index, --size)
322+
// Clear received data after WebSocket frame was processed
323+
if (WsReceived)
334324
{
335-
if (size == 0)
336-
return;
337-
WsReceiveBuffer.Add(buffer[offset + index]);
325+
WsReceived = false;
326+
WsHeaderSize = 0;
327+
WsPayloadSize = 0;
328+
WsReceiveBuffer.Clear();
329+
Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length);
338330
}
339-
}
340331

341-
byte opcode = (byte) (WsReceiveBuffer[0] & 0x0F);
342-
bool fin = ((WsReceiveBuffer[0] >> 7) & 0x01) != 0;
343-
bool mask = ((WsReceiveBuffer[1] >> 7) & 0x01) != 0;
344-
int payload = WsReceiveBuffer[1] & (~0x80);
345-
346-
// Prepare WebSocket frame size
347-
if (payload <= 125)
348-
{
349-
WsHeaderSize = 2 + (mask ? 4 : 0);
350-
WsPayloadSize = payload;
351-
WsReceiveBuffer.Capacity = WsHeaderSize + WsPayloadSize;
352-
}
353-
else if (payload == 126)
354-
{
355-
if (WsReceiveBuffer.Count < 4)
332+
// Prepare WebSocket frame opcode and mask flag
333+
if (WsReceiveBuffer.Count < 2)
356334
{
357335
for (int i = 0; i < 2; ++i, ++index, --size)
358336
{
@@ -362,83 +340,108 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
362340
}
363341
}
364342

365-
payload = ((WsReceiveBuffer[2] << 8) | (WsReceiveBuffer[3] << 0));
366-
WsHeaderSize = 4 + (mask ? 4 : 0);
367-
WsPayloadSize = payload;
343+
byte opcode = (byte) (WsReceiveBuffer[0] & 0x0F);
344+
bool fin = ((WsReceiveBuffer[0] >> 7) & 0x01) != 0;
345+
bool mask = ((WsReceiveBuffer[1] >> 7) & 0x01) != 0;
346+
int payload = WsReceiveBuffer[1] & (~0x80);
347+
348+
// Prepare WebSocket frame size
349+
if (payload <= 125)
350+
{
351+
WsHeaderSize = 2 + (mask ? 4 : 0);
352+
WsPayloadSize = payload;
368353
WsReceiveBuffer.Capacity = WsHeaderSize + WsPayloadSize;
369-
}
370-
else if (payload == 127)
371-
{
372-
if (WsReceiveBuffer.Count < 10)
354+
}
355+
else if (payload == 126)
373356
{
374-
for (int i = 0; i < 8; ++i, ++index, --size)
357+
if (WsReceiveBuffer.Count < 4)
375358
{
376-
if (size == 0)
377-
return;
378-
WsReceiveBuffer.Add(buffer[offset + index]);
359+
for (int i = 0; i < 2; ++i, ++index, --size)
360+
{
361+
if (size == 0)
362+
return;
363+
WsReceiveBuffer.Add(buffer[offset + index]);
364+
}
379365
}
366+
367+
payload = ((WsReceiveBuffer[2] << 8) | (WsReceiveBuffer[3] << 0));
368+
WsHeaderSize = 4 + (mask ? 4 : 0);
369+
WsPayloadSize = payload;
370+
WsReceiveBuffer.Capacity = WsHeaderSize + WsPayloadSize;
380371
}
372+
else if (payload == 127)
373+
{
374+
if (WsReceiveBuffer.Count < 10)
375+
{
376+
for (int i = 0; i < 8; ++i, ++index, --size)
377+
{
378+
if (size == 0)
379+
return;
380+
WsReceiveBuffer.Add(buffer[offset + index]);
381+
}
382+
}
381383

382-
payload = ((WsReceiveBuffer[2] << 56) | (WsReceiveBuffer[3] << 48) | (WsReceiveBuffer[4] << 40) | (WsReceiveBuffer[5] << 32) | (WsReceiveBuffer[6] << 24) | (WsReceiveBuffer[7] << 16) | (WsReceiveBuffer[8] << 8) | (WsReceiveBuffer[9] << 0));
383-
WsHeaderSize = 10 + (mask ? 4 : 0);
384-
WsPayloadSize = payload;
384+
payload = ((WsReceiveBuffer[2] << 56) | (WsReceiveBuffer[3] << 48) | (WsReceiveBuffer[4] << 40) | (WsReceiveBuffer[5] << 32) | (WsReceiveBuffer[6] << 24) | (WsReceiveBuffer[7] << 16) | (WsReceiveBuffer[8] << 8) | (WsReceiveBuffer[9] << 0));
385+
WsHeaderSize = 10 + (mask ? 4 : 0);
386+
WsPayloadSize = payload;
385387
WsReceiveBuffer.Capacity = WsHeaderSize + WsPayloadSize;
386-
}
388+
}
387389

388-
// Prepare WebSocket frame mask
389-
if (mask)
390-
{
391-
if (WsReceiveBuffer.Count < WsHeaderSize)
390+
// Prepare WebSocket frame mask
391+
if (mask)
392392
{
393-
for (int i = 0; i < 4; ++i, ++index, --size)
393+
if (WsReceiveBuffer.Count < WsHeaderSize)
394394
{
395-
if (size == 0)
396-
return;
397-
WsReceiveBuffer.Add(buffer[offset + index]);
398-
WsReceiveMask[i] = buffer[offset + index];
395+
for (int i = 0; i < 4; ++i, ++index, --size)
396+
{
397+
if (size == 0)
398+
return;
399+
WsReceiveBuffer.Add(buffer[offset + index]);
400+
WsReceiveMask[i] = buffer[offset + index];
401+
}
399402
}
400403
}
401-
}
402404

403-
int total = WsHeaderSize + WsPayloadSize;
404-
int length = Math.Min(total - WsReceiveBuffer.Count, (int)size);
405+
int total = WsHeaderSize + WsPayloadSize;
406+
int length = Math.Min(total - WsReceiveBuffer.Count, (int)size);
405407

406-
// Prepare WebSocket frame payload
407-
WsReceiveBuffer.AddRange(buffer[((int)offset + index)..((int)offset + index + length)]);
408-
index += length;
409-
size -= length;
408+
// Prepare WebSocket frame payload
409+
WsReceiveBuffer.AddRange(buffer[((int)offset + index)..((int)offset + index + length)]);
410+
index += length;
411+
size -= length;
410412

411-
// Process WebSocket frame
412-
if (WsReceiveBuffer.Count == total)
413-
{
414-
int bufferOffset = WsHeaderSize;
413+
// Process WebSocket frame
414+
if (WsReceiveBuffer.Count == total)
415+
{
416+
int bufferOffset = WsHeaderSize;
415417

416-
// Unmask WebSocket frame content
417-
if (mask)
418-
for (int i = 0; i < WsPayloadSize; ++i)
419-
WsReceiveBuffer[bufferOffset + i] ^= WsReceiveMask[i % 4];
418+
// Unmask WebSocket frame content
419+
if (mask)
420+
for (int i = 0; i < WsPayloadSize; ++i)
421+
WsReceiveBuffer[bufferOffset + i] ^= WsReceiveMask[i % 4];
420422

421-
WsReceived = true;
423+
WsReceived = true;
422424

423-
if ((opcode & WS_PING) == WS_PING)
424-
{
425-
// Call the WebSocket ping handler
426-
_wsHandler.OnWsPing(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
427-
}
428-
else if ((opcode & WS_PONG) == WS_PONG)
429-
{
430-
// Call the WebSocket pong handler
431-
_wsHandler.OnWsPong(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
432-
}
433-
else if ((opcode & WS_CLOSE) == WS_CLOSE)
434-
{
435-
// Call the WebSocket close handler
436-
_wsHandler.OnWsClose(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
437-
}
438-
else if (((opcode & WS_TEXT) == WS_TEXT) || ((opcode & WS_BINARY) == WS_BINARY))
439-
{
440-
// Call the WebSocket received handler
441-
_wsHandler.OnWsReceived(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
425+
if ((opcode & WS_PING) == WS_PING)
426+
{
427+
// Call the WebSocket ping handler
428+
_wsHandler.OnWsPing(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
429+
}
430+
else if ((opcode & WS_PONG) == WS_PONG)
431+
{
432+
// Call the WebSocket pong handler
433+
_wsHandler.OnWsPong(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
434+
}
435+
else if ((opcode & WS_CLOSE) == WS_CLOSE)
436+
{
437+
// Call the WebSocket close handler
438+
_wsHandler.OnWsClose(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
439+
}
440+
else if (((opcode & WS_TEXT) == WS_TEXT) || ((opcode & WS_BINARY) == WS_BINARY))
441+
{
442+
// Call the WebSocket received handler
443+
_wsHandler.OnWsReceived(WsReceiveBuffer.ToArray(), bufferOffset, WsPayloadSize);
444+
}
442445
}
443446
}
444447
}
@@ -449,42 +452,48 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
449452
/// </summary>
450453
public int RequiredReceiveFrameSize()
451454
{
452-
if (WsReceived)
453-
return 0;
455+
lock (WsReceiveLock)
456+
{
457+
if (WsReceived)
458+
return 0;
454459

455-
// Required WebSocket frame opcode and mask flag
456-
if (WsReceiveBuffer.Count < 2)
457-
return 2 - WsReceiveBuffer.Count;
460+
// Required WebSocket frame opcode and mask flag
461+
if (WsReceiveBuffer.Count < 2)
462+
return 2 - WsReceiveBuffer.Count;
458463

459-
bool mask = ((WsReceiveBuffer[1] >> 7) & 0x01) != 0;
460-
int payload = WsReceiveBuffer[1] & (~0x80);
464+
bool mask = ((WsReceiveBuffer[1] >> 7) & 0x01) != 0;
465+
int payload = WsReceiveBuffer[1] & (~0x80);
461466

462-
// Required WebSocket frame size
463-
if ((payload == 126) && (WsReceiveBuffer.Count < 4))
464-
return 4 - WsReceiveBuffer.Count;
465-
if ((payload == 127) && (WsReceiveBuffer.Count < 10))
466-
return 10 - WsReceiveBuffer.Count;
467+
// Required WebSocket frame size
468+
if ((payload == 126) && (WsReceiveBuffer.Count < 4))
469+
return 4 - WsReceiveBuffer.Count;
470+
if ((payload == 127) && (WsReceiveBuffer.Count < 10))
471+
return 10 - WsReceiveBuffer.Count;
467472

468-
// Required WebSocket frame mask
469-
if ((mask) && (WsReceiveBuffer.Count < WsHeaderSize))
470-
return WsHeaderSize - WsReceiveBuffer.Count;
473+
// Required WebSocket frame mask
474+
if ((mask) && (WsReceiveBuffer.Count < WsHeaderSize))
475+
return WsHeaderSize - WsReceiveBuffer.Count;
471476

472-
// Required WebSocket frame payload
473-
return WsHeaderSize + WsPayloadSize - WsReceiveBuffer.Count;
477+
// Required WebSocket frame payload
478+
return WsHeaderSize + WsPayloadSize - WsReceiveBuffer.Count;
479+
}
474480
}
475481

476482
/// <summary>
477483
/// Clear WebSocket send/receive buffers
478484
/// </summary>
479485
public void ClearWsBuffers()
480486
{
481-
WsReceived = false;
482-
WsHeaderSize = 0;
483-
WsPayloadSize = 0;
484-
WsReceiveBuffer.Clear();
485-
Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length);
487+
lock (WsReceiveLock)
488+
{
489+
WsReceived = false;
490+
WsHeaderSize = 0;
491+
WsPayloadSize = 0;
492+
WsReceiveBuffer.Clear();
493+
Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length);
494+
}
486495

487-
lock(WsSendLock)
496+
lock (WsSendLock)
488497
{
489498
WsSendBuffer.Clear();
490499
Array.Clear(WsSendMask, 0, WsSendMask.Length);
@@ -508,6 +517,10 @@ public void ClearWsBuffers()
508517
/// </summary>
509518
internal int WsPayloadSize;
510519

520+
/// <summary>
521+
/// Receive buffer lock
522+
/// </summary>
523+
internal readonly object WsReceiveLock = new object();
511524
/// <summary>
512525
/// Receive buffer
513526
/// </summary>
@@ -531,5 +544,3 @@ public void ClearWsBuffers()
531544
internal readonly byte[] WsSendMask = new byte[4];
532545
}
533546
}
534-
535-

source/NetCoreServer/WsClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class WsClient : HttpClient, IWebSocket
4343

4444
public long SendText(byte[] buffer, long offset, long size)
4545
{
46-
lock(WebSocket.WsSendLock)
46+
lock (WebSocket.WsSendLock)
4747
{
4848
WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, true, buffer, offset, size);
4949
return base.Send(WebSocket.WsSendBuffer.ToArray());

0 commit comments

Comments
 (0)