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