private void PresenceHelloSend() { byte[] buffer; TTNet.GeneratePresenceBuffer(MacAddress, out buffer, TTInstruction.Discovery_Hello, Settings.SettingsData.Name, DeviceType); socketUDP.SendTo(buffer, PresenceEndPoint); }
private void PresenceByeSend() { byte[] buffer; TTNet.GeneratePresenceBuffer(MacAddress, out buffer, TTInstruction.Discovery_Bye); socketUDP.SendTo(buffer, PresenceEndPoint); }
private CommunicationResult TryRead(string ipPort, int count, bool doEncryption) { ReadResult result = server.ReadWithTimeout(maxPingMs, ipPort, count); TTInstruction ins = TTInstruction.Empty; byte[] buffer = null; if (result.Status != ReadResultStatus.Success) { throw new FailedReceivingException($"Did not receive response ({result.Status})."); } if (doEncryption && clientEncryptor != null) { buffer = clientEncryptor.AESDecryptBytes(result.Data); } else { buffer = result.Data; } byte[] dat = null; if (!TTNet.UnpackTCPBuffer(buffer, ref ins, ref dat)) { throw new FailedReceivingException($"Received invalid response."); } return(new CommunicationResult(ins, dat)); }
private CommunicationResult TryRead(int count, int?overrideTimeoutMs = null) { int timeout = overrideTimeoutMs ?? maxPingMs; ReadResult result = client.ReadWithTimeout(timeout, count); if (result.Status != ReadResultStatus.Success) { throw new FailedReceivingException($"Did not receive response ({result.Status})."); } TTInstruction ins = TTInstruction.Empty; byte[] dat = null; if (!TTNet.UnpackTCPBuffer(result.Data, ref ins, ref dat)) { throw new FailedReceivingException($"Received invalid response."); } return(new CommunicationResult(ins, dat)); }
private void Grid_Loaded(object sender, RoutedEventArgs e) { SetSendButtonEnabled(true); InitializeNetworkInfo(); // TCP transferServer = new TransferServer(IPAddress, Settings.SettingsData.NetworkTransferPort, Settings.SettingsData.MaxNetworkPingMs, Settings.SettingsData.MaxBufferSize, TransferProgress); transferServer.OnRecordableEvent += OnRecordableEvent; transferServer.Start(); transferClient = new TransferClient(Settings.SettingsData.NetworkTransferPort, Settings.SettingsData.MaxNetworkPingMs, Settings.SettingsData.MaxBufferSize, TransferProgress); transferClient.OnRecordableEvent += OnRecordableEvent; TTNet.GeneratePresenceBuffer(MacAddress, out PresenceBuffer, TTInstruction.Discovery_Present, Settings.SettingsData.Name, DeviceType); PresenceTimer = new Timer(new TimerCallback(PresenceSend), null, 2000, Settings.SettingsData.PresenceSendPeriod); PresenceTimeoutCheckTimer = new Timer(new TimerCallback(PresenceTimeoutTick), null, Settings.SettingsData.MaxNetworkPingMs, Settings.SettingsData.PresenceTimeoutCheckPeriod); presenceReceiveThread = new Thread(new ThreadStart(PresenceReceiveLoop)); presenceReceiveThread.IsBackground = true; presenceReceiveThread.Start(); PresenceHelloSend(); }
private void PresenceReceiveLoop() { IPEndPoint remoteIpEndPoint; PhysicalAddressSerializable remoteMac; TTInstruction instruction; List <byte> data; while (true) { remoteIpEndPoint = null; remoteMac = null; instruction = TTInstruction.Empty; data = null; if (TTNet.UnpackBuffer(clientUDP.Receive(ref remoteIpEndPoint), ref remoteMac, ref instruction, ref data)) { //OnRecordableEvent($"Received presence from: {remoteIpEndPoint.Address.ToString()}", Console.ConsoleMessageType.Common); // Skip if from self if (remoteIpEndPoint.Address.ToString() == IPAddress.ToString()) { continue; } // Add or update device in saved list if (instruction == TTInstruction.Discovery_Hello || instruction == TTInstruction.Discovery_Present) { if (!Enum.IsDefined(typeof(DeviceType), (int)data[0])) { continue; } DeviceType deviceType = (DeviceType)data[0]; string deviceName = Encoding.UTF8.GetString(data.GetRange(1, data.Count - 1).ToArray()); Application.Current.Dispatcher.Invoke(() => { Settings.SettingsData.AddUpdateDevice(remoteMac, deviceName, remoteIpEndPoint.Address, deviceType); }); } // Keep track of online status switch (instruction) { case TTInstruction.Discovery_Hello: OnlineDevices.SetOnline(remoteMac); PresenceSend(null); break; case TTInstruction.Discovery_Present: OnlineDevices.SetOnline(remoteMac); break; case TTInstruction.Discovery_Bye: OnlineDevices.SetOffline(remoteMac); break; } } } }
// General private void InitializeNetworkInfo() { IPAddress internetIp; using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0)) { socket.Connect("8.8.8.8", 65530); IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint; internetIp = endPoint.Address; } // Mac - this will either select the interface based on the selected mac address or the interface which will connect to internet MacAddress = null; PhysicalAddress backupMac = null; IPAddress backupIp = null; IPAddress backupMask = null; var nics = TTNet.GetUsableNetworkInterfaces(); foreach (NetworkInterface nic in nics) { var interNetwork = nic.GetIPProperties().UnicastAddresses.Where(u => u.Address.AddressFamily == AddressFamily.InterNetwork); IPAddress interfaceIp = interNetwork.Select(u => u.Address).FirstOrDefault(); IPAddress interfaceMask = interNetwork.Select(u => u.IPv4Mask).FirstOrDefault(); if (interfaceIp == null) { continue; } PhysicalAddress interfaceMac = nic.GetPhysicalAddress(); if (Settings.SettingsData.InterfaceMac != null && Settings.SettingsData.InterfaceMac.Equals(interfaceMac)) { MacAddress = interfaceMac; IPAddress = interfaceIp; IPMask = interfaceMask; break; } if (interfaceIp.ToString() == internetIp.ToString()) { backupMac = interfaceMac; backupIp = interfaceIp; backupMask = interfaceMask; } } // If interface with selected mac doesn't exist, select the one which connect to internet if (MacAddress == null) { if (backupMac != null) { MacAddress = backupMac; IPAddress = internetIp; IPMask = backupMask; Settings.SettingsData.InterfaceMac = MacAddress; } else { throw new Exception("Could not find a usable network interface."); } } // Broadcast endpoint PresenceEndPoint = new IPEndPoint(TTNet.GetBroadcastAddress(IPAddress, IPMask), Settings.SettingsData.NetworkPresencePort); }
// Data private async Task SendData() { transferStopwatch = new Stopwatch(); transferStopwatch.Start(); int totalItemCount = 0; await Task.Run(() => { // Send files info byte[] infoBuffer = new byte[13]; infoBuffer[0] = (byte)TTInstruction.Transfer_TransferInfo; totalItemCount = items.Count(); foreach (var item in items) { totalItemCount += item.GetTotalChildCount(); } byte[] countBytes = BitConverter.GetBytes(totalItemCount); Array.Copy(countBytes, 0, infoBuffer, 1, 4); long totalSize = 0; foreach (var item in items) { totalSize += item.GetTotalSize(); } byte[] sizeBytes = BitConverter.GetBytes(totalSize); Array.Copy(sizeBytes, 0, infoBuffer, 1 + 4, 8); TrySend(infoBuffer, true); // Send data bytesSent = 0; totalBytes = totalSize; foreach (var item in items) { if (item.IsFolder) { SendFolder(item, ""); } else { SendFile(item, ""); } } }); transferStopwatch.Stop(); OnRecordableEvent($"Sucessfully sent {totalItemCount} item/s ({ExplorerControl.FormatFileSize(bytesSent)}) in {TTNet.FormatTimeSpan(transferStopwatch.Elapsed)} at average { ExplorerControl.FormatFileSize(totalBytes * 1000 / transferStopwatch.ElapsedMilliseconds)}/s.", Console.ConsoleMessageType.Common); }
private async Task EstablishConnection() { await Task.Run(() => { CommunicationResult res = null; byte[] buffer = null; // Deny, accept, or askpass res = TryRead(1, maxPingMs + Settings.SettingsData.MaxPermissionAskWaitMs); // Denied switch (res.Instruction) { case TTInstruction.Connection_RefuseBusy: throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it's busy right now."); case TTInstruction.Connection_RefuseDeny: throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it hasn't allowed you to send them files."); } // Encryption DataEncryptor encryptor = null; if (serverDevice.EncryptionEnabled) { // Check if server also has password set if (res.Instruction != TTInstruction.Connection_AskPass) { TrySend(new byte[] { (byte)TTInstruction.Connection_RefusePass }, false); throw new FailedConnectingException($"Connection to {serverDevice.Name} refused because you have set a password and it has none."); } // Send password encryptor = new DataEncryptor(serverDevice.EncryptionPassword); byte[] timePassword = TTNet.GenerateTimePasswordBytes(); buffer = new byte[1] { (byte)TTInstruction.Connection_SendPass }.ToList().Concat(encryptor.AESEncryptBytes(timePassword)).ToArray(); TrySend(buffer, false); // Receive password response res = TryRead(1); if (res.Instruction != TTInstruction.Connection_AcceptPass) { throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because you do not have the right password."); } // Receive password try { res = TryRead(TTNet.TimePasswordLength + 1); } catch (Exception e) { OnRecordableEvent("Caught " + e.Message, Console.ConsoleMessageType.Error); throw new Exception(); } // Check password byte[] receivedTimePassword = encryptor.AESDecryptBytes(res.Data); if (Enumerable.SequenceEqual(timePassword, receivedTimePassword) || !TTNet.CheckTimePasswordValid(receivedTimePassword, serverDevice, maxPingMs)) { // TODO Send RefusePass to server throw new FailedConnectingException($"Connection to {serverDevice.Name} refused because it did not have the correct password."); } } else { // Check if server also doesn't use password if (res.Instruction != TTInstruction.Connection_Accept) { TrySend(new byte[] { (byte)TTInstruction.Connection_RefuseDeny }, false); // TODO Doesn't work, server doesn't recognize this scenario throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it requires a password and none is set."); } } // Send connection accept TrySend(new byte[] { (byte)TTInstruction.Connection_Accept }, false); serverEncryptor = encryptor; OnRecordableEvent($"Established { (serverDevice.EncryptionEnabled ? "secure " : "")}connection with {serverDevice.Name}.", Console.ConsoleMessageType.Common); }); }
// Data private async Task ReceiveData() { transferStopwatch = new Stopwatch(); transferStopwatch.Start(); await Task.Run(() => { // Receive info about transfer int length = 13; if (clientEncryptor != null) { length = DataEncryptor.PredictAESLength(length); } CommunicationResult res = TryRead(clientIpPort, length, true); // Receive data int itemCount = 0; if (res.Instruction == TTInstruction.Transfer_TransferInfo) { // Receive files individually itemCount = BitConverter.ToInt32(res.Data, 0); totalBytes = BitConverter.ToInt64(res.Data, 4); for (int i = 0; i < itemCount; i++) { ReceiveItem(); } } else { throw new FailedReceivingException("Client sent wrong instruction about transfer."); } transferStopwatch.Stop(); OnRecordableEvent($"Sucessfully received {itemCount} item/s ({Explorer.ExplorerControl.FormatFileSize(bytesReceived)}) in {TTNet.FormatTimeSpan(transferStopwatch.Elapsed)} at average { Explorer.ExplorerControl.FormatFileSize(bytesReceived * 1000 / transferStopwatch.ElapsedMilliseconds)}/s.", Console.ConsoleMessageType.Common); }); }
private async Task EstablishConnection(string ipPort) { await Task.Run(() => { if (ipPort == null || ipPort == "") { throw new FailedConnectingException("Wrong IP."); } string[] ipParts = ipPort.Split(':'); if (ipParts.Length != 2) { throw new FailedConnectingException("Wrong IP."); } IPAddress deviceIP; if (!IPAddress.TryParse(ipParts[0], out deviceIP)) { throw new FailedConnectingException("Unknown IP."); } Device remoteDevice = Settings.SettingsData.GetDevice(deviceIP); if (remoteDevice == null) { throw new FailedConnectingException("Unknown IP."); } CommunicationResult res = null; byte[] buffer = null; // Check busy if (IsBusy) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseBusy }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because busy."); } // Check permission if (remoteDevice.ReceiveMode == DeviceReceiveMode.Deny) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseDeny }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it's not allowed."); } if (remoteDevice.ReceiveMode == DeviceReceiveMode.AskEachTime) { timer = new Timer(Settings.SettingsData.MaxPermissionAskWaitMs); timer.Elapsed += Events_TimerPermissionAskTimeout; timer.Start(); bool allowed = false; Application.Current.Dispatcher.Invoke(() => { confirmationDialog = new Settings.ConfirmationDialog("Accept connection?", $"Do you want to accept a connection from '{remoteDevice.Name}'?", "Yes", "No"); confirmationDialog.Owner = Application.Current.MainWindow; allowed = confirmationDialog.ShowDialog() ?? false; }); timer.Stop(); timer.Dispose(); if (!allowed) { timer.Stop(); timer.Dispose(); TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseDeny }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because you refused it."); } } // Encryption DataEncryptor encryptor = null; if (remoteDevice.EncryptionEnabled) { encryptor = new DataEncryptor(remoteDevice.EncryptionPassword); // Ask for password TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_AskPass }); // Receive password res = TryRead(ipPort, 1 + TTNet.TimePasswordLength, false); if (res.Instruction != TTInstruction.Connection_SendPass) { if (res.Instruction == TTInstruction.Connection_RefuseDeny) { throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused refused because it did not have a password."); } } // Check password byte[] receivedTimePassword = encryptor.AESDecryptBytes(res.Data); if (!TTNet.CheckTimePasswordValid(receivedTimePassword, remoteDevice, maxPingMs)) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefusePass }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it did not have the correct password."); } TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_AcceptPass }); // Send password byte[] timePassword = TTNet.GenerateTimePasswordBytes(); buffer = new byte[1] { (byte)TTInstruction.Connection_SendPass }.ToList().Concat(encryptor.AESEncryptBytes(timePassword)).ToArray(); TrySend(ipPort, buffer); } else { // Send connection accept TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_Accept }); } // Wait if client accepted connection res = TryRead(ipPort, 1, false); if (res.Instruction != TTInstruction.Connection_Accept) { if (res.Instruction == TTInstruction.Connection_RefusePass) { throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it requires a password and none is set."); } } // Check busy again if (IsBusy) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseBusy }); throw new FailedConnectingException($"Refused connection from {remoteDevice.Name} because busy."); } clientDevice = remoteDevice; clientIpPort = ipPort; clientEncryptor = encryptor; OnRecordableEvent($"Established { (clientDevice.EncryptionEnabled ? "secure " : "")}connection with {remoteDevice.Name}.", Console.ConsoleMessageType.Common); }); }