SocketStuff.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Concurrent; 7 using System.Collections.Generic; 8 using System.Diagnostics; 9 using System.Diagnostics.CodeAnalysis; 10 using System.Globalization; 11 using System.IO; 12 using System.Linq; 13 using System.Net; 14 using System.Net.NetworkInformation; 15 using System.Net.Sockets; 16 using System.Security.Cryptography; 17 using System.Threading; 18 using System.Threading.Tasks; 19 using System.Windows.Forms; 20 using MouseWithoutBorders.Core; 21 22 // <summary> 23 // Socket code. 24 // </summary> 25 // <history> 26 // 2008 created by Truong Do (ductdo). 27 // 2009-... modified by Truong Do (TruongDo). 28 // 2023- Included in PowerToys. 29 // </history> 30 using MouseWithoutBorders.Exceptions; 31 32 using Clipboard = MouseWithoutBorders.Core.Clipboard; 33 using Thread = MouseWithoutBorders.Core.Thread; 34 35 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[])", Justification = "Dotnet port with style preservation")] 36 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#Close()", Justification = "Dotnet port with style preservation")] 37 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#CreateSocket(System.Boolean)", Justification = "Dotnet port with style preservation")] 38 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[],MouseWithoutBorders.IP)", Justification = "Dotnet port with style preservation")] 39 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Object)", Justification = "Dotnet port with style preservation")] 40 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendFile(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")] 41 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#MainTCPRoutine(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")] 42 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#TCPServerThread(System.Object)", Justification = "Dotnet port with style preservation")] 43 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendClipboardData(System.Object)", Justification = "Dotnet port with style preservation")] 44 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#StartNewTcpClient(MouseWithoutBorders.MachineInf)", Justification = "Dotnet port with style preservation")] 45 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#StartNewTcpServer(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")] 46 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#UpdateTCPClients()", Justification = "Dotnet port with style preservation")] 47 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#UpdateTcpSockets(System.Net.Sockets.Socket,MouseWithoutBorders.SocketStatus)", Justification = "Dotnet port with style preservation")] 48 [module: SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#.ctor(System.Int32,System.Boolean)", Justification = "Dotnet port with style preservation")] 49 [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[],MouseWithoutBorders.IP,System.Int32)", Justification = "Dotnet port with style preservation")] 50 [module: SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Scope = "type", Target = "MouseWithoutBorders.SocketStuff", Justification = "Dotnet port with style preservation")] 51 52 namespace MouseWithoutBorders.Class 53 { 54 internal enum SocketStatus : int 55 { 56 NA = 0, 57 Resolving = 1, 58 Connecting = 2, 59 Handshaking = 3, 60 Error = 4, 61 ForceClosed = 5, 62 InvalidKey = 6, 63 Timeout = 7, 64 SendError = 8, 65 Connected = 9, 66 } 67 68 internal class TcpSk : IDisposable 69 { 70 public TcpSk(bool isClient, Socket s, SocketStatus status, string machineName, IPAddress address = null) 71 { 72 IsClient = isClient; 73 BackingSocket = s; 74 Status = status; 75 MachineName = machineName; 76 Address = address; 77 BirthTime = Common.GetTick(); 78 } 79 80 public bool IsClient { get; set; } 81 82 public Socket BackingSocket { get; set; } 83 84 public SocketStatus Status { get; set; } 85 86 public string MachineName { get; set; } 87 88 public long BirthTime { get; set; } 89 90 public uint MachineId { get; set; } 91 92 public IPAddress Address { get; set; } 93 94 private Stream encryptedStream; 95 private Stream decryptedStream; 96 private Stream socketStream; 97 98 public Stream EncryptedStream 99 { 100 get 101 { 102 if (encryptedStream == null && BackingSocket.Connected) 103 { 104 encryptedStream = Encryption.GetEncryptedStream(new NetworkStream(BackingSocket)); 105 Common.SendOrReceiveARandomDataBlockPerInitialIV(encryptedStream); 106 } 107 108 return encryptedStream; 109 } 110 } 111 112 public Stream DecryptedStream 113 { 114 get 115 { 116 if (decryptedStream == null && BackingSocket.Connected) 117 { 118 decryptedStream = Encryption.GetDecryptedStream(new NetworkStream(BackingSocket)); 119 Common.SendOrReceiveARandomDataBlockPerInitialIV(decryptedStream, false); 120 } 121 122 return decryptedStream; 123 } 124 } 125 126 public Stream SocketStream 127 { 128 get 129 { 130 if (socketStream == null && BackingSocket.Connected) 131 { 132 socketStream = new NetworkStream(BackingSocket); 133 } 134 135 return socketStream; 136 } 137 } 138 139 public void Dispose() 140 { 141 encryptedStream?.Dispose(); 142 143 decryptedStream?.Dispose(); 144 145 socketStream?.Dispose(); 146 } 147 } 148 149 internal class SocketStuff 150 { 151 private readonly int bASE_PORT; 152 private TcpServer skClipboardServer; 153 private TcpServer skMessageServer; 154 internal object TcpSocketsLock = new(); 155 internal static bool InvalidKeyFound; 156 internal static bool InvalidKeyFoundOnClientSocket; 157 158 internal const int CONNECT_TIMEOUT = 60000; 159 private static readonly ConcurrentDictionary<string, int> FailedAttempt = new(); 160 161 internal List<TcpSk> TcpSockets 162 { 163 get; private set; 164 165 // set { tcpSockets = value; } 166 } 167 168 internal int TcpPort 169 { 170 get; 171 172 // set { tcpPort = value; } 173 } 174 175 private static bool firstRun; 176 private readonly long connectTimeout; 177 private static int restartCount; 178 179 internal SocketStuff(int port, bool byUser) 180 { 181 Logger.LogDebug("SocketStuff started."); 182 183 bASE_PORT = port; 184 Encryption.Ran = new Random(); 185 186 Logger.LogDebug("Validating session..."); 187 188 if (Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId()) 189 { 190 if (Common.DesMachineID != Common.MachineID) 191 { 192 MachineStuff.SwitchToMultipleMode(false, true); 193 } 194 195 if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 196 { 197 Common.MainForm.SetTrayIconText("Not physical console session."); 198 if (byUser) 199 { 200 Common.ShowToolTip("Not physical console session.", 5000); 201 } 202 } 203 204 Common.MMSleep(1); 205 Logger.Log("Not physical console session."); 206 207 throw new NotPhysicalConsoleException("Not physical console session."); 208 } 209 210 Logger.LogDebug("Creating socket list and mutex..."); 211 212 try 213 { 214 lock (TcpSocketsLock) 215 { 216 TcpSockets = new List<TcpSk>(); 217 } 218 219 bool dummy1 = Setting.Values.MatrixOneRow; // Reading from reg to variable 220 dummy1 = Setting.Values.MatrixCircle; 221 222 if (Setting.Values.IsMyKeyRandom) 223 { 224 Setting.Values.MyKey = Encryption.MyKey; 225 } 226 227 Encryption.MagicNumber = Encryption.Get24BitHash(Encryption.MyKey); 228 Package.PackageID = Setting.Values.PackageID; 229 230 TcpPort = bASE_PORT; 231 232 if (Common.SocketMutex == null) 233 { 234 firstRun = true; 235 Common.SocketMutex = new Mutex(false, $"Global\\{Application.ProductName}-{FrmAbout.AssemblyVersion}-FF7CDABE-1015-0904-1103-24670FA5D16E"); 236 } 237 238 Common.AcquireSocketMutex(); 239 } 240 catch (AbandonedMutexException e) 241 { 242 Logger.TelemetryLogTrace($"{nameof(SocketStuff)}: {e.Message}", SeverityLevel.Warning); 243 } 244 245 WinAPI.GetScreenConfig(); 246 247 if (firstRun && Common.RunOnScrSaverDesktop) 248 { 249 firstRun = false; 250 } 251 252 // JUST_GOT_BACK_FROM_SCREEN_SAVER: For bug: monitor does not turn off after logon screen saver exits 253 else if (!Common.RunOnScrSaverDesktop) 254 { 255 if (Setting.Values.LastX == Common.JUST_GOT_BACK_FROM_SCREEN_SAVER) 256 { 257 MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID; 258 } 259 else 260 { 261 // Common.Log("Getting IP: " + Setting.Values.DesMachineID.ToString(CultureInfo.CurrentCulture)); 262 Common.LastX = Setting.Values.LastX; 263 Common.LastY = Setting.Values.LastY; 264 265 if (Common.RunOnLogonDesktop && Setting.Values.DesMachineID == (uint)ID.ALL) 266 { 267 MachineStuff.SwitchToMultipleMode(true, false); 268 } 269 else 270 { 271 MachineStuff.SwitchToMultipleMode(false, false); 272 } 273 } 274 } 275 276 connectTimeout = Common.GetTick() + (CONNECT_TIMEOUT / 2); 277 Exception openSocketErr; 278 279 /* 280 * The machine might be getting a new IP address from its DHCP server 281 * for ex, when a laptop with a wireless connection just wakes up, might take long time:( 282 * */ 283 284 Common.GetMachineName(); // IPs might have been changed 285 InitAndCleanup.UpdateMachineTimeAndID(); 286 287 Logger.LogDebug("Creating sockets..."); 288 289 openSocketErr = CreateSocket(); 290 291 int sleepSecs = 0, errCode = 0; 292 293 if (openSocketErr != null) 294 { 295 if (openSocketErr is SocketException) 296 { 297 errCode = (openSocketErr as SocketException).ErrorCode; 298 299 switch (errCode) 300 { 301 case 0: // No error. 302 break; 303 304 case 10048: // WSAEADDRINUSE 305 sleepSecs = 10; 306 307 // It is reasonable to give a try on restarting MwB processes in other sessions. 308 if (restartCount++ < 5 && WinAPI.IsMyDesktopActive() && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 309 { 310 Logger.TelemetryLogTrace("Restarting the service dues to WSAEADDRINUSE.", SeverityLevel.Warning); 311 Program.StartService(); 312 InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET; 313 } 314 315 break; 316 317 case 10049: // WSAEADDRNOTAVAIL 318 sleepSecs = 1; 319 break; 320 321 default: 322 sleepSecs = 5; 323 break; 324 } 325 } 326 else 327 { 328 sleepSecs = 10; 329 } 330 331 if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 332 { 333 if (byUser) 334 { 335 Common.ShowToolTip(errCode.ToString(CultureInfo.CurrentCulture) + ": " + openSocketErr.Message, 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 336 } 337 } 338 339 Common.MMSleep(sleepSecs); 340 Common.ReleaseSocketMutex(); 341 throw new ExpectedSocketException(openSocketErr.Message); 342 } 343 else 344 { 345 restartCount = 0; 346 347 if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 348 { 349 IpcHelper.CreateIpcServer(false); 350 } 351 352 Common.MainForm.UpdateNotifyIcon(); 353 } 354 } 355 356 internal void Close(bool sentWait) 357 { 358 try 359 { 360 if (!Common.RunOnScrSaverDesktop) 361 { 362 Setting.Values.LastX = Common.LastX; 363 Setting.Values.LastY = Common.LastY; 364 Setting.Values.PackageID = Package.PackageID; 365 366 // Common.Log("Saving IP: " + Setting.Values.DesMachineID.ToString(CultureInfo.CurrentCulture)); 367 Setting.Values.DesMachineID = (uint)Common.DesMachineID; 368 } 369 370 _ = Common.ExecuteAndTrace( 371 "Closing sockets", 372 () => 373 { 374 Logger.LogDebug($"Closing socket [{skMessageServer?.Name}]."); 375 skMessageServer?.Close(); // The original ones, not the socket instances produced by the accept() method. 376 skMessageServer = null; 377 378 Logger.LogDebug($"Closing socket [{skClipboardServer?.Name}]."); 379 skClipboardServer?.Close(); 380 skClipboardServer = null; 381 try 382 { 383 // If these sockets are failed to be closed then the tool would not function properly, more logs are added for debugging. 384 lock (TcpSocketsLock) 385 { 386 int c = 0; 387 388 if (TcpSockets != null) 389 { 390 Logger.LogDebug("********** Closing Sockets: " + TcpSockets.Count.ToString(CultureInfo.InvariantCulture)); 391 392 List<TcpSk> notClosedSockets = new(); 393 394 foreach (TcpSk t in TcpSockets) 395 { 396 if (t != null && t.BackingSocket != null && t.Status != SocketStatus.Resolving) 397 { 398 try 399 { 400 t.MachineName = "$*NotUsed*$"; 401 t.Status = t.Status >= 0 ? 0 : t.Status - 1; 402 403 if (sentWait) 404 { 405 t.BackingSocket.Close(1); 406 } 407 else 408 { 409 t.BackingSocket.Close(); 410 } 411 412 c++; 413 414 continue; 415 } 416 catch (SocketException e) 417 { 418 string log = $"Socket.Close error: {e.GetType()}/{e.Message}. This is expected when the socket is already closed by remote host."; 419 Logger.Log(log); 420 } 421 catch (ObjectDisposedException e) 422 { 423 string log = $"Socket.Close error: {e.GetType()}/{e.Message}. This is expected when the socket is already disposed."; 424 Logger.Log(log); 425 } 426 catch (Exception e) 427 { 428 Logger.Log(e); 429 } 430 431 // If there was an error closing the socket: 432 if ((int)t.Status > -5) 433 { 434 notClosedSockets.Add(t); // Try to give a few times to close the socket later on. 435 } 436 } 437 } 438 439 TcpSockets = notClosedSockets; 440 } 441 442 Logger.LogDebug("********** Sockets Closed: " + c.ToString(CultureInfo.CurrentCulture)); 443 } 444 } 445 catch (Exception e) 446 { 447 Logger.Log(e); 448 } 449 }, 450 TimeSpan.FromSeconds(3), 451 true); 452 } 453 catch (Exception e) 454 { 455 Logger.Log(e); 456 } 457 finally 458 { 459 Common.ReleaseSocketMutex(); 460 } 461 462 if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 463 { 464 try 465 { 466 IpcHelper.CreateIpcServer(true); 467 } 468 catch (Exception e) 469 { 470 Logger.Log(e); 471 } 472 } 473 } 474 475 private Exception CreateSocket() 476 { 477 try 478 { 479 skMessageServer = new TcpServer(TcpPort + 1, new ParameterizedThreadStart(TCPServerThread)); 480 skClipboardServer = new TcpServer(TcpPort, new ParameterizedThreadStart(AcceptConnectionAndSendClipboardData)); 481 } 482 catch (SocketException e) 483 { 484 Logger.Log(e); 485 return e; 486 } 487 catch (Exception e) 488 { 489 Logger.Log(e); 490 return e; 491 } 492 493 Logger.LogDebug("=================================================="); 494 return null; 495 } 496 497 private static int TcpSendData(TcpSk tcp, byte[] bytes) 498 { 499 Stream encryptedStream = tcp.EncryptedStream; 500 501 if (tcp.BackingSocket == null || !tcp.BackingSocket.Connected || encryptedStream == null) 502 { 503 string log = $"{nameof(TcpSendData)}: The socket is no longer connected, it could have been closed by the remote host."; 504 Logger.Log(log); 505 throw new ExpectedSocketException(log); 506 } 507 508 bytes[3] = (byte)((Encryption.MagicNumber >> 24) & 0xFF); 509 bytes[2] = (byte)((Encryption.MagicNumber >> 16) & 0xFF); 510 bytes[1] = 0; 511 for (int i = 2; i < Package.PACKAGE_SIZE; i++) 512 { 513 bytes[1] = (byte)(bytes[1] + bytes[i]); 514 } 515 516 try 517 { 518 encryptedStream.Write(bytes, 0, bytes.Length); 519 } 520 catch (IOException e) 521 { 522 string log = $"{nameof(TcpSendData)}: Exception writing to the socket: {tcp.MachineName}: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 523 Logger.Log(log); 524 525 throw e.InnerException is SocketException se ? new ExpectedSocketException(se) : new ExpectedSocketException(log); 526 } 527 528 return bytes.Length; 529 } 530 531 private static void ProcessReceivedDataEx(byte[] buf) 532 { 533 int magic; 534 byte checksum = 0; 535 536 magic = (buf[3] << 24) + (buf[2] << 16); 537 538 if (magic != (Encryption.MagicNumber & 0xFFFF0000)) 539 { 540 Logger.Log("Magic number invalid!"); 541 buf[0] = (byte)PackageType.Invalid; 542 } 543 544 for (int i = 2; i < Package.PACKAGE_SIZE; i++) 545 { 546 checksum = (byte)(checksum + buf[i]); 547 } 548 549 if (buf[1] != checksum) 550 { 551 Logger.Log("Checksum invalid!"); 552 buf[0] = (byte)PackageType.Invalid; 553 } 554 555 buf[3] = buf[2] = buf[1] = 0; 556 } 557 558 internal static DATA TcpReceiveData(TcpSk tcp, out int bytesReceived) 559 { 560 byte[] buf = new byte[Package.PACKAGE_SIZE_EX]; 561 Stream decryptedStream = tcp.DecryptedStream; 562 563 if (tcp.BackingSocket == null || !tcp.BackingSocket.Connected || decryptedStream == null) 564 { 565 string log = $"{nameof(TcpReceiveData)}: The socket is no longer connected, it could have been closed by the remote host."; 566 Logger.Log(log); 567 throw new ExpectedSocketException(log); 568 } 569 570 DATA package; 571 572 try 573 { 574 bytesReceived = decryptedStream.ReadEx(buf, 0, Package.PACKAGE_SIZE); 575 576 if (bytesReceived != Package.PACKAGE_SIZE) 577 { 578 buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid; 579 } 580 else 581 { 582 ProcessReceivedDataEx(buf); 583 } 584 585 package = new DATA(buf); 586 587 if (package.IsBigPackage) 588 { 589 bytesReceived = decryptedStream.ReadEx(buf, Package.PACKAGE_SIZE, Package.PACKAGE_SIZE); 590 591 if (bytesReceived != Package.PACKAGE_SIZE) 592 { 593 buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid; 594 } 595 else 596 { 597 package.Bytes = buf; 598 } 599 } 600 } 601 catch (IOException e) 602 { 603 string log = $"{nameof(TcpReceiveData)}: Exception reading from the socket: {tcp.MachineName}: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 604 Logger.Log(log); 605 606 throw e.InnerException is SocketException se ? new ExpectedSocketException(se) : new ExpectedSocketException(log); 607 } 608 609 return package; 610 } 611 612 private static void PreProcessData(PackageType type) 613 { 614 switch (type) 615 { 616 case PackageType.Keyboard: 617 Package.PackageSent.Keyboard++; 618 break; 619 620 case PackageType.Mouse: 621 Package.PackageSent.Mouse++; 622 break; 623 624 case PackageType.Heartbeat: 625 case PackageType.Heartbeat_ex: 626 Package.PackageSent.Heartbeat++; 627 break; 628 629 case PackageType.Hello: 630 Package.PackageSent.Hello++; 631 break; 632 633 case PackageType.ByeBye: 634 Package.PackageSent.ByeBye++; 635 break; 636 637 case PackageType.Matrix: 638 Package.PackageSent.Matrix++; 639 break; 640 641 default: 642 byte subtype = (byte)((uint)type & 0x000000FF); 643 switch (subtype) 644 { 645 case (byte)PackageType.ClipboardText: 646 Package.PackageSent.ClipboardText++; 647 break; 648 649 case (byte)PackageType.ClipboardImage: 650 Package.PackageSent.ClipboardImage++; 651 break; 652 653 default: 654 // Common.Log("Send: Other type (1-17)"); 655 break; 656 } 657 658 break; 659 } 660 } 661 662 internal int TcpSend(TcpSk tcp, DATA data) 663 { 664 PreProcessData(data.Type); 665 666 if (data.Src == ID.NONE) 667 { 668 data.Src = Common.MachineID; 669 } 670 671 byte[] dataAsBytes = data.Bytes; 672 int rv = TcpSendData(tcp, dataAsBytes); 673 if (rv < dataAsBytes.Length) 674 { 675 Logger.Log("TcpSend error! Length of sent data is unexpected."); 676 UpdateTcpSockets(tcp, SocketStatus.SendError); 677 throw new SocketException((int)SocketStatus.SendError); 678 } 679 680 return rv; 681 } 682 683 private void TCPServerThread(object param) 684 { 685 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 686 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 687 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 688 689 try 690 { 691 TcpListener server = param as TcpListener; 692 do 693 { 694 Logger.LogDebug("TCPServerThread: Waiting for request..."); 695 Socket s = server.AcceptSocket(); 696 697 _ = Task.Run(() => 698 { 699 try 700 { 701 AddSocket(s); 702 } 703 catch (Exception e) 704 { 705 Logger.Log(e); 706 } 707 }); 708 } 709 while (true); 710 } 711 catch (InvalidOperationException e) 712 { 713 string log = $"TCPServerThread.AcceptSocket: The server socket could have been closed. {e.Message}"; 714 Logger.Log(log); 715 } 716 catch (SocketException e) 717 { 718 if (e.ErrorCode == (int)SocketError.Interrupted) 719 { 720 Logger.Log("TCPServerThread.AcceptSocket: A blocking socket call was canceled."); 721 } 722 else 723 { 724 Logger.Log(e); 725 } 726 } 727 catch (Exception e) 728 { 729 Logger.Log(e); 730 } 731 } 732 733 private static string GetMachineNameFromSocket(Socket socket) 734 { 735 string stringIP = socket.RemoteEndPoint.ToString(); 736 string name = null; 737 738 try 739 { 740 // Remote machine has IP changed, update it. 741 name = Dns.GetHostEntry((socket.RemoteEndPoint as IPEndPoint).Address).HostName; 742 } 743 catch (SocketException e) 744 { 745 Logger.Log($"{nameof(GetMachineNameFromSocket)}: {e.Message}"); 746 return stringIP; 747 } 748 749 // Remove the domain part. 750 if (!string.IsNullOrEmpty(name)) 751 { 752 int dotPos = name.IndexOf('.'); 753 754 if (dotPos > 0) 755 { 756 Logger.LogDebug("Removing domain part from the full machine name: {0}.", name); 757 name = name[..dotPos]; 758 } 759 } 760 761 return string.IsNullOrEmpty(name) ? stringIP : name; 762 } 763 764 private void AddSocket(Socket s) 765 { 766 string machineName = GetMachineNameFromSocket(s); 767 Logger.Log($"New connection from client: [{machineName}]."); 768 TcpSk tcp = AddTcpSocket(false, s, SocketStatus.Connecting, machineName); 769 StartNewTcpServer(tcp, machineName); 770 } 771 772 private void StartNewTcpServer(TcpSk tcp, string machineName) 773 { 774 void ServerThread() 775 { 776 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 777 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 778 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 779 780 try 781 { 782 // Receiving packages 783 MainTCPRoutine(tcp, machineName, false); 784 } 785 catch (Exception e) 786 { 787 Logger.Log(e); 788 } 789 } 790 791 Thread t = new(ServerThread, "TCP Server Thread " + tcp.BackingSocket.LocalEndPoint.ToString() + " : " + machineName); 792 793 t.SetApartmentState(ApartmentState.STA); 794 t.Start(); 795 } 796 797 internal void UpdateTCPClients() 798 { 799 if (InvalidKeyFound) 800 { 801 return; 802 } 803 804 Logger.LogDebug("!!!!! UpdateTCPClients !!!!!"); 805 806 try 807 { 808 if (MachineStuff.MachineMatrix != null) 809 { 810 Logger.LogDebug("MachineMatrix = " + string.Join(", ", MachineStuff.MachineMatrix)); 811 812 foreach (string st in MachineStuff.MachineMatrix) 813 { 814 string machineName = st.Trim(); 815 if (!string.IsNullOrEmpty(machineName) && 816 !machineName.Equals(Common.MachineName.Trim(), StringComparison.OrdinalIgnoreCase)) 817 { 818 bool found = false; 819 820 found = Common.IsConnectedByAClientSocketTo(machineName); 821 822 if (found) 823 { 824 Logger.LogDebug(machineName + " is already connected! ^^^^^^^^^^^^^^^^^^^^^"); 825 continue; 826 } 827 828 StartNewTcpClient(machineName); 829 } 830 } 831 } 832 } 833 catch (Exception e) 834 { 835 Logger.Log(e); 836 } 837 } 838 839 private static readonly Dictionary<string, List<IPAddress>> BadIPs = new(); 840 private static readonly Lock BadIPsLock = new(); 841 842 private static bool IsBadIP(string machineName, IPAddress ip) 843 { 844 lock (BadIPsLock) 845 { 846 return BadIPs.ContainsKey(machineName) && BadIPs.TryGetValue(machineName, out List<IPAddress> ips) && ips.Contains(ip); 847 } 848 } 849 850 private static void AddBadIP(string machineName, IPAddress ip) 851 { 852 if (!IsBadIP(machineName, ip)) 853 { 854 lock (BadIPsLock) 855 { 856 List<IPAddress> ips; 857 858 if (BadIPs.ContainsKey(machineName)) 859 { 860 _ = BadIPs.TryGetValue(machineName, out ips); 861 } 862 else 863 { 864 ips = new List<IPAddress>(); 865 BadIPs.Add(machineName, ips); 866 } 867 868 ips.Add(ip); 869 } 870 } 871 } 872 873 internal static void ClearBadIPs() 874 { 875 lock (BadIPsLock) 876 { 877 if (BadIPs.Count > 0) 878 { 879 BadIPs.Clear(); 880 } 881 } 882 } 883 884 internal void StartNewTcpClient(string machineName) 885 { 886 void ClientThread(object obj) 887 { 888 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 889 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 890 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 891 892 IPHostEntry host; 893 bool useName2IP = false; 894 List<IPAddress> validAddresses = new(); 895 List<IPAddress> validatedAddresses = new(); 896 string validAddressesSt = string.Empty; 897 898 // Add a dummy socket to show the status. 899 Socket dummySocket = new(AddressFamily.Unspecified, SocketType.Stream, ProtocolType.Tcp); 900 TcpSk dummyTcp = AddTcpSocket(true, dummySocket, SocketStatus.Resolving, machineName); 901 902 Logger.LogDebug("Connecting to: " + machineName); 903 904 if (!string.IsNullOrEmpty(Setting.Values.Name2IP)) 905 { 906 string combinedName2ipList = Setting.Values.Name2IpPolicyList + Separator + Setting.Values.Name2IP; 907 string[] name2ip = combinedName2ipList.Split(Separator, StringSplitOptions.RemoveEmptyEntries); 908 string[] nameNip; 909 910 if (name2ip != null) 911 { 912 foreach (string st in name2ip) 913 { 914 nameNip = st.Split(BlankSeparator, StringSplitOptions.RemoveEmptyEntries); 915 916 if (nameNip != null && nameNip.Length >= 2 && nameNip[0].Trim().Equals(machineName, StringComparison.OrdinalIgnoreCase) 917 && IPAddress.TryParse(nameNip[1].Trim(), out IPAddress ip) && !validAddressesSt.Contains("[" + ip.ToString() + "]") 918 ) 919 { 920 validatedAddresses.Add(ip); 921 validAddressesSt += "[" + ip.ToString() + "]"; 922 } 923 } 924 } 925 926 if (validatedAddresses.Count > 0) 927 { 928 useName2IP = true; 929 930 Logger.LogDebug("Using both user-defined Name-to-IP mappings and DNS result for " + machineName); 931 932 Common.ShowToolTip("Using both user-defined Name-to-IP mappings and DNS result for " + machineName, 3000, ToolTipIcon.Info, false); 933 934 if (!CheckForSameSubNet(validatedAddresses, machineName)) 935 { 936 return; 937 } 938 939 foreach (IPAddress vip in validatedAddresses) 940 { 941 StartNewTcpClientThread(machineName, vip); 942 } 943 944 validatedAddresses.Clear(); 945 } 946 } 947 948 try 949 { 950 host = Dns.GetHostEntry(machineName); 951 } 952 catch (SocketException e) 953 { 954 host = null; 955 956 UpdateTcpSockets(dummyTcp, SocketStatus.Timeout); 957 958 Common.ShowToolTip(e.Message + ": " + machineName, 10000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 959 960 Logger.Log($"{nameof(StartNewTcpClient)}.{nameof(Dns.GetHostEntry)}: {e.Message}"); 961 } 962 963 UpdateTcpSockets(dummyTcp, SocketStatus.NA); 964 965 if (!MachineStuff.InMachineMatrix(machineName)) 966 { 967 // While Resolving from name to IP, user may have changed the machine name and clicked on Apply. 968 return; 969 } 970 971 if (host != null) 972 { 973 string ipLog = string.Empty; 974 975 foreach (IPAddress ip in host.AddressList) 976 { 977 ipLog += "<" + ip.ToString() + ">"; 978 979 if ((ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6) && !validAddressesSt.Contains("[" + ip.ToString() + "]")) 980 { 981 validAddresses.Add(ip); 982 validAddressesSt += "[" + ip.ToString() + "]"; 983 } 984 } 985 986 Logger.LogDebug(machineName + ipLog); 987 } 988 989 if (validAddresses.Count > 0) 990 { 991 if (!Setting.Values.ReverseLookup) 992 { 993 validatedAddresses = validAddresses; 994 ClearBadIPs(); 995 } 996 else 997 { 998 foreach (IPAddress ip in validAddresses) 999 { 1000 if (IsBadIP(machineName, ip)) 1001 { 1002 Logger.Log($"Skip bad IP address: {ip}"); 1003 continue; 1004 } 1005 1006 try 1007 { 1008 // Reverse lookup to validate the IP Address. 1009 string hn = Dns.GetHostEntry(ip).HostName; 1010 1011 if (hn.StartsWith(machineName, StringComparison.CurrentCultureIgnoreCase) || hn.Equals(ip.ToString(), StringComparison.OrdinalIgnoreCase)) 1012 { 1013 validatedAddresses.Add(ip); 1014 } 1015 else 1016 { 1017 Logger.Log($"DNS information of machine not matched: {machineName} => {ip} => {hn}."); 1018 AddBadIP(machineName, ip); 1019 } 1020 } 1021 catch (SocketException se) 1022 { 1023 Logger.Log($"{nameof(StartNewTcpClient)}: DNS information of machine not matched: {machineName} => {ip} => {se.Message}."); 1024 AddBadIP(machineName, ip); 1025 } 1026 catch (ArgumentException ae) 1027 { 1028 Logger.Log($"{nameof(StartNewTcpClient)}: DNS information of machine not matched: {machineName} => {ip} => {ae.Message}."); 1029 AddBadIP(machineName, ip); 1030 } 1031 } 1032 } 1033 } 1034 1035 if (validatedAddresses.Count > 0) 1036 { 1037 if (!CheckForSameSubNet(validatedAddresses, machineName)) 1038 { 1039 return; 1040 } 1041 1042 foreach (IPAddress ip in validatedAddresses) 1043 { 1044 StartNewTcpClientThread(machineName, ip); 1045 } 1046 } 1047 else 1048 { 1049 Logger.Log("Cannot resolve IPv4 Addresses of machine: " + machineName); 1050 1051 if (!useName2IP) 1052 { 1053 Common.ShowToolTip($"Cannot resolve IP Address of the remote machine: {machineName}.\r\nPlease fix your DNS or use the Mapping option in the Settings form.", 10000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 1054 } 1055 } 1056 } 1057 1058 Thread t = new( 1059 ClientThread, "StartNewTcpClient." + machineName); 1060 1061 t.SetApartmentState(ApartmentState.STA); 1062 t.Start(); 1063 } 1064 1065 private bool CheckForSameSubNet(List<IPAddress> validatedAddresses, string machineName) 1066 { 1067 if (!Setting.Values.SameSubNetOnly) 1068 { 1069 return true; 1070 } 1071 1072 // Only support if IPv4 addresses found in both. 1073 IEnumerable<IPAddress> remoteIPv4Addresses = validatedAddresses.Where(addr => addr?.AddressFamily == AddressFamily.InterNetwork); 1074 1075 if (!remoteIPv4Addresses.Any()) 1076 { 1077 Logger.Log($"No IPv4 resolved from the remote machine: {machineName}."); 1078 return true; 1079 } 1080 1081 List<IPAddress> localIPv4Addresses = GetMyIPv4Addresses().ToList(); 1082 1083 if (localIPv4Addresses.Count == 0) 1084 { 1085 Logger.Log($"No IPv4 resolved from the local machine: {Common.MachineName}"); 1086 return true; 1087 } 1088 1089 foreach (IPAddress remote in remoteIPv4Addresses) 1090 { 1091 foreach (IPAddress local in localIPv4Addresses) 1092 { 1093 byte[] myIPAddressBytes = local.GetAddressBytes(); 1094 byte[] yourIPAddressBytes = remote.GetAddressBytes(); 1095 1096 // Same WAN? 1097 if (myIPAddressBytes[0] == yourIPAddressBytes[0] && myIPAddressBytes[1] == yourIPAddressBytes[1]) 1098 { 1099 return true; 1100 } 1101 } 1102 } 1103 1104 Logger.Log($"Skip machine not in the same network: {machineName}."); 1105 1106 return false; 1107 } 1108 1109 private IEnumerable<IPAddress> GetMyIPv4Addresses() 1110 { 1111 try 1112 { 1113 IEnumerable<IPAddress> ip4addresses = NetworkInterface.GetAllNetworkInterfaces()? 1114 .Where(networkInterface => 1115 (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet || networkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211) 1116 && networkInterface.OperationalStatus == OperationalStatus.Up) 1117 .SelectMany(ni => ni?.GetIPProperties()?.UnicastAddresses.Select(uni => uni?.Address)) 1118 .Where(addr => addr?.AddressFamily == AddressFamily.InterNetwork); 1119 1120 return ip4addresses; 1121 } 1122 catch (Exception e) 1123 { 1124 Logger.Log(e); 1125 return Enumerable.Empty<IPAddress>(); 1126 } 1127 } 1128 1129 private void StartNewTcpClientThread(string machineName, IPAddress ip) 1130 { 1131 void NewTcpClient() 1132 { 1133 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 1134 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 1135 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 1136 1137 TcpClient tcpClient = null; 1138 1139 try 1140 { 1141 tcpClient = new TcpClient(AddressFamily.InterNetworkV6); 1142 tcpClient.Client.DualMode = true; 1143 1144 if (Common.IsConnectedByAClientSocketTo(machineName)) 1145 { 1146 Logger.LogDebug(machineName + " is already connected by another client socket."); 1147 return; 1148 } 1149 1150 if (Common.IsConnectingByAClientSocketTo(machineName, ip)) 1151 { 1152 Logger.LogDebug($"{machineName}:{ip} is already being connected by another client socket."); 1153 return; 1154 } 1155 1156 TcpSk tcp = AddTcpSocket(true, tcpClient.Client, SocketStatus.Connecting, machineName, ip); 1157 1158 // Update the other server socket's machine name based on this corresponding client socket. 1159 UpdateTcpSockets(tcp, SocketStatus.Connecting); 1160 1161 Logger.LogDebug(string.Format(CultureInfo.CurrentCulture, "=====> Connecting to: {0}:{1}", machineName, ip.ToString())); 1162 1163 long timeoutLeft; 1164 1165 do 1166 { 1167 try 1168 { 1169 tcpClient.Connect(ip, TcpPort + 1); 1170 } 1171 catch (ObjectDisposedException) 1172 { 1173 // When user reconnects. 1174 Logger.LogDebug($"tcpClient.Connect: The socket has already been disposed: {machineName}:{ip}"); 1175 return; 1176 } 1177 catch (SocketException e) 1178 { 1179 timeoutLeft = connectTimeout - Common.GetTick(); 1180 1181 if (timeoutLeft > 0) 1182 { 1183 Logger.LogDebug($"tcpClient.Connect: {timeoutLeft}: {e.Message}"); 1184 Thread.Sleep(1000); 1185 continue; 1186 } 1187 else 1188 { 1189 Logger.Log($"tcpClient.Connect: Unable to connect after a timeout: {machineName}:{ip} : {e.Message}"); 1190 1191 string message = $"Connection timed out: {machineName}:{ip}"; 1192 1193 Common.ShowToolTip(message, 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 1194 1195 UpdateTcpSockets(tcp, SocketStatus.Timeout); 1196 return; 1197 } 1198 } 1199 1200 break; 1201 } 1202 while (true); 1203 1204 Logger.LogDebug($"=====> Connected: {tcpClient.Client.LocalEndPoint} => {machineName}: {ip}"); 1205 1206 // Sending/Receiving packages 1207 MainTCPRoutine(tcp, machineName, true); 1208 } 1209 catch (ObjectDisposedException e) 1210 { 1211 Logger.Log($"{nameof(StartNewTcpClientThread)}: The socket could have been closed/disposed due to machine switch: {e.Message}"); 1212 } 1213 catch (SocketException e) 1214 { 1215 // DHCP error, etc. 1216 string localIP = tcpClient?.Client?.LocalEndPoint?.ToString(); 1217 1218 if (localIP != null && (localIP.StartsWith("169.254", StringComparison.InvariantCulture) || localIP.ToString().StartsWith("0.0", StringComparison.InvariantCulture))) 1219 { 1220 Common.ShowToolTip($"Error: The machine has limited connectivity on [{localIP}].", 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 1221 } 1222 else 1223 { 1224 Logger.TelemetryLogTrace($"{nameof(StartNewTcpClientThread)}: Error: {e.Message} on the IP Address: {localIP}", SeverityLevel.Error); 1225 } 1226 } 1227 catch (Exception e) 1228 { 1229 Logger.Log(e); 1230 } 1231 } 1232 1233 Thread t = new(NewTcpClient, "TCP Client Thread " + machineName + " " + ip.ToString()); 1234 1235 t.SetApartmentState(ApartmentState.STA); 1236 t.Start(); 1237 } 1238 1239 private void FlagReopenSocketIfNeeded(Exception e) 1240 { 1241 /* SCENARIO: MachineA has MM blocked by firewall but MachineA can connect to MachineB so the tool would work normally (MM is not blocked by firewall in MachineB). 1242 * 1. a connection from A to B is working. Mouse/Keyboard is connected to A. 1243 * 2. User moves Mouse to B and lock B by Ctrl+Alt+L. 1244 * 3. B closes all sockets before switches to logon desktop. The client socket in A gets reset by B (the only connection between A and B). 1245 * 4. B is now on the logon desktop and tries to connect to A, connection fails since it is block by firewall in A. 1246 * 5. When the client socket gets reset in A, it should retry to connect to B => this is the fix implemented by few lines of code below. 1247 * */ 1248 1249 // WSAECONNRESET 1250 if (e is ExpectedSocketException se && se.ShouldReconnect) 1251 { 1252 InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET; 1253 Logger.Log($"MainTCPRoutine: {nameof(FlagReopenSocketIfNeeded)}"); 1254 } 1255 } 1256 1257 private long lastRemoteMachineID; 1258 internal static readonly string[] Separator = new string[] { "\r\n" }; 1259 internal static readonly char[] BlankSeparator = new char[] { ' ' }; 1260 1261 private void MainTCPRoutine(TcpSk tcp, string machineName, bool isClient) 1262 { 1263 int packageCount = 0; 1264 DATA d; 1265 string remoteMachine = string.Empty; 1266 string strIP = string.Empty; 1267 ID remoteID = ID.NONE; 1268 1269 byte[] buf = RandomNumberGenerator.GetBytes(Package.PACKAGE_SIZE_EX); 1270 d = new DATA(buf); 1271 1272 TcpSk currentTcp = tcp; 1273 Socket currentSocket = currentTcp.BackingSocket; 1274 1275 if (currentSocket == null) 1276 { 1277 Logger.LogDebug($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads."); 1278 return; 1279 } 1280 1281 try 1282 { 1283 currentSocket.SendBufferSize = Package.PACKAGE_SIZE * 10000; 1284 currentSocket.ReceiveBufferSize = Package.PACKAGE_SIZE * 10000; 1285 currentSocket.NoDelay = true; // This is very interesting to know:( 1286 currentSocket.SendTimeout = 500; 1287 d.MachineName = Common.MachineName; 1288 1289 d.Type = PackageType.Handshake; 1290 1291 for (int i = 0; i < 10; i++) 1292 { 1293 _ = TcpSend(currentTcp, d); 1294 } 1295 1296 d.Machine1 = ~d.Machine1; 1297 d.Machine2 = ~d.Machine2; 1298 d.Machine3 = ~d.Machine3; 1299 d.Machine4 = ~d.Machine4; 1300 1301 UpdateTcpSockets(currentTcp, SocketStatus.Handshaking); 1302 1303 strIP = Common.GetRemoteStringIP(currentSocket, true); 1304 remoteMachine = string.IsNullOrEmpty(machineName) ? GetMachineNameFromSocket(currentSocket) : machineName; 1305 1306 Logger.LogDebug($"MainTCPRoutine: Remote machineName/IP = {remoteMachine}/{strIP}"); 1307 } 1308 catch (ObjectDisposedException e) 1309 { 1310 InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET; 1311 UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed); 1312 currentSocket.Close(); 1313 Logger.Log($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads: {e.Message}"); 1314 } 1315 catch (Exception e) 1316 { 1317 UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed); 1318 FlagReopenSocketIfNeeded(e); 1319 currentSocket.Close(); 1320 Logger.Log(e); 1321 } 1322 1323 int errCount = 0; 1324 1325 while (true) 1326 { 1327 try 1328 { 1329 DATA package = TcpReceiveData(currentTcp, out int receivedCount); 1330 remoteID = package.Src; 1331 1332 if (package.Type == PackageType.Error) 1333 { 1334 errCount++; 1335 1336 string log = $"{nameof(MainTCPRoutine)}.TcpReceive error, invalid package from {remoteMachine}: {receivedCount}"; 1337 Logger.Log(log); 1338 1339 if (receivedCount > 0) 1340 { 1341 Common.ShowToolTip($"Invalid package from {remoteMachine}. Ensure the security keys are the same in both machines.", 5000, ToolTipIcon.Warning, false); 1342 } 1343 1344 if (errCount > 5) 1345 { 1346 Common.MMSleep(1); 1347 1348 UpdateTcpSockets(currentTcp, SocketStatus.Error); 1349 currentSocket.Close(); 1350 1351 /* 1352 * Sometimes when the peer machine closes the connection, we do not actually get an exception. 1353 * Socket status is still connected and a read on the socket stream returns 0 byte. 1354 * In this case, we should give ONE try to reconnect. 1355 */ 1356 1357 if (InitAndCleanup.ReopenSocketDueToReadError) 1358 { 1359 InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET; 1360 InitAndCleanup.ReopenSocketDueToReadError = false; 1361 } 1362 1363 break; 1364 } 1365 } 1366 else 1367 { 1368 errCount = 0; 1369 } 1370 1371 if (package.Type == PackageType.Handshake) 1372 { 1373 // Common.Log("Got a Handshake signal!"); 1374 package.Type = PackageType.HandshakeAck; 1375 package.Src = ID.NONE; 1376 package.MachineName = Common.MachineName; 1377 1378 package.Machine1 = ~package.Machine1; 1379 package.Machine2 = ~package.Machine2; 1380 package.Machine3 = ~package.Machine3; 1381 package.Machine4 = ~package.Machine4; 1382 1383 _ = TcpSend(currentTcp, package); 1384 } 1385 else 1386 { 1387 if (packageCount >= 0) 1388 { 1389 if (++packageCount >= 10) 1390 { 1391 // Common.ShowToolTip("Invalid Security Key from " + remoteMachine, 5000); 1392 Logger.Log("More than 10 invalid packages received!"); 1393 1394 package.Type = PackageType.Invalid; 1395 1396 for (int i = 0; i < 10; i++) 1397 { 1398 _ = TcpSend(currentTcp, package); 1399 } 1400 1401 Common.MMSleep(2); 1402 1403 UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey); 1404 currentSocket.Close(); 1405 break; 1406 } 1407 else if (package.Type == PackageType.HandshakeAck) 1408 { 1409 if (package.Machine1 == d.Machine1 && package.Machine2 == d.Machine2 && 1410 package.Machine3 == d.Machine3 && package.Machine4 == d.Machine4) 1411 { 1412 string claimedMachineName = package.MachineName; 1413 1414 if (!remoteMachine.Equals(claimedMachineName, StringComparison.Ordinal)) 1415 { 1416 Logger.LogDebug($"DNS.RemoteMachineName({remoteMachine}) <> Claimed.MachineName({claimedMachineName}), using the claimed machine name."); 1417 remoteMachine = claimedMachineName; 1418 currentTcp.MachineName = remoteMachine; 1419 } 1420 1421 // Double check to avoid a redundant client socket. 1422 if (isClient && Common.IsConnectedByAClientSocketTo(remoteMachine)) 1423 { 1424 Logger.LogDebug("=====> Duplicate connected client socket for: " + remoteMachine + ":" + strIP + " is being removed."); 1425 UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed); 1426 currentSocket.Close(); 1427 return; 1428 } 1429 1430 if (remoteMachine.Equals(Common.MachineName, StringComparison.OrdinalIgnoreCase)) 1431 { 1432 Logger.LogDebug("Connected to/from local socket: " + strIP + (isClient ? "-Client" : "-Server")); 1433 UpdateTcpSockets(currentTcp, SocketStatus.NA); 1434 Common.MMSleep(1); 1435 currentSocket.Close(); 1436 return; 1437 } 1438 1439 packageCount = -1; // Trusted 1440 InvalidKeyFound = false; 1441 currentTcp.MachineId = (uint)remoteID; 1442 currentTcp.Status = SocketStatus.Connected; 1443 UpdateTcpSockets(currentTcp, SocketStatus.Connected); 1444 Logger.LogDebug("))))))))))))))) Machine got trusted: " + remoteMachine + ":" + strIP + ", Is client: " + isClient); 1445 1446 if (Math.Abs(Common.GetTick() - Common.LastReconnectByHotKeyTime) < 5000) 1447 { 1448 Common.ShowToolTip("Connected to " + remoteMachine, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus); 1449 } 1450 1451 Common.SendHeartBeat(initial: true); 1452 1453 if (MachineStuff.MachinePool.TryFindMachineByName(remoteMachine, out MachineInf machineInfo)) 1454 { 1455 Logger.LogDebug("Machine updated: " + remoteMachine + "/" + remoteID.ToString()); 1456 1457 if (machineInfo.Name.Equals(MachineStuff.DesMachineName, StringComparison.OrdinalIgnoreCase)) 1458 { 1459 Logger.LogDebug("Des ID updated: " + Common.DesMachineID.ToString() + 1460 "/" + remoteID.ToString()); 1461 MachineStuff.NewDesMachineID = Common.DesMachineID = remoteID; 1462 } 1463 1464 _ = MachineStuff.MachinePool.TryUpdateMachineID(remoteMachine, remoteID, true); 1465 MachineStuff.UpdateMachinePoolStringSetting(); 1466 } 1467 else 1468 { 1469 Logger.LogDebug("New machine connected: {0}.", remoteMachine); 1470 1471 if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) 1472 { 1473 Common.ShowToolTip("Connected to new machine " + remoteMachine, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus); 1474 } 1475 } 1476 1477 if (!isClient) 1478 { 1479 MachineStuff.UpdateClientSockets("MainTCPRoutine"); 1480 } 1481 } 1482 else 1483 { 1484 Logger.LogDebug("Invalid ACK from " + remoteMachine); 1485 UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey); 1486 1487 string remoteEP = currentSocket.RemoteEndPoint.ToString(); 1488 1489 if (FailedAttempt.AddOrUpdate(remoteEP, 1, (key, value) => value + 1) > 10) 1490 { 1491 _ = FailedAttempt.AddOrUpdate(remoteEP, 0, (key, value) => 0); 1492 1493 _ = MessageBox.Show($"Too many connection attempts from [{remoteEP}]!\r\nRestart the app to retry.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); 1494 Common.MainForm.Quit(true, false); 1495 } 1496 1497 currentSocket.Close(); 1498 break; 1499 } 1500 } 1501 else if (package.Type == PackageType.Mouse) 1502 { 1503 if (packageCount > 5) 1504 { 1505 packageCount--; 1506 } 1507 } 1508 else if (package.Type is PackageType.Heartbeat or PackageType.Heartbeat_ex) 1509 { 1510 if (packageCount > 5) 1511 { 1512 packageCount--; 1513 } 1514 } 1515 else 1516 { 1517 if (packageCount > 5) 1518 { 1519 UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey); 1520 } 1521 else 1522 { 1523 Logger.Log(string.Format( 1524 CultureInfo.CurrentCulture, 1525 "Unexpected package, size = {0}, type = {1}", 1526 receivedCount, 1527 package.Type)); 1528 } 1529 } 1530 } 1531 else if (receivedCount > 0) 1532 { 1533 // Add some log when remote machine switches. 1534 if (lastRemoteMachineID != (long)remoteID) 1535 { 1536 _ = Interlocked.Exchange(ref lastRemoteMachineID, (long)remoteID); 1537 Logger.LogDebug($"MainTCPRoutine: Remote machine = {strIP}/{lastRemoteMachineID}"); 1538 } 1539 1540 if (package.Type == PackageType.HandshakeAck) 1541 { 1542 Logger.LogDebug("Skipping the rest of the Handshake packages."); 1543 } 1544 else 1545 { 1546 Receiver.ProcessPackage(package, currentTcp); 1547 } 1548 } 1549 } 1550 } 1551 catch (Exception e) 1552 { 1553 UpdateTcpSockets(currentTcp, SocketStatus.Error); 1554 FlagReopenSocketIfNeeded(e); 1555 currentSocket.Close(); 1556 Logger.Log(e); 1557 break; 1558 } 1559 } 1560 1561 if (remoteID != ID.NONE) 1562 { 1563 _ = MachineStuff.RemoveDeadMachines(remoteID); 1564 } 1565 } 1566 1567 private static void AcceptConnectionAndSendClipboardData(object param) 1568 { 1569 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 1570 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 1571 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 1572 1573 TcpListener server = param as TcpListener; 1574 1575 do 1576 { 1577 Logger.LogDebug("SendClipboardData: Waiting for request..."); 1578 Socket s = null; 1579 1580 try 1581 { 1582 s = server.AcceptSocket(); 1583 } 1584 catch (InvalidOperationException e) 1585 { 1586 Logger.Log($"The clipboard socket could have been closed. {e.Message}"); 1587 break; 1588 } 1589 catch (SocketException e) 1590 { 1591 if (e.ErrorCode == (int)SocketError.Interrupted) 1592 { 1593 Logger.Log("server.AcceptSocket: A blocking socket call was canceled."); 1594 continue; 1595 } 1596 else 1597 { 1598 Logger.Log(e); 1599 break; 1600 } 1601 } 1602 catch (Exception e) 1603 { 1604 Logger.Log(e); 1605 break; 1606 } 1607 1608 if (s != null) 1609 { 1610 try 1611 { 1612 new Task(() => 1613 { 1614 // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. 1615 // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 1616 using var asyncFlowControl = ExecutionContext.SuppressFlow(); 1617 1618 System.Threading.Thread thread = Thread.CurrentThread; 1619 thread.Name = $"{nameof(SendOrReceiveClipboardData)}.{thread.ManagedThreadId}"; 1620 Thread.UpdateThreads(thread); 1621 SendOrReceiveClipboardData(s); 1622 }).Start(); 1623 } 1624 catch (Exception e) 1625 { 1626 Logger.Log(e); 1627 } 1628 } 1629 } 1630 while (true); 1631 } 1632 1633 internal static void SendOrReceiveClipboardData(Socket s) 1634 { 1635 try 1636 { 1637 string remoteEndPoint = s.RemoteEndPoint.ToString(); 1638 Logger.LogDebug("SendClipboardData: Request accepted: " + s.LocalEndPoint.ToString() + "/" + remoteEndPoint); 1639 DragDrop.IsDropping = false; 1640 DragDrop.IsDragging = false; 1641 DragDrop.DragMachine = (ID)1; 1642 1643 bool clientPushData = true; 1644 ClipboardPostAction postAction = ClipboardPostAction.Other; 1645 bool handShaken = Clipboard.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction); 1646 1647 if (!handShaken) 1648 { 1649 s.Close(); 1650 return; 1651 } 1652 else 1653 { 1654 Logger.LogDebug($"{nameof(SendOrReceiveClipboardData)}: Clipboard connection accepted: " + remoteEndPoint); 1655 Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_SMALL_CLIPBOARD, -1, -1, -1 }); 1656 } 1657 1658 if (clientPushData) 1659 { 1660 Clipboard.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}"); 1661 } 1662 else 1663 { 1664 SendClipboardData(s, enStream); 1665 } 1666 } 1667 catch (Exception e) 1668 { 1669 Logger.Log(e); 1670 } 1671 } 1672 1673 internal static void SendClipboardData(Socket s, Stream ecStream) 1674 { 1675 if (Common.RunWithNoAdminRight && Setting.Values.OneWayClipboardMode) 1676 { 1677 s?.Close(); 1678 return; 1679 } 1680 1681 const int CLOSE_TIMEOUT = 10; 1682 byte[] header = new byte[1024]; 1683 string headerString = string.Empty; 1684 if (Clipboard.LastDragDropFile != null) 1685 { 1686 string fileName = null; 1687 1688 if (!Launch.ImpersonateLoggedOnUserAndDoSomething(() => 1689 { 1690 if (!File.Exists(Clipboard.LastDragDropFile)) 1691 { 1692 headerString = Directory.Exists(Clipboard.LastDragDropFile) 1693 ? $"{0}*{Clipboard.LastDragDropFile} - Folder is not supported, zip it first!" 1694 : Clipboard.LastDragDropFile.Contains("- File too big") 1695 ? $"{0}*{Clipboard.LastDragDropFile}" 1696 : $"{0}*{Clipboard.LastDragDropFile} not found!"; 1697 } 1698 else 1699 { 1700 fileName = Clipboard.LastDragDropFile; 1701 headerString = $"{new FileInfo(fileName).Length}*{fileName}"; 1702 } 1703 })) 1704 { 1705 s?.Close(); 1706 return; 1707 } 1708 1709 Common.GetBytesU(headerString).CopyTo(header, 0); 1710 1711 try 1712 { 1713 ecStream.Write(header, 0, header.Length); 1714 1715 if (!string.IsNullOrEmpty(fileName)) 1716 { 1717 if (SendFile(s, ecStream, fileName)) 1718 { 1719 s.Close(CLOSE_TIMEOUT); 1720 } 1721 } 1722 else 1723 { 1724 s.Close(CLOSE_TIMEOUT); 1725 } 1726 } 1727 catch (IOException e) 1728 { 1729 string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 1730 Logger.Log(log); 1731 } 1732 catch (SocketException e) 1733 { 1734 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host."; 1735 Logger.Log(log); 1736 } 1737 catch (ObjectDisposedException e) 1738 { 1739 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex.."; 1740 Logger.Log(log); 1741 } 1742 } 1743 else if (!Clipboard.IsClipboardDataImage && Clipboard.LastClipboardData != null) 1744 { 1745 try 1746 { 1747 byte[] data = Clipboard.LastClipboardData; 1748 1749 headerString = $"{data.Length}*{"text"}"; 1750 Common.GetBytesU(headerString).CopyTo(header, 0); 1751 1752 if (data != null) 1753 { 1754 ecStream.Write(header, 0, header.Length); 1755 _ = SendData(s, ecStream, data); 1756 Logger.LogDebug("Text sent: " + data.Length.ToString(CultureInfo.CurrentCulture)); 1757 } 1758 1759 s.Close(CLOSE_TIMEOUT); 1760 } 1761 catch (IOException e) 1762 { 1763 string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 1764 Logger.Log(log); 1765 } 1766 catch (SocketException e) 1767 { 1768 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host."; 1769 Logger.Log(log); 1770 } 1771 catch (ObjectDisposedException e) 1772 { 1773 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex.."; 1774 Logger.Log(log); 1775 } 1776 } 1777 else if (Clipboard.LastClipboardData != null && Clipboard.LastClipboardData.Length > 0) 1778 { 1779 byte[] data = Clipboard.LastClipboardData; 1780 1781 headerString = $"{data.Length}*{"image"}"; 1782 Common.GetBytesU(headerString).CopyTo(header, 0); 1783 try 1784 { 1785 ecStream.Write(header, 0, header.Length); 1786 _ = SendData(s, ecStream, data); 1787 Logger.LogDebug("Image sent: " + data.Length.ToString(CultureInfo.CurrentCulture)); 1788 s.Close(CLOSE_TIMEOUT); 1789 } 1790 catch (IOException e) 1791 { 1792 string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 1793 Logger.Log(log); 1794 } 1795 catch (SocketException e) 1796 { 1797 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host."; 1798 Logger.Log(log); 1799 } 1800 catch (ObjectDisposedException e) 1801 { 1802 string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex.."; 1803 Logger.Log(log); 1804 } 1805 } 1806 else 1807 { 1808 Logger.Log("No data available in clipboard or LastDragDropFile!"); 1809 s.Close(); 1810 } 1811 } 1812 1813 private static bool SendFileEx(Socket s, Stream ecStream, string fileName) 1814 { 1815 try 1816 { 1817 using (FileStream f = File.OpenRead(fileName)) 1818 { 1819 byte[] buf = new byte[Common.NETWORK_STREAM_BUF_SIZE]; 1820 int rv, sentCount = 0; 1821 1822 do 1823 { 1824 if ((rv = f.Read(buf, 0, Common.NETWORK_STREAM_BUF_SIZE)) > 0) 1825 { 1826 ecStream.Write(buf, 0, rv); 1827 sentCount += rv; 1828 } 1829 } 1830 while (rv > 0); 1831 1832 if ((rv = Package.PACKAGE_SIZE - (sentCount % Package.PACKAGE_SIZE)) > 0) 1833 { 1834 Array.Clear(buf, 0, buf.Length); 1835 ecStream.Write(buf, 0, rv); 1836 } 1837 1838 ecStream.Flush(); 1839 1840 Logger.LogDebug("File sent: " + fileName); 1841 } 1842 1843 return true; 1844 } 1845 catch (Exception e) 1846 { 1847 if (e is IOException) 1848 { 1849 string log = $"{nameof(SendFileEx)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 1850 Logger.Log(log); 1851 } 1852 else 1853 { 1854 Logger.Log(e); 1855 } 1856 1857 Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 1858 s.Close(); 1859 } 1860 1861 return false; 1862 } 1863 1864 private static bool SendFile(Socket s, Stream ecStream, string fileName) 1865 { 1866 bool r = false; 1867 1868 if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop) 1869 { 1870 if (fileName.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\" + Common.BinaryName + @"\ScreenCaptures\", StringComparison.CurrentCultureIgnoreCase)) 1871 { 1872 r = SendFileEx(s, ecStream, fileName); 1873 } 1874 } 1875 else 1876 { 1877 _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { r = SendFileEx(s, ecStream, fileName); }); 1878 } 1879 1880 return r; 1881 } 1882 1883 private static bool SendData(Socket s, Stream ecStream, byte[] data) 1884 { 1885 bool r = false; 1886 1887 try 1888 { 1889 using MemoryStream f = new(data); 1890 byte[] buf = new byte[Common.NETWORK_STREAM_BUF_SIZE]; 1891 int rv, sentCount = 0; 1892 1893 do 1894 { 1895 if ((rv = f.Read(buf, 0, Common.NETWORK_STREAM_BUF_SIZE)) > 0) 1896 { 1897 ecStream.Write(buf, 0, rv); 1898 sentCount += rv; 1899 } 1900 } 1901 while (rv > 0); 1902 1903 if ((rv = sentCount % Package.PACKAGE_SIZE) > 0) 1904 { 1905 Array.Clear(buf, 0, buf.Length); 1906 ecStream.Write(buf, 0, rv); 1907 } 1908 1909 ecStream.Flush(); 1910 Logger.LogDebug("Data sent: " + data.Length.ToString(CultureInfo.InvariantCulture)); 1911 r = true; 1912 } 1913 catch (Exception e) 1914 { 1915 if (e is IOException) 1916 { 1917 string log = $"{nameof(SendData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; 1918 Logger.Log(log); 1919 } 1920 else 1921 { 1922 Logger.Log(e); 1923 } 1924 1925 Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus); 1926 ecStream.Close(); 1927 s.Close(); 1928 } 1929 1930 return r; 1931 } 1932 1933 private TcpSk AddTcpSocket(bool isClient, Socket s, SocketStatus status, string machineName) 1934 { 1935 Common.CloseAnUnusedSocket(); 1936 TcpSk tcp = new(isClient, s, status, machineName); 1937 1938 lock (TcpSocketsLock) 1939 { 1940 #if ENABLE_LEGACY_DOS_PROTECTION 1941 PreventDoS(TcpSockets); 1942 #endif 1943 TcpSockets.Add(tcp); 1944 } 1945 1946 return tcp; 1947 } 1948 1949 private TcpSk AddTcpSocket(bool isClient, Socket s, SocketStatus status, string machineName, IPAddress ip) 1950 { 1951 Common.CloseAnUnusedSocket(); 1952 TcpSk tcp = new(isClient, s, status, machineName, ip); 1953 1954 lock (TcpSocketsLock) 1955 { 1956 #if ENABLE_LEGACY_DOS_PROTECTION 1957 PreventDoS(TcpSockets); 1958 #endif 1959 TcpSockets.Add(tcp); 1960 } 1961 1962 return tcp; 1963 } 1964 1965 private void UpdateTcpSockets(TcpSk tcp, SocketStatus status) 1966 { 1967 if (status == SocketStatus.InvalidKey) 1968 { 1969 InvalidKeyFound = true; 1970 } 1971 1972 InvalidKeyFoundOnClientSocket = tcp.IsClient && InvalidKeyFound; 1973 1974 try 1975 { 1976 lock (TcpSocketsLock) 1977 { 1978 if (TcpSockets != null) 1979 { 1980 if (status == SocketStatus.Connected && tcp.IsClient) 1981 { 1982 List<TcpSk> tobeRemovedSockets = TcpSockets; 1983 1984 if (tcp.MachineId == Setting.Values.MachineId) 1985 { 1986 tcp = null; 1987 Setting.Values.MachineId = Encryption.Ran.Next(); 1988 InitAndCleanup.UpdateMachineTimeAndID(); 1989 InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY; 1990 1991 Logger.TelemetryLogTrace("MachineID conflict.", SeverityLevel.Information); 1992 } 1993 else 1994 { 1995 // Keep the first connected one. 1996 tobeRemovedSockets = TcpSockets.Where(item => item.IsClient && !ReferenceEquals(item, tcp) && item.MachineName.Equals(tcp.MachineName, StringComparison.OrdinalIgnoreCase)).ToList(); 1997 } 1998 1999 foreach (TcpSk t in tobeRemovedSockets) 2000 { 2001 t.Status = SocketStatus.ForceClosed; 2002 Logger.LogDebug($"Closing duplicated socket {t.MachineName}: {t.Address}"); 2003 } 2004 } 2005 2006 List<TcpSk> toBeRemoved = new(); 2007 2008 foreach (TcpSk t in TcpSockets) 2009 { 2010 if (t.Status is SocketStatus.Error or 2011 SocketStatus.ForceClosed or 2012 2013 // SocketStatus.InvalidKey or 2014 SocketStatus.NA or 2015 SocketStatus.Timeout or 2016 SocketStatus.SendError) 2017 { 2018 try 2019 { 2020 if (t.BackingSocket != null) 2021 { 2022 t.MachineName = "$*NotUsed*$"; 2023 t.Status = t.Status >= 0 ? 0 : t.Status - 1; // If error closing, the socket will be closed again at SocketStuff.Close(). 2024 t.BackingSocket.Close(); 2025 } 2026 2027 toBeRemoved.Add(t); 2028 } 2029 catch (SocketException e) 2030 { 2031 string log = $"{nameof(UpdateTcpSockets)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host."; 2032 Logger.Log(log); 2033 } 2034 catch (ObjectDisposedException e) 2035 { 2036 string log = $"{nameof(UpdateTcpSockets)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex.."; 2037 Logger.Log(log); 2038 } 2039 } 2040 } 2041 2042 if (tcp != null) 2043 { 2044 tcp.Status = status; 2045 2046 if (status == SocketStatus.Connected) 2047 { 2048 // Update the socket's machine name based on its corresponding client/server socket. 2049 foreach (TcpSk t in TcpSockets) 2050 { 2051 if (t.MachineId == tcp.MachineId && t.IsClient != tcp.IsClient) 2052 { 2053 if ((string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':')) 2054 && !(string.IsNullOrEmpty(t.MachineName) || t.MachineName.Contains('.') || t.MachineName.Contains(':'))) 2055 { 2056 tcp.MachineName = t.MachineName; 2057 } 2058 else if ((string.IsNullOrEmpty(t.MachineName) || t.MachineName.Contains('.') || t.MachineName.Contains(':')) 2059 && !(string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))) 2060 { 2061 t.MachineName = tcp.MachineName; 2062 } 2063 } 2064 } 2065 2066 if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':')) 2067 { 2068 tcp.MachineName = MachineStuff.NameFromID((ID)tcp.MachineId); 2069 } 2070 2071 if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':')) 2072 { 2073 tcp.MachineName = Common.GetRemoteStringIP(tcp.BackingSocket); 2074 } 2075 } 2076 } 2077 else 2078 { 2079 Logger.Log("UpdateTcpSockets.Exception: Socket not found!"); 2080 } 2081 2082 foreach (TcpSk t in toBeRemoved) 2083 { 2084 _ = TcpSockets.Remove(t); 2085 } 2086 } 2087 } 2088 } 2089 catch (Exception e) 2090 { 2091 Logger.Log(e); 2092 } 2093 } 2094 2095 private void PreventDoS(List<TcpSk> sockets) 2096 { 2097 if (sockets.Count > 100) 2098 { 2099 TcpSk tcp; 2100 2101 try 2102 { 2103 string msg = Application.ProductName + " has been terminated, too many connections."; 2104 2105 for (int i = 0; i < 10; i++) 2106 { 2107 tcp = sockets[i * 10]; 2108 2109 if (tcp != null) 2110 { 2111 msg += $"\r\n{Common.MachineName}{(tcp.IsClient ? "=>" : "<=")}{tcp.MachineName}:{tcp.Status}"; 2112 } 2113 } 2114 2115 _ = Launch.CreateLowIntegrityProcess( 2116 "\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", 2117 "InternalError" + " \"" + msg + "\"", 2118 0, 2119 false, 2120 0, 2121 (short)ProcessWindowStyle.Hidden); 2122 } 2123 finally 2124 { 2125 Common.MainForm.Quit(true, false); 2126 } 2127 } 2128 } 2129 } 2130 }