/// <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);
        }
Beispiel #6
0
 /// <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;
 }
Beispiel #8
0
 /// <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;
 }
Beispiel #9
0
        /// <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);
 }
Beispiel #12
0
        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 { }
        }
Beispiel #13
0
        /// <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;
        }
Beispiel #14
0
        // 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();
                }
            }
        }
Beispiel #15
0
        /// <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);
                }
            }
        }
Beispiel #16
0
        /// <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
        }
Beispiel #22
0
        /// <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);
        }
Beispiel #25
0
        /// <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);
            }
        }
Beispiel #27
0
        /// <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;
 }
Beispiel #29
0
        /// <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);
        }