/// <summary> /// Manage the connected client /// </summary> /// <param name="result">TCPClient object</param> /// <returns>Return a task, it is used to allow the Task asynchronous programming model (TAP)</returns> public async Task ServeClient(object result) { NetworkStream stream = null; TcpClient client = null; Dictionary <string, FileRecvStatus> updateRecvDictionary = new Dictionary <string, FileRecvStatus>(); Dictionary <string, FileSendStatus> updateSendDictionary = new Dictionary <string, FileSendStatus>(); try { client = (TcpClient)result; Console.WriteLine($"{DateTime.Now.ToString()}\t - TCPListener Client connected! {((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString()}"); byte[] bytes = new byte[1 + 256 + 8]; stream = client.GetStream(); int i = 0; if ((i = await stream.ReadAsync(bytes, 0, bytes.Length)) != 0) { // The first byte define the type of the packet byte[] readPacket = new byte[1]; Array.Copy(bytes, 0, readPacket, 0, 1); // If it is not correct, send an Exception if ((int)readPacket[0] > 5) { throw new Exception($"Packet not valid"); } // The following 256 bytes are the name of the file (UTF8 coding) PacketType type = (PacketType)readPacket[0]; readPacket = new byte[256]; Array.Copy(bytes, 1, readPacket, 0, 256); string filename = ""; UTF8Encoding encoder; // Trown an exception in case the sequence of bytes cannot be converted as a stirng try { encoder = new UTF8Encoding(); filename = encoder.GetString(readPacket); filename = filename.Replace("\0", string.Empty); } catch (Exception e) { throw new Exception($"Packet not valid - Reason {e.Message}"); } long dimFile = 0; string ipClient = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString(); switch (type) { case PacketType.RFILE: if (_referenceData.GetInfoLocalUser().AcceptAllFile) { _referenceData.AddOrUpdateRecvStatus(ipClient, filename, FileRecvStatus.YSEND); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ipClient, filename, FileRecvStatus.YSEND, "-", 0.0f); MainWindow.main.NotifySistem(); MainWindow.main.SendResponse(filename, ipClient, PacketType.YFILE); })); } else { _referenceData.AddOrUpdateRecvStatus(ipClient, filename, FileRecvStatus.TOCONF); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ipClient, filename, FileRecvStatus.TOCONF, "-", 0.0f); MainWindow.main.NotifySistem(); })); } break; case PacketType.YFILE: if (_referenceData.UpdateSendStatusFileForUser(ipClient, filename, FileSendStatus.CONFERMED)) { await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ipClient, filename, FileSendStatus.CONFERMED, "-", 0); MainWindow.main.SendFile(filename, ipClient); })); } else { throw new Exception("No file with name " + filename + " was announced from this client"); } break; case PacketType.NFILE: if (_referenceData.UpdateSendStatusFileForUser(ipClient, filename, FileSendStatus.REJECTED)) { await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ipClient, filename, FileSendStatus.REJECTED, "-", 0); MainWindow.main.SendFile(filename, ipClient); })); } else { throw new Exception("No file with name " + filename + " was announced from this client"); } break; case PacketType.FSEND: { if (_referenceData.CheckPacketRecvFileStatus(ipClient, filename)) { throw new Exception("File with name " + filename + " never confirmed or need to be resend to the user"); } string fileNameOriginal = filename; readPacket = new byte[8]; Array.Copy(bytes, 257, readPacket, 0, 8); try { dimFile = BitConverter.ToInt64(readPacket, 0); } catch (Exception e) { throw new Exception($"Packet not valid - Reason {e.Message}"); } await ServeReceiveFile(client, stream, ipClient, filename, dimFile); } break; case PacketType.CIMAGE: readPacket = new byte[8]; Array.Copy(bytes, 257, readPacket, 0, 8); try { dimFile = BitConverter.ToInt64(readPacket, 0); } catch (Exception e) { throw new Exception($"Packet not valid - Reason {e.Message}"); } await ServeReceiveProfileImage(client, stream, ipClient, filename, dimFile); break; } } } catch (SocketException e) { Console.WriteLine($"{DateTime.Now.ToString()}\t - Serve TCPClient SocketException - {e.Message}"); } catch (Exception e) { Console.WriteLine($"{DateTime.Now.ToString()}\t - Serve TCPClient Exception - {e.GetType()} {e.Message}"); } finally { stream.Close(); client.Close(); } }
/// <summary> /// Send file to the remote user that accept it /// </summary> /// <param name="filename">File name</param> /// <param name="ip">Ip remote user</param> public async Task SendFile(string filename, string ip) { // Check if the file is in a status to be rended or if it was confirmed if (!_referenceData.CheckPacketSendFileStatus(ip, filename)) { return; } if (_referenceData.GetUserStatus(ip).Equals("offline")) { _referenceData.UpdateSendStatusFileForUser(ip, Utility.PathToFileName(filename), FileSendStatus.RESENT); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.RESENT, "-", 0); })); return; } IPAddress serverAddr = IPAddress.Parse(ip); // In case of exception resend the packet three times TcpClient client = null; NetworkStream stream = null; if (!_referenceData.CheckPacketSendFileStatus(ip, filename)) { return; } try { client = new TcpClient(); await client.ConnectAsync(serverAddr.ToString(), SharedInfo.TCPPort).ConfigureAwait(false); byte[] bytes = new byte[1 + 256 + 8]; // 1^ byte: packet type bytes[0] = (byte)PacketType.FSEND; // Following 256 bytes : file name UTF8Encoding encorder = new UTF8Encoding(); encorder.GetBytes(Utility.PathToFileName(filename)).CopyTo(bytes, 1); // Open file image filename = Utility.PathTmp() + "\\" + filename; using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize * 1024, FileOptions.Asynchronous | FileOptions.SequentialScan)) { // Following 8 bytes : file legth BitConverter.GetBytes(file.Length).CopyTo(bytes, 257); stream = client.GetStream(); // Primi 265 byte di header await stream.WriteAsync(bytes, 0, 265).ConfigureAwait(false); _referenceData.UpdateSendStatusFileForUser(serverAddr.ToString(), Utility.PathToFileName(filename), FileSendStatus.INPROGRESS); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.INPROGRESS, "-", 0); })); // First 297 : header bytes = new byte[bufferSize * 64]; int i; long dataReceived = file.Length; uint estimatedTimePacketCount = 0; double numerator = 0.0; double estimateTime = 0.0; DateTime started = DateTime.Now; TimeSpan estimatedTime = TimeSpan.FromSeconds(0); while (((i = file.Read(bytes, 0, bytes.Length)) != 0) && dataReceived >= 0) { double dataReceivedJet = 0.0f; if (_referenceData.CheckSendStatusFile(ip, Utility.PathToFileName(filename), FileSendStatus.REJECTED)) { throw new RejectedFileException("File is rejected by remote host"); } if (_referenceData.GetUserStatus(ip).Equals("offline")) { throw new Exception("User offline"); } if (dataReceived > 0 && dataReceived < i) { await stream.WriteAsync(bytes, 0, Convert.ToInt32(dataReceived)); dataReceivedJet = 100f; } else { await stream.WriteAsync(bytes, 0, i); dataReceivedJet = Math.Ceiling((double)(file.Length - dataReceived) / ((double)file.Length) * 100); } dataReceived -= i; if (estimatedTimePacketCount < 5) { numerator += (double)(file.Length - dataReceived); estimatedTimePacketCount++; } else { TimeSpan elapsedTime = DateTime.Now - started; estimateTime = elapsedTime.TotalSeconds * dataReceived / numerator; estimatedTime = TimeSpan.FromSeconds(estimateTime); numerator = 0.0; estimatedTimePacketCount = 0; } string estimatedTimeJet = string.Format("{00:00}", estimatedTime.Minutes) + ":" + string.Format("{00:00}", estimatedTime.Seconds) + ":" + string.Format("{00:00}", estimatedTime.Milliseconds); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.INPROGRESS, estimatedTimeJet, dataReceivedJet); })); } } _referenceData.UpdateSendStatusFileForUser(serverAddr.ToString(), Utility.PathToFileName(filename), FileSendStatus.END); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.END, "-", 100); })); } catch (RejectedFileException e) { Console.WriteLine($"{DateTime.Now.ToString()}\t - RejectedFileException on SendFile - {e.Message}"); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.REJECTED, "-", 0); })); } catch (SocketException e) { Console.WriteLine($"{DateTime.Now.ToString()}\t - SocketException on SendFile - {e.Message}"); _referenceData.UpdateSendStatusFileForUser(serverAddr.ToString(), Utility.PathToFileName(filename), FileSendStatus.REJECTED); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.REJECTED, "-", 0); })); } catch (Exception e) { Console.WriteLine($"{DateTime.Now.ToString()}\t - Exception on SendFile - {e.Message}"); // If the remote host was offline, try to resend it for three times _referenceData.UpdateSendStatusFileForUser(serverAddr.ToString(), Utility.PathToFileName(filename), FileSendStatus.REJECTED); await MainWindow.main.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { MainWindow.main.AddOrUpdateListFile(ip, Utility.PathToFileName(filename), FileSendStatus.REJECTED, "-", 0); })); } finally { client.Close(); stream.Close(); } }