SocketAsyncEventArgs.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. // System.Net.Sockets.SocketAsyncEventArgs.cs
  2. //
  3. // Authors:
  4. // Marek Habersack ([email protected])
  5. //
  6. // Copyright (c) 2008 Novell, Inc. (http://www.novell.com)
  7. //
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if NET_2_0
  29. using System;
  30. using System.Collections.Generic;
  31. using System.Reflection;
  32. using System.Security;
  33. using System.Threading;
  34. namespace System.Net.Sockets
  35. {
  36. public class SocketAsyncEventArgs : EventArgs, IDisposable
  37. {
  38. #if NET_2_1 && !MONOTOUCH
  39. static MethodInfo check_socket_policy;
  40. static SocketAsyncEventArgs ()
  41. {
  42. Type type = Type.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
  43. check_socket_policy = type.GetMethod ("CheckEndPoint");
  44. }
  45. static internal bool CheckEndPoint (EndPoint endpoint)
  46. {
  47. if (check_socket_policy == null)
  48. throw new SecurityException ();
  49. return ((bool) check_socket_policy.Invoke (null, new object [1] { endpoint }));
  50. }
  51. #endif
  52. public event EventHandler<SocketAsyncEventArgs> Completed;
  53. IList <ArraySegment <byte>> _bufferList;
  54. public Socket AcceptSocket { get; set; }
  55. public byte[] Buffer { get; private set; }
  56. [MonoTODO ("not supported in all cases")]
  57. public IList<ArraySegment<byte>> BufferList {
  58. get { return _bufferList; }
  59. set {
  60. if (Buffer != null && value != null)
  61. throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
  62. _bufferList = value;
  63. }
  64. }
  65. public int BytesTransferred { get; private set; }
  66. public int Count { get; private set; }
  67. public bool DisconnectReuseSocket { get; set; }
  68. public SocketAsyncOperation LastOperation { get; private set; }
  69. public int Offset { get; private set; }
  70. public EndPoint RemoteEndPoint { get; set; }
  71. #if !NET_2_1
  72. public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
  73. public SendPacketsElement[] SendPacketsElements { get; set; }
  74. public TransmitFileOptions SendPacketsFlags { get; set; }
  75. #endif
  76. [MonoTODO ("unused property")]
  77. public int SendPacketsSendSize { get; set; }
  78. public SocketError SocketError { get; set; }
  79. public SocketFlags SocketFlags { get; set; }
  80. public object UserToken { get; set; }
  81. Socket curSocket;
  82. #if NET_2_1
  83. public Socket ConnectSocket {
  84. get {
  85. switch (SocketError) {
  86. case SocketError.AccessDenied:
  87. return null;
  88. default:
  89. return curSocket;
  90. }
  91. }
  92. }
  93. internal bool PolicyRestricted { get; private set; }
  94. internal SocketAsyncEventArgs (bool policy) :
  95. this ()
  96. {
  97. PolicyRestricted = policy;
  98. }
  99. #endif
  100. public SocketAsyncEventArgs ()
  101. {
  102. AcceptSocket = null;
  103. Buffer = null;
  104. BufferList = null;
  105. BytesTransferred = 0;
  106. Count = 0;
  107. DisconnectReuseSocket = false;
  108. LastOperation = SocketAsyncOperation.None;
  109. Offset = 0;
  110. RemoteEndPoint = null;
  111. #if !NET_2_1
  112. SendPacketsElements = null;
  113. SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
  114. #endif
  115. SendPacketsSendSize = -1;
  116. SocketError = SocketError.Success;
  117. SocketFlags = SocketFlags.None;
  118. UserToken = null;
  119. }
  120. ~SocketAsyncEventArgs ()
  121. {
  122. Dispose (false);
  123. }
  124. void Dispose (bool disposing)
  125. {
  126. Socket acceptSocket = AcceptSocket;
  127. if (acceptSocket != null)
  128. acceptSocket.Close ();
  129. if (disposing)
  130. GC.SuppressFinalize (this);
  131. }
  132. public void Dispose ()
  133. {
  134. Dispose (true);
  135. }
  136. protected virtual void OnCompleted (SocketAsyncEventArgs e)
  137. {
  138. if (e == null)
  139. return;
  140. if (e.Completed != null)
  141. e.Completed (e.curSocket, e);
  142. }
  143. public void SetBuffer (int offset, int count)
  144. {
  145. SetBufferInternal (Buffer, offset, count);
  146. }
  147. public void SetBuffer (byte[] buffer, int offset, int count)
  148. {
  149. SetBufferInternal (buffer, offset, count);
  150. }
  151. void SetBufferInternal (byte[] buffer, int offset, int count)
  152. {
  153. if (buffer != null) {
  154. if (BufferList != null)
  155. throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
  156. int buflen = buffer.Length;
  157. if (offset < 0 || (offset != 0 && offset >= buflen))
  158. throw new ArgumentOutOfRangeException ("offset");
  159. if (count < 0 || count > buflen - offset)
  160. throw new ArgumentOutOfRangeException ("count");
  161. Count = count;
  162. Offset = offset;
  163. }
  164. Buffer = buffer;
  165. }
  166. #region Internals
  167. void ReceiveCallback ()
  168. {
  169. SocketError = SocketError.Success;
  170. LastOperation = SocketAsyncOperation.Receive;
  171. SocketError error = SocketError.Success;
  172. if (!curSocket.Connected) {
  173. SocketError = SocketError.NotConnected;
  174. return;
  175. }
  176. try {
  177. // FIXME: this does not support using BufferList
  178. BytesTransferred = curSocket.Receive_nochecks (Buffer, Offset, Count, SocketFlags, out error);
  179. } finally {
  180. SocketError = error;
  181. OnCompleted (this);
  182. }
  183. }
  184. void ConnectCallback ()
  185. {
  186. LastOperation = SocketAsyncOperation.Connect;
  187. SocketError error = SocketError.Success;
  188. try {
  189. #if NET_2_1 && !MONOTOUCH
  190. // Connect to the first address that match the host name, like:
  191. // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
  192. // while skipping entries that do not match the address family
  193. DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
  194. if (dep != null) {
  195. IPAddress[] addresses = Dns.GetHostAddresses (dep.Host);
  196. foreach (IPAddress addr in addresses) {
  197. try {
  198. if (curSocket.AddressFamily == addr.AddressFamily) {
  199. error = TryConnect (new IPEndPoint (addr, dep.Port));
  200. if (error == SocketError.Success)
  201. break;
  202. }
  203. }
  204. catch (SocketException) {
  205. error = SocketError.AccessDenied;
  206. }
  207. }
  208. } else {
  209. error = TryConnect (RemoteEndPoint);
  210. }
  211. #else
  212. error = TryConnect (RemoteEndPoint);
  213. #endif
  214. } finally {
  215. SocketError = error;
  216. OnCompleted (this);
  217. }
  218. }
  219. SocketError TryConnect (EndPoint endpoint)
  220. {
  221. curSocket.Connected = false;
  222. SocketError error = SocketError.Success;
  223. #if NET_2_1 && !MONOTOUCH
  224. // if we're not downloading a socket policy then check the policy
  225. if (!PolicyRestricted) {
  226. error = SocketError.AccessDenied;
  227. if (!CheckEndPoint (endpoint)) {
  228. return error;
  229. }
  230. }
  231. #endif
  232. try {
  233. if (!curSocket.Blocking) {
  234. int success;
  235. curSocket.Poll (-1, SelectMode.SelectWrite, out success);
  236. error = (SocketError)success;
  237. if (success == 0)
  238. curSocket.Connected = true;
  239. else
  240. return error;
  241. } else {
  242. curSocket.seed_endpoint = endpoint;
  243. curSocket.Connect (endpoint);
  244. curSocket.Connected = true;
  245. }
  246. } catch (SocketException se){
  247. error = se.SocketErrorCode;
  248. }
  249. return error;
  250. }
  251. void SendCallback ()
  252. {
  253. SocketError = SocketError.Success;
  254. LastOperation = SocketAsyncOperation.Send;
  255. SocketError error = SocketError.Success;
  256. if (!curSocket.Connected) {
  257. SocketError = SocketError.NotConnected;
  258. return;
  259. }
  260. try {
  261. if (Buffer != null) {
  262. BytesTransferred = curSocket.Send_nochecks (Buffer, Offset, Count, SocketFlags.None, out error);
  263. } else if (BufferList != null) {
  264. BytesTransferred = 0;
  265. foreach (ArraySegment<byte> asb in BufferList) {
  266. BytesTransferred += curSocket.Send_nochecks (asb.Array, asb.Offset, asb.Count,
  267. SocketFlags.None, out error);
  268. if (error != SocketError.Success)
  269. break;
  270. }
  271. }
  272. } finally {
  273. SocketError = error;
  274. OnCompleted (this);
  275. }
  276. }
  277. #if !NET_2_1
  278. void AcceptCallback ()
  279. {
  280. SocketError = SocketError.Success;
  281. LastOperation = SocketAsyncOperation.Accept;
  282. try {
  283. curSocket.Accept (AcceptSocket);
  284. } catch (SocketException ex) {
  285. SocketError = ex.SocketErrorCode;
  286. throw;
  287. } finally {
  288. OnCompleted (this);
  289. }
  290. }
  291. void DisconnectCallback ()
  292. {
  293. SocketError = SocketError.Success;
  294. LastOperation = SocketAsyncOperation.Disconnect;
  295. try {
  296. curSocket.Disconnect (DisconnectReuseSocket);
  297. } catch (SocketException ex) {
  298. SocketError = ex.SocketErrorCode;
  299. throw;
  300. } finally {
  301. OnCompleted (this);
  302. }
  303. }
  304. void ReceiveFromCallback ()
  305. {
  306. SocketError = SocketError.Success;
  307. LastOperation = SocketAsyncOperation.ReceiveFrom;
  308. try {
  309. EndPoint ep = RemoteEndPoint;
  310. BytesTransferred = curSocket.ReceiveFrom_nochecks (Buffer, Offset, Count, SocketFlags, ref ep);
  311. } catch (SocketException ex) {
  312. SocketError = ex.SocketErrorCode;
  313. throw;
  314. } finally {
  315. OnCompleted (this);
  316. }
  317. }
  318. void SendToCallback ()
  319. {
  320. SocketError = SocketError.Success;
  321. LastOperation = SocketAsyncOperation.SendTo;
  322. int total = 0;
  323. try {
  324. int count = Count;
  325. while (total < count)
  326. total += curSocket.SendTo_nochecks (Buffer, Offset, count, SocketFlags, RemoteEndPoint);
  327. BytesTransferred = total;
  328. } catch (SocketException ex) {
  329. SocketError = ex.SocketErrorCode;
  330. throw;
  331. } finally {
  332. OnCompleted (this);
  333. }
  334. }
  335. #endif
  336. internal void DoOperation (SocketAsyncOperation operation, Socket socket)
  337. {
  338. ThreadStart callback;
  339. curSocket = socket;
  340. switch (operation) {
  341. #if !NET_2_1
  342. case SocketAsyncOperation.Accept:
  343. callback = new ThreadStart (AcceptCallback);
  344. break;
  345. case SocketAsyncOperation.Disconnect:
  346. callback = new ThreadStart (DisconnectCallback);
  347. break;
  348. case SocketAsyncOperation.ReceiveFrom:
  349. callback = new ThreadStart (ReceiveFromCallback);
  350. break;
  351. case SocketAsyncOperation.SendTo:
  352. callback = new ThreadStart (SendToCallback);
  353. break;
  354. #endif
  355. case SocketAsyncOperation.Receive:
  356. callback = new ThreadStart (ReceiveCallback);
  357. break;
  358. case SocketAsyncOperation.Connect:
  359. callback = new ThreadStart (ConnectCallback);
  360. break;
  361. case SocketAsyncOperation.Send:
  362. callback = new ThreadStart (SendCallback);
  363. break;
  364. default:
  365. throw new NotSupportedException ();
  366. }
  367. Thread t = new Thread (callback);
  368. t.IsBackground = true;
  369. t.Start ();
  370. }
  371. #endregion
  372. }
  373. }
  374. #endif