980ad06e5b2f909333222afba5fea6ea9da6ead2
[mono.git] / mcs / class / System / System.Net.Sockets / SocketAsyncResult.cs
1 // System.Net.Sockets.SocketAsyncResult.cs
2 //
3 // Authors:
4 //      Ludovic Henry <ludovic@xamarin.com>
5 //
6 // Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.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
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.InteropServices;
32 using System.Runtime.Remoting.Messaging;
33 using System.Threading;
34
35 namespace System.Net.Sockets
36 {
37         [StructLayout (LayoutKind.Sequential)]
38         internal sealed class SocketAsyncResult: IOAsyncResult
39         {
40                 public Socket socket;
41                 public SocketOperation operation;
42
43                 Exception DelayedException;
44
45                 public EndPoint EndPoint;                 // Connect,ReceiveFrom,SendTo
46                 public byte [] Buffer;                    // Receive,ReceiveFrom,Send,SendTo
47                 public int Offset;                        // Receive,ReceiveFrom,Send,SendTo
48                 public int Size;                          // Receive,ReceiveFrom,Send,SendTo
49                 public SocketFlags SockFlags;             // Receive,ReceiveFrom,Send,SendTo
50                 public Socket AcceptSocket;               // AcceptReceive
51                 public IPAddress[] Addresses;             // Connect
52                 public int Port;                          // Connect
53                 public IList<ArraySegment<byte>> Buffers; // Receive, Send
54                 public bool ReuseSocket;                  // Disconnect
55                 public int CurrentAddress;                // Connect
56
57                 public Socket AcceptedSocket;
58                 public int Total;
59
60                 internal int error;
61
62                 public int EndCalled;
63
64                 public IntPtr Handle {
65                         get { return socket != null ? socket.Handle : IntPtr.Zero; }
66                 }
67
68                 /* Used by SocketAsyncEventArgs */
69                 public SocketAsyncResult ()
70                         : base ()
71                 {
72                 }
73
74                 public void Init (Socket socket, AsyncCallback callback, object state, SocketOperation operation)
75                 {
76                         base.Init (callback, state);
77
78                         this.socket = socket;
79                         this.operation = operation;
80
81                         DelayedException = null;
82
83                         EndPoint = null;
84                         Buffer = null;
85                         Offset = 0;
86                         Size = 0;
87                         SockFlags = SocketFlags.None;
88                         AcceptSocket = null;
89                         Addresses = null;
90                         Port = 0;
91                         Buffers = null;
92                         ReuseSocket = false;
93                         CurrentAddress = 0;
94
95                         AcceptedSocket = null;
96                         Total = 0;
97
98                         error = 0;
99
100                         EndCalled = 0;
101                 }
102
103                 public SocketAsyncResult (Socket socket, AsyncCallback callback, object state, SocketOperation operation)
104                         : base (callback, state)
105                 {
106                         this.socket = socket;
107                         this.operation = operation;
108                 }
109
110                 public SocketError ErrorCode {
111                         get {
112                                 SocketException ex = DelayedException as SocketException;
113                                 if (ex != null)
114                                         return ex.SocketErrorCode;
115
116                                 if (error != 0)
117                                         return (SocketError) error;
118
119                                 return SocketError.Success;
120                         }
121                 }
122
123                 public void CheckIfThrowDelayedException ()
124                 {
125                         if (DelayedException != null) {
126                                 socket.is_connected = false;
127                                 throw DelayedException;
128                         }
129
130                         if (error != 0) {
131                                 socket.is_connected = false;
132                                 throw new SocketException (error);
133                         }
134                 }
135
136                 internal override void CompleteDisposed ()
137                 {
138                         Complete ();
139                 }
140
141                 public void Complete ()
142                 {
143                         if (operation != SocketOperation.Receive && socket.is_disposed)
144                                 DelayedException = new ObjectDisposedException (socket.GetType ().ToString ());
145
146                         IsCompleted = true;
147
148                         AsyncCallback callback = AsyncCallback;
149                         if (callback != null) {
150                                 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (this), null);
151                         }
152
153                         Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue = null;
154                         switch (operation) {
155                         case SocketOperation.Receive:
156                         case SocketOperation.ReceiveFrom:
157                         case SocketOperation.ReceiveGeneric:
158                         case SocketOperation.Accept:
159                                 queue = socket.readQ;
160                                 break;
161                         case SocketOperation.Send:
162                         case SocketOperation.SendTo:
163                         case SocketOperation.SendGeneric:
164                                 queue = socket.writeQ;
165                                 break;
166                         }
167
168                         if (queue != null) {
169                                 lock (queue) {
170                                         /* queue.Count will only be 0 if the socket is closed while receive/send/accept
171                                          * operation(s) are pending and at least one call to this method is waiting
172                                          * on the lock while another one calls CompleteAllOnDispose() */
173                                         if (queue.Count > 0)
174                                                 queue.Dequeue (); /* remove ourselves */
175                                         if (queue.Count > 0) {
176                                                 if (!socket.is_disposed) {
177                                                         IOSelector.Add (queue.Peek ().Key, queue.Peek ().Value);
178                                                 } else {
179                                                         /* CompleteAllOnDispose */
180                                                         KeyValuePair<IntPtr, IOSelectorJob> [] jobs = queue.ToArray ();
181                                                         for (int i = 0; i < jobs.Length; i++)
182                                                                 ThreadPool.QueueUserWorkItem (j => ((IOSelectorJob) j).MarkDisposed (), jobs [i].Value);
183                                                         queue.Clear ();
184                                                 }
185                                         }
186                                 }
187                         }
188
189                         // IMPORTANT: 'callback', if any is scheduled from unmanaged code
190                 }
191
192                 public void Complete (bool synch)
193                 {
194                         CompletedSynchronously = synch;
195                         Complete ();
196                 }
197
198                 public void Complete (int total)
199                 {
200                         Total = total;
201                         Complete ();
202                 }
203
204                 public void Complete (Exception e, bool synch)
205                 {
206                         DelayedException = e;
207                         CompletedSynchronously = synch;
208                         Complete ();
209                 }
210
211                 public void Complete (Exception e)
212                 {
213                         DelayedException = e;
214                         Complete ();
215                 }
216
217                 public void Complete (Socket s)
218                 {
219                         AcceptedSocket = s;
220                         Complete ();
221                 }
222
223                 public void Complete (Socket s, int total)
224                 {
225                         AcceptedSocket = s;
226                         Total = total;
227                         Complete ();
228                 }
229         }
230 }