1 // System.Net.Sockets.SocketAsyncEventArgs.cs
4 // Marek Habersack (mhabersack@novell.com)
6 // Copyright (c) 2008 Novell, Inc. (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
32 using System.Threading;
34 namespace System.Net.Sockets
36 public class SocketAsyncEventArgs : EventArgs, IDisposable
38 public event EventHandler<SocketAsyncEventArgs> Completed;
40 IList <ArraySegment <byte>> _bufferList;
42 public Socket AcceptSocket { get; set; }
43 public byte[] Buffer { get; private set; }
45 [MonoTODO ("not supported in all cases")]
46 public IList<ArraySegment<byte>> BufferList {
47 get { return _bufferList; }
50 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
55 public int BytesTransferred { get; private set; }
56 public int Count { get; private set; }
57 public bool DisconnectReuseSocket { get; set; }
58 public SocketAsyncOperation LastOperation { get; private set; }
59 public int Offset { get; private set; }
60 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
61 public EndPoint RemoteEndPoint { get; set; }
62 public SendPacketsElement[] SendPacketsElements { get; set; }
63 public TransmitFileOptions SendPacketsFlags { get; set; }
64 public int SendPacketsSendSize { get; set; }
65 public SocketError SocketError { get; set; }
66 public SocketFlags SocketFlags { get; set; }
67 public object UserToken { get; set; }
71 public Socket ConnectSocket {
73 switch (SocketError) {
74 case SocketError.AccessDenied:
83 public SocketAsyncEventArgs ()
90 DisconnectReuseSocket = false;
91 LastOperation = SocketAsyncOperation.None;
93 RemoteEndPoint = null;
94 SendPacketsElements = null;
95 SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
96 SendPacketsSendSize = 0;
97 SocketError = SocketError.Success;
98 SocketFlags = SocketFlags.None;
102 ~SocketAsyncEventArgs ()
107 void Dispose (bool disposing)
109 Socket acceptSocket = AcceptSocket;
110 if (acceptSocket != null)
111 acceptSocket.Close ();
114 GC.SuppressFinalize (this);
117 public void Dispose ()
122 protected virtual void OnCompleted (SocketAsyncEventArgs e)
127 if (e.Completed != null)
128 e.Completed (e.curSocket, e);
131 public void SetBuffer (int offset, int count)
133 SetBufferInternal (Buffer, offset, count);
136 public void SetBuffer (byte[] buffer, int offset, int count)
138 SetBufferInternal (buffer, offset, count);
141 void SetBufferInternal (byte[] buffer, int offset, int count)
143 if (buffer != null) {
144 if (BufferList != null)
145 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
147 int buflen = buffer.Length;
148 if (offset < 0 || offset >= buflen)
149 throw new ArgumentOutOfRangeException ("offset");
151 if (count < 0 || count + offset > buflen)
152 throw new ArgumentOutOfRangeException ("count");
161 void ReceiveCallback ()
163 SocketError = SocketError.Success;
164 LastOperation = SocketAsyncOperation.Receive;
165 SocketError error = SocketError.Success;
167 if (!curSocket.Connected) {
168 SocketError = SocketError.NotConnected;
173 // FIXME: this does not support using BufferList
174 BytesTransferred = curSocket.Receive_nochecks (Buffer, Offset, Count, SocketFlags, out error);
181 void ConnectCallback ()
183 LastOperation = SocketAsyncOperation.Connect;
185 if (SocketError == SocketError.AccessDenied) {
186 curSocket.Connected = false;
191 SocketError = SocketError.Success;
192 SocketError error = SocketError.Success;
195 if (!curSocket.Blocking) {
197 curSocket.Poll (-1, SelectMode.SelectWrite, out success);
198 SocketError = (SocketError)success;
200 curSocket.Connected = true;
204 curSocket.seed_endpoint = RemoteEndPoint;
205 curSocket.Connect (RemoteEndPoint);
206 curSocket.Connected = true;
208 } catch (SocketException se){
209 error = se.SocketErrorCode;
218 SocketError = SocketError.Success;
219 LastOperation = SocketAsyncOperation.Send;
220 SocketError error = SocketError.Success;
222 if (!curSocket.Connected) {
223 SocketError = SocketError.NotConnected;
228 if (Buffer != null) {
229 BytesTransferred = curSocket.Send_nochecks (Buffer, Offset, Count, SocketFlags.None, out error);
230 } else if (BufferList != null) {
231 BytesTransferred = 0;
232 foreach (ArraySegment<byte> asb in BufferList) {
233 BytesTransferred += curSocket.Send_nochecks (asb.Array, asb.Offset, asb.Count,
234 SocketFlags.None, out error);
235 if (error != SocketError.Success)
245 void AcceptCallback ()
247 SocketError = SocketError.Success;
248 LastOperation = SocketAsyncOperation.Accept;
250 curSocket.Accept (AcceptSocket);
251 } catch (SocketException ex) {
252 SocketError = ex.SocketErrorCode;
259 void DisconnectCallback ()
261 SocketError = SocketError.Success;
262 LastOperation = SocketAsyncOperation.Disconnect;
265 curSocket.Disconnect (DisconnectReuseSocket);
266 } catch (SocketException ex) {
267 SocketError = ex.SocketErrorCode;
274 void ReceiveFromCallback ()
276 SocketError = SocketError.Success;
277 LastOperation = SocketAsyncOperation.ReceiveFrom;
280 EndPoint ep = RemoteEndPoint;
281 BytesTransferred = curSocket.ReceiveFrom_nochecks (Buffer, Offset, Count, SocketFlags, ref ep);
282 } catch (SocketException ex) {
283 SocketError = ex.SocketErrorCode;
290 void SendToCallback ()
292 SocketError = SocketError.Success;
293 LastOperation = SocketAsyncOperation.SendTo;
299 while (total < count)
300 total += curSocket.SendTo_nochecks (Buffer, Offset, count, SocketFlags, RemoteEndPoint);
301 BytesTransferred = total;
302 } catch (SocketException ex) {
303 SocketError = ex.SocketErrorCode;
310 internal void DoOperation (SocketAsyncOperation operation, Socket socket)
312 ThreadStart callback;
317 case SocketAsyncOperation.Accept:
318 callback = new ThreadStart (AcceptCallback);
321 case SocketAsyncOperation.Disconnect:
322 callback = new ThreadStart (DisconnectCallback);
325 case SocketAsyncOperation.ReceiveFrom:
326 callback = new ThreadStart (ReceiveFromCallback);
329 case SocketAsyncOperation.SendTo:
330 callback = new ThreadStart (SendToCallback);
333 case SocketAsyncOperation.Receive:
334 callback = new ThreadStart (ReceiveCallback);
337 case SocketAsyncOperation.Connect:
338 callback = new ThreadStart (ConnectCallback);
341 case SocketAsyncOperation.Send:
342 callback = new ThreadStart (SendCallback);
346 throw new NotSupportedException ();
349 Thread t = new Thread (callback);
350 t.IsBackground = true;