//
// Authors:
// Marek Habersack (mhabersack@novell.com)
+// Gonzalo Paniagua Javier (gonzalo@xamarin.com)
//
-// Copyright (c) 2008 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2008,2010 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2011 Xamarin, Inc. (http://xamarin.com)
//
//
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_2_0
using System;
using System.Collections.Generic;
+using System.Reflection;
+using System.Security;
using System.Threading;
namespace System.Net.Sockets
{
public class SocketAsyncEventArgs : EventArgs, IDisposable
{
+ bool disposed;
+ int in_progress;
+ internal Socket.Worker Worker;
+ EndPoint remote_ep;
+#if NET_4_0
+ public Exception ConnectByNameError { get; internal set; }
+#endif
+
public event EventHandler<SocketAsyncEventArgs> Completed;
IList <ArraySegment <byte>> _bufferList;
public IList<ArraySegment<byte>> BufferList {
get { return _bufferList; }
set {
- if (Buffer != null)
+ if (Buffer != null && value != null)
throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
_bufferList = value;
}
}
- public int BytesTransferred { get; private set; }
- public int Count { get; private set; }
+ public int BytesTransferred { get; internal set; }
+ public int Count { get; internal set; }
public bool DisconnectReuseSocket { get; set; }
public SocketAsyncOperation LastOperation { get; private set; }
public int Offset { get; private set; }
+ public EndPoint RemoteEndPoint {
+ get { return remote_ep; }
+ set { remote_ep = value; }
+ }
+#if !NET_2_1
public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
- public EndPoint RemoteEndPoint { get; set; }
public SendPacketsElement[] SendPacketsElements { get; set; }
public TransmitFileOptions SendPacketsFlags { get; set; }
+#endif
+ [MonoTODO ("unused property")]
public int SendPacketsSendSize { get; set; }
public SocketError SocketError { get; set; }
public SocketFlags SocketFlags { get; set; }
public object UserToken { get; set; }
+ internal Socket curSocket;
+#if NET_2_1
+ public Socket ConnectSocket {
+ get {
+ switch (SocketError) {
+ case SocketError.AccessDenied:
+ return null;
+ default:
+ return curSocket;
+ }
+ }
+ }
+
+ internal bool PolicyRestricted { get; private set; }
- Socket curSocket;
+ internal SocketAsyncEventArgs (bool policy) :
+ this ()
+ {
+ PolicyRestricted = policy;
+ }
+#endif
public SocketAsyncEventArgs ()
{
+ Worker = new Socket.Worker (this);
AcceptSocket = null;
Buffer = null;
BufferList = null;
LastOperation = SocketAsyncOperation.None;
Offset = 0;
RemoteEndPoint = null;
+#if !NET_2_1
SendPacketsElements = null;
SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
- SendPacketsSendSize = 0;
+#endif
+ SendPacketsSendSize = -1;
SocketError = SocketError.Success;
SocketFlags = SocketFlags.None;
UserToken = null;
void Dispose (bool disposing)
{
- Socket acceptSocket = AcceptSocket;
- if (acceptSocket != null)
- acceptSocket.Close ();
-
- if (disposing)
- GC.SuppressFinalize (this);
+ disposed = true;
+
+ if (disposing) {
+ if (disposed || Interlocked.CompareExchange (ref in_progress, 0, 0) != 0)
+ return;
+ if (Worker != null) {
+ Worker.Dispose ();
+ Worker = null;
+ }
+ }
+ AcceptSocket = null;
+ Buffer = null;
+ BufferList = null;
+ RemoteEndPoint = null;
+ UserToken = null;
+#if !NET_2_1
+ SendPacketsElements = null;
+#endif
}
public void Dispose ()
{
Dispose (true);
+ GC.SuppressFinalize (this);
}
-
+
+ internal void SetLastOperation (SocketAsyncOperation op)
+ {
+ if (disposed)
+ throw new ObjectDisposedException ("System.Net.Sockets.SocketAsyncEventArgs");
+ if (Interlocked.Exchange (ref in_progress, 1) != 0)
+ throw new InvalidOperationException ("Operation already in progress");
+ LastOperation = op;
+ }
+
protected virtual void OnCompleted (SocketAsyncEventArgs e)
{
if (e == null)
return;
- if (e.Completed != null)
- e.Completed (e.curSocket, e);
+ EventHandler<SocketAsyncEventArgs> handler = e.Completed;
+ if (handler != null)
+ handler (e.curSocket, e);
}
public void SetBuffer (int offset, int count)
throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
int buflen = buffer.Length;
- if (offset < 0 || offset >= buflen)
+ if (offset < 0 || (offset != 0 && offset >= buflen))
throw new ArgumentOutOfRangeException ("offset");
- if (count < 0 || count + offset > buflen)
+ if (count < 0 || count > buflen - offset)
throw new ArgumentOutOfRangeException ("count");
- }
- Count = count;
- Offset = offset;
+ Count = count;
+ Offset = offset;
+ }
Buffer = buffer;
}
#region Internals
- void AcceptCallback ()
+ internal static AsyncCallback Dispatcher = new AsyncCallback (DispatcherCB);
+
+ static void DispatcherCB (IAsyncResult ares)
+ {
+ SocketAsyncEventArgs args = (SocketAsyncEventArgs) ares.AsyncState;
+ if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+ SocketAsyncOperation op = args.LastOperation;
+ // Notes;
+ // -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
+ // -SendPackets and ReceiveMessageFrom are not implemented yet
+ if (op == SocketAsyncOperation.Receive)
+ args.ReceiveCallback (ares);
+ else if (op == SocketAsyncOperation.Send)
+ args.SendCallback (ares);
+ else if (op == SocketAsyncOperation.ReceiveFrom)
+ args.ReceiveFromCallback (ares);
+ else if (op == SocketAsyncOperation.SendTo)
+ args.SendToCallback (ares);
+ else if (op == SocketAsyncOperation.Accept)
+ args.AcceptCallback (ares);
+ else if (op == SocketAsyncOperation.Disconnect)
+ args.DisconnectCallback (ares);
+ else if (op == SocketAsyncOperation.Connect)
+ args.ConnectCallback ();
+ /*
+ else if (op == Socket.SocketOperation.ReceiveMessageFrom)
+ else if (op == Socket.SocketOperation.SendPackets)
+ */
+ else
+ throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
+
+ }
+
+ internal void ReceiveCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Accept;
try {
- curSocket.Accept (AcceptSocket);
- } catch (SocketException ex) {
- SocketError = ex.SocketErrorCode;
- throw;
+ BytesTransferred = curSocket.EndReceive (ares);
+ } catch (SocketException se){
+ SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
- void ReceiveCallback ()
+ void ConnectCallback ()
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Receive;
- SocketError error = SocketError.Success;
-
try {
- BytesTransferred = curSocket.Receive_nochecks (Buffer, Offset, Count, SocketFlags, out error);
+ SocketError = (SocketError) Worker.result.error;
} finally {
- SocketError = error;
OnCompleted (this);
}
}
- void ConnectCallback ()
+ internal void SendCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Connect;
- SocketError error = SocketError.Success;
-
try {
- if (!curSocket.Blocking) {
- int success;
- curSocket.Poll (-1, SelectMode.SelectWrite, out success);
- SocketError = (SocketError)success;
- if (success == 0)
- curSocket.Connected = true;
- else
- return;
- } else {
- curSocket.seed_endpoint = RemoteEndPoint;
- curSocket.Connect (RemoteEndPoint);
- curSocket.Connected = true;
- }
+ BytesTransferred = curSocket.EndSend (ares);
} catch (SocketException se){
- error = se.SocketErrorCode;
+ SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
- SocketError = error;
OnCompleted (this);
}
}
- void SendCallback ()
+ internal void AcceptCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Send;
- SocketError error = SocketError.Success;
-
try {
- BytesTransferred = curSocket.Send_nochecks (Buffer, Offset, Count, SocketFlags.None, out error);
+ AcceptSocket = curSocket.EndAccept (ares);
+ } catch (SocketException ex) {
+ SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
- SocketError = error;
+ if (AcceptSocket == null)
+ AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, (IntPtr)(-1));
OnCompleted (this);
}
}
- void DisconnectCallback ()
+ internal void DisconnectCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Disconnect;
-
try {
- curSocket.Disconnect (DisconnectReuseSocket);
+ curSocket.EndDisconnect (ares);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
- throw;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
- void ReceiveFromCallback ()
+ internal void ReceiveFromCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.ReceiveFrom;
-
try {
- EndPoint ep = RemoteEndPoint;
- BytesTransferred = curSocket.ReceiveFrom_nochecks (Buffer, Offset, Count, SocketFlags, ref ep);
+ BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
- throw;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
- void SendToCallback ()
+ internal void SendToCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.SendTo;
- int total = 0;
-
try {
- int count = Count;
-
- while (total < count)
- total += curSocket.SendTo_nochecks (Buffer, Offset, count, SocketFlags, RemoteEndPoint);
- BytesTransferred = total;
+ BytesTransferred = curSocket.EndSendTo (ares);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
- throw;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
-
- internal void DoOperation (SocketAsyncOperation operation, Socket socket)
- {
- ThreadStart callback;
- curSocket = socket;
-
- switch (operation) {
- case SocketAsyncOperation.Accept:
- callback = new ThreadStart (AcceptCallback);
- break;
-
- case SocketAsyncOperation.Receive:
- callback = new ThreadStart (ReceiveCallback);
- break;
-
- case SocketAsyncOperation.Connect:
- callback = new ThreadStart (ConnectCallback);
- break;
-
- case SocketAsyncOperation.Disconnect:
- callback = new ThreadStart (DisconnectCallback);
- break;
-
- case SocketAsyncOperation.ReceiveFrom:
- callback = new ThreadStart (ReceiveFromCallback);
- break;
-
- case SocketAsyncOperation.Send:
- callback = new ThreadStart (SendCallback);
- break;
-
- case SocketAsyncOperation.SendTo:
- callback = new ThreadStart (SendToCallback);
- break;
-
- default:
- throw new NotSupportedException ();
- }
-
- Thread t = new Thread (callback);
- t.IsBackground = true;
- t.Start ();
- }
#endregion
}
}
-#endif