示例#1
0
        private async Task <bool> updateLastSeenTime(string markId)
        {
            bool updateWasSuccessful = false;

            using (DbContextTransaction transaction = context.Database.BeginTransaction())
            {
                try
                {
                    UserMarkExperience userMarkExperience = await context.UserMarkExperiences.FindAsync(LoggedUserId, markId);

                    validateOwner(userMarkExperience);

                    userMarkExperience.LastSeen = DateTime.Now;

                    await context.SaveChangesAsync();

                    transaction.Commit();
                    updateWasSuccessful = true;
                }

                catch (Exception ex)
                {
                    LogTools.LogException(ex);
                    transaction.Rollback();
                    throw ex;
                }
            }

            return(updateWasSuccessful);
        }
        private void AddFileInfo(PacketHeader header, Connection connection, SendInfo info)
        {
            try
            {
                byte[]       data = null;
                ReceivedFile file = null;

                lock (syncRoot)
                {
                    long sequenceNumber = info.PacketSequenceNumber;

                    if (incomingDataCache.ContainsKey(connection.ConnectionInfo) && incomingDataCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
                    {
                        data = incomingDataCache[connection.ConnectionInfo][sequenceNumber];
                        incomingDataCache[connection.ConnectionInfo].Remove(sequenceNumber);

                        if (!receivedFilesDict.ContainsKey(connection.ConnectionInfo))
                        {
                            receivedFilesDict.Add(connection.ConnectionInfo, new Dictionary <string, ReceivedFile>());
                        }

                        if (!receivedFilesDict[connection.ConnectionInfo].ContainsKey(info.Filename))
                        {
                            receivedFilesDict[connection.ConnectionInfo].Add(info.Filename, new ReceivedFile(info.Filename, connection.ConnectionInfo, info.TotalBytes));
                            AddNewReceivedItem(receivedFilesDict[connection.ConnectionInfo][info.Filename]);
                        }

                        file = receivedFilesDict[connection.ConnectionInfo][info.Filename];
                        Console.WriteLine("Info was received " + info.Filename);
                    }
                    else
                    {
                        if (!incomingDataInfoCache.ContainsKey(connection.ConnectionInfo))
                        {
                            incomingDataInfoCache.Add(connection.ConnectionInfo, new Dictionary <long, SendInfo>());
                        }

                        incomingDataInfoCache[connection.ConnectionInfo].Add(sequenceNumber, info);
                    }
                }

                if (data != null && file != null && !file.IsCompleted)
                {
                    file.AddData(info.BytesStart, 0, data.Length, data);

                    file = null;
                    data = null;
                    GC.Collect();
                }
                else if (data == null ^ file == null)
                {
                    throw new Exception("Either both are null or both are set. Data is " + (data == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed."));
                }
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "IncomingPartialFileDataInfo");
            }
        }
示例#3
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
                {
#if NET2
                    //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, false);
                    }
                    else
                    {
                        workedThreadSignal.WaitOne(100, false);
                    }
#else
                    //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);
                    }
#endif

                    //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)
                {
                    LogTools.LogException(ex, "ConnectionKeepAlivePollError");
                }
            }
        }
示例#4
0
        // GET api/ClosestMark
        public async Task <Mark> Get(double?latitude, double?longitude)
        {
            Mark closestMark = null;

            if (latitude != null && longitude != null)
            {
                m_UserLatitude  = latitude.Value;
                m_UserLongitude = longitude.Value;
            }

            try
            {
                int relevantCategoriesCode = context.GetUserRelevantCateogiresCode(LoggedUserId);

                IEnumerable <string> seenMarksIds = from userMarkExperiences in context.UserMarkExperiences
                                                    where userMarkExperiences.UserId == LoggedUserId
                                                    select userMarkExperiences.MarkId;

                IEnumerable <Mark> unseenRelevantMarks = from mark in context.Marks
                                                         where (relevantCategoriesCode & mark.CategoriesCode) != 0 &&
                                                         !seenMarksIds.Contains(mark.Id)
                                                         select mark;

                if (unseenRelevantMarks.Count() != 0)
                {
                    closestMark = unseenRelevantMarks.OrderByDescending((mark) => distanceFromUserKm(mark)).Last();

                    double distanceFromClosestMark = distanceFromUserKm(closestMark);
                    if (distanceFromClosestMark > 0.04)
                    {
                        // Closest mark is too far
                        closestMark = null;
                    }

                    else
                    {
                        // Insert a UserMarkExperience to avoid notifying this user about this mark again
                        await context.InsertUserMarkExperience(LoggedUserId, closestMark.Id);
                    }
                }
            }

            catch (Exception e)
            {
                LogTools.LogException(e);
            }

            return(closestMark);
        }
        private void newListenerInstance_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        {
            try
            {
                IPEndPoint localEndPoint  = new IPEndPoint(IPAddress.Parse(args.Socket.Information.LocalAddress.DisplayName.ToString()), int.Parse(args.Socket.Information.LocalPort));
                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(args.Socket.Information.RemoteAddress.DisplayName.ToString()), int.Parse(args.Socket.Information.RemotePort));

                ConnectionInfo newConnectionInfo = new ConnectionInfo(ConnectionType.TCP, remoteEndPoint, localEndPoint, ApplicationLayerProtocol, this);
                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"))
                    {
                        LogTools.LogException(ex, "ConnectionSetupError_SE");
                    }
                    else
                    {
                        LogTools.LogException(ex, "ConnectionSetupError");
                    }
                }
            }
        }
示例#6
0
        private async Task <bool> updateMarkRating(string markId, float?rating)
        {
            bool updateWasSuccessful = false;

            using (DbContextTransaction transaction = context.Database.BeginTransaction())
            {
                try
                {
                    UserMarkExperience userMarkExperience = await context.UserMarkExperiences.FindAsync(LoggedUserId, markId);

                    validateOwner(userMarkExperience);

                    userMarkExperience.Mark.RatingsSum -= userMarkExperience.UserRating;
                    userMarkExperience.Mark.RatingsSum += rating.Value;
                    userMarkExperience.UserRating       = rating.Value;
                    userMarkExperience.LastSeen         = DateTime.Now;

                    if (!userMarkExperience.HasUserRated)
                    {
                        userMarkExperience.Mark.RatingsCount++;
                        userMarkExperience.HasUserRated = true;
                    }

                    userMarkExperience.Mark.UpdateRating();
                    await context.SaveChangesAsync();

                    transaction.Commit();
                    updateWasSuccessful = true;
                }

                catch (Exception ex)
                {
                    LogTools.LogException(ex);
                    transaction.Rollback();
                    throw ex;
                }
            }

            return(updateWasSuccessful);
        }
示例#7
0
        /// <summary>
        /// Shutdown any static connection components
        /// </summary>
        /// <param name="threadShutdownTimeoutMS"></param>
        internal static void Shutdown(int threadShutdownTimeoutMS = 1000)
        {
            try
            {
                StopListening();
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "CommsShutdownError");
            }

            try
            {
                shutdownWorkerThreads = true;
#if NETFX_CORE
                if (connectionKeepAliveWorker != null && !connectionKeepAliveWorker.Wait(threadShutdownTimeoutMS))
                {
                    throw new CommsSetupShutdownException("Connection keep alive worker failed to shutdown");
                }
#else
                if (connectionKeepAliveWorker != null && !connectionKeepAliveWorker.Join(threadShutdownTimeoutMS))
                {
                    connectionKeepAliveWorker.Abort();
                }
#endif
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "CommsShutdownError");
            }
            finally
            {
                shutdownWorkerThreads = false;
                workedThreadSignal.Reset();
            }
        }
        public void sendMessages(string peerMessage, string packetType)
        {
            string peerAddress = File.ReadLines("peerAddress.txt").First();


            //winViewer.peerReturn(out peerMessage, out peerAddress, out sendMessage, out exitCode);



            //Request a message to send somewhere
            //Console.WriteLine("\nPlease enter your message and press enter (Type 'exit' to quit):");
            //string stringToSend = Console.ReadLine();
            //Console.WriteLine("Message to send: " + propTest.peerMessage + " to " + propTest.peerAddress);
            //Console.WriteLine("Waiting...");

            string stringToSend = peerMessage;


            //Console.WriteLine("ready to send: " + stringToSend);

            //Console.WriteLine("exit");


            //If the user has typed exit then we leave our loop and end the example

            Console.WriteLine("Message to send: " + peerMessage + " to " + peerAddress);

            try
            {
                //Once we have a message we need to know where to send it
                //We have created a small wrapper class to help keep things clean here
                //ConnectionInfo targetServerConnectionInfo = ExampleHelper.GetServerDetails();
                IPEndPoint lastServerIPEndPoint = IPTools.ParseEndPointFromString(peerAddress);
                ApplicationLayerProtocolStatus applicationLayerProtocol = ApplicationLayerProtocolStatus.Enabled;
                ConnectionInfo targetServerConnectionInfo = new ConnectionInfo(lastServerIPEndPoint, applicationLayerProtocol);

                //We get a connection to the desired target server
                //This is performed using a static method, i.e. 'TCPConnection.GetConnection()' instead of
                //using 'new TCPConnection()' to ensure thread safety. This means if you have a multi threaded application
                //and attempt to get a connection the same target server simultaneously, you will only ever create
                //a single connection.
                Connection conn = TCPConnection.GetConnection(targetServerConnectionInfo);

                //We send the string using a 'Message' packet type
                //There are a large number of overrides to SendObject
                //Please see our other examples or the online API
                //http://www.networkcomms.net/api/
                //conn.SendObject("Message", stringToSend);
                conn.SendObject(packetType, stringToSend);
            }
            catch (CommsException ex)
            {
                //All NetworkComms.Net exception inherit from CommsException so we can easily
                //catch all just by catching CommsException. For the break down of exceptions please
                //see our online API.
                //http://www.networkcomms.net/api/

                //If an error occurs we need to decide what to do.
                //In this example we will just log to a file and continue.
                LogTools.LogException(ex, "IntermediateSendExampleError");
                Console.WriteLine("\nError: CommsException was caught. Please see the log file created for more information.\n");
            }
        }
示例#9
0
        static void Main(string[] args)
        {
            try
            {
                Console.SetBufferSize(120, 200);
                Console.SetWindowSize(120, 25);
            }
            catch (NotImplementedException) { }

            Thread.CurrentThread.Name = "MainThread";

            Console.WriteLine("Initiating NetworkCommsDotNet examples.\n");

            //Ask user if they want to enable comms logging
            SelectLogging();

#if DEBUG
            //Set debug timeouts
            SetDebugTimeouts();
#endif

            //All we do here is let the user choice a specific example
            Console.WriteLine("Please selected an example:\n");

            //Print out the available examples
            int totalNumberOfExamples = 9;
            Console.WriteLine("1 - Basic - Message Send (Only 11 lines!)");
            Console.WriteLine();
            Console.WriteLine("2 - Intermediate - Message Send");
            Console.WriteLine("3 - Intermediate - Peer Discovery");
            Console.WriteLine();
            Console.WriteLine("4 - Advanced - Object Send");
            Console.WriteLine("5 - Advanced - Distributed File System");
            Console.WriteLine("6 - Advanced - Remote Procedure Call");
            Console.WriteLine("7 - Advanced - Unmanaged Connections");
            Console.WriteLine("8 - Advanced - TCP (SSL) Connections");
            Console.WriteLine("");
            Console.WriteLine("9 - Debug - Speed Test");

            //Get the user choice
            Console.WriteLine("");
            int selectedExample;
            while (true)
            {
                bool parseSucces = int.TryParse(Console.ReadKey().KeyChar.ToString(), out selectedExample);
                if (parseSucces && selectedExample <= totalNumberOfExamples)
                {
                    break;
                }
                Console.WriteLine("\nInvalid example choice. Please try again.");
            }

            //Clear all input so that each example can do it's own thing
            Console.Clear();

            //Run the selected example
            try
            {
                #region Run Example
                switch (selectedExample)
                {
                case 1:
                    BasicSend.RunExample();
                    break;

                case 2:
                    IntermediateSend.RunExample();
                    break;

                case 3:
                    PeerDiscoveryExample.RunExample();
                    break;

                case 4:
                    AdvancedSend.RunExample();
                    break;

                case 5:
                    DFSTest.RunExample();
                    break;

                case 6:
                    RPCExample.RunExample();
                    break;

                case 7:
                    UnmanagedConnectionExample.RunExample();
                    break;

                case 8:
                    SSLExample.RunExample();
                    break;

                case 9:
                    SpeedTest.RunExample();
                    break;

                default:
                    Console.WriteLine("Selected an invalid example number. Please restart and try again.");
                    break;
                }
                #endregion
            }
            catch (Exception ex)
            {
                //If an error was uncaught by the examples we can log the exception to a file here
                LogTools.LogException(ex, "ExampleError");
                NetworkComms.Shutdown();
                Console.WriteLine(ex.ToString());
            }

            //When we are done we give the user a chance to see all output
            Console.WriteLine("\n\nExample has completed. Please press any key to close.");
            Console.ReadKey(true);
        }
        /// <summary>
        /// Synchronous incoming connection data worker
        /// </summary>
        private 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
                        //If packetBuilder.TotalBytesExpected is 0 we know we're going to start waiting for a fresh packet. Therefore use the initial buffer size
                        if (packetBuilder.TotalBytesExpected == 0)
                        {
                            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];
                        }
                        else
                        //Otherwise this can only be a supplementary buffer for THIS packet. Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                        {
                            long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                            dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                        }
                    }

                    //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 = connectionStream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;

                    //Check to see if there is more data ready to be read
                    if (SSLOptions.SSLEnabled)
                    {
                        //SSLstream does not have a DataAvailable property. We will just assume false.
                        dataAvailable = false;
                    }
                    else
                    {
                        dataAvailable = ((NetworkStream)connectionStream).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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && 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 " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                            }

                            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 hand off
                    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)
            {
                LogTools.LogException(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);
            }
        }
        private void IncomingTCPPacketHandler(IAsyncResult ar)
#endif
        {
            //Initialised with false so that logic still works in WP8
            bool dataAvailable = false;

#if !WINDOWS_PHONE && !NETFX_CORE
            //Incoming data always gets handled in a timeCritical fashion at this point
            //Windows phone and RT platforms do not support thread priorities
            Thread.CurrentThread.Priority = NetworkComms.timeCriticalThreadPriority;
#endif

            try
            {
#if WINDOWS_PHONE
                Stream stream = ar.AsyncState as Stream;
                totalBytesRead = stream.EndRead(ar) + totalBytesRead;
#elif NETFX_CORE
                buffer.CopyTo(0, dataBuffer, totalBytesRead, (int)buffer.Length);
                totalBytesRead = (int)buffer.Length + totalBytesRead;
#else
                Stream stream;
                if (SSLOptions.SSLEnabled)
                {
                    stream = (SslStream)ar.AsyncState;
                }
                else
                {
                    stream = (NetworkStream)ar.AsyncState;
                }

                if (!stream.CanRead)
                {
                    throw new ObjectDisposedException("Unable to read from stream.");
                }

                if (!asyncListenerInRead)
                {
                    throw new InvalidDataException("The asyncListenerInRead flag should be true. 1");
                }
                totalBytesRead      = stream.EndRead(ar) + totalBytesRead;
                asyncListenerInRead = false;

                if (SSLOptions.SSLEnabled)
                {
                    //SSLstream does not have a DataAvailable property. We will just assume false.
                    dataAvailable = false;
                }
                else
                {
                    dataAvailable = ((NetworkStream)stream).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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled &&
                        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 for " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                        }

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

#if !WINDOWS_PHONE && !NETFX_CORE
                        //If we have more data we might as well continue reading synchronously
                        //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. As we are in this loop this can only be a suplementary buffer for THIS packet.
                            //Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                            {
                                long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                                dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                            }

                            totalBytesRead = stream.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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... null packet ignored in IncomingPacketHandler() from " + ConnectionInfo + ". 2");
                                    }
                                    //LastTrafficTime = DateTime.Now;
                                }
                                else
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                                    }
                                    packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);

                                    if (SSLOptions.SSLEnabled)
                                    {
                                        //SSLstream does not have a DataAvailable property. We will just assume false.
                                        dataAvailable = false;
                                    }
                                    else
                                    {
                                        dataAvailable = ((NetworkStream)stream).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 hand off
                    //Should we have a complete packet this method will start the appropriate 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
                        //If packetBuilder.TotalBytesExpected is 0 we know we're going to start waiting for a fresh packet. Therefore use the initial buffer size
                        if (packetBuilder.TotalBytesExpected == 0)
                        {
                            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];
                        }
                        else
                        //Otherwise this can only be a supplementary buffer for THIS packet. Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                        {
                            long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                            dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                        }

                        totalBytesRead = 0;
                    }

#if NETFX_CORE
                    IBuffer newBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(dataBuffer);
                    var     task      = IncomingTCPPacketHandler(await socket.InputStream.ReadAsync(newBuffer, newBuffer.Capacity - (uint)totalBytesRead, InputStreamOptions.Partial));
#elif WINDOWS_PHONE
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#else
                    if (asyncListenerInRead)
                    {
                        throw new InvalidDataException("The asyncListenerInRead flag should be false. 2");
                    }
                    asyncListenerInRead = true;
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#endif
                }
            }
            catch (IOException)
            {
                CloseConnection(true, 12);
            }
            catch (ObjectDisposedException)
            {
                CloseConnection(true, 13);
            }
            catch (SocketException)
            {
                CloseConnection(true, 14);
            }
            catch (InvalidOperationException)
            {
                CloseConnection(true, 15);
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "Error_TCPConnectionIncomingPacketHandler");
                CloseConnection(true, 31);
            }

#if !WINDOWS_PHONE && !NETFX_CORE
            Thread.CurrentThread.Priority = ThreadPriority.Normal;
#endif
        }
        /// <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);

#if !NETFX_CORE
                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 thread 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)
                {
                }
#endif
                //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)
                {
                    LogTools.LogException(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)
                {
                    LogTools.LogException(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 !NETFX_CORE
                if (ex is ThreadAbortException)
                { /*Ignore the threadabort exception if we had to nuke a thread*/
                }
                else
#endif
                LogTools.LogException(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
            }
        }
示例#13
0
        /// <summary>
        /// The distributed file system (DFS) allows for the high performance distribution of large files
        /// within a cluster of peers. This sytem replicates the behaviour the bitTorrent protocol by using
        /// NetworkCommsDotNet. This example demonstrates the DFS in action.
        /// </summary>
        public static void RunExample()
        {
            //Select launch mode
            Console.WriteLine("Launching DFS system ...\n");
            Console.WriteLine("Please select host or peer mode:");
            Console.WriteLine("1 - Host Mode (Original source of data)");
            Console.WriteLine("2 - Peer Mode (Builds data and then acts as subhost)");

            //Read in user choice
            //if (Console.ReadKey(true).Key == ConsoleKey.D1) hostMode = true;
            //else hostMode = false;
            hostMode = false;

            if (hostMode)
            {
                //Prepare DFS in host mode
                #region ServerMode
                Console.WriteLine("\n ... host mode selected.");
                Console.WriteLine("\nPlease enter how large the test data packet should be in MB and press return, e.g. 50:");
                int numberMegsToCreate = int.Parse(Console.ReadLine());

                //Fill a byte[] with random data
                DateTime startTime      = DateTime.Now;
                Random   randGen        = new Random();
                byte[]   someRandomData = new byte[numberMegsToCreate * 1024 * 1024];
                randGen.NextBytes(someRandomData);

                Console.WriteLine("\n ... successfully created a {0}MB test packet.", ((double)someRandomData.Length / (1024.0 * 1024.0)).ToString("0.###"));

                object            listLocker       = new object();
                List <IPEndPoint> connectedClients = new List <IPEndPoint>();

                //Initialise the DFS before creating the test object to ensure the correct port and IP are used as the seed
                DFS.Initialise(10000);

                //Create the item to be distributed
                List <ConnectionInfo> seedConnectionInfoList = (from current in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP) select new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, current, true)).ToList();

                DistributedItem newItem = new DistributedItem("exampleItem", "example1", new MemoryStream(someRandomData), seedConnectionInfoList, DataBuildMode.Memory_Single);

                NetworkComms.ConnectionEstablishShutdownDelegate clientEstablishDelegate = (connection) =>
                {
                    lock (listLocker)
                        connectedClients.Remove((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint);

                    Console.WriteLine("Client " + connection.ConnectionInfo + " connected.");
                };

                NetworkComms.ConnectionEstablishShutdownDelegate clientShutdownDelegate = (connection) =>
                {
                    lock (listLocker)
                        connectedClients.Remove((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint);

                    Console.WriteLine("Client " + connection.ConnectionInfo + " disconnected.");
                };

                NetworkComms.PacketHandlerCallBackDelegate <int> ReplyDelegate = (packetHeader, connection, incomingObject) =>
                {
                    //Push the item into the swarm
                    lock (listLocker)
                        if (!connectedClients.Contains(connection.ConnectionInfo.RemoteEndPoint))
                        {
                            connectedClients.Add((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint);
                        }

                    DFS.PushItemToPeer(connection, newItem, "BigDataRequestResponse");
                    Console.WriteLine("Pushing item to " + connection.ConnectionInfo + " (" + connection.ConnectionInfo.NetworkIdentifier + "). {0} in swarm. P#={1}, S#={2}.", connectedClients.Count, newItem.PushCount, newItem.TotalChunkSupplyCount);
                };

                NetworkComms.PacketHandlerCallBackDelegate <string> InfoDelegate = (packetHeader, connectionId, incomingString) =>
                {
                    Console.WriteLine(" ... " + connectionId + " - " + incomingString);
                };

                Console.WriteLine(" ... DFS has been initialised.");

                NetworkComms.AppendGlobalConnectionEstablishHandler(clientEstablishDelegate);
                NetworkComms.AppendGlobalConnectionCloseHandler(clientShutdownDelegate);
                NetworkComms.AppendGlobalIncomingPacketHandler("BigDataRequest", ReplyDelegate);
                NetworkComms.AppendGlobalIncomingPacketHandler("ClientInfo", InfoDelegate);

                Console.WriteLine("\nListening for incoming connections on:");
                foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP))
                {
                    Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);
                }

                Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier);
                Console.WriteLine("\nPress 's' to write out stats, 'q' to close any connected peers, 'ctrl+q' to close this host.\n");

                while (true)
                {
                    ConsoleKeyInfo pressedKey = Console.ReadKey(true);
                    #region Host Shutdown
                    if (pressedKey.Modifiers != ConsoleModifiers.Control && pressedKey.Key == ConsoleKey.Q)
                    {
                        Console.WriteLine("Sending shutdown to clients...");
                        lock (listLocker)
                        {
                            for (int i = 0; i < connectedClients.Count; i++)
                            {
                                try
                                {
                                    TCPConnection.GetConnection(new ConnectionInfo(connectedClients[i])).SendObject("ClientCommand", 0);
                                }
                                catch (Exception)
                                {
                                    Console.WriteLine("Exception telling client to shutdown. Probably already disconnected.");
                                }
                            }
                        }
                    }
                    else if (pressedKey.Modifiers == ConsoleModifiers.Control && pressedKey.Key == ConsoleKey.Q)
                    {
                        Console.WriteLine("Sending shutdown to clients and closing local host...");
                        lock (listLocker)
                        {
                            for (int i = 0; i < connectedClients.Count; i++)
                            {
                                try
                                {
                                    TCPConnection.GetConnection(new ConnectionInfo(connectedClients[i])).SendObject("ClientCommand", 0);
                                }
                                catch (Exception)
                                {
                                    Console.WriteLine("Exception telling client to shutdown. Probably already disconnected.");
                                }
                            }
                        }

                        Console.WriteLine("Closing host.");
                        break;
                    }
                    else if (pressedKey.Key == ConsoleKey.S)
                    {
                        #region Stats
                        Console.WriteLine("\nCurrent Stats:");
                        Console.WriteLine("{0} comms connections.", NetworkComms.TotalNumConnections());

                        if (NetworkComms.TotalNumConnections() > 0)
                        {
                            Console.WriteLine("Connections with: ");
                            var connections = NetworkComms.GetExistingConnection();
                            foreach (var connection in connections)
                            {
                                Console.WriteLine("\t{0}", connection.ConnectionInfo);
                            }
                        }
                        #endregion
                    }
                    #endregion
                }
                #endregion
            }
            else if (!hostMode)
            {
                //Prepare DFS in peer mode
                #region PeerMode
                Console.WriteLine("\n ... peer mode selected.");

                try
                {
                    ConnectionInfo serverConnectionInfo = new ConnectionInfo("192.168.0.105", 10000);
                    //ExampleHelper.GetServerDetails(out serverConnectionInfo);

                    DFS.Initialise(10000);
                    Console.WriteLine(" ... DFS has been initialised.");

                    bool     shutDown      = false;
                    bool     buildComplete = true;
                    DateTime startTime     = DateTime.Now;

                    int buildCount = 0;

                    NetworkComms.PacketHandlerCallBackDelegate <byte[]> ReplyDelegate = (packetHeader, connection, dataBytes) =>
                    {
                        try
                        {
                            buildCount++;
                            DistributedItem item = DFS.MostRecentlyCompletedItem();
                            Console.WriteLine(" ... full item build " + buildCount + " took {0} secs ({1} MB/s) using {2} total peers. {3} builds completed.", (DateTime.Now - startTime).TotalSeconds.ToString("0.00"), (((double)dataBytes.Length / 1048576.0) / (DateTime.Now - startTime).TotalSeconds).ToString("0.0"), item.SwarmChunkAvailability.NumPeersInSwarm(), buildCount);

                            double speed = (((double)dataBytes.Length / 1048576.0) / (DateTime.Now - startTime).TotalSeconds);
                            connection.SendObject("ClientInfo", " ... build " + buildCount + " took " + (DateTime.Now - startTime).TotalSeconds.ToString("0.00") + " secs (" + speed.ToString("0.0") + " MB/s) using " + item.SwarmChunkAvailability.NumPeersInSwarm() + " peers. " + buildCount + " builds completed.");
                            buildComplete = true;
                            dataBytes     = null;
                            GC.Collect();
                        }
                        catch (Exception ex)
                        {
                            LogTools.LogException(ex, "DFSTestCallbackError");
                            Console.WriteLine("Shutting down due to exception.");
                            shutDown = true;
                        }
                    };

                    NetworkComms.PacketHandlerCallBackDelegate <int> ShutdownDelegate = (packetHeader, connectionId, packetDataBytes) =>
                    {
                        shutDown = true;
                    };

                    NetworkComms.AppendGlobalIncomingPacketHandler("BigDataRequestResponse", ReplyDelegate);
                    NetworkComms.AppendGlobalIncomingPacketHandler("ClientCommand", ShutdownDelegate);

                    Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier);
                    Console.WriteLine("\nListening for incoming objects on:");
                    foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP))
                    {
                        Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);
                    }

                    startTime = DateTime.Now;

                    //while (true)
                    //{
                    if (!shutDown && buildComplete)
                    {
                        //Console.WriteLine("\nPress 'r' to rebuild or any other key to shutdown.");
                        //var shutdownKey = Console.ReadKey(true).Key;
                        //if (shutdownKey != ConsoleKey.R) shutDown = true;

                        //if (!shutDown)
                        //{
                        DistributedItem item = DFS.MostRecentlyCompletedItem();
                        if (item != null)
                        {
                            DFS.RemoveItem(item.Data.CompleteDataCheckSum);
                            Console.WriteLine("\n ... item removed from local and rebuilding at {0}.", DateTime.Now.ToString("HH:mm:ss.fff"));
                            startTime = DateTime.Now;
                        }

                        buildComplete = false;

                        TCPConnection.GetConnection(serverConnectionInfo).SendObject("BigDataRequest");

                        Console.WriteLine(" ... initiating item build ...");
                        //}
                    }
                    else if (shutDown)
                    {
                        shutDown = true;
                        DFS.Shutdown();
                        //break;
                    }

                    Thread.Sleep(250);
                    //}

                    while (!buildComplete)
                    {
                        Thread.Sleep(250);
                    }

                    try
                    {
                        TCPConnection.GetConnection(serverConnectionInfo).SendObject("ClientInfo", "... shutting down, initiating DFS shutdown.");
                    }
                    catch (CommsException)
                    {
                        Console.WriteLine("... unable to inform local of shutdown. Connection probably already closed.");
                    }

                    Console.WriteLine("Done. Completed {0} builds.", buildCount);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Bad Error!");
                    LogTools.LogException(ex, "DFSTestError_" + NetworkComms.NetworkIdentifier);
                }

                #endregion
            }

            DFS.Shutdown();
            NetworkComms.Shutdown();
        }
示例#14
0
        /// <summary>
        /// Internal UDP creation method that performs the necessary tasks
        /// </summary>
        /// <param name="connectionInfo"></param>
        /// <param name="defaultSendReceiveOptions"></param>
        /// <param name="level"></param>
        /// <param name="listenForReturnPackets"></param>
        /// <param name="existingListenerConnection"></param>
        /// <param name="possibleHandshakeUDPDatagram"></param>
        /// <param name="establishIfRequired">Will establish the connection, triggering connection establish delegates if a new
        /// connection is returned</param>
        /// <returns></returns>
        internal static UDPConnection GetConnection(ConnectionInfo connectionInfo, UDPOptions level, SendReceiveOptions defaultSendReceiveOptions, bool listenForReturnPackets, UDPConnection existingListenerConnection, HandshakeUDPDatagram possibleHandshakeUDPDatagram, bool establishIfRequired = true)
        {
            connectionInfo.ConnectionType = ConnectionType.UDP;

            bool          newConnection = false;
            UDPConnection connection    = null;

            lock (NetworkComms.globalDictAndDelegateLocker)
            {
                List <Connection> existingConnections = NetworkComms.GetExistingConnection(connectionInfo.RemoteIPEndPoint, connectionInfo.LocalIPEndPoint, ConnectionType.UDP, connectionInfo.ApplicationLayerProtocol);
                if (existingConnections.Count > 0)
                {
                    connection = (UDPConnection)existingConnections[0];
                }
                else
                {
                    //If we are listening on what will be the outgoing adaptor we send with that client to ensure if our connection info is handed off we are connectable by others
                    if (existingListenerConnection == null)
                    {
                        try
                        {
                            IPEndPoint localEndPoint = IPTools.BestLocalEndPoint(connectionInfo.RemoteIPEndPoint);
                            //Set the port to 0 so that we match any listener
                            localEndPoint.Port = 0;
                            List <UDPConnectionListener> existingListeners = Connection.ExistingLocalListeners <UDPConnectionListener>(localEndPoint);

                            for (int i = 0; i < existingListeners.Count; i++)
                            {
                                if (existingListeners[i].UDPConnection.ConnectionInfo.ApplicationLayerProtocol == connectionInfo.ApplicationLayerProtocol)
                                {
                                    existingListenerConnection = existingListeners[i].UDPConnection;

                                    //If we are using an existing listener there is no need to listen for packets
                                    listenForReturnPackets = false;

                                    //Once we have a matching connection we can break
                                    break;
                                }
                            }
                        }
                        catch (Exception)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace("Failed to determine preferred existing udpClientListener to " + connectionInfo.RemoteIPEndPoint.Address + ":" + connectionInfo.RemoteIPEndPoint.Port.ToString() + ". Will create an isolated UDP connection instead.");
                            }
                        }
                    }

                    //If an existing connection does not exist but the info we are using suggests it should we need to reset the info
                    //so that it can be reused correctly. This case generally happens when using Comms in the format
                    //UDPConnection.GetConnection(info).SendObject(packetType, objToSend);
                    if (connectionInfo.ConnectionState == ConnectionState.Established || connectionInfo.ConnectionState == ConnectionState.Shutdown)
                    {
                        connectionInfo.ResetConnectionInfo();
                    }

                    connection    = new UDPConnection(connectionInfo, defaultSendReceiveOptions, level, listenForReturnPackets, existingListenerConnection);
                    newConnection = true;
                }
            }

            //If we expect a UDP handshake we need to handle incoming datagrams here, if we have it available,
            //  before trying to establish the connection.
            //This is different for TCP connections because things happen in the reverse order
            //UDP - Already listening, receive connectionsetup, configure connection
            //TCP - Receive TCPClient, configure connection, start listening for connectionsetup, wait for connectionsetup
            //
            //possibleHandshakeUDPDatagram will only be set when GetConnection() is called from a listener
            //If multiple threads try to create an outgoing UDP connection to the same endPoint all but the originating
            //thread will be held on connection.WaitForConnectionEstablish();
            if (possibleHandshakeUDPDatagram != null &&
                (connection.ConnectionUDPOptions & UDPOptions.Handshake) == UDPOptions.Handshake)
            {
                lock (connection.packetBuilder.Locker)
                {
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace(" ... " + possibleHandshakeUDPDatagram.DatagramBytes.Length.ToString() + " handshake bytes added to packetBuilder for " + connection.ConnectionInfo + ". Cached " + connection.packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + connection.packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                    }

                    connection.packetBuilder.AddPartialPacket(possibleHandshakeUDPDatagram.DatagramBytes.Length, possibleHandshakeUDPDatagram.DatagramBytes);
                    if (connection.packetBuilder.TotalBytesCached > 0)
                    {
                        connection.IncomingPacketHandleHandOff(connection.packetBuilder);
                    }
                }

                if (connection.packetBuilder.TotalPartialPacketCount > 0)
                {
                    LogTools.LogException(new Exception("Packet builder had " + connection.packetBuilder.TotalBytesCached + " bytes remaining after a call to IncomingPacketHandleHandOff with connection " + connection.ConnectionInfo + ". Until sequenced packets are implemented this indicates a possible error."), "UDPConnectionError");
                }

                possibleHandshakeUDPDatagram.DatagramHandled = true;
            }

            //We must perform the establish outside the lock as for TCP connections
            if (newConnection && establishIfRequired)
            {
                //Call establish on the connection if it is not a rogue sender or listener
                if (!connectionInfo.RemoteIPEndPoint.Address.Equals(IPAddress.Any) && !connectionInfo.RemoteIPEndPoint.Address.Equals(IPAddress.IPv6Any))
                {
                    connection.EstablishConnection();
                }
            }
            else if (!newConnection)
            {
                connection.WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS);
            }

            //UDP does not need keep alives
            //if (!NetworkComms.commsShutdown)
            //    TriggerConnectionKeepAliveThread();

            return(connection);
        }
示例#15
0
        /// <summary>
        /// Sends requested file to the remoteIP and port set in GUI
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendFileButton_Click(object sender, RoutedEventArgs e)
        {
            //Create an OpenFileDialog so that we can request the file to send
            OpenFileDialog openDialog = new OpenFileDialog();

            openDialog.Multiselect = false;

            //If a file was selected
            if (openDialog.ShowDialog() == true)
            {
                //Disable the send and compression buttons
                sendFileButton.IsEnabled = false;
                UseCompression.IsEnabled = false;

                //Parse the necessary remote information
                string filename   = openDialog.FileName;
                string remoteIP   = this.remoteIP.Text;
                string remotePort = this.remotePort.Text;

                //Set the send progress bar to 0
                UpdateSendProgress(0);

                //Perform the send in a task so that we don't lock the GUI
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        //Create a fileStream from the selected file
                        FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);

                        //Wrap the fileStream in a threadSafeStream so that future operations are thread safe
                        StreamTools.ThreadSafeStream safeStream = new StreamTools.ThreadSafeStream(stream);

                        //Get the filename without the associated path information
                        string shortFileName = System.IO.Path.GetFileName(filename);

                        //Parse the remote connectionInfo
                        //We have this in a separate try catch so that we can write a clear message to the log window
                        //if there are problems
                        ConnectionInfo remoteInfo;
                        try
                        {
                            remoteInfo = new ConnectionInfo(remoteIP, int.Parse(remotePort));
                        }
                        catch (Exception)
                        {
                            throw new InvalidDataException("Failed to parse remote IP and port. Check and try again.");
                        }

                        //Get a connection to the remote side
                        Connection connection = TCPConnection.GetConnection(remoteInfo);

                        //Break the send into 20 segments. The less segments the less overhead
                        //but we still want the progress bar to update in sensible steps
                        long sendChunkSizeBytes = (long)(stream.Length / 20.0) + 1;

                        //Limit send chunk size to 500MB
                        long maxChunkSizeBytes = 500L * 1024L * 1024L;
                        if (sendChunkSizeBytes > maxChunkSizeBytes)
                        {
                            sendChunkSizeBytes = maxChunkSizeBytes;
                        }

                        long totalBytesSent = 0;
                        do
                        {
                            //Check the number of bytes to send as the last one may be smaller
                            long bytesToSend = (totalBytesSent + sendChunkSizeBytes < stream.Length ? sendChunkSizeBytes : stream.Length - totalBytesSent);

                            //Wrap the threadSafeStream in a StreamSendWrapper so that we can get NetworkComms.Net
                            //to only send part of the stream.
                            StreamTools.StreamSendWrapper streamWrapper = new StreamTools.StreamSendWrapper(safeStream, totalBytesSent, bytesToSend);

                            //We want to record the packetSequenceNumber
                            long packetSequenceNumber;
                            //Send the select data
                            connection.SendObject("PartialFileData", streamWrapper, customOptions, out packetSequenceNumber);
                            //Send the associated SendInfo for this send so that the remote can correctly rebuild the data
                            connection.SendObject("PartialFileDataInfo", new SendInfo(shortFileName, stream.Length, totalBytesSent, packetSequenceNumber), customOptions);

                            totalBytesSent += bytesToSend;

                            //Update the GUI with our send progress
                            UpdateSendProgress((double)totalBytesSent / stream.Length);
                        } while (totalBytesSent < stream.Length);

                        //Clean up any unused memory
                        GC.Collect();

                        AddLineToLog("Completed file send to '" + connection.ConnectionInfo.ToString() + "'.");
                    }
                    catch (CommunicationException)
                    {
                        //If there is a communication exception then we just write a connection
                        //closed message to the log window
                        AddLineToLog("Failed to complete send as connection was closed.");
                    }
                    catch (Exception ex)
                    {
                        //If we get any other exception which is not an InvalidDataException
                        //we log the error
                        if (!windowClosing && ex.GetType() != typeof(InvalidDataException))
                        {
                            AddLineToLog(ex.Message.ToString());
                            LogTools.LogException(ex, "SendFileError");
                        }
                    }

                    //Once the send is finished reset the send progress bar
                    UpdateSendProgress(0);

                    //Once complete enable the send button again
                    sendFileButton.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        sendFileButton.IsEnabled = true;
                        UseCompression.IsEnabled = true;
                    }));
                });
            }
        }
示例#16
0
        /// <summary>
        /// Handle a new incoming bluetooth connection
        /// </summary>
        /// <param name="ar"></param>
        private void BluetoothConnectionReceivedAsync(IAsyncResult ar)
        {
            if (!IsListening)
            {
                return;
            }

            try
            {
                var            newBTClient       = listenerInstance.EndAcceptBluetoothClient(ar);
                ConnectionInfo newConnectionInfo = new ConnectionInfo(ConnectionType.Bluetooth, newBTClient.Client.RemoteEndPoint, newBTClient.Client.LocalEndPoint, ApplicationLayerProtocol, this);

                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Info("New bluetooth connection from " + newConnectionInfo);
                }

                NetworkComms.IncomingConnectionEstablishThreadPool.EnqueueItem(QueueItemPriority.Normal, new WaitCallback((obj) =>
                {
                    #region Pickup The New Connection
                    try
                    {
                        BluetoothConnection.GetConnection(newConnectionInfo, ListenerDefaultSendReceiveOptions, newBTClient, 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"))
                            {
                                LogTools.LogException(ex, "ConnectionSetupError_SE");
                            }
                            else
                            {
                                LogTools.LogException(ex, "ConnectionSetupError");
                            }
                        }
                    }
                    #endregion
                }), null);
            }
            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"))
                    {
                        LogTools.LogException(ex, "ConnectionSetupError_SE");
                    }
                    else
                    {
                        LogTools.LogException(ex, "ConnectionSetupError");
                    }
                }
            }
            finally
            {
                listenerInstance.BeginAcceptBluetoothClient(BluetoothConnectionReceivedAsync, null);
            }
        }
        /// <summary>
        /// Attempts to use the data provided in packetBuilder to recreate something useful. 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)
        {
            int loopCounter = 0;

            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
                while (true)
                {
                    //If we have ended up with a null packet at the front, probably due to some form of concatenation 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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && packetBuilder.FirstByte() == 0)
                    {
                        #region Ignore Null Packet
                        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;
                        }
                        #endregion
                    }
                    else
                    {
                        int          packetHeaderSize = 0;
                        PacketHeader topPacketHeader;

                        #region Set topPacketHeader
                        if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                        {
                            //First determine the expected size of a header packet
                            packetHeaderSize = packetBuilder.FirstByte() + 1;

                            //Do we have enough data to build a header?
                            if (packetBuilder.TotalBytesCached < packetHeaderSize)
                            {
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace("     ... require " + packetHeaderSize + " bytes for packet header, only " + packetBuilder.TotalBytesCached + " bytes cached.");
                                }

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

                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace("     ... deserializing header using " + packetHeaderSize + " bytes, " + packetBuilder.TotalBytesCached + " bytes cached.");
                            }

                            //We have enough for a header
                            using (MemoryStream headerStream = packetBuilder.ReadDataSection(1, packetHeaderSize - 1))
                                topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions);
                        }
                        else
                        {
                            topPacketHeader = new PacketHeader(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged), packetBuilder.TotalBytesCached);
                        }
                        #endregion

                        //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.TotalPayloadSize)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace("     ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " total packet bytes.");
                            }

                            //Set the expected number of bytes and then return
                            packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.TotalPayloadSize;
                            return;
                        }
                        //Second case is we have enough data
                        else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.TotalPayloadSize)
                        {
                            #region Handle Packet
                            //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
                            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.TotalPayloadSize.ToString() + " payload bytes.");
                            }

                            bool isReservedPacketType = (topPacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged) &&
                                                         NetworkComms.ReservedPacketTypeNames.ContainsKey(topPacketHeader.PacketType));

                            //Get the packet sequence number if logging
                            string packetSeqNumStr = "";
                            if (NetworkComms.LoggingEnabled)
                            {
                                packetSeqNumStr = (topPacketHeader.ContainsOption(PacketHeaderLongItems.PacketSequenceNumber) ? ". pSeq#-" + topPacketHeader.GetOption(PacketHeaderLongItems.PacketSequenceNumber).ToString() + "." : "");
                            }

                            //Only reserved packet types get completed inline by default
                            if (isReservedPacketType)
                            {
#if WINDOWS_PHONE || NETFX_CORE
                                QueueItemPriority priority = QueueItemPriority.Normal;
#else
                                QueueItemPriority priority = (QueueItemPriority)Thread.CurrentThread.Priority;
#endif
                                PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions);
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
                                }
                                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.TotalPayloadSize), incomingPacketSendReceiveOptions);

                                //QueueItemPriority.Highest is the only priority that is executed inline
                                if (itemPriority == QueueItemPriority.Highest)
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
                                    }
                                    NetworkComms.CompleteIncomingItemTask(item);
                                }
                                else
                                {
#if NETFX_CORE
                                    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() + ") with priority " + itemPriority.ToString() + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr);
                                    }
#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() + packetSeqNumStr);
                                    }
#endif
                                }
                            }

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

                            //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;
                            }
                            #endregion
                        }
                        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 occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information.");
                }

                if (this is IPConnection)
                {
                    //Log the exception in DOS protection if enabled
                    if (IPConnection.DOSProtection.Enabled && ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint))
                    {
                        IPConnection.DOSProtection.LogMalformedData(ConnectionInfo.RemoteIPEndPoint.Address);
                    }
                }

                LogTools.LogException(ex, "CommsError", "A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. Loop counter " + loopCounter.ToString() + ". Packet builder contained " + packetBuilder.TotalBytesCached + " total cached bytes.");
                CloseConnection(true, 45);
            }
        }
        /// <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="returnObject">The deserialised payload object</param>
        /// <returns>Returns true if connection specific handlers were executed.</returns>
        public bool TriggerSpecificPacketHandlers(PacketHeader packetHeader, object returnObject)
        {
            try
            {
                if (packetHeader == null)
                {
                    throw new ArgumentNullException("packetHeader", "Provided PacketHeader cannot not be null.");
                }

                //We take a copy of the handlers list in case it is modified outside of the lock
                List <IPacketTypeHandlerDelegateWrapper> handlersCopy = null;
                lock (_syncRoot)
                    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.");
                    }

                    //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 delegates
                    //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.");
                            }
                            LogTools.LogException(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.");
                }
                LogTools.LogException(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType);
            }

            return(true);
        }
        /// <summary>
        /// Run example
        /// </summary>
        public static void RunExample()
        {
            Console.WriteLine("IntermediateSend Example ...\n");

            //Set the default send receive options to use for all communication
            //
            //Serializers convert custom objects into byte[] which is required for transmission
            //  - Here we have selected the ProtobufSerializer. For more please see the AdvancedSend example.
            //
            //Data processors manipulate the raw byte[] of an object, some encrypt, some compress etc etc.
            //  - Here we have selected a single data processor which will compress data, the LZMACompressor
            //       For more please see the AdvancedSend example.
            NetworkComms.DefaultSendReceiveOptions = new SendReceiveOptions <ProtobufSerializer, LZMACompressor>();

            //Ensure the packet construction time is included in all sent packets
            NetworkComms.DefaultSendReceiveOptions.IncludePacketConstructionTime = true;

            //Ensure all incoming packets are handled with the priority AboveNormal
            NetworkComms.DefaultSendReceiveOptions.ReceiveHandlePriority = QueueItemPriority.AboveNormal;

            //We need to define what happens when packets are received.
            //To do this we add an incoming packet handler for a 'Message' packet type.
            //You are free to choose your own packet types.
            //
            //This handler will expect the incoming raw bytes to be converted to a string (this is what the <string> bit means).
            NetworkComms.AppendGlobalIncomingPacketHandler <string>("Message", HandleIncomingMessagePacket);

            //Start listening for incoming 'TCP' connections.
            //We want to select a random port on all available adaptors so provide
            //an IPEndPoint using IPAddress.Any and port 0.
            //See also Connection.StartListening(ConnectionType.UDP, IPEndPoint)
            Connection.StartListening(ConnectionType.TCP, new IPEndPoint(IPAddress.Any, 0));

            //Print the IP addresses and ports we are listening on to make sure everything
            //worked as expected.
            Console.WriteLine("Listening for TCP messages on:");
            foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP))
            {
                Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);
            }

            //We loop here to allow any number of test messages to be sent and received
            while (true)
            {
                //Request a message to send somewhere
                Console.WriteLine("\nPlease enter your message and press enter (Type 'exit' to quit):");
                string stringToSend = Console.ReadLine();

                //If the user has typed exit then we leave our loop and end the example
                if (stringToSend == "exit")
                {
                    break;
                }
                else
                {
                    try
                    {
                        //Once we have a message we need to know where to send it
                        //We have created a small wrapper class to help keep things clean here
                        ConnectionInfo targetServerConnectionInfo = ExampleHelper.GetServerDetails();

                        //We get a connection to the desired target server
                        //This is performed using a static method, i.e. 'TCPConnection.GetConnection()' instead of
                        //using 'new TCPConnection()' to ensure thread safety. This means if you have a multi threaded application
                        //and attempt to get a connection the same target server simultaneously, you will only ever create
                        //a single connection.
                        Connection conn = TCPConnection.GetConnection(targetServerConnectionInfo);

                        //We send the string using a 'Message' packet type
                        //There are a large number of overrides to SendObject
                        //Please see our other examples or the online API
                        //http://www.networkcomms.net/api/
                        conn.SendObject("Message", stringToSend);
                    }
                    catch (CommsException ex)
                    {
                        //All NetworkComms.Net exception inherit from CommsException so we can easily
                        //catch all just by catching CommsException. For the break down of exceptions please
                        //see our online API.
                        //http://www.networkcomms.net/api/

                        //If an error occurs we need to decide what to do.
                        //In this example we will just log to a file and continue.
                        LogTools.LogException(ex, "IntermediateSendExampleError", "rekt m9");
                        Console.WriteLine("\nError: CommsException was caught. Please see the log file created for more information.\n");
                    }
                }
            }

            //We should always call shutdown on NetworkComms.Net if we have used it
            NetworkComms.Shutdown();
        }
        private void AddFileData(PacketHeader header, Connection connection, byte[] data)
        {
            try
            {
                SendInfo     info = null;
                ReceivedFile file = null;

                lock (syncRoot)
                {
                    long sequenceNumber = header.GetOption(PacketHeaderLongItems.PacketSequenceNumber);

                    if (incomingDataInfoCache.ContainsKey(connection.ConnectionInfo) && incomingDataInfoCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
                    {
                        info = incomingDataInfoCache[connection.ConnectionInfo][sequenceNumber];
                        incomingDataInfoCache[connection.ConnectionInfo].Remove(sequenceNumber);

                        if (!receivedFilesDict.ContainsKey(connection.ConnectionInfo))
                        {
                            receivedFilesDict.Add(connection.ConnectionInfo, new Dictionary <string, ReceivedFile>());
                        }

                        if (!receivedFilesDict[connection.ConnectionInfo].ContainsKey(info.Filename))
                        {
                            receivedFilesDict[connection.ConnectionInfo].Add(info.Filename, new ReceivedFile(info.Filename, connection.ConnectionInfo, info.TotalBytes));
                            AddNewReceivedItem(receivedFilesDict[connection.ConnectionInfo][info.Filename]);
                        }

                        file = receivedFilesDict[connection.ConnectionInfo][info.Filename];

                        Console.WriteLine("File was received " + info.Filename);
                    }
                    else
                    {
                        if (!incomingDataCache.ContainsKey(connection.ConnectionInfo))
                        {
                            incomingDataCache.Add(connection.ConnectionInfo, new Dictionary <long, byte[]>());
                        }

                        incomingDataCache[connection.ConnectionInfo].Add(sequenceNumber, data);
                    }
                }

                //If we have everything we need we can add data to the ReceivedFile
                if (info != null && file != null && !file.IsCompleted)
                {
                    file.AddData(info.BytesStart, 0, data.Length, data);
                    Console.WriteLine("Received: " + file.CompletedPercent + "%");
                    //Perform a little clean-up
                    file = null;
                    data = null;
                    GC.Collect();
                }
                else if (info == null ^ file == null)
                {
                    throw new Exception("Either both are null or both are set. Info is " + (info == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed."));
                }
            }
            catch (Exception ex)
            {
                //If an exception occurs we write to the log window and also create an error file
                LogTools.LogException(ex, "IncomingPartialFileDataError");
            }
        }
示例#21
0
        /// <summary>
        /// Handles an incoming packet of type 'PartialFileDataInfo'
        /// </summary>
        /// <param name="header">Header associated with incoming packet</param>
        /// <param name="connection">The connection associated with incoming packet</param>
        /// <param name="data">The incoming data automatically converted to a SendInfo object</param>
        private void IncomingPartialFileDataInfo(PacketHeader header, Connection connection, SendInfo info)
        {
            try
            {
                byte[]       data = null;
                ReceivedFile file = null;

                //Perform this in a thread safe way
                lock (syncRoot)
                {
                    //Extract the packet sequence number from the header
                    //The header can also user defined parameters
                    long sequenceNumber = info.PacketSequenceNumber;

                    if (incomingDataCache.ContainsKey(connection.ConnectionInfo) && incomingDataCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
                    {
                        //We already have the associated data in the cache
                        data = incomingDataCache[connection.ConnectionInfo][sequenceNumber];
                        incomingDataCache[connection.ConnectionInfo].Remove(sequenceNumber);

                        //Check to see if we have already received any files from this location
                        if (!receivedFilesDict.ContainsKey(connection.ConnectionInfo))
                        {
                            receivedFilesDict.Add(connection.ConnectionInfo, new Dictionary <string, ReceivedFile>());
                        }

                        //Check to see if we have already initialised this file
                        if (!receivedFilesDict[connection.ConnectionInfo].ContainsKey(info.Filename))
                        {
                            receivedFilesDict[connection.ConnectionInfo].Add(info.Filename, new ReceivedFile(info.Filename, connection.ConnectionInfo, info.TotalBytes));
                            AddNewReceivedItem(receivedFilesDict[connection.ConnectionInfo][info.Filename]);
                        }

                        file = receivedFilesDict[connection.ConnectionInfo][info.Filename];
                    }
                    else
                    {
                        //We do not yet have the necessary data corresponding with this SendInfo so we add the
                        //info to the cache
                        if (!incomingDataInfoCache.ContainsKey(connection.ConnectionInfo))
                        {
                            incomingDataInfoCache.Add(connection.ConnectionInfo, new Dictionary <long, SendInfo>());
                        }

                        incomingDataInfoCache[connection.ConnectionInfo].Add(sequenceNumber, info);
                    }
                }

                //If we have everything we need we can add data to the ReceivedFile
                if (data != null && file != null && !file.IsCompleted)
                {
                    file.AddData(info.BytesStart, 0, data.Length, data);

                    //Perform a little clean-up
                    file = null;
                    data = null;
                    GC.Collect();
                }
                else if (data == null ^ file == null)
                {
                    throw new Exception("Either both are null or both are set. Data is " + (data == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed."));
                }
            }
            catch (Exception ex)
            {
                //If an exception occurs we write to the log window and also create an error file
                AddLineToLog("Exception - " + ex.ToString());
                LogTools.LogException(ex, "IncomingPartialFileDataInfo");
            }
        }
示例#22
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);

                //Received data after comms shutdown initiated. We should just close the connection
                if (NetworkComms.commsShutdown)
                {
                    CloseConnection(false, -15);
                }

                stream = null;

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

                UDPConnection        connection;
                HandshakeUDPDatagram possibleHandshakeUDPDatagram = new HandshakeUDPDatagram(receivedBytes);
                if (isIsolatedUDPConnection)
                {
                    //This connection was created for a specific remoteEndPoint so we can handle the data internally
                    connection = this;
                }
                else
                {
                    IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(args.RemoteAddress.DisplayName.ToString()), int.Parse(args.RemotePort));
                    IPEndPoint localEndPoint  = new IPEndPoint(IPAddress.Parse(sender.Information.LocalAddress.DisplayName.ToString()), int.Parse(sender.Information.LocalPort));

                    ConnectionInfo desiredConnection = new ConnectionInfo(ConnectionType.UDP, remoteEndPoint, localEndPoint, ConnectionInfo.ApplicationLayerProtocol, ConnectionInfo.ConnectionListener);
                    try
                    {
                        //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
                        connection = GetConnection(desiredConnection, ConnectionUDPOptions, ConnectionDefaultSendReceiveOptions, false, this, possibleHandshakeUDPDatagram);
                    }
                    catch (ConnectionShutdownException)
                    {
                        if ((ConnectionUDPOptions & UDPOptions.Handshake) == UDPOptions.Handshake)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace("Attempted to get connection " + desiredConnection + " but this caused a ConnectionShutdownException. Exception caught and ignored as should only happen if the connection was closed shortly after being created.");
                            }
                            connection = null;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                if (connection != null && !possibleHandshakeUDPDatagram.DatagramHandled)
                {
                    //We pass the data off to the specific connection
                    //Lock on the packetbuilder locker as we may receive 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)
                        {
                            LogTools.LogException(new Exception("Packet builder had " + connection.packetBuilder.TotalBytesCached + " bytes remaining after a call to IncomingPacketHandleHandOff with connection " + connection.ConnectionInfo + ". 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)
            {
                //Receive 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 (ConnectionSetupException)
            {
                //Can occur if data is received as comms is being shutdown.
                //Method will attempt to create new connection which will throw ConnectionSetupException.
                CloseConnection(true, 50);
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "Error_UDPConnectionIncomingPacketHandler");
                CloseConnection(true, 30);
            }
        }
示例#23
0
        /// <summary>
        /// Attempts to complete the connection establish with a minimum of locking to avoid possible deadlocking
        /// </summary>
        /// <param name="remoteConnectionInfo"><see cref="ConnectionInfo"/> corresponding with remoteEndPoint</param>
        /// <param name="possibleClashWithExistingConnection">True if a connection already exists with provided remoteEndPoint</param>
        /// <param name="existingConnection">A reference to an existing connection if it exists</param>
        /// <returns>True if connection is successfully setup, otherwise false</returns>
        private bool ConnectionSetupHandlerFinal(ConnectionInfo remoteConnectionInfo, ref bool possibleClashWithExistingConnection, ref Connection existingConnection)
        {
            lock (NetworkComms.globalDictAndDelegateLocker)
            {
                List <Connection> connectionByEndPoint = NetworkComms.GetExistingConnection(ConnectionInfo.RemoteEndPoint, ConnectionInfo.LocalEndPoint, ConnectionInfo.ConnectionType, ConnectionInfo.ApplicationLayerProtocol);

                //If we no longer have the original endPoint reference (set in the constructor) then the connection must have been closed already
                if (connectionByEndPoint.Count == 0)
                {
                    connectionSetupException    = true;
                    connectionSetupExceptionStr = "Connection setup received after connection closure with " + ConnectionInfo;
                }
                else
                {
                    //COMMENT: As of version 3.0.0 we have allowed loop back connections where the identifier is the same
                    //We need to check for a possible GUID clash
                    //Probability of a clash is approx 0.1% if 1E19 connections are maintained simultaneously (This many connections has not be tested ;))
                    //but hey, we live in a crazy world!
                    //if (remoteConnectionInfo.NetworkIdentifier == NetworkComms.NetworkIdentifier)
                    //{
                    //    connectionSetupException = true;
                    //    connectionSetupExceptionStr = "Remote peer has same network identifier to local, " + remoteConnectionInfo.NetworkIdentifier + ". A real duplication is vanishingly improbable so this exception has probably been thrown because the local and remote application are the same.";
                    //}
                    //else
                    if (connectionByEndPoint[0] != this)
                    {
                        possibleClashWithExistingConnection = true;
                        existingConnection = connectionByEndPoint[0];
                    }
                    else if (connectionByEndPoint[0].ConnectionInfo.NetworkIdentifier != ShortGuid.Empty &&
                             connectionByEndPoint[0].ConnectionInfo.NetworkIdentifier != remoteConnectionInfo.NetworkIdentifier)
                    {
                        //We are in the same connection, so don't need to throw and exception but the remote network identifier
                        //has changed.
                        //This can happen for connection types where the local connection (this) may not have been closed
                        //when the remote peer closed. We need to trigger the connection close delegates with the old info, update
                        //the connection info and then call the establish delegates
                        #region Reset Connection without closing
                        //Call the connection close delegates
                        try
                        {
                            //Almost there
                            //Last thing is to call any connection specific shutdown delegates
                            if (ConnectionSpecificShutdownDelegate != null)
                            {
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Debug("Triggered connection specific shutdown delegates with " + ConnectionInfo);
                                }
                                ConnectionSpecificShutdownDelegate(this);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogTools.LogException(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 (NetworkComms.globalConnectionShutdownDelegates != null)
                            {
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Debug("Triggered global shutdown delegates with " + ConnectionInfo);
                                }
                                NetworkComms.globalConnectionShutdownDelegates(this);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogTools.LogException(ex, "GlobalConnectionShutdownDelegateError", "Error while executing global connection shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
                        }

                        EndPoint newRemoteEndPoint;
                        if (this.ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint) &&
                            remoteConnectionInfo.LocalEndPoint.GetType() == typeof(IPEndPoint))
                        {
                            newRemoteEndPoint = new IPEndPoint(this.ConnectionInfo.RemoteIPEndPoint.Address, remoteConnectionInfo.LocalIPEndPoint.Port);
                        }
                        else
                        {
                            throw new NotImplementedException("ConnectionSetupHandlerFinal not implemented for EndPoints of type " + this.ConnectionInfo.RemoteEndPoint.GetType());
                        }

                        NetworkComms.UpdateConnectionReferenceByEndPoint(this, newRemoteEndPoint, this.ConnectionInfo.LocalEndPoint);

                        ConnectionInfo.UpdateInfoAfterRemoteHandshake(remoteConnectionInfo, newRemoteEndPoint);

                        //Trigger the establish delegates
                        TriggerConnectionEstablishDelegates();
                        #endregion

                        return(true);
                    }
                    else
                    {
                        //Update the connection info
                        //We never change the this.ConnectionInfo.RemoteEndPoint.Address as there might be NAT involved
                        //We may update the port however
                        EndPoint newRemoteEndPoint;
                        if (this is IPConnection)
                        {
                            newRemoteEndPoint = new IPEndPoint(this.ConnectionInfo.RemoteIPEndPoint.Address, remoteConnectionInfo.LocalIPEndPoint.Port);
                        }
#if NET35 || NET4
                        else if (this is BluetoothConnection)
                        {
                            newRemoteEndPoint = ConnectionInfo.RemoteBTEndPoint;
                        }
#endif
                        else
                        {
                            throw new NotImplementedException("ConnectionSetupHandlerFinal not implemented for EndPoints of type " + this.ConnectionInfo.RemoteEndPoint.GetType());
                        }

                        NetworkComms.UpdateConnectionReferenceByEndPoint(this, newRemoteEndPoint, this.ConnectionInfo.LocalEndPoint);

                        ConnectionInfo.UpdateInfoAfterRemoteHandshake(remoteConnectionInfo, newRemoteEndPoint);

                        return(true);
                    }
                }
            }

            return(false);
        }
示例#24
0
        /// <summary>
        /// Incoming data listen sync method
        /// </summary>
        private void IncomingUDPPacketWorker()
        {
            try
            {
                while (true)
                {
                    if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                    {
                        break;
                    }

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

                    //Received data after comms shutdown initiated. We should just close the connection
                    if (NetworkComms.commsShutdown)
                    {
                        CloseConnection(false, -14);
                    }

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

                    UDPConnection        connection;
                    HandshakeUDPDatagram possibleHandshakeUDPDatagram = new HandshakeUDPDatagram(receivedBytes);
                    if (isIsolatedUDPConnection)
                    {
                        //This connection was created for a specific remoteEndPoint so we can handle the data internally
                        connection = this;
                    }
                    else
                    {
                        ConnectionInfo desiredConnection = new ConnectionInfo(ConnectionType.UDP, remoteEndPoint, udpClient.LocalIPEndPoint, ConnectionInfo.ApplicationLayerProtocol, ConnectionInfo.ConnectionListener);
                        try
                        {
                            //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
                            connection = GetConnection(desiredConnection, ConnectionUDPOptions, ConnectionDefaultSendReceiveOptions, false, this, possibleHandshakeUDPDatagram);
                        }
                        catch (ConnectionShutdownException)
                        {
                            if ((ConnectionUDPOptions & UDPOptions.Handshake) == UDPOptions.Handshake)
                            {
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace("Attempted to get connection " + desiredConnection + " but this caused a ConnectionShutdownException. Exception caught and ignored as should only happen if the connection was closed shortly after being created.");
                                }
                                connection = null;
                            }
                            else
                            {
                                throw;
                            }
                        }
                    }

                    if (connection != null && !possibleHandshakeUDPDatagram.DatagramHandled)
                    {
                        //We pass the data off to the specific connection
                        //Lock on the packetbuilder locker as we may receive UDP packets in parallel from this host
                        lock (connection.packetBuilder.Locker)
                        {
                            if (NetworkComms.LoggingEnabled)
                            {
                                NetworkComms.Logger.Trace(" ... " + receivedBytes.Length.ToString() + " bytes added to packetBuilder for " + connection.ConnectionInfo + ". Cached " + connection.packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + connection.packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                            }

                            connection.packetBuilder.AddPartialPacket(receivedBytes.Length, receivedBytes);
                            if (connection.packetBuilder.TotalBytesCached > 0)
                            {
                                connection.IncomingPacketHandleHandOff(connection.packetBuilder);
                            }

                            if (connection.packetBuilder.TotalPartialPacketCount > 0)
                            {
                                LogTools.LogException(new Exception("Packet builder had " + connection.packetBuilder.TotalBytesCached + " bytes remaining after a call to IncomingPacketHandleHandOff with connection " + connection.ConnectionInfo + ". 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)
            {
                //Receive 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 (ConnectionSetupException)
            {
                //Can occur if data is received as comms is being shutdown.
                //Method will attempt to create new connection which will throw ConnectionSetupException.
                CloseConnection(true, 50);
            }
            catch (Exception ex)
            {
                LogTools.LogException(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);
            }
        }
示例#25
0
        /// <summary>
        /// Sends a <see cref="Packet"/> to the provided endPoint. Offers more performance if an identical packet is being sent to multiple peers.
        /// NOTE: Any possible reply will be ignored unless listening for incoming UDP packets.
        /// </summary>
        /// <typeparam name="packetPayloadObjectType">The type of object encapsulated by the provided packet</typeparam>
        /// <param name="packetToSend">The packet to send</param>
        /// <param name="ipEndPoint">The destination IPEndPoint. Supports multicast endpoints.</param>
        /// <param name="sendReceiveOptions">The sendReceiveOptions to use for this send</param>
        /// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom
        /// application layer protocol to provide useful features such as inline serialisation,
        /// transparent packet transmission, remote peer handshake and information etc. We strongly
        /// recommend you use the NetworkComms.Net application layer protocol.</param>
        public static void SendObject <packetPayloadObjectType>(IPacket packetToSend, IPEndPoint ipEndPoint, SendReceiveOptions sendReceiveOptions, ApplicationLayerProtocolStatus applicationLayerProtocol)
        {
            if (ipEndPoint == null)
            {
                throw new ArgumentNullException("ipEndPoint");
            }
            if (sendReceiveOptions == null)
            {
                throw new ArgumentNullException("sendReceiveOptions");
            }

            if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Undefined)
            {
                throw new ArgumentException("A value of ApplicationLayerProtocolStatus.Undefined is invalid when using this method.", "applicationLayerProtocol");
            }

            if (sendReceiveOptions.Options.ContainsKey("ReceiveConfirmationRequired"))
            {
                throw new ArgumentException("Attempted to use a rouge UDP sender when the provided send receive" +
                                            " options specified the ReceiveConfirmationRequired option, which is unsupported. Please create a specific connection" +
                                            "instance to use this feature.", "sendReceiveOptions");
            }

            //Check the send receive options
            if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
            {
                if (sendReceiveOptions.DataSerializer != DPSManager.GetDataSerializer <NullSerializer>())
                {
                    throw new ArgumentException("Attempted to use a rouge UDP sender when the provided send receive" +
                                                " options serialiser was not NullSerializer. Please provide compatible send receive options in order to successfully" +
                                                " instantiate this unmanaged connection.", "sendReceiveOptions");
                }

                if (sendReceiveOptions.DataProcessors.Count > 0)
                {
                    throw new ArgumentException("Attempted to use a rouge UDP sender when the provided send receive" +
                                                " options contains data processors. Data processors may not be used with unmanaged connections." +
                                                " Please provide compatible send receive options in order to successfully instantiate this unmanaged connection.", "sendReceiveOptions");
                }
            }

            List <UDPConnection> connectionsToUse = null;

            //If we are already listening on what will be the outgoing adaptor we can send with that client to ensure reply packets are collected
            //The exception here is the broadcasting which goes out all adaptors
            if (ipEndPoint.Address != IPAddress.Broadcast)
            {
                #region Discover best local endpoint

                //Initialise best local end point as match all
                IPEndPoint bestLocalEndPoint = new IPEndPoint(IPAddress.Any, 0);
                try
                {
                    bestLocalEndPoint = IPTools.BestLocalEndPoint(ipEndPoint);
                    //Set the port to 0 to match all.
                    bestLocalEndPoint.Port = 0;
                }
                catch (SocketException ex)
                {
                    throw new ConnectionSetupException("Attempting to determine the best local endPoint to connect to " + ipEndPoint + " resulted in a socket exception.", ex);
                }
                catch (Exception ex)
                {
                    LogTools.LogException(ex, "BestLocalEndPointError", "Error while attempting to determine the best local end point to contact " + ipEndPoint.ToString());
                }

                #endregion Discover best local endpoint

                #region Check For Existing Local Listener

                List <UDPConnectionListener> existingListeners = Connection.ExistingLocalListeners <UDPConnectionListener>(bestLocalEndPoint);

                for (int i = 0; i < existingListeners.Count; i++)
                {
                    if (existingListeners[i].UDPConnection.ConnectionInfo.ApplicationLayerProtocol == applicationLayerProtocol)
                    {
                        connectionsToUse = new List <UDPConnection> {
                            existingListeners[i].UDPConnection
                        };

                        //Once we have a matching connection we can break
                        break;
                    }
                }

                #endregion Check For Existing Local Listener

                //If we have not picked up an existing listener we need to use/create a rougeSender
                if (connectionsToUse == null)
                {
                    #region Check For Suitable Rouge Sender

                    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(applicationLayerProtocol) ||
                                !udpRogueSenders[applicationLayerProtocol].ContainsKey(bestLocalEndPoint) ||
                                udpRogueSenders[applicationLayerProtocol][bestLocalEndPoint].ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                            {
                                //Create a new rogue sender
                                if (NetworkComms.LoggingEnabled)
                                {
                                    NetworkComms.Logger.Trace("Creating UDPRougeSender.");
                                }

                                if (!udpRogueSenders.ContainsKey(applicationLayerProtocol))
                                {
                                    udpRogueSenders.Add(applicationLayerProtocol, new Dictionary <IPEndPoint, UDPConnection>());
                                }

                                IPAddress anyRemoteIP = AnyRemoteIPAddress(ipEndPoint.AddressFamily);
                                udpRogueSenders[applicationLayerProtocol][bestLocalEndPoint] = new UDPConnection(new ConnectionInfo(ConnectionType.UDP, new IPEndPoint(anyRemoteIP, 0), bestLocalEndPoint, applicationLayerProtocol), sendReceiveOptions, UDPConnection.DefaultUDPOptions, false);
                            }

                            connectionsToUse = new List <UDPConnection> {
                                udpRogueSenders[applicationLayerProtocol][bestLocalEndPoint]
                            };
                        }
                    }

                    #endregion Check For Suitable Rouge Sender
                }
            }
            else
            {
                #region Get A Sender On All Interfaces For Broadcast

                lock (udpRogueSenderCreationLocker)
                {
                    //We do something special for broadcasts by selected EVERY adaptor
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace("Getting senders for UDP broadcasting.");
                    }

                    if (!udpRogueSenders.ContainsKey(applicationLayerProtocol))
                    {
                        udpRogueSenders.Add(applicationLayerProtocol, new Dictionary <IPEndPoint, UDPConnection>());
                    }

                    connectionsToUse = new List <UDPConnection>();

                    //This is a broadcast and we need to send the broadcast over every local adaptor
                    List <IPAddress> validLocalIPAddresses = HostInfo.IP.FilteredLocalAddresses();
                    foreach (IPAddress address in validLocalIPAddresses)
                    {
                        IPEndPoint currentLocalIPEndPoint = new IPEndPoint(address, 0);
                        List <UDPConnectionListener> existingListeners = Connection.ExistingLocalListeners <UDPConnectionListener>(currentLocalIPEndPoint);

                        //If there is an existing listener we use that
                        if (existingListeners.Count > 0)
                        {
                            for (int i = 0; i < existingListeners.Count; i++)
                            {
                                if (existingListeners[i].UDPConnection.ConnectionInfo.ApplicationLayerProtocol == applicationLayerProtocol)
                                {
                                    connectionsToUse.Add(existingListeners[i].UDPConnection);

                                    //Once we have a matching connection we can break
                                    break;
                                }
                            }
                        }
                        else
                        {
                            //If not we check the rouge senders
                            if (!udpRogueSenders[applicationLayerProtocol].ContainsKey(currentLocalIPEndPoint) ||
                                udpRogueSenders[applicationLayerProtocol][currentLocalIPEndPoint].ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                            {
                                IPAddress anyRemoteIP = AnyRemoteIPAddress(currentLocalIPEndPoint.AddressFamily);

                                udpRogueSenders[applicationLayerProtocol][currentLocalIPEndPoint] = new UDPConnection(new ConnectionInfo(ConnectionType.UDP, new IPEndPoint(anyRemoteIP, 0), currentLocalIPEndPoint, applicationLayerProtocol), sendReceiveOptions, UDPConnection.DefaultUDPOptions, false);
                            }

                            connectionsToUse.Add(udpRogueSenders[applicationLayerProtocol][currentLocalIPEndPoint]);
                        }
                    }
                }

                #endregion Get A Sender On All Interfaces For Broadcast
            }

            foreach (UDPConnection connection in connectionsToUse)
            {
                try
                {
                    //This has been commented out for the time being as it made no difference to the broadcast issue
                    //we were investigating at the time we had issues
                    //Use the network broadcast address instead of the global broadcast address where possible
                    //if (ipEndPoint.Address == IPAddress.Broadcast && connection.ConnectionInfo.LocalIPEndPoint.AddressFamily == AddressFamily.InterNetwork)
                    //{
                    //    IPEndPoint ipEndPointToUse = new IPEndPoint(IPTools.GetIPv4NetworkBroadcastAddress(connection.ConnectionInfo.LocalIPEndPoint.Address), ipEndPoint.Port);
                    //    connection.SendPacketSpecific<packetPayloadObjectType>(packetToSend, ipEndPointToUse);
                    //}
                    //else
                    connection.SendPacketSpecific <packetPayloadObjectType>(packetToSend, ipEndPoint);
                }
                catch (SocketException) { /* Ignore any socket exceptions */ }
            }

            //Dispose of the packet
            packetToSend.Dispose();
        }
示例#26
0
        /// <summary>
        /// Asynchronous incoming connection data delegate
        /// </summary>
        /// <param name="ar">The call back state object</param>
        void IncomingBluetoothPacketHandler(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
                var 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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled &&
                        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 synchronously
                        //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. As we are in this loop this can only be a suplementary buffer for THIS packet.
                            //Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                            {
                                long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                                dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                            }

                            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 (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
                                {
                                    if (NetworkComms.LoggingEnabled)
                                    {
                                        NetworkComms.Logger.Trace(" ... null packet ignored 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 hand off
                    //Should we have a complete packet this method will start the appropriate 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
                        //If packetBuilder.TotalBytesExpected is 0 we know we're going to start waiting for a fresh packet. Therefore use the initial buffer size
                        if (packetBuilder.TotalBytesExpected == 0)
                        {
                            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];
                        }
                        else
                        //Otherwise this can only be a supplementary buffer for THIS packet. Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                        {
                            long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                            dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                        }

                        totalBytesRead = 0;
                    }

#if WINDOWS_PHONE
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#else
                    netStream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingBluetoothPacketHandler, 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)
            {
                LogTools.LogException(ex, "Error_BluetoothConnectionIncomingPacketHandler");
                CloseConnection(true, 31);
            }

#if !WINDOWS_PHONE
            Thread.CurrentThread.Priority = ThreadPriority.Normal;
#endif
        }