Exemplo n.º 1
0
        /// <summary>
        /// A callback that gets invoked after we disconnect from the IPEndpoint.
        /// </summary>
        /// <param name="result"></param>
        private void DisconnectCallback(IAsyncResult result)
        {
            Promise <ISockNetChannel> promise = (Promise <ISockNetChannel>)result.AsyncState;

            try
            {
                Socket.EndDisconnect(result);

                if (TryFlaggingAs(ClientSockNetChannelState.Disconnected, ClientSockNetChannelState.Disconnecting))
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Disconnected from [{0}]", RemoteEndpoint);

                    stream.Close();

                    Pipe.HandleClosed();

                    promise.CreateFulfiller().Fulfill(this);
                }
                else
                {
                    promise.CreateFulfiller().Fulfill(new Exception("Unable to mark channel as disconnected. State was: " + State));
                }
            } catch (Exception e)
            {
                promise.CreateFulfiller().Fulfill(e);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Flushes this stream and clears any read pooled memory chunks.
        /// </summary>
        public void Flush()
        {
            lock (_syncRoot)
            {
                ValidateBuffer();

                MemoryChunkNode currentChunk = rootChunk;

                while (currentChunk != null)
                {
                    if (currentChunk.count > ReadPosition)
                    {
                        break;
                    }

                    if (currentChunk.pooledObject != null && currentChunk.pooledObject.RefCount.Decrement() < 1)
                    {
                        if (currentChunk.pooledObject.State == PooledObjectState.USED)
                        {
                            currentChunk.pooledObject.Return();
                        }
                        else
                        {
                            SockNetLogger.Log(SockNetLogger.LogLevel.WARN, this, "Potential resource leak found.");
                        }
                    }
                    rootChunk     = currentChunk.next;
                    ReadPosition -= currentChunk.count;
                    WritePosition = Math.Max(0, WritePosition - currentChunk.count);
                    currentChunk  = currentChunk.next;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// A callback that gets invoked after we bind.
        /// </summary>
        /// <param name="result"></param>
        private void AcceptCallback(IAsyncResult result)
        {
            if (!IsActive)
            {
                return;
            }

            Socket remoteSocket = null;

            try
            {
                remoteSocket = Socket.EndAccept(result);

                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Accepted connection from: [{0}]", remoteSocket.RemoteEndPoint);
            }
            finally
            {
                if (ServerSockNetChannelState.Bound.Equals(State))
                {
                    Socket.BeginAccept(new AsyncCallback(AcceptCallback), Socket);
                }
                else
                {
                    remoteSocket.Close();
                    remoteSocket = null;
                }
            }

            if (remoteSocket != null)
            {
                RemoteSockNetChannel channel = new RemoteSockNetChannel(this, remoteSocket, BufferPool, modules.Values);

                remoteChannels[channel.Id] = channel;
            }
        }
            /// <summary>
            /// Handles an incoming raw HTTP response.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="obj"></param>
            private void HandleIncomingResponse(ISockNetChannel channel, ref object obj)
            {
                if (!(obj is ChunkedBuffer))
                {
                    return;
                }

                ChunkedBuffer data = (ChunkedBuffer)obj;

                if (currentIncoming == null)
                {
                    currentIncoming = new HttpResponse(channel.BufferPool);
                }

                if (currentIncoming.Parse(data.Stream, channel.IsActive))
                {
                    if (SockNetLogger.DebugEnabled)
                    {
                        SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received HTTP Response: Command Line: [{0}], Body Size [{1}]", currentIncoming.CommandLine, currentIncoming.BodySize);
                    }

                    obj             = currentIncoming;
                    currentIncoming = null;
                }
            }
Exemplo n.º 5
0
        /// <summary>
        /// Binds to the configured endpoint and sets security variables.
        /// </summary>
        /// <param name="isSsl"></param>
        /// <param name="certificateValidationCallback"></param>
        /// <returns></returns>
        private Promise <ISockNetChannel> BindInternal(bool isSsl, X509Certificate serverCertificate, RemoteCertificateValidationCallback certificateValidationCallback)
        {
            Promise <ISockNetChannel> promise = new Promise <ISockNetChannel>();

            if (TryFlaggingAs(ServerSockNetChannelState.Binding, ServerSockNetChannelState.Closed))
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Binding to [{0}]...", bindEndpoint);

                this.IsSsl = isSsl;
                this.CertificateValidationCallback = certificateValidationCallback;
                this.ServerCertificate             = serverCertificate;

                Socket.Bind(bindEndpoint);
                Socket.Listen(backlog);

                this.State = ServerSockNetChannelState.Bound;

                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Bound to [{0}].", LocalEndpoint);

                Socket.BeginAccept(new AsyncCallback(AcceptCallback), Socket);

                promise.CreateFulfiller().Fulfill(this);
            }
            else
            {
                throw new Exception("The server is already bound.");
            }

            return(promise);
        }
Exemplo n.º 6
0
        /// <summary>
        /// A callback that gets invoked after we connect.
        /// </summary>
        /// <param name="result"></param>
        private void ConnectCallback(IAsyncResult result)
        {
            if (TryFlaggingAs(ClientSockNetChannelState.Connected, ClientSockNetChannelState.Connecting))
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Connected to [{0}].", connectEndpoint);

                Socket.EndConnect(result);

                // create inital fake promise fulfilment delegate
                Promise <ISockNetChannel> .OnFulfilledDelegate onFulfilled = new Promise <ISockNetChannel> .OnFulfilledDelegate(
                    (ISockNetChannel value, Exception e, Promise <ISockNetChannel> promise) => { });

                onFulfilled = (ISockNetChannel value, Exception e, Promise <ISockNetChannel> promise) =>
                {
                    promise.OnFulfilled = null;

                    Pipe.HandleOpened();

                    ((Promise <ISockNetChannel>)result.AsyncState).CreateFulfiller().Fulfill(this);
                };

                if (isSsl)
                {
                    AttachAsSslClient(certificateValidationCallback).OnFulfilled = onFulfilled;
                }
                else
                {
                    Attach().OnFulfilled = onFulfilled;
                }
            }
            else
            {
                throw new Exception("The client isn't connecting.");
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Handles incoming data.
        /// </summary>
        public void HandleIncomingData(ref object message)
        {
            lock (incomingHandlers)
            {
                foreach (IDelegateReference delegateRef in incomingHandlers)
                {
                    try
                    {
                        if (delegateRef != null && delegateRef.DelegateType.IsAssignableFrom(message.GetType()))
                        {
                            object[] args = new object[2]
                            {
                                parent,
                                message
                            };

                            delegateRef.Delegate.DynamicInvoke(args);
                            message = args[1];
                        }
                    }
                    catch (Exception e)
                    {
                        SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, parent, "Pipe incoming invokation failed on: " + delegateRef.Delegate.Target + "." + delegateRef.Delegate.Method, e);
                    }
                }
            }
        }
Exemplo n.º 8
0
        public void DebugLog()
        {
            lock (openedHandlers)
            {
                foreach (OnOpenedDelegate del in openedHandlers)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "OnOpen: " + del.Target + "." + del.Method);
                }
            }

            lock (closedHandlers)
            {
                foreach (OnClosedDelegate del in closedHandlers)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "OnClosed: " + del.Target + "." + del.Method);
                }
            }

            lock (incomingHandlers)
            {
                foreach (IDelegateReference del in incomingHandlers)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "OnIncoming: " + del.Delegate.Target + "." + del.Delegate.Method);
                }
            }

            lock (outgoingHandlers)
            {
                foreach (IDelegateReference del in outgoingHandlers)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "OnOutgoing: " + del.Delegate.Target + "." + del.Delegate.Method);
                }
            }
        }
            /// <summary>
            /// Handles incoming raw frames and translates them into WebSocketFrame(s)
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="request"></param>
            private void HandleIncomingFrames(ISockNetChannel channel, ref object data)
            {
                if (!(data is ChunkedBuffer))
                {
                    return;
                }

                ChunkedBuffer stream           = (ChunkedBuffer)data;
                long          startingPosition = stream.ReadPosition;

                try
                {
                    WebSocketFrame frame = WebSocketFrame.ParseFrame(stream.Stream);

                    if (combineContinuations)
                    {
                        if (frame.IsFinished)
                        {
                            UpdateContinuation(ref continuationFrame, frame);

                            data = continuationFrame;
                            continuationFrame = null;
                        }
                        else
                        {
                            UpdateContinuation(ref continuationFrame, frame);
                        }
                    }
                    else
                    {
                        data = frame;
                    }

                    if (SockNetLogger.DebugEnabled)
                    {
                        SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received WebSocket message. Size: {0}, Type: {1}, IsFinished: {2}", frame.Data.Length, Enum.GetName(typeof(WebSocketFrame.WebSocketFrameOperation), frame.Operation), frame.IsFinished);
                    }
                }
                catch (EndOfStreamException)
                {
                    // websocket frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (ArgumentOutOfRangeException)
                {
                    // websocket frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (Exception e)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Unable to parse web-socket request", e);

                    channel.Close();
                }
            }
Exemplo n.º 10
0
            /// <summary>
            /// Handles an incomming raw Gds message.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="obj"></param>
            public void HandleIncoming(ISockNetChannel channel, ref object obj)
            {
                if (!(obj is ChunkedBuffer))
                {
                    return;
                }

                ChunkedBuffer stream           = (ChunkedBuffer)obj;
                long          startingPosition = stream.ReadPosition;

                try
                {
                    GdsFrame frame = GdsFrame.ParseFrame(stream.Stream, channel.BufferPool);

                    if (combineChunks)
                    {
                        if (frame.IsComplete)
                        {
                            UpdateChunk(ref chunkedFrame, frame, channel);

                            obj          = chunkedFrame;
                            chunkedFrame = null;
                        }
                        else
                        {
                            UpdateChunk(ref chunkedFrame, frame, channel);
                        }
                    }
                    else
                    {
                        obj = frame;
                    }

                    if (SockNetLogger.DebugEnabled)
                    {
                        SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received Gds message. Body Size: {0}, Type: {1}, IsComplete: {2}", frame.Body.AvailableBytesToRead, Enum.GetName(typeof(GdsFrame.GdsFrameType), frame.Type), frame.IsComplete);
                    }
                }
                catch (EndOfStreamException)
                {
                    // frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (ArgumentOutOfRangeException)
                {
                    // frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (Exception e)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Unable to parse Gds message", e);
                }
            }
Exemplo n.º 11
0
            /// <summary>
            /// Handles the WebSocket handshake.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="request"></param>
            private void HandleHandshake(ISockNetChannel channel, ref HttpRequest request)
            {
                string connection  = request.Header["Connection"];
                string upgrade     = request.Header["Upgrade"];
                string securityKey = request.Header[WebSocketUtil.WebSocketKeyHeader];

                if (connection != null && upgrade != null && securityKey != null && "websocket".Equals(upgrade.Trim().ToLower()) && "upgrade".Equals(connection.Trim().ToLower()))
                {
                    string[] requestProtocols = request.Headers[WebSocketUtil.WebSocketProtocolHeader];

                    List <string> handledProtocols = new List <string>();
                    if (requestProtocols != null && protocolDelegate != null)
                    {
                        for (int i = 0; i < requestProtocols.Length; i++)
                        {
                            if (protocolDelegate(channel, requestProtocols[i]))
                            {
                                handledProtocols.Add(requestProtocols[i]);
                            }
                        }
                    }

                    HttpResponse response = new HttpResponse(channel.BufferPool)
                    {
                        Version = "HTTP/1.1",
                        Code    = "101",
                        Reason  = "Switching Protocols"
                    };
                    response.Header["Upgrade"]    = "websocket";
                    response.Header["Connection"] = "Upgrade";
                    response.Header[WebSocketUtil.WebSocketAcceptHeader]   = WebSocketUtil.GenerateAccept(securityKey);
                    response.Header[WebSocketUtil.WebSocketProtocolHeader] = string.Join(",", handledProtocols.ToArray());

                    channel.Send(response);

                    channel.RemoveModule(httpModule);

                    channel.Pipe.AddIncomingFirst <object>(HandleIncomingFrames);
                    channel.Pipe.AddOutgoingLast <object>(HandleOutgoingFrames);
                }
                else
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Expecting upgrade request.");

                    channel.Close();
                }
            }
Exemplo n.º 12
0
        /// <summary>
        /// Disconnects from the IPEndpoint.
        /// </summary>
        public Promise <ISockNetChannel> Disconnect()
        {
            Promise <ISockNetChannel> promise = new Promise <ISockNetChannel>();

            if (TryFlaggingAs(ClientSockNetChannelState.Disconnecting, ClientSockNetChannelState.Connected))
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Disconnecting from [{0}]...", RemoteEndpoint);

                Socket.Shutdown(SocketShutdown.Both);

                Socket.BeginDisconnect(true, new AsyncCallback(DisconnectCallback), promise);
            }
            else
            {
                promise.CreateFulfiller().Fulfill(this);
            }

            return(promise);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Closes this server.
        /// </summary>
        /// <returns></returns>
        public override Promise <ISockNetChannel> Close()
        {
            if (TryFlaggingAs(ServerSockNetChannelState.Closing, ServerSockNetChannelState.Bound))
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Unbinding from [{0}]...", LocalEndpoint);

                foreach (RemoteSockNetChannel remoteChannel in remoteChannels.Values)
                {
                    remoteChannel.Close().WaitForValue(TimeSpan.FromSeconds(5));
                }

                Socket.Close();

                this.State = ServerSockNetChannelState.Closed;

                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Not bound to [{0}].", bindEndpoint);
            }

            return(new Promise <ISockNetChannel>(this));
        }
Exemplo n.º 14
0
        /// <summary>
        /// Connects to the configured endpoint and sets security variables.
        /// </summary>
        /// <param name="isSsl"></param>
        /// <param name="certificateValidationCallback"></param>
        /// <returns></returns>
        private Promise <ISockNetChannel> Connect(bool isSsl, RemoteCertificateValidationCallback certificateValidationCallback)
        {
            Promise <ISockNetChannel> promise = new Promise <ISockNetChannel>();

            if (TryFlaggingAs(ClientSockNetChannelState.Connecting, ClientSockNetChannelState.Disconnected))
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Connecting to [{0}]...", connectEndpoint);

                this.isSsl = isSsl;
                this.certificateValidationCallback = certificateValidationCallback;

                Socket.BeginConnect((EndPoint)connectEndpoint, new AsyncCallback(ConnectCallback), promise);
            }
            else
            {
                throw new Exception("The client is already connected.");
            }

            return(promise);
        }
Exemplo n.º 15
0
 /// <summary>
 /// Handles opened channel.
 /// </summary>
 public void HandleClosed()
 {
     lock (closedHandlers)
     {
         foreach (OnClosedDelegate delegateRef in closedHandlers)
         {
             try
             {
                 if (delegateRef != null)
                 {
                     delegateRef(parent);
                 }
             }
             catch (Exception e)
             {
                 SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, parent, "Pipe closed invokation failed on: " + delegateRef.Target + "." + delegateRef.Method, e);
             }
         }
     }
 }
            /// <summary>
            /// Invoked on channel connect.
            /// </summary>
            /// <param name="channel"></param>
            public void OnConnected(ISockNetChannel channel)
            {
                SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Sending WebSocket upgrade request.");

                channel.Pipe.AddIncomingLast <HttpResponse>(HandleHandshake);

                HttpRequest request = new HttpRequest(channel.BufferPool)
                {
                    Action  = "GET",
                    Path    = path,
                    Version = "HTTP/1.1"
                };

                request.Header["Host"]       = hostname;
                request.Header["Upgrade"]    = "websocket";
                request.Header["Connection"] = "Upgrade";
                request.Header[WebSocketUtil.WebSocketKeyHeader]     = secKey;
                request.Header[WebSocketUtil.WebSocketVersionHeader] = "13";

                channel.Send(request);
            }
            /// <summary>
            /// Handles an outgoing HttpRequest and converts it to a raw buffer.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="obj"></param>
            private void HandleOutgoingRequest(ISockNetChannel channel, ref object obj)
            {
                if (!(obj is HttpRequest))
                {
                    return;
                }

                HttpRequest data = (HttpRequest)obj;

                if (SockNetLogger.DebugEnabled)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Sending HTTP Request: Command Line: [{0}], Body Size [{1}]", data.CommandLine, data.BodySize);
                }

                ChunkedBuffer buffer = new ChunkedBuffer(channel.BufferPool);

                data.Write(buffer.Stream);

                data.Dispose();

                obj = buffer;
            }
            /// <summary>
            /// Handles the WebSocket handshake.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="request"></param>
            private void HandleHandshake(ISockNetChannel channel, ref HttpResponse data)
            {
                if (expectedAccept.Equals(data.Header[WebSocketUtil.WebSocketAcceptHeader]))
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Established Web-Socket connection.");
                    channel.Pipe.RemoveIncoming <HttpResponse>(HandleHandshake);
                    channel.Pipe.AddIncomingFirst <object>(HandleIncomingFrames);
                    channel.Pipe.AddOutgoingLast <object>(HandleOutgoingFrames);

                    channel.RemoveModule(httpModule);

                    if (onWebSocketEstablished != null)
                    {
                        onWebSocketEstablished(channel);
                    }
                }
                else
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Web-Socket handshake incomplete.");

                    channel.Close();
                }
            }