You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Listener.cs 4.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. using Shadowsocks.Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Net.NetworkInformation;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. namespace Shadowsocks.Controller
  9. {
  10. public class Listener
  11. {
  12. public interface Service
  13. {
  14. bool Handle(byte[] firstPacket, int length, Socket socket);
  15. }
  16. Configuration _config;
  17. bool _shareOverLAN;
  18. Socket _socket;
  19. IList<Service> _services;
  20. public Listener(IList<Service> services)
  21. {
  22. this._services = services;
  23. }
  24. private bool CheckIfPortInUse(int port)
  25. {
  26. IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
  27. IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
  28. foreach (IPEndPoint endPoint in ipEndPoints)
  29. {
  30. if (endPoint.Port == port)
  31. {
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. public void Start(Configuration config)
  38. {
  39. this._config = config;
  40. this._shareOverLAN = config.shareOverLan;
  41. if (CheckIfPortInUse(_config.localPort))
  42. throw new Exception(I18N.GetString("Port already in use"));
  43. try
  44. {
  45. // Create a TCP/IP socket.
  46. _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  47. _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
  48. IPEndPoint localEndPoint = null;
  49. if (_shareOverLAN)
  50. {
  51. localEndPoint = new IPEndPoint(IPAddress.Any, _config.localPort);
  52. }
  53. else
  54. {
  55. localEndPoint = new IPEndPoint(IPAddress.Loopback, _config.localPort);
  56. }
  57. // Bind the socket to the local endpoint and listen for incoming connections.
  58. _socket.Bind(localEndPoint);
  59. _socket.Listen(1024);
  60. // Start an asynchronous socket to listen for connections.
  61. Console.WriteLine("Shadowsocks started");
  62. _socket.BeginAccept(
  63. new AsyncCallback(AcceptCallback),
  64. _socket);
  65. }
  66. catch (SocketException)
  67. {
  68. _socket.Close();
  69. throw;
  70. }
  71. }
  72. public void Stop()
  73. {
  74. if (_socket != null)
  75. {
  76. _socket.Close();
  77. _socket = null;
  78. }
  79. }
  80. public void AcceptCallback(IAsyncResult ar)
  81. {
  82. Socket listener = (Socket)ar.AsyncState;
  83. try
  84. {
  85. Socket conn = listener.EndAccept(ar);
  86. byte[] buf = new byte[4096];
  87. object[] state = new object[] {
  88. conn,
  89. buf
  90. };
  91. conn.BeginReceive(buf, 0, buf.Length, 0,
  92. new AsyncCallback(ReceiveCallback), state);
  93. }
  94. catch (ObjectDisposedException)
  95. {
  96. }
  97. catch (Exception e)
  98. {
  99. Console.WriteLine(e);
  100. }
  101. finally
  102. {
  103. try
  104. {
  105. listener.BeginAccept(
  106. new AsyncCallback(AcceptCallback),
  107. listener);
  108. }
  109. catch (ObjectDisposedException)
  110. {
  111. // do nothing
  112. }
  113. catch (Exception e)
  114. {
  115. Logging.LogUsefulException(e);
  116. }
  117. }
  118. }
  119. private void ReceiveCallback(IAsyncResult ar)
  120. {
  121. object[] state = (object[])ar.AsyncState;
  122. Socket conn = (Socket)state[0];
  123. byte[] buf = (byte[])state[1];
  124. try
  125. {
  126. int bytesRead = conn.EndReceive(ar);
  127. foreach (Service service in _services)
  128. {
  129. if (service.Handle(buf, bytesRead, conn))
  130. {
  131. return;
  132. }
  133. }
  134. // no service found for this
  135. // shouldn't happen
  136. conn.Close();
  137. }
  138. catch (Exception e)
  139. {
  140. Console.WriteLine(e);
  141. conn.Close();
  142. }
  143. }
  144. }
  145. }