Esempio n. 1
0
        /// <summary>
        /// Shutdown everything TCP related
        /// </summary>
        internal static void Shutdown(int threadShutdownTimeoutMS = 1000)
        {
#if WINDOWS_PHONE
            try
            {
                CloseAndRemoveAllLocalConnectionListeners();
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "TCPCommsShutdownError");
            }
#else
            try
            {
                shutdownIncomingConnectionWorkerThread = true;

                CloseAndRemoveAllLocalConnectionListeners();

                //If the worker thread does not shutdown in the required time we kill it
                if (newIncomingConnectionWorker != null && !newIncomingConnectionWorker.Join(threadShutdownTimeoutMS))
                {
                    newIncomingConnectionWorker.Abort();
                }
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "TCPCommsShutdownError");
            }
            finally
            {
                shutdownIncomingConnectionWorkerThread = false;
            }
#endif
        }
Esempio n. 2
0
        /// <summary>
        /// Prevent any additional threads from starting and return once all existing workers have completed.
        /// </summary>
        /// <param name="threadShutdownTimeoutMS"></param>
        public void EndShutdown(int threadShutdownTimeoutMS = 1000)
        {
            List <Thread> allWorkerThreads = new List <Thread>();

            lock (SyncRoot)
            {
                foreach (var thread in threadDict)
                {
                    workerInfoDict[thread.Key].ThreadSignal.Set();
                    allWorkerThreads.Add(thread.Value);
                }
            }

            //Wait for all threads to finish
            foreach (Thread thread in allWorkerThreads)
            {
                try
                {
                    if (!thread.Join(threadShutdownTimeoutMS))
                    {
                        thread.Abort();
                    }
                }
                catch (Exception ex)
                {
                    NetworkComms.LogError(ex, "ManagedThreadPoolShutdownError");
                }
            }

            lock (SyncRoot)
            {
                jobQueue.Clear();
                shutdown = false;
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Shutdown everything UDP related
        /// </summary>
        internal static void Shutdown()
        {
            //Close any established udp listeners
            try
            {
                CloseAndRemoveAllLocalConnectionListeners();
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "UDPCommsShutdownError");
            }

            //reset the rouge senders to null so that it is recreated if we restart anything
            udpRogueSenders = new Dictionary <AddressFamily, UDPConnection>();
        }
Esempio n. 4
0
        /// <summary>
        /// A single static worker thread which keeps connections alive
        /// </summary>
        private static void ConnectionKeepAliveWorker()
        {
            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Debug("Connection keep alive polling thread has started.");
            }
            DateTime lastPollCheck = DateTime.Now;

            while (!shutdownWorkerThreads)
            {
                try
                {
                    //We have a short sleep here so that we can exit the thread fairly quickly if we need too
                    if (ConnectionKeepAlivePollIntervalSecs == int.MaxValue)
                    {
                        workedThreadSignal.WaitOne(5000);
                    }
                    else
                    {
                        workedThreadSignal.WaitOne(100);
                    }

                    //Check for shutdown here
                    if (shutdownWorkerThreads)
                    {
                        break;
                    }

                    //Any connections which we have not seen in the last poll interval get tested using a null packet
                    if (ConnectionKeepAlivePollIntervalSecs < int.MaxValue && (DateTime.Now - lastPollCheck).TotalSeconds > (double)ConnectionKeepAlivePollIntervalSecs)
                    {
                        AllConnectionsSendNullPacketKeepAlive();
                        lastPollCheck = DateTime.Now;
                    }
                }
                catch (Exception ex)
                {
                    NetworkComms.LogError(ex, "ConnectionKeepAlivePollError");
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Shutdown any static connection components
        /// </summary>
        /// <param name="threadShutdownTimeoutMS"></param>
        internal static void ShutdownBase(int threadShutdownTimeoutMS = 1000)
        {
            try
            {
                shutdownWorkerThreads = true;

                if (connectionKeepAliveWorker != null && !connectionKeepAliveWorker.Join(threadShutdownTimeoutMS))
                {
                    connectionKeepAliveWorker.Abort();
                }
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "CommsShutdownError");
            }
            finally
            {
                shutdownWorkerThreads = false;
                workedThreadSignal.Reset();
            }
        }
Esempio n. 6
0
 private static void newListenerInstance_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
 {
     try
     {
         var newConnectionInfo = new ConnectionInfo(true, ConnectionType.TCP, new IPEndPoint(IPAddress.Parse(args.Socket.Information.RemoteAddress.DisplayName.ToString()), int.Parse(args.Socket.Information.RemotePort)));
         TCPConnection.GetConnection(newConnectionInfo, NetworkComms.DefaultSendReceiveOptions, args.Socket, true);
     }
     catch (ConfirmationTimeoutException)
     {
         //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
     }
     catch (CommunicationException)
     {
         //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
     }
     catch (ConnectionSetupException)
     {
         //If we are the server end and we did not pick the incoming connection up then tooo bad!
     }
     catch (SocketException)
     {
         //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
     }
     catch (Exception ex)
     {
         //For some odd reason SocketExceptions don't always get caught above, so another check
         if (ex.GetBaseException().GetType() != typeof(SocketException))
         {
             //Can we catch the socketException by looking at the string error text?
             if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
             {
                 NetworkComms.LogError(ex, "ConnectionSetupError_SE");
             }
             else
             {
                 NetworkComms.LogError(ex, "ConnectionSetupError");
             }
         }
     }
 }
Esempio n. 7
0
        /// <summary>
        /// Incoming data listen sync method
        /// </summary>
        private void IncomingUDPPacketWorker()
        {
            try
            {
                while (true)
                {
                    if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                    {
                        break;
                    }

                    IPEndPoint endPoint      = new IPEndPoint(IPAddress.None, 0);
                    byte[]     receivedBytes = udpClientThreadSafe.Receive(ref endPoint);

                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace("Received " + receivedBytes.Length.ToString() + " bytes via UDP from " + endPoint.Address + ":" + endPoint.Port.ToString() + ".");
                    }

                    if (isIsolatedUDPConnection)
                    {
                        //This connection was created for a specific remoteEndPoint so we can handle the data internally
                        //Lock on the packetbuilder locker as we may recieve udp packets in parallel from this host
                        lock (packetBuilder.Locker)
                        {
                            packetBuilder.AddPartialPacket(receivedBytes.Length, receivedBytes);
                            if (packetBuilder.TotalBytesCached > 0)
                            {
                                IncomingPacketHandleHandOff(packetBuilder);
                            }
                        }
                    }
                    else
                    {
                        //Look for an existing connection, if one does not exist we will create it
                        //This ensures that all further processing knows about the correct endPoint
                        UDPConnection connection = GetConnection(new ConnectionInfo(true, ConnectionType.UDP, endPoint, udpClientThreadSafe.LocalEndPoint), ConnectionDefaultSendReceiveOptions, UDPOptions, false, this);

                        //Lock on the packetbuilder locker as we may recieve udp packets in parallel from this host
                        lock (connection.packetBuilder.Locker)
                        {
                            //We pass the data off to the specific connection
                            connection.packetBuilder.AddPartialPacket(receivedBytes.Length, receivedBytes);
                            if (connection.packetBuilder.TotalBytesCached > 0)
                            {
                                connection.IncomingPacketHandleHandOff(connection.packetBuilder);
                            }

                            if (connection.packetBuilder.TotalPartialPacketCount > 0)
                            {
                                connection.packetBuilder.ClearNTopBytes(connection.packetBuilder.TotalBytesCached);
                                //We cant close the connection here because it may be one of the shared udp listeners. For now we will just log.
                                NetworkComms.LogError(new Exception("Packet builder had remaining packets after a call to IncomingPacketHandleHandOff. Until sequenced packets are implemented this indicates a possible error."), "UDPConnectionError");
                            }
                        }
                    }
                }
            }
            //On any error here we close the connection
            catch (NullReferenceException)
            {
                CloseConnection(true, 20);
            }
            catch (ArgumentNullException)
            {
                CloseConnection(true, 37);
            }
            catch (IOException)
            {
                CloseConnection(true, 21);
            }
            catch (ObjectDisposedException)
            {
                CloseConnection(true, 22);
            }
            catch (SocketException)
            {
                //Recieve may throw a SocketException ErrorCode=10054  after attempting to send a datagram to an unreachable target.
                //We will try to get around this by ignoring the ICMP packet causing these problems on client creation
                CloseConnection(true, 23);
            }
            catch (InvalidOperationException)
            {
                CloseConnection(true, 24);
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "Error_UDPConnectionIncomingPacketHandler");
                CloseConnection(true, 41);
            }

            //Clear the listen thread object because the thread is about to end
            incomingDataListenThread = null;

            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Trace("Incoming data listen thread ending for " + ConnectionInfo);
            }
        }
Esempio n. 8
0
        void socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
            try
            {
                var stream     = args.GetDataStream().AsStreamForRead();
                var dataLength = args.GetDataReader().UnconsumedBufferLength;

                byte[] receivedBytes = new byte[dataLength];
                using (MemoryStream mem = new MemoryStream(receivedBytes))
                    stream.CopyTo(mem);

                stream = null;

                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Trace("Received " + receivedBytes.Length + " bytes via UDP from " + args.RemoteAddress + ":" + args.RemotePort + ".");
                }

                if (isIsolatedUDPConnection)
                {
                    //This connection was created for a specific remoteEndPoint so we can handle the data internally
                    //Lock on the packetbuilder locker as we may recieve udp packets in parallel from this host
                    lock (packetBuilder.Locker)
                    {
                        packetBuilder.AddPartialPacket(receivedBytes.Length, receivedBytes);
                        if (packetBuilder.TotalBytesCached > 0)
                        {
                            IncomingPacketHandleHandOff(packetBuilder);
                        }
                    }
                }
                else
                {
                    var remoteEndPoint = new IPEndPoint(IPAddress.Parse(args.RemoteAddress.DisplayName.ToString()), int.Parse(args.RemotePort));
                    var localEndPoint  = new IPEndPoint(IPAddress.Parse(sender.Information.LocalAddress.DisplayName.ToString()), int.Parse(sender.Information.LocalPort));

                    //Look for an existing connection, if one does not exist we will create it
                    //This ensures that all further processing knows about the correct endPoint
                    UDPConnection connection = GetConnection(new ConnectionInfo(true, ConnectionType.UDP, remoteEndPoint, localEndPoint), ConnectionDefaultSendReceiveOptions, UDPOptions, false, this);

                    //We pass the data off to the specific connection
                    //Lock on the packetbuilder locker as we may recieve udp packets in parallel from this host
                    lock (connection.packetBuilder.Locker)
                    {
                        connection.packetBuilder.AddPartialPacket(receivedBytes.Length, receivedBytes);
                        if (connection.packetBuilder.TotalBytesCached > 0)
                        {
                            connection.IncomingPacketHandleHandOff(connection.packetBuilder);
                        }

                        if (connection.packetBuilder.TotalPartialPacketCount > 0)
                        {
                            connection.packetBuilder.ClearNTopBytes(connection.packetBuilder.TotalBytesCached);
                            //We cant close the connection here because it may be one of the shared udp listeners. For now we will just log.
                            NetworkComms.LogError(new Exception("Packet builder had remaining packets after a call to IncomingPacketHandleHandOff. Until sequenced packets are implemented this indicates a possible error."), "UDPConnectionError");
                        }
                    }
                }
            }
            //On any error here we close the connection
            catch (NullReferenceException)
            {
                CloseConnection(true, 25);
            }
            catch (ArgumentNullException)
            {
                CloseConnection(true, 38);
            }
            catch (IOException)
            {
                CloseConnection(true, 26);
            }
            catch (ObjectDisposedException)
            {
                CloseConnection(true, 27);
            }
            catch (SocketException)
            {
                //Recieve may throw a SocketException ErrorCode=10054  after attempting to send a datagram to an unreachable target.
                //We will try to get around this by ignoring the ICMP packet causing these problems on client creation
                CloseConnection(true, 28);
            }
            catch (InvalidOperationException)
            {
                CloseConnection(true, 29);
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "Error_UDPConnectionIncomingPacketHandler");
                CloseConnection(true, 30);
            }
        }
        /// <summary>
        /// Trigger connection specific packet delegates with the provided parameters. Returns true if connection specific handlers were executed.
        /// </summary>
        /// <param name="packetHeader">The packetHeader for which all delegates should be triggered with</param>
        /// <param name="incomingObjectBytes">The serialised and or compressed bytes to be used</param>
        /// <param name="options">The incoming sendReceiveOptions to use overriding defaults</param>
        /// <returns>Returns true if connection specific handlers were executed.</returns>
        public bool TriggerSpecificPacketHandlers(PacketHeader packetHeader, MemoryStream incomingObjectBytes, SendReceiveOptions options)
        {
            try
            {
                if (packetHeader == null)
                {
                    throw new ArgumentNullException("packetHeader", "Provided PacketHeader cannot not be null.");
                }
                if (incomingObjectBytes == null)
                {
                    throw new ArgumentNullException("incomingObjectBytes", "Provided MemoryStream cannot not be null for packetType " + packetHeader.PacketType);
                }
                if (options == null)
                {
                    throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot not be null for packetType " + packetHeader.PacketType);
                }

                //We take a copy of the handlers list incase it is modified outside of the lock
                List <IPacketTypeHandlerDelegateWrapper> handlersCopy = null;
                lock (delegateLocker)
                    if (incomingPacketHandlers.ContainsKey(packetHeader.PacketType))
                    {
                        handlersCopy = new List <IPacketTypeHandlerDelegateWrapper>(incomingPacketHandlers[packetHeader.PacketType]);
                    }

                if (handlersCopy == null)
                {
                    //If we have received an unknown packet type we ignore them on this connection specific level and just finish here
                    return(false);
                }
                else
                {
                    //Idiot check
                    if (handlersCopy.Count == 0)
                    {
                        throw new PacketHandlerException("An entry exists in the packetHandlers list but it contains no elements. This should not be possible.");
                    }

                    //Deserialise the object only once
                    object returnObject = handlersCopy[0].DeSerialize(incomingObjectBytes, options);

                    //Pass the data onto the handler and move on.
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace(" ... passing completed data packet to selected connection specific handlers.");
                    }

                    //Pass the object to all necessary delgates
                    //We need to use a copy because we may modify the original delegate list during processing
                    foreach (IPacketTypeHandlerDelegateWrapper wrapper in handlersCopy)
                    {
                        try
                        {
                            wrapper.Process(packetHeader, this, returnObject);
                        }
                        catch (Exception ex)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Fatal("An unhandled exception was caught while processing a packet handler for a packet type '" + packetHeader.PacketType + "'. Make sure to catch errors in packet handlers. See error log file for more information.");
                            }
                            NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //If anything goes wrong here all we can really do is log the exception
                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Fatal("An exception occured in TriggerPacketHandler() for a packet type '" + packetHeader.PacketType + "'. See error log file for more information.");
                }
                NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType);
            }

            return(true);
        }
Esempio n. 10
0
        /// <summary>
        /// Sends a single object to the provided endPoint. NOTE: Any possible reply will be ignored unless listening for incoming udp packets.
        /// </summary>
        /// <param name="sendingPacketType">The sending packet type</param>
        /// <param name="objectToSend">The object to send</param>
        /// <param name="ipEndPoint">The destination IPEndPoint. Supports multicast endpoints.</param>
        /// <param name="sendReceiveOptions">The sendReceiveOptions to use for this send</param>
        public static void SendObject(string sendingPacketType, object objectToSend, IPEndPoint ipEndPoint, SendReceiveOptions sendReceiveOptions)
        {
            UDPConnection connectionToUse;

            lock (udpRogueSenderCreationLocker)
            {
                if (NetworkComms.commsShutdown)
                {
                    throw new CommunicationException("Attempting to send UDP packet but NetworkCommsDotNet is in the process of shutting down.");
                }
                else if (!udpRogueSenders.ContainsKey(ipEndPoint.AddressFamily) || udpRogueSenders[ipEndPoint.AddressFamily].ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                {
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace("Creating UDPRougeSender.");
                    }

                    IPAddress any;
                    if (ipEndPoint.AddressFamily == AddressFamily.InterNetwork)
                    {
                        any = IPAddress.Any;
                    }
                    else if (ipEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        any = IPAddress.IPv6Any;
                    }
                    else
                    {
                        throw new CommunicationException("Attempting to send UDP packet over unsupported network address family: " + ipEndPoint.AddressFamily.ToString());
                    }

                    udpRogueSenders[ipEndPoint.AddressFamily] = new UDPConnection(new ConnectionInfo(true, ConnectionType.UDP, new IPEndPoint(any, 0), new IPEndPoint(any, 0)), NetworkComms.DefaultSendReceiveOptions, UDPOptions.None, false);
                }

                //Get the rouge sender here
                connectionToUse = udpRogueSenders[ipEndPoint.AddressFamily];
            }

            //Get connection defaults if no sendReceiveOptions were provided
            if (sendReceiveOptions == null)
            {
                sendReceiveOptions = connectionToUse.ConnectionDefaultSendReceiveOptions;
            }

            //If we are listening on what will be the outgoing adaptor we send with that client to ensure reply packets are collected
            //Determining this is annoyingly non-trivial

            //For now we will use the following method and look to improve upon it in future
            //Some very quick testing gave an average runtime of this method to be 0.12ms (averageover 1000 iterations) (perhaps not so bad after all)
            try
            {
                IPEndPoint localEndPoint = NetworkComms.BestLocalEndPoint(ipEndPoint);

                lock (udpClientListenerLocker)
                {
                    IPEndPoint existingLocalEndPoint = ExistingLocalListenEndPoints(localEndPoint.Address);
                    if (existingLocalEndPoint != null)
                    {
                        connectionToUse = udpConnectionListeners[existingLocalEndPoint];
                    }
                }
            }
            catch (Exception ex)
            {
                //if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Failed to determine preferred existing udpClientListener to " + ipEndPoint.Address + ":" + ipEndPoint.Port + ". Will just use the rogue udp sender instead.");
                NetworkComms.LogError(ex, "BestLocalEndPointError");
            }

            using (Packet sendPacket = new Packet(sendingPacketType, objectToSend, sendReceiveOptions))
                connectionToUse.SendPacketSpecific(sendPacket, ipEndPoint);
        }
Esempio n. 11
0
        /// <summary>
        /// The worker object for the thread pool
        /// </summary>
        /// <param name="state"></param>
        private void ThreadWorker(object state)
        {
            WorkerInfo threadInfo = (WorkerInfo)state;

            do
            {
                //While there are jobs in the queue process the jobs
                while (true)
                {
                    if (threadInfo.CurrentCallBackWrapper == null)
                    {
                        KeyValuePair <QueueItemPriority, WaitCallBackWrapper> packetQueueItem;
                        lock (SyncRoot)
                        {
                            UpdateThreadWaitSleepJoinCountCache();
                            int numInJobActiveThreadsCount = Math.Max(0, threadDict.Count - CurrentNumWaitSleepJoinThreadsCache - requireJobThreadsCount);

                            if (shutdown || threadDict.Count > MaxTotalThreadsCount) //If we have too many active threads
                            {
                                //If shutdown was true then we may need to set thread to idle
                                if (threadInfo.ThreadIdle && requireJobThreadsCount > 0)
                                {
                                    requireJobThreadsCount--;
                                }

                                threadInfo.ClearThreadIdle();

                                threadDict.Remove(threadInfo.ThreadId);
                                workerInfoDict.Remove(threadInfo.ThreadId);

                                UpdateThreadWaitSleepJoinCountCache();
                                return;
                            }
                            else if (numInJobActiveThreadsCount > MaxActiveThreadsCount) //If we have too many active threads
                            {
                                //We wont close here to prevent thread creation/destruction thrashing.
                                //We will instead act as if there is no work and wait to potentially be timed out
                                if (!threadInfo.ThreadIdle)
                                {
                                    threadInfo.SetThreadIdle();
                                    requireJobThreadsCount++;
                                }

                                break;
                            }
                            else
                            {
                                //Try to get a job
                                if (!jobQueue.TryTake(out packetQueueItem)) //We fail to get a new job
                                {
                                    //If we failed to get a job we switch to idle and wait to be triggered
                                    if (!threadInfo.ThreadIdle)
                                    {
                                        threadInfo.SetThreadIdle();
                                        requireJobThreadsCount++;
                                    }

                                    break;
                                }
                                else
                                {
                                    if (threadInfo.ThreadIdle && requireJobThreadsCount > 0)
                                    {
                                        requireJobThreadsCount--;
                                    }

                                    threadInfo.UpdateCurrentCallBackWrapper(packetQueueItem.Value);
                                    threadInfo.ClearThreadIdle();
                                }
                            }
                        }
                    }

                    //Perform the waitcallBack
                    try
                    {
                        threadInfo.SetInsideCallBack();
                        threadInfo.CurrentCallBackWrapper.WaitCallBack(threadInfo.CurrentCallBackWrapper.State);
                    }
                    catch (Exception ex)
                    {
                        NetworkComms.LogError(ex, "ManagedThreadPoolCallBackError", "An unhandled exception was caught while processing a callback. Make sure to catch errors in callbacks to prevent this error file being produced.");
                    }
                    finally
                    {
                        threadInfo.ClearInsideCallBack();
                    }

                    threadInfo.UpdateLastActiveTime();
                    threadInfo.ClearCallBackWrapper();
                }

                //As soon as the queue is empty we wait until perhaps close time
                if (!threadInfo.ThreadSignal.WaitOne(250))
                {
                    //While we are waiting we check to see if we need to close
                    if (DateTime.Now - threadInfo.LastActiveTime > ThreadIdleTimeoutClose)
                    {
                        lock (SyncRoot)
                        {
                            //We have timed out but we don't go below the minimum
                            if (threadDict.Count > MinThreadsCount)
                            {
                                if (threadInfo.ThreadIdle && requireJobThreadsCount > 0)
                                {
                                    requireJobThreadsCount--;
                                }

                                threadInfo.ClearThreadIdle();

                                threadDict.Remove(threadInfo.ThreadId);
                                workerInfoDict.Remove(threadInfo.ThreadId);

                                UpdateThreadWaitSleepJoinCountCache();
                                return;
                            }
                        }
                    }
                }

                //We only leave via one of our possible breaks
            } while (true);
        }
Esempio n. 12
0
        /// <summary>
        /// Asynchronous incoming connection data delegate
        /// </summary>
        /// <param name="ar">The call back state object</param>
        void IncomingTCPPacketHandler(IAsyncResult ar)
        {
            //Initialised with true so that logic still works in WP8
            bool dataAvailable = true;

#if !WINDOWS_PHONE
            //Incoming data always gets handled in a timeCritical fashion at this point
            Thread.CurrentThread.Priority = NetworkComms.timeCriticalThreadPriority;
            //int bytesRead;
#endif

            try
            {
#if WINDOWS_PHONE
                var stream = ar.AsyncState as Stream;
                var count  = stream.EndRead(ar);
                totalBytesRead = count + totalBytesRead;
#else
                NetworkStream netStream = (NetworkStream)ar.AsyncState;
                if (!netStream.CanRead)
                {
                    throw new ObjectDisposedException("Unable to read from stream.");
                }

                totalBytesRead = netStream.EndRead(ar) + totalBytesRead;
                dataAvailable  = netStream.DataAvailable;
#endif
                if (totalBytesRead > 0)
                {
                    ConnectionInfo.UpdateLastTrafficTime();

                    //If we have read a single byte which is 0 and we are not expecting other data
                    if (totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
                    {
                        if (NetworkComms.LoggingEnabled)
                        {
                            NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandler() from " + ConnectionInfo + ". 1");
                        }
                    }
                    else
                    {
                        //if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder.");

                        //If there is more data to get then add it to the packets lists;
                        packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);

#if !WINDOWS_PHONE
                        //If we have more data we might as well continue reading syncronously
                        //In order to deal with data as soon as we think we have sufficient we will leave this loop
                        while (dataAvailable && packetBuilder.TotalBytesCached < packetBuilder.TotalBytesExpected)
                        {
                            int bufferOffset = 0;

                            //We need a buffer for our incoming data
                            //First we try to reuse a previous buffer
                            if (packetBuilder.TotalPartialPacketCount > 0 && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > 0)
                            {
                                dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref bufferOffset);
                            }
                            else
                            {
                                //If we have nothing to reuse we allocate a new buffer
                                dataBuffer = new byte[NetworkComms.ReceiveBufferSizeBytes];
                            }

                            totalBytesRead = netStream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;

                            if (totalBytesRead > 0)
                            {
                                ConnectionInfo.UpdateLastTrafficTime();

                                //If we have read a single byte which is 0 and we are not expecting other data
                                if (totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandler() from " + ConnectionInfo + ". 2");
                                    }
                                    //LastTrafficTime = DateTime.Now;
                                }
                                else
                                {
                                    //if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for connection with " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + "B, expecting " + packetBuilder.TotalBytesExpected.ToString() + "B.");
                                    packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);
                                    dataAvailable = netStream.DataAvailable;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
#endif
                    }
                }

                if (packetBuilder.TotalBytesCached > 0 && packetBuilder.TotalBytesCached >= packetBuilder.TotalBytesExpected)
                {
                    //Once we think we might have enough data we call the incoming packet handle handoff
                    //Should we have a complete packet this method will start the appriate task
                    //This method will now clear byes from the incoming packets if we have received something complete.
                    IncomingPacketHandleHandOff(packetBuilder);
                }

                if (totalBytesRead == 0 && (!dataAvailable || ConnectionInfo.ConnectionState == ConnectionState.Shutdown))
                {
                    CloseConnection(false, -2);
                }
                else
                {
                    //We need a buffer for our incoming data
                    //First we try to reuse a previous buffer
                    if (packetBuilder.TotalPartialPacketCount > 0 && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > 0)
                    {
                        dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref totalBytesRead);
                    }
                    else
                    {
                        //If we have nothing to reuse we allocate a new buffer
                        dataBuffer     = new byte[NetworkComms.ReceiveBufferSizeBytes];
                        totalBytesRead = 0;
                    }

#if WINDOWS_PHONE
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#else
                    netStream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, netStream);
#endif
                }
            }
            catch (IOException)
            {
                CloseConnection(true, 12);
            }
            catch (ObjectDisposedException)
            {
                CloseConnection(true, 13);
            }
            catch (SocketException)
            {
                CloseConnection(true, 14);
            }
            catch (InvalidOperationException)
            {
                CloseConnection(true, 15);
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "Error_TCPConnectionIncomingPacketHandler");
                CloseConnection(true, 31);
            }

#if !WINDOWS_PHONE
            Thread.CurrentThread.Priority = ThreadPriority.Normal;
#endif
        }
Esempio n. 13
0
        /// <summary>
        /// Synchronous incoming connection data worker
        /// </summary>
        void IncomingTCPDataSyncWorker()
        {
            bool dataAvailable = false;

            try
            {
                while (true)
                {
                    if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                    {
                        break;
                    }

                    int bufferOffset = 0;

                    //We need a buffer for our incoming data
                    //First we try to reuse a previous buffer
                    if (packetBuilder.TotalPartialPacketCount > 0 && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > 0)
                    {
                        dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref bufferOffset);
                    }
                    else
                    {
                        //If we have nothing to reuse we allocate a new buffer
                        dataBuffer = new byte[NetworkComms.ReceiveBufferSizeBytes];
                    }

                    //We block here until there is data to read
                    //When we read data we read until method returns or we fill the buffer length
                    totalBytesRead = tcpClientNetworkStream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;

                    //Check to see if there is more data ready to be read
                    dataAvailable = tcpClientNetworkStream.DataAvailable;

                    //If we read any data it gets handed off to the packetBuilder
                    if (totalBytesRead > 0)
                    {
                        ConnectionInfo.UpdateLastTrafficTime();

                        //If we have read a single byte which is 0 and we are not expecting other data
                        if (totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace(" ... null packet removed in IncomingDataSyncWorker() from " + ConnectionInfo + ".");
                            }
                        }
                        else
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for connection with " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + "B, expecting " + packetBuilder.TotalBytesExpected.ToString() + "B.");
                            }

                            packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);
                        }
                    }
                    else if (totalBytesRead == 0 && (!dataAvailable || ConnectionInfo.ConnectionState == ConnectionState.Shutdown))
                    {
                        //If we read 0 bytes and there is no data available we should be shutting down
                        CloseConnection(false, -10);
                        break;
                    }

                    //If we have read some data and we have more or equal what was expected we attempt a data handoff
                    if (packetBuilder.TotalBytesCached > 0 && packetBuilder.TotalBytesCached >= packetBuilder.TotalBytesExpected)
                    {
                        IncomingPacketHandleHandOff(packetBuilder);
                    }
                }
            }
            //On any error here we close the connection
            catch (NullReferenceException)
            {
                CloseConnection(true, 7);
            }
            catch (IOException)
            {
                CloseConnection(true, 8);
            }
            catch (ObjectDisposedException)
            {
                CloseConnection(true, 9);
            }
            catch (SocketException)
            {
                CloseConnection(true, 10);
            }
            catch (InvalidOperationException)
            {
                CloseConnection(true, 11);
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "Error_TCPConnectionIncomingPacketHandler");
                CloseConnection(true, 39);
            }

            //Clear the listen thread object because the thread is about to end
            incomingDataListenThread = null;

            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Trace("Incoming data listen thread ending for " + ConnectionInfo);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Polls all existing connections based on ConnectionKeepAlivePollIntervalSecs value. Serverside connections are polled slightly earlier than client side to help reduce potential congestion.
        /// </summary>
        /// <param name="returnImmediately"></param>
        private static void AllConnectionsSendNullPacketKeepAlive(bool returnImmediately = false)
        {
            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Trace("Starting AllConnectionsSendNullPacketKeepAlive");
            }

            //Loop through all connections and test the alive state
            List <Connection> allConnections = NetworkComms.GetExistingConnection();
            int remainingConnectionCount     = allConnections.Count;

#if WINDOWS_PHONE
            QueueItemPriority nullSendPriority = QueueItemPriority.High;
#else
            QueueItemPriority nullSendPriority = QueueItemPriority.AboveNormal;
#endif

            ManualResetEvent allConnectionsComplete = new ManualResetEvent(false);
            for (int i = 0; i < allConnections.Count; i++)
            {
                //We don't send null packets to unconnected udp connections
                UDPConnection asUDP = allConnections[i] as UDPConnection;
                if (asUDP != null && asUDP.UDPOptions == UDPOptions.None)
                {
                    if (Interlocked.Decrement(ref remainingConnectionCount) == 0)
                    {
                        allConnectionsComplete.Set();
                    }

                    continue;
                }
                else
                {
                    int innerIndex = i;
                    NetworkComms.CommsThreadPool.EnqueueItem(nullSendPriority, new WaitCallback((obj) =>
                    {
                        try
                        {
                            //If the connection is server side we poll preferentially
                            if (allConnections[innerIndex] != null)
                            {
                                if (allConnections[innerIndex].ConnectionInfo.ServerSide)
                                {
                                    //We check the last incoming traffic time
                                    //In scenarios where the client is sending us lots of data there is no need to poll
                                    if ((DateTime.Now - allConnections[innerIndex].ConnectionInfo.LastTrafficTime).TotalSeconds > ConnectionKeepAlivePollIntervalSecs)
                                    {
                                        allConnections[innerIndex].SendNullPacket();
                                    }
                                }
                                else
                                {
                                    //If we are client side we wait upto an additional 3 seconds to do the poll
                                    //This means the server will probably beat us
                                    if ((DateTime.Now - allConnections[innerIndex].ConnectionInfo.LastTrafficTime).TotalSeconds > ConnectionKeepAlivePollIntervalSecs + 1.0 + (NetworkComms.randomGen.NextDouble() * 2.0))
                                    {
                                        allConnections[innerIndex].SendNullPacket();
                                    }
                                }
                            }
                        }
                        catch (Exception) { }
                        finally
                        {
                            if (Interlocked.Decrement(ref remainingConnectionCount) == 0)
                            {
                                allConnectionsComplete.Set();
                            }
                        }
                    }), null);
                }
            }

            //Max wait is 1 seconds per connection
            if (!returnImmediately && allConnections.Count > 0)
            {
                if (!allConnectionsComplete.WaitOne(allConnections.Count * 2500))
                {
                    //This timeout should not really happen so we are going to log an error if it does
                    NetworkComms.LogError(new TimeoutException("Timeout after " + allConnections.Count.ToString() + " seconds waiting for null packet sends to finish. " + remainingConnectionCount.ToString() + " connection waits remain. This error indicates very high send load or a possible send deadlock."), "NullPacketKeepAliveTimeoutError");
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Attempts to use the data provided in packetBuilder to recreate something usefull. If we don't have enough data yet that value is set in packetBuilder.
        /// </summary>
        /// <param name="packetBuilder">The <see cref="PacketBuilder"/> containing incoming cached data</param>
        protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder)
        {
            try
            {
                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read.");
                }

                if (packetBuilder.TotalPartialPacketCount == 0)
                {
                    throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder.");
                }

                //Loop until we are finished with this packetBuilder
                int loopCounter = 0;
                while (true)
                {
                    //If we have ended up with a null packet at the front, probably due to some form of concatentation we can pull it off here
                    //It is possible we have concatenation of several null packets along with real data so we loop until the firstByte is greater than 0
                    if (packetBuilder.FirstByte() == 0)
                    {
                        if (NetworkComms.LoggingEnabled)
                        {
                            NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString());
                        }

                        packetBuilder.ClearNTopBytes(1);

                        //Reset the expected bytes to 0 so that the next check starts from scratch
                        packetBuilder.TotalBytesExpected = 0;

                        //If we have run out of data completely then we can return immediately
                        if (packetBuilder.TotalBytesCached == 0)
                        {
                            return;
                        }
                    }
                    else
                    {
                        //First determine the expected size of a header packet
                        int packetHeaderSize = packetBuilder.FirstByte() + 1;

                        //Do we have enough data to build a header?
                        if (packetBuilder.TotalBytesCached < packetHeaderSize)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace(" ... ... more data required for complete packet header.");
                            }

                            //Set the expected number of bytes and then return
                            packetBuilder.TotalBytesExpected = packetHeaderSize;
                            return;
                        }

                        //We have enough for a header
                        PacketHeader topPacketHeader;
                        using (MemoryStream headerStream = packetBuilder.ReadDataSection(1, packetHeaderSize - 1))
                            topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions);

                        //Idiot test
                        if (topPacketHeader.PacketType == null)
                        {
                            throw new SerialisationException("packetType value in packetHeader should never be null");
                        }

                        //We can now use the header to establish if we have enough payload data
                        //First case is when we have not yet received enough data
                        if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.PayloadPacketSize)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace(" ... ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " total packet bytes.");
                            }

                            //Set the expected number of bytes and then return
                            packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.PayloadPacketSize;
                            return;
                        }
                        //Second case is we have enough data
                        else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.PayloadPacketSize)
                        {
                            //We can either have exactly the right amount or even more than we were expecting
                            //We may have too much data if we are sending high quantities and the packets have been concatenated
                            //no problem!!
                            SendReceiveOptions incomingPacketSendReceiveOptions = IncomingPacketSendReceiveOptions(topPacketHeader);
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Debug("Received packet of type '" + topPacketHeader.PacketType + "' from " + ConnectionInfo + ", containing " + packetHeaderSize.ToString() + " header bytes and " + topPacketHeader.PayloadPacketSize.ToString() + " payload bytes.");
                            }

                            //If this is a reserved packetType we call the method inline so that it gets dealt with immediately
                            bool isReservedType = false;
                            foreach (var tName in NetworkComms.reservedPacketTypeNames)
                            {
                                //isReservedType |= topPacketHeader.PacketType == tName;
                                if (topPacketHeader.PacketType == tName)
                                {
                                    isReservedType = true;
                                    break;
                                }
                            }

                            //Only reserved packet types get completed inline
                            if (isReservedType)
                            {
#if WINDOWS_PHONE
                                var priority = QueueItemPriority.Normal;
#else
                                var priority = (QueueItemPriority)Thread.CurrentThread.Priority;
#endif

                                PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.PayloadPacketSize), incomingPacketSendReceiveOptions);
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString());
                                }
                                NetworkComms.CompleteIncomingItemTask(item);
                            }
                            else
                            {
                                QueueItemPriority itemPriority = (incomingPacketSendReceiveOptions.Options.ContainsKey("ReceiveHandlePriority") ? (QueueItemPriority)Enum.Parse(typeof(QueueItemPriority), incomingPacketSendReceiveOptions.Options["ReceiveHandlePriority"]) : QueueItemPriority.Normal);
                                PriorityQueueItem item         = new PriorityQueueItem(itemPriority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.PayloadPacketSize), incomingPacketSendReceiveOptions);

                                //QueueItemPriority.Highest is the only priority that is executed inline
#if !WINDOWS_PHONE
                                if (itemPriority == QueueItemPriority.Highest)
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString());
                                    }
                                    NetworkComms.CompleteIncomingItemTask(item);
                                }
                                else
                                {
                                    int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + ".");
                                    }
                                }
#else
                                int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + ".");
                                }
#endif
                            }

                            //We clear the bytes we have just handed off
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " bytes from incoming packet buffer from connection with " + ConnectionInfo + ".");
                            }
                            packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.PayloadPacketSize);

                            //Reset the expected bytes to 0 so that the next check starts from scratch
                            packetBuilder.TotalBytesExpected = 0;

                            //If we have run out of data completely then we can return immediately
                            if (packetBuilder.TotalBytesCached == 0)
                            {
                                return;
                            }
                        }
                        else
                        {
                            throw new CommunicationException("This should be impossible!");
                        }
                    }

                    loopCounter++;
                }
            }
            catch (Exception ex)
            {
                //Any error, throw an exception.
                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Fatal("A fatal exception occured in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information.");
                }

                NetworkComms.LogError(ex, "CommsError");
                CloseConnection(true, 45);
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Closes the connection and trigger any associated shutdown delegates.
        /// </summary>
        /// <param name="closeDueToError">Closing a connection due an error possibly requires a few extra steps.</param>
        /// <param name="logLocation">Optional debug parameter.</param>
        public void CloseConnection(bool closeDueToError, int logLocation = 0)
        {
            try
            {
                if (NetworkComms.LoggingEnabled)
                {
                    if (closeDueToError)
                    {
                        NetworkComms.Logger.Debug("Closing connection with " + ConnectionInfo + " due to error from [" + logLocation.ToString() + "].");
                    }
                    else
                    {
                        NetworkComms.Logger.Debug("Closing connection with " + ConnectionInfo + " from [" + logLocation.ToString() + "].");
                    }
                }

                ConnectionInfo.NoteConnectionShutdown();

                //Set possible error cases
                if (closeDueToError)
                {
                    connectionSetupException    = true;
                    connectionSetupExceptionStr = "Connection was closed during setup from [" + logLocation.ToString() + "].";
                }

                //Ensure we are not waiting for a connection to be established if we have died due to error
                connectionSetupWait.Set();

                //Call any connection specific close requirements
                CloseConnectionSpecific(closeDueToError, logLocation);

                try
                {
                    //If we are calling close from the listen thread we are actually in the same thread
                    //We must guarantee the listen thread stops even if that means we need to nuke it
                    //If we did not we may not be able to shutdown properly.
                    if (incomingDataListenThread != null && incomingDataListenThread != Thread.CurrentThread && (incomingDataListenThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin || incomingDataListenThread.ThreadState == System.Threading.ThreadState.Running))
                    {
                        //If we have made it this far we give the ythread a further 50ms to finish before nuking.
                        if (!incomingDataListenThread.Join(50))
                        {
                            incomingDataListenThread.Abort();
                            if (NetworkComms.LoggingEnabled && ConnectionInfo != null)
                            {
                                NetworkComms.Logger.Warn("Incoming data listen thread with " + ConnectionInfo + " aborted.");
                            }
                        }
                    }
                }
                catch (Exception)
                {
                }

                //Close connection my get called multiple times for a given connection depending on the reason for being closed
                bool firstClose = NetworkComms.RemoveConnectionReference(this);

                try
                {
                    //Almost there
                    //Last thing is to call any connection specific shutdown delegates
                    if (firstClose && ConnectionSpecificShutdownDelegate != null)
                    {
                        if (NetworkComms.LoggingEnabled)
                        {
                            NetworkComms.Logger.Debug("Triggered connection specific shutdown delegates with " + ConnectionInfo);
                        }
                        ConnectionSpecificShutdownDelegate(this);
                    }
                }
                catch (Exception ex)
                {
                    NetworkComms.LogError(ex, "ConnectionSpecificShutdownDelegateError", "Error while executing connection specific shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
                }

                try
                {
                    //Last but not least we call any global connection shutdown delegates
                    if (firstClose && NetworkComms.globalConnectionShutdownDelegates != null)
                    {
                        if (NetworkComms.LoggingEnabled)
                        {
                            NetworkComms.Logger.Debug("Triggered global shutdown delegates with " + ConnectionInfo);
                        }
                        NetworkComms.globalConnectionShutdownDelegates(this);
                    }
                }
                catch (Exception ex)
                {
                    NetworkComms.LogError(ex, "GlobalConnectionShutdownDelegateError", "Error while executing global connection shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
                }
            }
            catch (Exception ex)
            {
                if (ex is ThreadAbortException)
                { /*Ignore the threadabort exception if we had to nuke a thread*/
                }
                else
                {
                    NetworkComms.LogError(ex, "NCError_CloseConnection", "Error closing connection with " + ConnectionInfo + ". Close called from " + logLocation.ToString() + (closeDueToError ? " due to error." : "."));
                }

                //We try to rethrow where possible but CloseConnection could very likely be called from within networkComms so we just have to be happy with a log here
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Picks up any new incoming connections
        /// </summary>
        private static void IncomingConnectionWorker()
        {
            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Info("TCP IncomingConnectionWorker thread started.");
            }

            try
            {
                while (!shutdownIncomingConnectionWorkerThread)
                {
                    try
                    {
                        bool pickedUpNewConnection = false;

                        List <TcpListener> currentTCPListeners = new List <TcpListener>();
                        lock (staticTCPConnectionLocker)
                        {
                            foreach (var pair in tcpListenerDict)
                            {
                                currentTCPListeners.Add(pair.Value);
                            }
                        }

                        foreach (var listener in currentTCPListeners)
                        {
                            if (listener.Pending() && !shutdownIncomingConnectionWorkerThread)
                            {
                                pickedUpNewConnection = true;

                                //Pick up the new connection
                                TcpClient newClient = listener.AcceptTcpClient();

                                //Perform the establish in a task so that we can continue picking up new connections here
                                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
                                {
                                    #region Pickup The New Connection
                                    try
                                    {
                                        GetConnection(new ConnectionInfo(true, ConnectionType.TCP, (IPEndPoint)newClient.Client.RemoteEndPoint), NetworkComms.DefaultSendReceiveOptions, newClient, true);
                                    }
                                    catch (ConfirmationTimeoutException)
                                    {
                                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                                    }
                                    catch (CommunicationException)
                                    {
                                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                                    }
                                    catch (ConnectionSetupException)
                                    {
                                        //If we are the server end and we did not pick the incoming connection up then tooo bad!
                                    }
                                    catch (SocketException)
                                    {
                                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                                    }
                                    catch (Exception ex)
                                    {
                                        //For some odd reason SocketExceptions don't always get caught above, so another check
                                        if (ex.GetBaseException().GetType() != typeof(SocketException))
                                        {
                                            //Can we catch the socketException by looking at the string error text?
                                            if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
                                            {
                                                NetworkComms.LogError(ex, "ConnectionSetupError_SE");
                                            }
                                            else
                                            {
                                                NetworkComms.LogError(ex, "ConnectionSetupError");
                                            }
                                        }
                                    }
                                    #endregion
                                }));
                            }
                        }

                        //We will only pause if we didnt get any new connections
                        if (!pickedUpNewConnection && !shutdownIncomingConnectionWorkerThread)
                        {
                            Thread.Sleep(100);
                        }
                    }
                    catch (ConfirmationTimeoutException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (CommunicationException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (ConnectionSetupException)
                    {
                        //If we are the server end and we did not pick the incoming connection up then tooo bad!
                    }
                    catch (SocketException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (ObjectDisposedException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (Exception ex)
                    {
                        //For some odd reason SocketExceptions don't always get caught above, so another check
                        if (ex.GetBaseException().GetType() != typeof(SocketException))
                        {
                            //Can we catch the socketException by looking at the string error text?
                            if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
                            {
                                NetworkComms.LogError(ex, "CommsSetupError_SE");
                            }
                            else
                            {
                                NetworkComms.LogError(ex, "CommsSetupError");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                NetworkComms.LogError(ex, "CriticalCommsError");
            }
            finally
            {
                //We try to close all of the tcpListeners
                CloseAndRemoveAllLocalConnectionListeners();
            }

            //newIncomingListenThread = null;
            if (NetworkComms.LoggingEnabled)
            {
                NetworkComms.Logger.Info("TCP IncomingConnectionWorker thread ended.");
            }
        }