/// <summary> /// Reads the Flash policy request and returns the policy response if Flash requests are allowed. /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">The bytes read from the socket</param> /// <param name="tag">A tag identifying the read request</param> void ReadPolicyRequest(AsyncSocket sender, byte[] readBytes, long tag) { // remove this now that we are done with it this.socket.DidRead -= new AsyncSocket.SocketDidRead(ReadPolicyRequest); if (tag == FLASH_POLICY_REQUEST_TAG) { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); string request = this.AlreadyReceivedData.ToString(); if (request == FlashPolicy.REQUEST) { if (this.allowFlash) { this.socket.Write(FlashPolicy.ResponseBytes, TIMEOUT_FLASHPOLICYRESPONSE, FLASH_POLICY_RESPONSE_TAG); this.socket.CloseAfterWriting(); } else { OnError(ErrorCode.NOT_AUTHORIZED, ErrorDescription.BROWSER_CONNECTIONS_NOT_ALLOWED); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_REQUEST); } } }
/// <summary> /// Initializes a new instance of the <see cref="GNTPSocketReader"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPSocketReader(AsyncSocket socket, PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) { this.parser = new GNTPParser(passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo); parser.Error += new GNTPParser.GNTPParserErrorEventHandler(parser_Error); parser.MessageParsed += new GNTPParser.GNTPParserMessageParsedEventHandler(parser_MessageParsed); this.socket = socket; this.socket.Tag = parser; }
/// <summary> /// Initializes a new instance of the <see cref="GNTPWebSocketReader"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPWebSocketReader(AsyncSocket socket, PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) : base(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo) { this.allowed = allowBrowserConnections; parser = new GNTPParser2(passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo); parser.MessageParsed += new GNTPParser2.GNTPParserMessageParsedEventHandler(parser_MessageParsed); parser.Error += new GNTPParser2.GNTPParserErrorEventHandler(parser_Error); }
/// <summary> /// Writes an error response back to the original sender. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> used to write the response</param> /// <param name="error">The error</param> private void WriteError(AsyncSocket socket, Error error) { if (this.Error != null) { this.Error(error); } HeaderCollection headers = error.ToHeaders(); MessageBuilder mb = new MessageBuilder(ResponseType.ERROR); foreach (Header header in headers) { mb.AddHeader(header); } Write(socket, mb, TIMEOUT_ERROR_RESPONSE, RESPONSE_ERROR_TAG, true, true); }
/// <summary> /// Writes data to the specified socket. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> to write the data to</param> /// <param name="mb">The <see cref="MessageBuilder"/> containing the data to write</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 virtual void Write(AsyncSocket socket, MessageBuilder mb, int timeout, long tag, bool disconnectAfterWriting, bool requestComplete) { //Console.WriteLine(alreadyReceived.ToString()); byte[] bytes = mb.GetBytes(); mb = null; FinalWrite(socket, bytes, timeout, tag, disconnectAfterWriting, requestComplete); }
/// <summary> /// Called when a socket is done being used (for example, after all responses and callbacks /// have been returned to the caller). /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> that has completed</param> void mh_SocketUsageComplete(AsyncSocket socket) { if (this.connectedSockets.Contains(socket)) { this.connectedSockets[socket].SafeToDisconnect = true; } }
/// <summary> /// Initializes a new instance of the <see cref="GNTPFlashSocketReader"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> making the request</param> /// <param name="allowFlash">Indicates if Flash requests are allowed</param> public GNTPFlashSocketReader(AsyncSocket socket, bool allowFlash) { this.socket = socket; this.allowFlash = allowFlash; }
/// <summary> /// Initializes a new instance of the <see cref="WebSocketHandshakeHandler"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> making the connection</param> /// <param name="origin">The allowed origin of connections, or *.</param> /// <param name="location">The location of the WebSocket endpoint</param> public WebSocketHandshakeHandler(AsyncSocket socket, string origin, string location) { this.socket = socket; this.origin = origin; this.location = location; }
/// <summary> /// Handles the <see cref="AsyncSocket.DidAccept"/> event. /// </summary> /// <param name="sender">The listening <see cref="AsyncSocket"/></param> /// <param name="newSocket">The new <see cref="AsyncSocket"/> that was accepted</param> private void listenSocket_DidAccept(AsyncSocket sender, AsyncSocket newSocket) { LogInfo("Accepted client {0}:{1}", newSocket.RemoteAddress, newSocket.RemotePort); // check origin bool isLocal = IPAddress.IsLoopback(newSocket.RemoteAddress); bool isLAN = Growl.CoreLibrary.IPUtilities.IsInSameSubnet(newSocket.LocalAddress, newSocket.RemoteAddress); if (!this.allowNetworkNotifications && !isLocal) { // remote connections not allowed - Should we return a GNTP error response? i think this is better (no reply at all) LogInfo("Blocked network request from '{0}'", newSocket.RemoteAddress); newSocket.Close(); return; } bool passwordRequired = true; if (isLocal && !this.RequireLocalPassword) passwordRequired = false; else if (isLAN && !this.RequireLANPassword) passwordRequired = false; // SUPER IMPORTANT newSocket.AllowMultithreadedCallbacks = true; MessageHandler mh = new MessageHandler(this.serverName, this.passwordManager, passwordRequired, this.logFolder, this.loggingEnabled, this.allowNetworkNotifications, this.allowWebNotifications, this.allowSubscriptions); newSocket.DidClose += new AsyncSocket.SocketDidClose(newSocket_DidClose); mh.MessageParsed += new MessageHandler.MessageHandlerMessageParsedEventHandler(mh_MessageParsed); mh.Error += new MessageHandler.MessageHandlerErrorEventHandler(mh_Error); mh.SocketUsageComplete += new MessageHandler.MessageHandlerSocketUsageCompleteEventHandler(mh_SocketUsageComplete); // lock here since in very rare cases, we can get flooded with so many incoming sockets that // the Add() throws an IndexOutOfRange exception (only ever happened when running GrowlHammer with loads of // simultaneous connections) lock (syncLock) { connectedSockets.Add(new ConnectedSocket(newSocket)); connectedHandlers.Add(newSocket, mh); } mh.InitialRead(newSocket); }
/// <summary> /// Handles the socket's DidRead event. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> protected virtual void SocketDidRead(AsyncSocket socket, byte[] readBytes, long tag) { try { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); GNTPParser parser = (GNTPParser)socket.Tag; NextIndicator next = parser.Parse(readBytes); if (next.ShouldContinue) { if (next.UseBytes) socket.Read(next.Bytes, TIMEOUT_GNTP_HEADER, parser.Tag); else socket.Read(next.Length, TIMEOUT_GNTP_BINARY, parser.Tag); } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }
void SocketReadRemainder(AsyncSocket sender, byte[] data, long tag) { socket.Read(TIMEOUT_USAGECOMPLETE, USAGECOMPLETE_TAG); }
private void DoDidAccept(AsyncSocket newSocket) { // Threading Notes: // This method is called when using a SynchronizingObject or AppForms, // so method is executed on the same thread that the delegate is using. // Thus, the kClosed flag prevents any callbacks after the delegate calls the close method. if ((flags & kClosed) != 0) return; try { if (DidAccept != null) { DidAccept(this, newSocket); } } catch { } }
/// <summary> /// Allows invoke options to be inherited from another AsyncSocket. /// This is usefull when accepting connections. /// </summary> /// <param name="fromSocket"> /// AsyncSocket object to copy invoke options from. /// </param> protected void InheritInvokeOptions(AsyncSocket fromSocket) { // We set the MultiThreadedCallback property first, // as it has the potential to affect the other properties. AllowMultithreadedCallbacks = fromSocket.AllowMultithreadedCallbacks; AllowApplicationForms = fromSocket.AllowApplicationForms; SynchronizingObject = fromSocket.SynchronizingObject; }
// What is going on with the event handler methods below? // // The asynchronous nature of this class means that we're very multithreaded. // But the client may not be. The client may be using a SynchronizingObject, // or has requested we use application forms for invoking. // // A problem arises from this situation: // If a client calls the Disconnect method, then he/she does NOT // expect to receive any other delegate methods after the // call to Diconnect completes. // // Primitive invoking from a background thread will not solve this problem. // So what we do instead is invoke into the same thread as the client, // then check to make sure the socket hasn't been closed, // and then execute the delegate method. protected virtual void OnSocketDidAccept(AsyncSocket newSocket) { // SYNCHRONOUS // This allows the newly accepted socket to register to receive the DidConnect event. if (DidAccept != null) { if (synchronizingObject != null) { object[] args = { newSocket }; synchronizingObject.Invoke(new DoDidAcceptDelegate(DoDidAccept), args); } else if (allowApplicationForms) { System.Windows.Forms.Form appForm = GetApplicationForm(); if (appForm != null) { appForm.Invoke(new DoDidAcceptDelegate(DoDidAccept), newSocket); } } else if (allowMultithreadedCallbacks) { object[] delPlusArgs = { DidAccept, this, newSocket }; eventQueue.Enqueue(delPlusArgs); ProcessEvent(); } } }
/// <summary> /// Description forthcoming /// </summary> /// <param name="iar"></param> private void socket_DidAccept(IAsyncResult iar) { lock (lockObj) { if ((flags & kClosed) > 0) return; try { Socket socket = (Socket)iar.AsyncState; Socket newSocket = socket.EndAccept(iar); AsyncSocket newAsyncSocket = new AsyncSocket(); newAsyncSocket.InheritInvokeOptions(this); newAsyncSocket.PreConfigure(newSocket); OnSocketDidAccept(newAsyncSocket); newAsyncSocket.PostConfigure(); // And listen for more connections socket.BeginAccept(new AsyncCallback(socket_DidAccept), socket); } catch (Exception e) { CloseWithException(e); } } }
/// <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); }
/// <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> /// Called when the request is successfully parsed. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> that the request came in on</param> private void OnMessageParsed(AsyncSocket socket) { // handle request information this.requestInfo.ReceivedFrom = socket.RemoteAddress.ToString(); this.requestInfo.ReceivedBy = String.Format("{0} ({1})", Environment.MachineName, GrowlServer.ServerID); this.requestInfo.ReceivedWith = this.serverName; // see if this machine has already processed this notification // (this prevents endless loops caused by forwarding messages back to the original forwarder) bool alreadyProcessed = CheckAlreadyProcessed(); if (alreadyProcessed) { WriteError(socket, ErrorCode.ALREADY_PROCESSED, ErrorDescription.ALREADY_PROCESSED); return; } // handle callback information this.callbackInfo.Context = this.Request.CallbackContext; this.callbackInfo.MessageHandler = this; this.callbackInfo.RequestInfo = requestInfo; if (this.MessageParsed != null) { this.MessageParsed(this); } else { // no handler - return some kind of error? (this should never really happen) WriteError(socket, ErrorCode.INTERNAL_SERVER_ERROR, ErrorDescription.INTERNAL_SERVER_ERROR); } }
void SocketDoneWriting(AsyncSocket sender, long tag) { socket.DidWrite -= SocketDoneWriting; sender.DidReadTimeout -= socket_DidReadTimeout; socket.Shutdown(System.Net.Sockets.SocketShutdown.Send); socket.DidRead += new AsyncSocket.SocketDidRead(SocketReadRemainder); socket.DidClose += new AsyncSocket.SocketDidClose(SocketCloseAfterReadingRemainder); socket.Read(TIMEOUT_USAGECOMPLETE, USAGECOMPLETE_TAG); OnSocketUsageComplete(socket); }
public ConnectedSocket(AsyncSocket socket) { this.socket = socket; }
void SocketCloseAfterReadingRemainder(AsyncSocket sender) { socket.DidRead -= SocketReadRemainder; socket.DidClose -= SocketCloseAfterReadingRemainder; // the socket will actually be closed by AsyncSocket when it reads 0 bytes. // the GrowlServer class will be notified and can clean itself up as well }
/// <summary> /// Handles the socket's DidWrite event. /// Calls the callback. /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/>.</param> /// <param name="tag">The tag identifying the write request.</param> void socket_DidWrite(AsyncSocket sender, long tag) { // remove this since we dont need it any more sender.DidWrite -= new AsyncSocket.SocketDidWrite(socket_DidWrite); if (tag == HANDSHAKE_RESPONSE_TAG) { this.callback.BeginInvoke(null, null); } }
/// <summary> /// Called when the socket usage is complete (all responses and callbacks have /// been written). /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> used in the transaction</param> protected void OnSocketUsageComplete(AsyncSocket socket) { // TODO: temporarily removed while figuring out socket shutdown // // kick of one final read so we know when the socket closes // socket.Read(TIMEOUT_USAGECOMPLETE, USAGECOMPLETE_TAG); if (this.SocketUsageComplete != null) { this.SocketUsageComplete(socket); } }
/// <summary> /// Performs an initial read of the received data to see if it looks like a /// valid request. /// </summary> /// <param name="socket"><see cref="AsyncSocket"/></param> public void InitialRead(AsyncSocket socket) { this.socket = socket; socket.DidReadTimeout += new AsyncSocket.SocketDidReadTimeout(socket_DidReadTimeout); // log where this notification came from bool isLocal = System.Net.IPAddress.IsLoopback(socket.RemoteAddress); bool isLAN = Growl.CoreLibrary.IPUtilities.IsInSameSubnet(socket.LocalAddress, socket.RemoteAddress); this.requestInfo.SaveHandlingInfo(String.Format("Notification Origin: {0} [{1}]", socket.RemoteAddress.ToString(), (isLocal ? "LOCAL MACHINE" : (isLAN ? "LAN - same subnet" : "REMOTE NETWORK")))); // read the first 4 bytes so we know what kind of request this is (GNTP, GNTP over WebSocket, Flash Policy request, etc) socket.DidRead += new AsyncSocket.SocketDidRead(this.SocketDidReadIndicatorBytes); socket.Read(4, TIMEOUT_INITIALREAD, ACCEPT_TAG); }
/// <summary> /// Creates a new instance of the Growl server. /// </summary> /// <param name="port">The port to listen on. The standard GNTP port is <see cref="ConnectorBase.TCP_PORT"/>.</param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing the list of allowed passwords.</param> /// <param name="userFolder">The full path to the user folder where logs, resource cache, and other files will be stored.</param> public GrowlServer(int port, PasswordManager passwordManager, string userFolder) { // this will set the server name and version properly ServerName = serverName; this.port = (ushort) port; this.passwordManager = passwordManager; this.userFolder = userFolder; this.logFolder = PathUtility.Combine(userFolder, @"Log\"); PathUtility.EnsureDirectoryExists(this.logFolder); this.resourceFolder = PathUtility.Combine(userFolder, @"Resources\"); PathUtility.EnsureDirectoryExists(this.resourceFolder); this.listenSocket = new AsyncSocket(); this.listenSocket.AllowMultithreadedCallbacks = true; // VERY IMPORTANT: if we dont set this, async socket events will silently be swallowed by the AsyncSocket class listenSocket.DidAccept += new AsyncSocket.SocketDidAccept(listenSocket_DidAccept); //listenSocket.DidClose += new AsyncSocket.SocketDidClose(listenSocket_DidClose); // Initialize list to hold connected sockets // We support multiple concurrent connections connectedSockets = new ConnectedSocketCollection(); connectedHandlers = new Dictionary<AsyncSocket, MessageHandler>(); socketCleanupTimer = new System.Timers.Timer(30 * 1000); socketCleanupTimer.Elapsed += new System.Timers.ElapsedEventHandler(socketCleanupTimer_Elapsed); ResourceCache.ResourceFolder = this.resourceFolder; ResourceCache.Enabled = true; this.bonjour = new BonjourService(BonjourServiceName, BONJOUR_SERVICE_TYPE); }
/// <summary> /// Handles the socket's DidRead event after reading only the first four bytes of data. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> private void SocketDidReadIndicatorBytes(AsyncSocket socket, byte[] readBytes, long tag) { // remove this event handler since we dont need it any more socket.DidRead -= new AsyncSocket.SocketDidRead(this.SocketDidReadIndicatorBytes); Data data = new Data(readBytes); string s = data.ToString(); if (tag == ACCEPT_TAG) { if (s == FlashPolicy.REQUEST_INDICATOR) { GNTPFlashSocketReader gfsr = new GNTPFlashSocketReader(socket, allowBrowserConnections); gfsr.Read(readBytes); } else if (s == WebSocketHandshakeHandler.REQUEST_INDICATOR) { // this is a GNTP over WebSocket request, so we have to do the WebSocket handshake first socket.Tag = readBytes; WebSocketHandshakeHandler wshh = new WebSocketHandshakeHandler(socket, "*", "ws://localhost:23053"); wshh.DoHandshake(delegate() { // now pass off to the GNTPWebSocketReader (which is just a normal GNTPSocketReader that can deal with the WebSocket framing of packets) GNTPWebSocketReader gwsr = new GNTPWebSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gwsr; gwsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gwsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gwsr.Read(readBytes); }); } else { // this is a normal GNTP/TCP connection, so handle it as such GNTPSocketReader gsr = new GNTPSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gsr; gsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gsr.Read(readBytes); } } else { WriteError(socket, ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST); } }
/// <summary> /// Handles the <see cref="AsyncSocket.DidClose"/> event /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/> that disconnected</param> void newSocket_DidClose(AsyncSocket sender) { if (sender != null) { lock (syncLock) { if (sender != null) { if (this.connectedHandlers.ContainsKey(sender)) { MessageHandler mh = this.connectedHandlers[sender]; this.connectedHandlers.Remove(sender); if (this.connectedSockets.Contains(sender)) { ConnectedSocket cs = this.connectedSockets[sender]; this.connectedSockets.Remove(sender); if (cs.Socket != null) { cs.Socket.DidClose -= new AsyncSocket.SocketDidClose(newSocket_DidClose); //cs.Socket.DidRead -= new AsyncSocket.SocketDidRead(mh.SocketDidRead); } cs = null; } if (mh != null) { mh.MessageParsed -= new MessageHandler.MessageHandlerMessageParsedEventHandler(mh_MessageParsed); mh.Error -= new MessageHandler.MessageHandlerErrorEventHandler(mh_Error); mh.SocketUsageComplete -= new MessageHandler.MessageHandlerSocketUsageCompleteEventHandler(mh_SocketUsageComplete); } mh = null; } } } sender = null; } }
/// <summary> /// Handles the socket's <see cref="AsyncSocket.DidReadTimeout"/> event /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/></param> /// <returns>Always returns <c>true</c></returns> bool socket_DidReadTimeout(AsyncSocket sender) { sender.DidReadTimeout -= new AsyncSocket.SocketDidReadTimeout(socket_DidReadTimeout); WriteError(sender, ErrorCode.TIMED_OUT, ErrorDescription.TIMED_OUT); return true; }
/// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected void Dispose(bool disposing) { if (disposing) { try { Stop(); if (this.listenSocket != null) { this.listenSocket.DidAccept -= new AsyncSocket.SocketDidAccept(listenSocket_DidAccept); this.listenSocket = null; } if (this.socketCleanupTimer != null) { this.socketCleanupTimer.Elapsed -= new System.Timers.ElapsedEventHandler(socketCleanupTimer_Elapsed); this.socketCleanupTimer.Close(); this.socketCleanupTimer.Dispose(); this.socketCleanupTimer = null; } if (this.bonjour != null) { this.bonjour.Stop(); this.bonjour.Dispose(); this.bonjour = null; } } catch { // suppress } } }
/// <summary> /// Writes an error response back to the original sender. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/> used to write the response</param> /// <param name="errorCode">The error code</param> /// <param name="errorMessage">The error message</param> /// <param name="args">Any additional data to include in the error message</param> private void WriteError(AsyncSocket socket, int errorCode, string errorMessage, params object[] args) { if (args != null) { foreach (object arg in args) { errorMessage += String.Format(" ({0})", arg); } } Error error = new Error(errorCode, errorMessage); WriteError(socket, error); }