private Task OnConectionFrameReceivedImplAsync(WebSocketsFrame.OpCodes opCode, ref Message message) { WebSocketServer.WriteStatus(connectionType, $"Processing {opCode}, {message.GetPayloadLength()} bytes..."); switch (opCode) { case WebSocketsFrame.OpCodes.Binary: return(OnBinaryAsync(ref message)); case WebSocketsFrame.OpCodes.Text: return(OnTextAsync(ref message)); case WebSocketsFrame.OpCodes.Close: connection.Input.Complete(); // respond to a close in-kind (2-handed close) try { Closed?.Invoke(); } catch { } if (connection.Output.Writing.IsCompleted) { return(TaskResult.True); // already closed } return(SendAsync(WebSocketsFrame.OpCodes.Close, ref message)); case WebSocketsFrame.OpCodes.Ping: // by default, respond to a ping with a matching pong return(SendAsync(WebSocketsFrame.OpCodes.Pong, ref message)); // right back at you case WebSocketsFrame.OpCodes.Pong: return(TaskResult.True); default: return(TaskResult.True); } }
private async Task SendAsyncImpl <T>(WebSocketsFrame.OpCodes opCode, T message) where T : struct, IMessageWriter { //TODO: come up with a better way of getting ordered access to the socket var writeLock = GetWriteSemaphore(); bool haveLock = writeLock.Wait(0); if (!haveLock) { // try to acquire asynchronously instead, then await writeLock.WaitAsync(); } try { WebSocketServer.WriteStatus($"Writing {opCode} message..."); await WebSocketProtocol.WriteAsync(this, opCode, ref message); if (opCode == WebSocketsFrame.OpCodes.Close) { Close(); } } finally { writeLock.Release(); } }
internal static Task WriteAsync <T>(WebSocketConnection connection, WebSocketsFrame.OpCodes opCode, WebSocketsFrame.FrameFlags flags, ref T message) where T : struct, IMessageWriter { int payloadLength = message.GetPayloadLength(); var buffer = connection.Connection.Output.Alloc(MaxHeaderLength + payloadLength); int mask = connection.ConnectionType == ConnectionType.Client ? CreateMask() : 0; WriteFrameHeader(ref buffer, WebSocketsFrame.FrameFlags.IsFinal, opCode, payloadLength, mask); if (payloadLength != 0) { if (mask == 0) { message.WritePayload(buffer); } else { var payloadStart = buffer.AsReadableBuffer().End; message.WritePayload(buffer); var payload = buffer.AsReadableBuffer().Slice(payloadStart); // note that this is a different AsReadableBuffer; call twice is good WebSocketsFrame.ApplyMask(ref payload, mask); } } return(buffer.FlushAsync().AsTask()); }
private async Task SendAsyncImpl <T>(WebSocketsFrame.OpCodes opCode, T message, WebSocketsFrame.FrameFlags flags) where T : struct, IMessageWriter { //TODO: come up with a better way of getting ordered access to the socket var writeLock = GetWriteSemaphore(); bool haveLock = writeLock.Wait(0); if (!haveLock) { // try to acquire asynchronously instead, then await writeLock.WaitAsync(); } try { WebSocketServer.WriteStatus(ConnectionType, $"Writing {opCode} message ({message.GetPayloadLength()} bytes)..."); await WebSocketProtocol.WriteAsync(this, opCode, flags, ref message); if (opCode == WebSocketsFrame.OpCodes.Close) { connection.Output.Complete(); } } finally { writeLock.Release(); } }
internal Task SendAsync(WebSocketsFrame.OpCodes opCode, ref Message message, WebSocketsFrame.FrameFlags flags = WebSocketsFrame.FrameFlags.IsFinal) { if (connection.Output.Writing.IsCompleted) { throw new InvalidOperationException("Connection has been closed"); } return(SendAsyncImpl(opCode, message, flags)); }
private Task OnServerFrameReceivedImplAsync(WebSocketsFrame.OpCodes opCode, ref Message message, WebSocketServer server) { switch (opCode) { case WebSocketsFrame.OpCodes.Binary: return(server.OnBinaryAsync(this, ref message)); case WebSocketsFrame.OpCodes.Text: return(server.OnTextAsync(this, ref message)); } return(TaskResult.True); }
internal static Task WriteAsync <T>(WebSocketConnection connection, WebSocketsFrame.OpCodes opCode, ref T message) where T : struct, IMessageWriter { int payloadLength = message.GetTotalBytes(); var buffer = connection.Connection.Output.Alloc(MaxHeaderLength + payloadLength); WriteFrameHeader(ref buffer, WebSocketsFrame.FrameFlags.IsFinal, opCode, payloadLength, 0); if (payloadLength != 0) { message.Write(ref buffer); } return(buffer.FlushAsync()); }
internal WebSocketsFrame.OpCodes GetEffectiveOpCode(ref WebSocketsFrame frame) { if (frame.IsControlFrame) { // doesn't change state return(frame.OpCode); } var frameOpCode = frame.OpCode; // re-use the previous opcode if we are a continuation var result = frameOpCode == WebSocketsFrame.OpCodes.Continuation ? lastOpCode : frameOpCode; // if final, clear the opcode; otherwise: use what we thought of lastOpCode = frame.IsFinal ? WebSocketsFrame.OpCodes.Continuation : result; return(result); }
private async Task <int> BroadcastAsync <T>(WebSocketsFrame.OpCodes opCode, T message, Func <WebSocketConnection, bool> predicate) where T : struct, IMessageWriter { int count = 0; foreach (var pair in connections) { var conn = pair.Key; if (!conn.IsClosed && (predicate == null || predicate(conn))) { try { await conn.SendAsync <T>(opCode, ref message); count++; } catch { } // not really all that bothered - they just won't get counted } } return(count); }
private Task OnFrameReceivedImplAsync(WebSocketConnection connection, WebSocketsFrame.OpCodes opCode, ref Message message) { switch (opCode) { case WebSocketsFrame.OpCodes.Binary: return(OnBinaryAsync(connection, ref message)); case WebSocketsFrame.OpCodes.Text: return(OnTextAsync(connection, ref message)); case WebSocketsFrame.OpCodes.Close: return(OnCloseAsync(connection, ref message)); case WebSocketsFrame.OpCodes.Ping: return(OnPingAsync(connection, ref message)); case WebSocketsFrame.OpCodes.Pong: return(OnPongAsync(connection, ref message)); default: return(TaskResult.True); } }
internal Task SendAsync <T>(WebSocketsFrame.OpCodes opCode, ref T message, WebSocketsFrame.FrameFlags flags = WebSocketsFrame.FrameFlags.IsFinal) where T : struct, IMessageWriter { return(SendAsyncImpl(opCode, message, flags)); }
internal Task SendAsync <T>(WebSocketsFrame.OpCodes opCode, ref T message) where T : struct, IMessageWriter { CheckCanSend(); return(SendAsyncImpl(opCode, message)); }
private void Process(NetContext context, Connection connection, Stream stream, WebSocketsFrame.OpCodes opCode) { using (stream) { switch (opCode) { case WebSocketsFrame.OpCodes.Text: string s; if (stream == null || stream.Length == 0) { s = ""; } else { stream.Position = 0; using (var reader = new StreamReader(stream, Encoding.UTF8)) { s = reader.ReadToEnd(); } } context.Handler.OnReceived(connection, s); break; case WebSocketsFrame.OpCodes.Binary: byte[] blob; int len; if (stream == null || (len = ((int)stream.Length - (int)stream.Position)) == 0) { blob = new byte[0]; } else { blob = new byte[len]; byte[] buffer = null; try { buffer = context.GetBuffer(); int offset = 0, read; stream.Position = 0; while ((read = stream.Read(buffer, offset, Math.Min(len, buffer.Length))) > 0) { offset += read; len -= read; } if (len != 0) { throw new EndOfStreamException(); } } finally { context.Recycle(buffer); } } context.Handler.OnReceived(connection, blob); break; default: throw new InvalidOperationException(); } } }
internal static void WriteFrameHeader(ref WritableBuffer output, WebSocketsFrame.FrameFlags flags, WebSocketsFrame.OpCodes opCode, int payloadLength, int mask) { output.Ensure(MaxHeaderLength); int index = 0; var span = output.Buffer.Span; span[index++] = (byte)(((int)flags & 240) | ((int)opCode & 15)); if (payloadLength > ushort.MaxValue) { // write as a 64-bit length span[index++] = (byte)((mask != 0 ? 128 : 0) | 127); span.Slice(index).Write((uint)0); span.Slice(index + 4).Write(ToNetworkByteOrder((uint)payloadLength)); index += 8; } else if (payloadLength > 125) { // write as a 16-bit length span[index++] = (byte)((mask != 0 ? 128 : 0) | 126); span.Slice(index).Write(ToNetworkByteOrder((ushort)payloadLength)); index += 2; } else { // write in the header span[index++] = (byte)((mask != 0 ? 128 : 0) | payloadLength); } if (mask != 0) { span.Slice(index).Write(mask); index += 4; } output.Advance(index); }
internal Task SendAsync(WebSocketsFrame.OpCodes opCode, ref Message message) { CheckCanSend(); return(SendAsyncImpl(opCode, message)); }
internal static unsafe void WriteFrameHeader(ref WritableBuffer output, WebSocketsFrame.FrameFlags flags, WebSocketsFrame.OpCodes opCode, int payloadLength, int mask) { byte *buffer = (byte *)output.Memory.BufferPtr; int bytesWritten; *buffer++ = (byte)(((int)flags & 240) | ((int)opCode & 15)); if (payloadLength > ushort.MaxValue) { // write as a 64-bit length *buffer++ = (byte)((mask != 0 ? 128 : 0) | 127); *buffer++ = 0; *buffer++ = 0; *buffer++ = 0; *buffer++ = 0; *buffer++ = (byte)(payloadLength >> 24); *buffer++ = (byte)(payloadLength >> 16); *buffer++ = (byte)(payloadLength >> 8); *buffer++ = (byte)(payloadLength); bytesWritten = 10; } else if (payloadLength > 125) { // write as a 16-bit length *buffer++ = (byte)((mask != 0 ? 128 : 0) | 126); *buffer++ = (byte)(payloadLength >> 8); *buffer++ = (byte)(payloadLength); bytesWritten = 4; } else { // write in the header *buffer++ = (byte)((mask != 0 ? 128 : 0) | payloadLength); bytesWritten = 2; } if (mask != 0) { *buffer++ = (byte)(mask >> 24); *buffer++ = (byte)(mask >> 16); *buffer++ = (byte)(mask >> 8); *buffer++ = (byte)(mask); bytesWritten += 4; } output.CommitBytes(bytesWritten); }
private async Task OnServerAndConnectionFrameReceivedImplAsync(WebSocketsFrame.OpCodes opCode, Message message, WebSocketServer server) { await OnConectionFrameReceivedImplAsync(opCode, ref message); await OnServerFrameReceivedImplAsync(opCode, ref message, server); }