1 // System.Net.Sockets.SocketAsyncResult.cs
4 // Ludovic Henry <ludovic@xamarin.com>
6 // Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.InteropServices;
32 using System.Runtime.Remoting.Messaging;
33 using System.Threading;
35 namespace System.Net.Sockets
37 [StructLayout (LayoutKind.Sequential)]
38 internal sealed class SocketAsyncResult: IAsyncResult, IThreadPoolWorkItem
40 /* Same structure in the runtime. Keep this in sync with
41 * MonoSocketAsyncResult in metadata/socket-io.h and
42 * ProcessAsyncReader in System.Diagnostics/Process.cs. */
47 AsyncCallback callback; // used from the runtime
48 WaitHandle wait_handle;
50 Exception delayed_exception;
52 public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo
53 public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo
54 public int Offset; // Receive,ReceiveFrom,Send,SendTo
55 public int Size; // Receive,ReceiveFrom,Send,SendTo
56 public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
57 public Socket AcceptSocket; // AcceptReceive
58 public IPAddress[] Addresses; // Connect
59 public int Port; // Connect
60 public IList<ArraySegment<byte>> Buffers; // Receive, Send
61 public bool ReuseSocket; // Disconnect
67 bool completed_synchronously;
71 public SocketOperation operation;
72 AsyncResult async_result;
75 /* These fields are not in MonoSocketAsyncResult */
76 public SocketAsyncWorker Worker;
77 public int CurrentAddress; // Connect
79 public SocketAsyncResult ()
83 public SocketAsyncResult (Socket socket, object state, AsyncCallback callback, SocketOperation operation)
85 Init (socket, state, callback, operation, new SocketAsyncWorker (this));
88 public object AsyncState {
94 public WaitHandle AsyncWaitHandle {
97 if (wait_handle == null)
98 wait_handle = new ManualResetEvent (completed);
108 public bool CompletedSynchronously {
110 return completed_synchronously;
114 public bool IsCompleted {
121 if (wait_handle != null && value)
122 ((ManualResetEvent) wait_handle).Set ();
127 public Socket Socket {
129 return accept_socket;
134 get { return total; }
135 set { total = value; }
138 public SocketError ErrorCode {
140 SocketException ex = delayed_exception as SocketException;
142 return ex.SocketErrorCode;
145 return (SocketError) error;
147 return SocketError.Success;
151 public void Init (Socket socket, object state, AsyncCallback callback, SocketOperation operation, SocketAsyncWorker worker)
153 this.socket = socket;
154 this.is_blocking = socket != null ? socket.is_blocking : true;
155 this.handle = socket != null ? socket.Handle : IntPtr.Zero;
157 this.callback = callback;
158 this.operation = operation;
160 if (wait_handle != null)
161 ((ManualResetEvent) wait_handle).Reset ();
163 delayed_exception = null;
169 SockFlags = SocketFlags.None;
175 accept_socket = null;
178 completed_synchronously = false;
187 public void DoMConnectCallback ()
189 if (callback == null)
191 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (this), null);
194 public void Dispose ()
196 Init (null, null, null, 0, Worker);
197 if (wait_handle != null) {
198 wait_handle.Close ();
203 public void CheckIfThrowDelayedException ()
205 if (delayed_exception != null) {
206 socket.is_connected = false;
207 throw delayed_exception;
211 socket.is_connected = false;
212 throw new SocketException (error);
216 void CompleteDisposed (object unused)
221 public void Complete ()
223 if (operation != SocketOperation.Receive && socket.is_disposed)
224 delayed_exception = new ObjectDisposedException (socket.GetType ().ToString ());
228 Queue<SocketAsyncWorker> queue = null;
230 case SocketOperation.Receive:
231 case SocketOperation.ReceiveFrom:
232 case SocketOperation.ReceiveGeneric:
233 case SocketOperation.Accept:
234 queue = socket.readQ;
236 case SocketOperation.Send:
237 case SocketOperation.SendTo:
238 case SocketOperation.SendGeneric:
239 queue = socket.writeQ;
245 /* queue.Count will only be 0 if the socket is closed while receive/send/accept
246 * operation(s) are pending and at least one call to this method is waiting
247 * on the lock while another one calls CompleteAllOnDispose() */
249 queue.Dequeue (); /* remove ourselves */
250 if (queue.Count > 0) {
251 if (!socket.is_disposed) {
252 Socket.socket_pool_queue (SocketAsyncWorker.Dispatcher, (queue.Peek ()).result);
254 /* CompleteAllOnDispose */
255 SocketAsyncWorker [] workers = queue.ToArray ();
256 for (int i = 0; i < workers.Length; i++)
257 ThreadPool.UnsafeQueueUserWorkItem (workers [i].result.CompleteDisposed, null);
264 // IMPORTANT: 'callback', if any is scheduled from unmanaged code
267 public void Complete (bool synch)
269 this.completed_synchronously = synch;
273 public void Complete (int total)
279 public void Complete (Exception e, bool synch)
281 this.completed_synchronously = synch;
282 this.delayed_exception = e;
286 public void Complete (Exception e)
288 this.delayed_exception = e;
292 public void Complete (Socket s)
294 this.accept_socket = s;
298 public void Complete (Socket s, int total)
300 this.accept_socket = s;
305 void IThreadPoolWorkItem.ExecuteWorkItem()
307 ((IThreadPoolWorkItem) async_result).ExecuteWorkItem ();
309 if (completed && callback != null) {
310 ThreadPool.UnsafeQueueCustomWorkItem (new AsyncResult (state => callback ((IAsyncResult) state), this, false), false);
314 void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)