public void SendMessage(WSAgent agent, OSD message, ThrottleCategory category) { byte[] messageData = Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(message)); byte[] data = BuildMessageBuffer_00(messageData, true); SendMessageData(agent, data, category); }
/// <summary> /// Process a reception conforming to rev 00 of the WebSocket spec /// </summary> /// <param name="agent"></param> /// <param name="socket"></param> /// <param name="remoteEndPoint"></param> /// <param name="args"></param> /// <returns></returns> private string HandleWebSocketReceive_00(WSAgent agent, Socket socket, IPEndPoint remoteEndPoint, SocketAsyncEventArgs args) { if (agent == null) { // m_log.Debug("Sending handshake response to " + remoteEndPoint); byte[] byteRequest = new byte[args.BytesTransferred]; Buffer.BlockCopy(args.Buffer, args.Offset, byteRequest, 0, args.BytesTransferred); // create the controlling agent for this new stream agent = new WSAgent(m_server, m_throttle, m_throttleRates, UUID.Random(), UUID.Random(), socket, false); m_clients.Add(agent.ID, remoteEndPoint, agent); // there are some fields in the header that we must extract the values of string requestString = Encoding.UTF8.GetString(byteRequest, 0, byteRequest.GetLength(0)); int originIndex = requestString.IndexOf("Origin: "); if (originIndex > 0) { // if the client specified an origin, we must echo it back in the response originIndex += 8; int originEnd = requestString.IndexOf('\r', originIndex); if (originEnd > 0) { m_webSocketOrigin = requestString.Substring(originIndex, originEnd - originIndex); } } // This is an initial handshake // Process the header and send the response byte[] response = BuildHandshake(byteRequest); SendMessageFinal(socket, response); // tell those who care that we are connected WebSocketClientConnectedEventHandler handler = Connected; if (handler != null) { handler(agent); } return(null); } // It is not the initial handshake so extract data from the header // and find the application data therein. int start = args.Offset; int end = start + args.BytesTransferred; if (args.Buffer[start] == 0 && args.Buffer[end - 1] == 0xff) { // we know about the spec rev0 character padding string dataString = Encoding.UTF8.GetString(args.Buffer, start + 1, end - start - 2); return(dataString); } else { m_log.Warn("Received message not conforming to rev 00 of the WebSocket specification"); } return(null); }
private void DataReceivedHandler(WSAgent agent, string data) { m_log.Debug("Agent from " + agent.Socket.RemoteEndPoint + " sent message \"" + data + "\""); OSDMap map = null; try { map = OSDParser.DeserializeJson(data) as OSDMap; } catch (Exception ex) { m_log.Error("Failed to deserialize message: " + ex.Message); } if (map != null) { string messageType = map["message"].AsString(); // TODO: Stuff incoming messages in a blocking queue instead of // directly firing the handler. Otherwise, our semaphore will // start blocking IOCP threads MessageEvents.BeginRaiseEvent(map, agent); } }
/// <summary> /// Fire the events registered for this message type asynchronously /// </summary> /// <param name="incomingMessage">The incoming message</param> internal void BeginRaiseEvent(OSDMap incomingMessage, WSAgent agent) { MessageCallback callback; if (m_eventTable.TryGetValue(incomingMessage["Type"].AsString(), out callback) && callback != null) { while (!m_eventPool.WaitOne(Simian.LONG_SLEEP_INTERVAL)) { m_scheduler.ThreadKeepAlive(); } MessageCallbackWrapper wrapper = new MessageCallbackWrapper { Callback = callback, Message = incomingMessage, Agent = agent }; m_scheduler.FireAndForget(MessageDelegate, wrapper); } else { m_log.Debug("No handler registered for message type \"" + incomingMessage["Type"].AsString() + "\""); } }
private void DisconnectedHandler(WSAgent agent) { m_log.Debug("Agent disconnected from " + agent.Socket.RemoteEndPoint); }
public void SendMessage(WSAgent agent, OSDMap message, ThrottleCategory category) { Server.SendMessage(agent, message, category); }
/// <summary> /// The WebSockets spec has been evolving. This routine processes data framing /// for verions 03 of the spec. /// </summary> /// <param name="agent"></param> /// <param name="socket"></param> /// <param name="remoteEndPoint"></param> /// <param name="args"></param> /// <returns></returns> private string HandleWebSocketReceive_03(WSAgent agent, Socket socket, IPEndPoint remoteEndPoint, SocketAsyncEventArgs args) { if (agent == null) { // m_log.Debug("Sending handshake response to " + remoteEndPoint); byte[] byteRequest = new byte[args.BytesTransferred]; Buffer.BlockCopy(args.Buffer, args.Offset, byteRequest, 0, args.BytesTransferred); // create the controlling agent for this new stream agent = new WSAgent(m_server, m_throttle, m_throttleRates, UUID.Random(), UUID.Random(), socket, false); m_clients.Add(agent.ID, remoteEndPoint, agent); // there are some fields in the header that we must extract the values of string requestString = Encoding.UTF8.GetString(byteRequest, 0, byteRequest.GetLength(0)); int originIndex = requestString.IndexOf("Origin: "); if (originIndex > 0) { // if the client specified an origin, we must echo it back in the response originIndex += 8; int originEnd = requestString.IndexOf('\r', originIndex); if (originEnd > 0) { m_webSocketOrigin = requestString.Substring(originIndex, originEnd - originIndex); } } // This is an initial handshake // Process the header and send the response byte[] response = BuildHandshake(byteRequest); SendMessageFinal(socket, response); // tell those who care that we are connected WebSocketClientConnectedEventHandler handler = Connected; if (handler != null) { handler(agent); } return(null); } // It is not the initial handshake so extract data from the header // and find the application data therein. int start = args.Offset; int end = start + args.BytesTransferred; bool headerMore = false; int headerOp = 0; int headerLen = 0; try { headerMore = (args.Buffer[start] & 0x80) != 0; headerOp = args.Buffer[start] & 0x0f; headerLen = args.Buffer[start + 1] & 0x7f; if (headerLen == 0x7e) { headerLen = (args.Buffer[start + 2] << 8) + args.Buffer[start + 3]; start += 2; } else { if (headerLen == 0x7f) { headerLen = args.Buffer[start + 2] << 24 + args.Buffer[start + 3] << 16 + args.Buffer[start + 4] << 8 + args.Buffer[start + 5]; start += 4; } } start += 2; } catch (Exception e) { // failure decoding the header (probably short) m_log.Warn("HandleWebSocketReceive: Failure parsing message header: " + e.ToString()); return(null); } if ((end - start) < headerLen) { // didn't receive enough data m_log.Warn("HandleWebSocketReceive: received less data than specified in length. Ignoring."); return(null); } // Opcode of '1' says 'close' if (headerOp == 1) { m_log.Warn("HandleWebSocketReceive: polite request to close connection"); // TODO: return(null); } // Opcode of '2' says 'ping' if (headerOp == 2) { byte[] pingResponse = GeneratePingResponse(); SendMessageFinal(socket, pingResponse); // The standard is undecided on whether a control message can also // include data. Here we presume not. return(null); } // TODO: someday do our own pings so we'll need to process pongs // if specified, remember the form of the data being received if (headerOp == 4) { agent.ReadingBinary = false; } if (headerOp == 5) { agent.ReadingBinary = true; } if (!agent.ReadingData) { // not yet reading data so initialize new buffers agent.ReadingData = true; agent.DataString = new StringBuilder(); agent.DataBinary = null; } if (agent.ReadingBinary) { // If binary, build up a buffer of the binary data int doffset = 0; if (agent.DataBinary == null) { agent.DataBinary = new byte[headerLen]; } else { byte[] temp = agent.DataBinary; doffset = temp.Length; agent.DataBinary = new byte[doffset + headerLen]; Buffer.BlockCopy(temp, 0, agent.DataBinary, 0, doffset); } Buffer.BlockCopy(args.Buffer, start, agent.DataBinary, doffset, headerLen); } else { // if just text, get the UTF8 characters into our growing string agent.DataString.Append(Encoding.UTF8.GetString(args.Buffer, start, headerLen)); } if (!headerMore) { // end of any fragmentation. no longer reading data agent.ReadingData = false; return(agent.DataString.ToString()); // Note the race condition here for the binary data. // Binary is not handled correctly as it can be immediately overwritten // by the next message. } // if this is part of a fragmented message, don't return any data this time return(null); }
private void SendMessageData(WSAgent agent, byte[] data, ThrottleCategory category) { // TODO: Throttling SendMessageFinal(agent.Socket, data); }
private string HandleWebSocketReceive(WSAgent agent, Socket socket, IPEndPoint remoteEndPoint, SocketAsyncEventArgs args) { if (agent == null) { //m_log.Debug("Sending handshake response to " + s.RemoteEndPoint); //string request = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred); agent = new WSAgent(m_server, m_throttle, m_throttleRates, UUID.Random(), UUID.Random(), socket, false); m_clients.Add(agent.ID, remoteEndPoint, agent); // This is an initial handshake byte[] response = BuildHandshake(); SendMessageFinal(socket, response); WebSocketClientConnectedEventHandler handler = Connected; if (handler != null) handler(agent); return null; } int start = args.Offset; int end = start + args.BytesTransferred; // If we are not already reading something, look for the start byte 0x00 if (!agent.ReadingData) { for (start = 0; start < end; start++) { if (args.Buffer[start] == 0x00) { agent.ReadingData = true; // We found the start byte and can now start reading agent.DataString = new StringBuilder(); start++; // Don't include the start byte in the string break; } } } if (agent.ReadingData) { bool endIsInThisBuffer = false; // Look for the end byte 0xFF for (int i = start; i < end; i++) { if (args.Buffer[i] == 0xFF) { // We found the ending byte endIsInThisBuffer = true; break; } } // Append this data into the string builder agent.DataString.Append(Encoding.UTF8.GetString(args.Buffer, start, end - start)); // The end is in this buffer, which means we can construct a message if (endIsInThisBuffer) { // We are no longer reading data agent.ReadingData = false; string data = agent.DataString.ToString(); agent.DataString = null; return data; } } return null; }
public void SendMessage(WSAgent agent, OSDMap message, ThrottleCategory category) { byte[] messageData = Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(message)); byte[] data = new byte[messageData.Length + 2]; // Start with 0x00 data[0] = 0x00; // Then the string Buffer.BlockCopy(messageData, 0, data, 1, messageData.Length); // End with 0xFF data[data.Length - 1] = 0xFF; SendMessageData(agent, data, category); }
/// <summary> /// Fire the events registered for this message type asynchronously /// </summary> /// <param name="incomingMessage">The incoming message</param> internal void BeginRaiseEvent(OSDMap incomingMessage, WSAgent agent) { MessageCallback callback; if (m_eventTable.TryGetValue(incomingMessage["Type"].AsString(), out callback) && callback != null) { while (!m_eventPool.WaitOne(Simian.LONG_SLEEP_INTERVAL)) m_scheduler.ThreadKeepAlive(); MessageCallbackWrapper wrapper = new MessageCallbackWrapper { Callback = callback, Message = incomingMessage, Agent = agent }; m_scheduler.FireAndForget(MessageDelegate, wrapper); } else { m_log.Debug("No handler registered for message type \"" + incomingMessage["Type"].AsString() + "\""); } }