/// <summary> /// Performs the actual writing of data to the socket. Used by all other Write* methods. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> to write the data to</param> /// <param name="bytes">The bytes to write to the socket</param> /// <param name="timeout">The socket write timeout value</param> /// <param name="tag">The tag that will identify the write operation (can be referenced in the socket's DidWrite event)</param> /// <param name="disconnectAfterWriting">Indicates if the server should disconnect the socket after writing the data</param> /// <param name="requestComplete">Indicates if the request is complete once the data is written</param> protected void FinalWrite(AsyncSocket socket, byte[] bytes, int timeout, long tag, bool disconnectAfterWriting, bool requestComplete) { Data data = new Data(bytes); Log(data); // give any custom readers the change to modify the output before we send it (especially useful for WebSockets that need to frame their data) if (this.requestReader != null) this.requestReader.BeforeResponse(ref bytes); // if we are done sending stuff back (all responses and callbacks), we need to initiate an orderly shutdown if (!disconnectAfterWriting && requestComplete) OrderlySocketShutdown(); // send the data socket.Write(bytes, timeout, tag); // if we are the ones disconnecting, do it now. (usually if we are sending back an error response) // if not, we can just leave the socket alone if (disconnectAfterWriting) { OnSocketUsageComplete(socket); socket.CloseAfterWriting(); } }
/// <summary> /// Handles the socket's DidRead event. /// Reads the HTTP headers and sends the handshake response. /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/>.</param> /// <param name="data">The data read.</param> /// <param name="tag">The tag identifying the read request.</param> void socket_DidRead(AsyncSocket sender, byte[] data, long tag) { // remove this event handler since we dont need it any more sender.DidRead -= new AsyncSocket.SocketDidRead(this.socket_DidRead); // handle any data that may already have been read by the MessageHandler byte[] previousBytes = (byte[])sender.Tag; if (previousBytes != null) this.requestBytes = previousBytes; sender.Tag = null; // append the new data to any already-read data (this cant really happen now that we updated to the 07 spec, but it doenst hurt anything) if (this.requestBytes != null) { byte[] tempBytes = new byte[this.requestBytes.Length + data.Length]; Array.Copy(this.requestBytes, tempBytes, this.requestBytes.Length); Array.Copy(data, 0, tempBytes, this.requestBytes.Length, data.Length); this.requestBytes = tempBytes; } else { this.requestBytes = data; } // check the handshake at this point so we know if we should be looking for the challenge bytes or not this.handshake = new Handshake(this.requestBytes, this.requestBytes.Length); // we could check the Sec-WebSocket-Origin here, but we really dont care where they are connecting from // calculate the handshake proof string key = handshake.Fields[HEADER_SEC_WEBSOCKET_KEY]; string concat = key + WEBSOCKET_GUID; byte[] keyBytes = Encoding.UTF8.GetBytes(concat); SHA1 sha1 = SHA1.Create(); byte[] sha1Bytes = sha1.ComputeHash(keyBytes); string accept = Convert.ToBase64String(sha1Bytes); // construct the handshake response string version = handshake.Fields[HEADER_SEC_WEBSOCKET_VERSION]; string protocol = handshake.Fields.ContainsKey(HEADER_SEC_WEBSOCKET_PROTOCOL) ? handshake.Fields[HEADER_SEC_WEBSOCKET_PROTOCOL] : null; string response = handshake.GetHostResponse(accept, version, protocol); byte[] byteResponse = Encoding.UTF8.GetBytes(response); // send the response sender.DidWrite += new AsyncSocket.SocketDidWrite(socket_DidWrite); sender.Write(byteResponse, 0, byteResponse.Length, -1, HANDSHAKE_RESPONSE_TAG); }