/// <summary>
        /// the filter that gets all disconnected event.
        /// </summary>
        /// <param name="obj">
        /// a TransportEvent object that contains the event to filt.
        /// </param>
        /// <returns>
        /// return a bool value that indicates whether the event is disconnected event.
        /// if true, the transport event is disconnected event; otherwise, return false.
        /// </returns>
        public bool FilterDisconnected(TransportEvent obj)
        {
            if (obj != null && obj.EventType == EventType.Disconnected)
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// filter the disconnected event from specified client.
        /// </summary>
        /// <param name="obj">
        /// a TransportEvent object that contains the event to filt.
        /// </param>
        /// <returns>
        /// if the disconnected event is from specified endpoint, return true; otherwise, false.
        /// </returns>
        public bool FilterEndPointDisconnected(TransportEvent obj)
        {
            if (obj == null || obj.EventType != EventType.Disconnected)
            {
                return false;
            }

            if (obj.EndPoint == null || !obj.EndPoint.Equals(this.endpoint))
            {
                return false;
            }

            return true;
        }
        /// <summary>
        /// add transport event to transport, TSD can invoke ExpectTransportEvent to get it.
        /// </summary>
        /// <param name="transportEvent">
        /// a TransportEvent object that contains the event to add to the queue
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the underlayer transport is null! the config for TransportStack is invalid.
        /// </exception>
        public virtual void AddEvent(TransportEvent transportEvent)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("TransportStack");
            }

            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "the underlayer transport is null! the config for TransportStack is invalid.");
            }

            this.transport.AddEvent(transportEvent);
        }
        /// <summary>
        /// add transport event to transport, TSD can invoke ExpectTransportEvent to get it.
        /// </summary>
        /// <param name="transportEvent">
        /// a TransportEvent object that contains the event to add to the queue
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportEvent is null
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the RemoteEndPoint of disconnected event is null
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the specified endpoint is not an IPEndPoint.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the connection specified by endpoint cannot be found!
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the connection specified by endpoint is null!
        /// </exception>
        public void AddEvent(TransportEvent transportEvent)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("TcpServerTransport");
            }

            if (transportEvent == null)
            {
                throw new ArgumentNullException("transportEvent");
            }

            if (transportEvent.EventType == EventType.Disconnected)
            {
                if (transportEvent.RemoteEndPoint == null)
                {
                    throw new InvalidOperationException("the RemoteEndPoint of disconnected event is null");
                }

                IPEndPoint endpoint = transportEvent.RemoteEndPoint as IPEndPoint;
                if (endpoint == null)
                {
                    throw new InvalidOperationException("the specified endpoint is not an IPEndPoint.");
                }

                if (!this.connections.ContainsKey(endpoint))
                {
                    throw new InvalidOperationException("the connection specified by endpoint cannot be found!");
                }

                TcpServerConnection connection = this.connections[endpoint];

                if (connection == null)
                {
                    throw new InvalidOperationException("the connection specified by endpoint is null!");
                }

                // if the disconnected event is triggered by server, skip it.
                if (connection.IsServerStopped)
                {
                    return;
                }
            }

            Utility.Enqueue(this.eventQueue, this.sequence, transportEvent);
        }
 /// <summary>
 /// Check if transportEvent is not null, and is not exception.
 /// </summary>
 /// <param name="transportEvent">An instance of TransportEvent to check.</param>
 /// <param name="expectedEventType">Expected event type, throw exception when not equal.</param>
 private void ValidateTransportEvent(TransportEvent transportEvent, EventType expectedEventType)
 {
     if (transportEvent == null)
     {
         throw new InvalidOperationException("Unknown object received from transport.");
     }
     if (transportEvent.EventType == EventType.Exception)
     {
         throw new InvalidOperationException(
             "Error occurred, please find details in innerException.",
             (Exception)transportEvent.EventObject);
     }
     if ((transportEvent.EventType & expectedEventType) == 0)
     {
         throw new InvalidOperationException(
             string.Format("{0} (unexpected) event received.", transportEvent.EventType));
     }
 }
        /// <summary>
        /// add transport event to transport, TSD can invoke ExpectTransportEvent to get it.
        /// </summary>
        /// <param name="transportEvent">
        /// a TransportEvent object that contains the event to add to the queue
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportEvent is null.
        /// </exception>
        public void AddEvent(TransportEvent transportEvent)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("StreamTransport");
            }

            if (transportEvent == null)
            {
                throw new ArgumentNullException("transportEvent");
            }

            this.eventQueue.Enqueue(transportEvent);
        }
        /// <summary>
        /// add transport event to transport, TSD can invoke ExpectTransportEvent to get it.
        /// </summary>
        /// <param name="transportEvent">
        /// a TransportEvent object that contains the event to add to the queue
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportEvent is null.
        /// </exception>
        public void AddEvent(TransportEvent transportEvent)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("UdpServerTransport");
            }

            if (transportEvent == null)
            {
                throw new ArgumentNullException("transportEvent");
            }

            this.eventQueue.Enqueue(transportEvent);

            this.buffer.Enqueue(new UdpReceivedBytes(null,
                transportEvent.RemoteEndPoint as IPEndPoint, transportEvent.LocalEndPoint as IPEndPoint));
        }
Пример #8
0
 /// <summary>
 /// enqueue the receivied transport event.<para/>
 /// add the transport event to the event queue, for user to expect specified event directly.<para/>
 /// add the transport event to data sequence, for user to expect any event(include received packet).<para/>
 /// it's thread-safe.
 /// </summary>
 /// <param name="eventQueue">
 /// a SyncFilterQueue&lt;TransportEvent&gt; that specifies the queue to store event.
 /// </param>
 /// <param name="sequence">
 /// a DataSequence object that stores the received data or event sequence.
 /// </param>
 /// <param name="transportEvent">
 /// a TransportEvent object that specifies the received event.
 /// </param>
 public static void Enqueue(SyncFilterQueue <TransportEvent> eventQueue, DataSequence sequence, TransportEvent transportEvent)
 {
     lock (eventQueue)
     {
         sequence.Add(transportEvent, new byte[0], null);
         eventQueue.Enqueue(transportEvent);
     }
 }
        /// <summary>
        /// Creates a new Socket for a newly created connection and  a new thread to receive packet in the loop.
        /// </summary>
        private void AcceptLoop()
        {
            while (!exitLoop)
            {
                if (this.receivingStreams.Count >= config.MaxConnections)
                {
                    // not listen untill the current connections are less than the max value.
                    // the interval to query is 1 seconds:
                    Thread.Sleep(1000);
                    continue;
                }

                Socket socket = null;
                try
                {
                    socket = this.listenSock.Accept();
                }
                catch (SocketException)
                {
                    exitLoop = true;
                    continue;
                }

                TransportEvent connectEvent;

                Stream receiveStream = null;
                Stream baseStream = new NetworkStream(socket);
                switch (streamType)
                {
                    case SecurityStreamType.None:
                        receiveStream = baseStream;
                        break;
                    case SecurityStreamType.Ssl:
                        receiveStream = new SslStream(
                            new ETWStream(
                            baseStream),
                            false
                            );
                        ((SslStream)receiveStream).AuthenticateAsServer(cert);
                        break;
                    case SecurityStreamType.CredSsp:
                        string targetSPN = ConstValue.CREDSSP_SERVER_NAME_PREFIX + config.LocalIpAddress;
                        RdpbcgrServerCredSspStream credSspStream = new RdpbcgrServerCredSspStream(new ETWStream(baseStream), targetSPN);
                        credSspStream.Authenticate(cert);
                        receiveStream = credSspStream;
                        break;
                    default:
                        receiveStream = baseStream;
                        break;
                }

                RdpbcgrReceiveThread receiveThread = new RdpbcgrReceiveThread(
                    socket.RemoteEndPoint,
                    this.packetQueue,
                    this.decoder,
                    receiveStream,
                    this.config.BufferSize,
                    this.rdpbcgrServer);

                connectEvent = new TransportEvent(EventType.Connected, socket.RemoteEndPoint, null);

                RdpbcgrServerSessionContext session = new RdpbcgrServerSessionContext();
                session.Identity = connectEvent.EndPoint;
                session.Server = this.rdpbcgrServer;
                session.LocalIdentity = socket.LocalEndPoint;
                session.IsClientToServerEncrypted = this.rdpbcgrServer.IsClientToServerEncrypted;
                this.rdpbcgrServer.ServerContext.AddSession(session);

                this.packetQueue.AddObject(connectEvent);

                lock (this.receivingStreams)
                {
                    this.receivingStreams.Add(socket, receiveThread);
                }

                receiveThread.Start();
            }
        }
 /// <summary>
 /// Add transport event to transport, TSD can invoke ExpectTransportEvent to get it.
 /// </summary>
 /// <param name="transportEvent">
 /// a TransportEvent object that contains the event to add to the queue
 /// </param>
 public void AddEvent(TransportEvent transportEvent)
 {
     this.packetQueue.AddObject(transportEvent);
 }
        /// <summary>
        /// Receive data, decode Packet and add them to QueueManager in the loop.
        /// </summary>
        private void ReceiveLoop()
        {
            StackPacket[] packets = null;
            ReceiveStatus receiveStatus = ReceiveStatus.Success;
            //object endPoint = null;
            int bytesRecv = 0;
            int leftCount = 0;
            int expectedLength = this.maxBufferSize;
            byte[] receivedCaches = new byte[0];

            while (!exitLoop)
            {
                if (expectedLength <= 0)
                {
                    expectedLength = this.maxBufferSize;
                }

                byte[] receivingBuffer = new byte[expectedLength];
                try
                {
                    bytesRecv = this.receiveStream.Read(receivingBuffer, 0, receivingBuffer.Length);

                    if (bytesRecv == 0)
                    {
                        receiveStatus = ReceiveStatus.Disconnected;
                    }
                    else
                    {
                        receiveStatus = ReceiveStatus.Success;
                    }
                }
                catch (System.IO.IOException)
                {
                    // If this is an IOException, treat it as a disconnection.
                    if (!exitLoop)
                    {
                        if (this.packetQueue != null)
                        {
                            TransportEvent exceptionEvent = new TransportEvent(EventType.Disconnected, this.endPointIdentity, null);
                            this.packetQueue.AddObject(exceptionEvent);
                            break;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (!exitLoop)
                    {
                        if (this.packetQueue != null)
                        {
                            TransportEvent exceptionEvent = new TransportEvent(EventType.Exception, this.endPointIdentity, e);
                            this.packetQueue.AddObject(exceptionEvent);
                            break;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                if (receiveStatus == ReceiveStatus.Success)
                {
                    byte[] data = new byte[bytesRecv + receivedCaches.Length];
                    Array.Copy(receivedCaches, data, receivedCaches.Length);
                    Array.Copy(receivingBuffer, 0, data, receivedCaches.Length, bytesRecv);
                    while (true)
                    {
                        int consumedLength;

                        try
                        {
                            packets = this.decoder(this.endPointIdentity, data, out consumedLength, out expectedLength);
                        }
                        catch (Exception e)
                        {
                            TransportEvent exceptionEvent = new TransportEvent(EventType.Exception, this.endPointIdentity, e);
                            this.packetQueue.AddObject(exceptionEvent);

                            // If decoder throw exception, we think decoder will throw exception again when it decode
                            // subsequent received data So here we terminate the receive thread.
                            return;
                        }

                        if (consumedLength > 0)
                        {
                            //add packet to queue
                            if (packets != null && packets.Length > 0)
                            {
                                AddPacketToQueueManager(this.endPointIdentity, packets);
                                bytesRecv = 0;
                                foreach (StackPacket pdu in packets)
                                {
                                    if (pdu.GetType() == typeof(Client_X_224_Connection_Request_Pdu))
                                    {
                                        // Block the thread if received a Client X224 Connection Request PDU
                                        // the main thread will resume the thread after it send X224 Connection confirm PDU and other necessary process, such as TLS Handshake
                                        rdpbcgrServer.ReceiveThreadControlEvent.WaitOne();
                                    }
                                }
                            }

                            //check if continue the decoding
                            leftCount = data.Length - consumedLength;
                            if (leftCount <= 0)
                            {
                                receivedCaches = new byte[0];
                                data = new byte[0];
                                break;
                            }
                            else
                            {
                                // Update caches contents to the bytes which is not consumed
                                receivedCaches = new byte[leftCount];
                                Array.Copy(data, consumedLength, receivedCaches, 0, leftCount);
                                data = new byte[receivedCaches.Length];
                                Array.Copy(receivedCaches, data, data.Length);
                            }
                        }
                        else
                        {
                            //if no data consumed, it means the left data cannot be decoded separately, so cache it and jump out.
                            receivedCaches = new byte[data.Length];
                            Array.Copy(data, receivedCaches, receivedCaches.Length);
                            break;
                        }
                    }
                }
                else if (receiveStatus == ReceiveStatus.Disconnected)
                {
                    if (this.packetQueue != null)
                    {
                        TransportEvent disconnectEvent = new TransportEvent(EventType.Disconnected, this.endPointIdentity, null);
                        this.packetQueue.AddObject(disconnectEvent);
                        break;
                    }
                    else
                    {
                        throw new InvalidOperationException("The transport is disconnected by remote host.");
                    }
                }
                else
                {
                    throw new InvalidOperationException("Unknown status returned from receiving method.");
                }
            }
        }
        /// <summary>
        /// Add the given stack packets to the QueueManager object if packet type not in filters or Customize filter.
        /// </summary>
        /// <param name="endPoint">the endpoint of the packets</param>
        /// <param name="packets">decoded packets</param>
        private void AddPacketToQueueManager(object endPoint, StackPacket[] packets)
        {
            if (packets == null)
            {
                return;
            }

            foreach (StackPacket packet in packets)
            {
                TransportEvent packetEvent = new TransportEvent(EventType.ReceivedPacket, endPoint, packet);
                this.packetQueue.AddObject(packetEvent);
            }
        }
        /// <summary>
        /// expect packet from transport.<para/>
        /// the transport must be a TcpServer or NetbiosServer.
        /// </summary>
        /// <param name="host">
        /// an IVisitorGetAnyPacket interface that specifies the host of visitor.
        /// </param>
        /// <param name="eventQueue">
        /// a SyncFilterQueue&lt;TransportEvent&gt; that specifies the queue to store event.
        /// </param>
        /// <param name="sequence">
        /// a DataSequence object that manages the sequence information of multiple clients.
        /// </param>
        /// <param name="timeout">
        /// a TimeSpan object that indicates the timeout to expect event.
        /// </param>
        /// <param name="skipEvent">
        /// a bool value that specifies whether skip the event.<para/>
        /// if true, just wait for packet coming; otherwise, both data and event will return.
        /// </param>
        /// <returns>
        /// a StackPacket object that specifies the received packet.<para/>
        /// if all buffer is closed in this while, and required to return if all buffer is closed, return null.<para/>
        /// otherwise never return null, if no packets coming in timespan, throw exception.
        /// </returns>
        public static TransportEvent Visit(
            IVisitorGetAnyData host,
            SyncFilterQueue <TransportEvent> eventQueue, DataSequence sequence, TimeSpan timeout, bool skipEvent)
        {
            // the end time for operation.
            DateTime endTime        = DateTime.Now + timeout;
            TimeSpan currentTimeout = timeout;

            while (true)
            {
                sequence.Reset();

                // try to decode packet from all clients in sequence.
                while (true)
                {
                    SequenceItem item = sequence.Next(TimeSpan.MinValue);

                    // all item in the sequences returned
                    if (item == null)
                    {
                        break;
                    }

                    TransportEvent transportEvent = item.Source as TransportEvent;

                    // if event arrived and donot skip the event, return the event directly.
                    if (transportEvent != null)
                    {
                        if (skipEvent)
                        {
                            continue;
                        }

                        sequence.Remove(transportEvent);
                        Utility.Remove(eventQueue, transportEvent);

                        return(transportEvent);
                    }

                    object remoteEndPoint;
                    object localEndPoint;

                    host.VisitorGetEndPoint(item.Source, out remoteEndPoint, out localEndPoint);

                    int         consumedLength = 0;
                    StackPacket packet         = null;

                    try
                    {
                        // set timeout to zero, must not wait for more data.
                        // if timeout, process next.
                        packet = host.VisitorDecodePackets(
                            item.Source, remoteEndPoint, localEndPoint, out consumedLength);

                        // remove the sequence information in data sequence.
                        sequence.Consume(item.Source, consumedLength);

                        if (packet != null)
                        {
                            TcpServerConnection connection = item.Source as TcpServerConnection;

                            if (connection != null)
                            {
                                return(connection.VisitorCreateTransportEvent(EventType.ReceivedPacket, packet));
                            }
                            else
                            {
                                return(new TransportEvent(EventType.ReceivedPacket, remoteEndPoint, localEndPoint, packet));
                            }
                        }
                    }
                    // skip timeout of any host.
                    catch (TimeoutException)
                    {
                    }
                }

                // waiting for next data coming.
                sequence.Next(currentTimeout);
                currentTimeout = endTime - DateTime.Now;
            }
        }