public async Task SendAsync(byte[] data, WebsockOpCode opcode = WebsockOpCode.Text) { WebsockFrame frame = new WebsockFrame(); frame.Fin = true; frame.Data = data; frame.Masked = true; frame.Opcode = opcode; byte[] frameData = frame.Dump(); await stream.WriteAsync(frameData, frameData.Length); }
// calculate the byte size of a frame for allocation private static UInt64 GetFrameSize(ref WebsockFrame frame) { UInt64 size = (UInt64)(2 + (frame.Masked ? 4 : 0) + frame.Data.Length); if (frame.Data.Length >= 126 && frame.Data.Length < 63336) { size += 2; } else if (frame.Data.Length >= 65536) { size += 8; } return(size); }
public async Task <byte[]> GetMessage() { int size = 0; byte[] buffer = new byte[2]; WebsockFrame frame = new WebsockFrame(); // read first byte of data buffer = await stream.ReadAsync(buffer.Length); frame.Fin = (buffer[0] & 0x80) != 0; // first bit frame.Rsv1 = (buffer[0] & 0x40) != 0; // second bit frame.Rsv2 = (buffer[0] & 0x20) != 0; // thrid bit frame.Rsv3 = (buffer[0] & 0x10) != 0; // fourth bit frame.Opcode = (WebsockOpCode)(buffer[0] & 0x0f); // fifth to eigth bits // read second byte of data frame.Masked = (buffer[1] & 0x80) != 0; // set second byte first bit size = (int)(buffer[1] & (~0x80)); // get deciding size // payload size is 64 bits long if (size == 127) { size = 0; buffer = new byte[8]; buffer = await stream.ReadAsync(buffer.Length); size |= (buffer[0] & 0xff) << 56; size |= (buffer[1] & 0xff) << 48; size |= (buffer[2] & 0xff) << 40; size |= (buffer[3] & 0xff) << 32; size |= (buffer[4] & 0xff) << 24; size |= (buffer[5] & 0xff) << 16; size |= (buffer[6] & 0xff) << 8; size |= (buffer[7] & 0xff) << 0; // payload size is 16 bits long } else if (size == 126) { size = 0; buffer = new byte[2]; buffer = await stream.ReadAsync(buffer.Length); size |= (buffer[0] & 0xff) << 8; size |= (buffer[1] & 0xff) << 0; } // read mask data if (frame.Masked) { frame.MaskingKey = new byte[4]; frame.MaskingKey = await stream.ReadAsync(frame.MaskingKey.Length); } // read payload data frame.Data = new byte[size]; frame.Data = await stream.ReadAsync(size); if (frame.Masked) { for (int i = 0; i < size; i++) { frame.Data[i] ^= frame.MaskingKey[i % 4]; } } // combine with continued data if (dataBuilder.Length > 0) { byte[] continued = dataBuilder.ToArray(); dataBuilder.SetLength(0); byte[] combined = new byte[continued.Length + frame.Data.Length]; Buffer.BlockCopy(continued, 0, combined, 0, continued.Length); Buffer.BlockCopy(frame.Data, 0, continued, continued.Length, frame.Data.Length); frame.Data = combined; } // build up fragmented frame & try again if (frame.Opcode == WebsockOpCode.Continue) { dataBuilder.Write(frame.Data, 0, frame.Data.Length); return(await GetMessage()); // echo back close data and close connection } else if (frame.Opcode == WebsockOpCode.Close) { await SendAsync(frame.Data, WebsockOpCode.Close); throw new WebsockCloseException(frame.Data); // perform ping callback that was queued up & try again } else if (frame.Opcode == WebsockOpCode.Pong) { await callbacks.Dequeue()(frame.Data); return(await GetMessage()); // frame is either Text or Binary, return data } else { return(frame.Data); } }