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"); } }
/// <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"); } } }
// 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"); } } } }
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); }
/// <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"); } }
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 } }
/// <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(); }
/// <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); }
/// <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; })); }); } }
/// <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"); } }
/// <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"); } }
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); } }
/// <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); }
/// <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); } }
/// <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(); }
/// <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 }