EndPointManager.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #region License
  2. /*
  3. * EndPointManager.cs
  4. *
  5. * This code is derived from EndPointManager.cs (System.Net) of Mono
  6. * (http://www.mono-project.com).
  7. *
  8. * The MIT License
  9. *
  10. * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
  11. * Copyright (c) 2012-2020 sta.blockhead
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a copy
  14. * of this software and associated documentation files (the "Software"), to deal
  15. * in the Software without restriction, including without limitation the rights
  16. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. * copies of the Software, and to permit persons to whom the Software is
  18. * furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice shall be included in
  21. * all copies or substantial portions of the Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  29. * THE SOFTWARE.
  30. */
  31. #endregion
  32. #region Authors
  33. /*
  34. * Authors:
  35. * - Gonzalo Paniagua Javier <gonzalo@ximian.com>
  36. */
  37. #endregion
  38. #region Contributors
  39. /*
  40. * Contributors:
  41. * - Liryna <liryna.stark@gmail.com>
  42. */
  43. #endregion
  44. using System;
  45. using System.Collections;
  46. using System.Collections.Generic;
  47. using System.Net;
  48. namespace WebSocketSharp.Net
  49. {
  50. internal sealed class EndPointManager
  51. {
  52. #region Private Fields
  53. private static readonly Dictionary<IPEndPoint, EndPointListener> _endpoints;
  54. #endregion
  55. #region Static Constructor
  56. static EndPointManager ()
  57. {
  58. _endpoints = new Dictionary<IPEndPoint, EndPointListener> ();
  59. }
  60. #endregion
  61. #region Private Constructors
  62. private EndPointManager ()
  63. {
  64. }
  65. #endregion
  66. #region Private Methods
  67. private static void addPrefix (string uriPrefix, HttpListener listener)
  68. {
  69. var pref = new HttpListenerPrefix (uriPrefix, listener);
  70. var addr = convertToIPAddress (pref.Host);
  71. if (addr == null) {
  72. var msg = "The URI prefix includes an invalid host.";
  73. throw new HttpListenerException (87, msg);
  74. }
  75. if (!addr.IsLocal ()) {
  76. var msg = "The URI prefix includes an invalid host.";
  77. throw new HttpListenerException (87, msg);
  78. }
  79. int port;
  80. if (!Int32.TryParse (pref.Port, out port)) {
  81. var msg = "The URI prefix includes an invalid port.";
  82. throw new HttpListenerException (87, msg);
  83. }
  84. if (!port.IsPortNumber ()) {
  85. var msg = "The URI prefix includes an invalid port.";
  86. throw new HttpListenerException (87, msg);
  87. }
  88. var path = pref.Path;
  89. if (path.IndexOf ('%') != -1) {
  90. var msg = "The URI prefix includes an invalid path.";
  91. throw new HttpListenerException (87, msg);
  92. }
  93. if (path.IndexOf ("//", StringComparison.Ordinal) != -1) {
  94. var msg = "The URI prefix includes an invalid path.";
  95. throw new HttpListenerException (87, msg);
  96. }
  97. var endpoint = new IPEndPoint (addr, port);
  98. EndPointListener lsnr;
  99. if (_endpoints.TryGetValue (endpoint, out lsnr)) {
  100. if (lsnr.IsSecure ^ pref.IsSecure) {
  101. var msg = "The URI prefix includes an invalid scheme.";
  102. throw new HttpListenerException (87, msg);
  103. }
  104. }
  105. else {
  106. lsnr = new EndPointListener (
  107. endpoint,
  108. pref.IsSecure,
  109. listener.CertificateFolderPath,
  110. listener.SslConfiguration,
  111. listener.ReuseAddress
  112. );
  113. _endpoints.Add (endpoint, lsnr);
  114. }
  115. lsnr.AddPrefix (pref);
  116. }
  117. private static IPAddress convertToIPAddress (string hostname)
  118. {
  119. if (hostname == "*")
  120. return IPAddress.Any;
  121. if (hostname == "+")
  122. return IPAddress.Any;
  123. return hostname.ToIPAddress ();
  124. }
  125. private static void removePrefix (string uriPrefix, HttpListener listener)
  126. {
  127. var pref = new HttpListenerPrefix (uriPrefix, listener);
  128. var addr = convertToIPAddress (pref.Host);
  129. if (addr == null)
  130. return;
  131. if (!addr.IsLocal ())
  132. return;
  133. int port;
  134. if (!Int32.TryParse (pref.Port, out port))
  135. return;
  136. if (!port.IsPortNumber ())
  137. return;
  138. var path = pref.Path;
  139. if (path.IndexOf ('%') != -1)
  140. return;
  141. if (path.IndexOf ("//", StringComparison.Ordinal) != -1)
  142. return;
  143. var endpoint = new IPEndPoint (addr, port);
  144. EndPointListener lsnr;
  145. if (!_endpoints.TryGetValue (endpoint, out lsnr))
  146. return;
  147. if (lsnr.IsSecure ^ pref.IsSecure)
  148. return;
  149. lsnr.RemovePrefix (pref);
  150. }
  151. #endregion
  152. #region Internal Methods
  153. internal static bool RemoveEndPoint (IPEndPoint endpoint)
  154. {
  155. lock (((ICollection) _endpoints).SyncRoot)
  156. return _endpoints.Remove (endpoint);
  157. }
  158. #endregion
  159. #region Public Methods
  160. public static void AddListener (HttpListener listener)
  161. {
  162. var added = new List<string> ();
  163. lock (((ICollection) _endpoints).SyncRoot) {
  164. try {
  165. foreach (var pref in listener.Prefixes) {
  166. addPrefix (pref, listener);
  167. added.Add (pref);
  168. }
  169. }
  170. catch {
  171. foreach (var pref in added)
  172. removePrefix (pref, listener);
  173. throw;
  174. }
  175. }
  176. }
  177. public static void AddPrefix (string uriPrefix, HttpListener listener)
  178. {
  179. lock (((ICollection) _endpoints).SyncRoot)
  180. addPrefix (uriPrefix, listener);
  181. }
  182. public static void RemoveListener (HttpListener listener)
  183. {
  184. lock (((ICollection) _endpoints).SyncRoot) {
  185. foreach (var pref in listener.Prefixes)
  186. removePrefix (pref, listener);
  187. }
  188. }
  189. public static void RemovePrefix (string uriPrefix, HttpListener listener)
  190. {
  191. lock (((ICollection) _endpoints).SyncRoot)
  192. removePrefix (uriPrefix, listener);
  193. }
  194. #endregion
  195. }
  196. }