// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Sridhar Kulkarni (sridharkulkarni@gmail.com)
// Brian Nickel (brian.nickel@gmail.com)
+// Ludovic Henry (ludovic@xamarin.com)
//
// Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
// http://www.myelin.co.nz
int linger_timeout;
- /* the field "safe_handle" is looked up by name by the runtime */
- SafeSocketHandle safe_handle;
-
AddressFamily address_family;
SocketType socket_type;
ProtocolType protocol_type;
+ /* the field "safe_handle" is looked up by name by the runtime */
+ internal SafeSocketHandle safe_handle;
+
/*
* This EndPoint is used when creating new endpoints. Because
* there are many types of EndPoints possible,
*/
internal EndPoint seed_endpoint = null;
- internal Queue readQ = new Queue (2);
- internal Queue writeQ = new Queue (2);
+ internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
+ internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
internal bool is_blocking = true;
internal bool is_bound;
static Socket ()
{
- // initialize ipv4_supported and ipv6_supported
- CheckProtocolSupport ();
+ if (ipv4_supported == -1) {
+ try {
+ Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ tmp.Close();
+
+ ipv4_supported = 1;
+ } catch {
+ ipv4_supported = 0;
+ }
+ }
+
+ if (ipv6_supported == -1) {
+ // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
+ // when run in a mono embedded application. This occurs as embedded applications do not have a setup
+ // for application config. The exception is not thrown when called from a normal .NET application.
+ //
+ // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
+ // exception, will fall through to the existing Socket / API directly below in the code.
+ //
+ // Also note that catching ConfigurationErrorsException specifically would require library dependency
+ // System.Configuration, and wanted to avoid that.
+#if !NET_2_1
+#if CONFIGURATION_DEP
+ try {
+ SettingsSection config;
+ config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
+ if (config != null)
+ ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
+ } catch {
+ ipv6_supported = -1;
+ }
+#else
+ try {
+ NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
+ if (config != null)
+ ipv6_supported = config.ipv6Enabled ? -1 : 0;
+ } catch {
+ ipv6_supported = -1;
+ }
+#endif
+#endif
+ if (ipv6_supported != 0) {
+ try {
+ Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
+ tmp.Close();
+
+ ipv6_supported = 1;
+ } catch {
+ ipv6_supported = 0;
+ }
+ }
+ }
}
- [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
+ //
+ // This constructor is used by servers that want to listen for instance on both
+ // ipv4 and ipv6. Mono has historically done that if you use InterNetworkV6 (at
+ // least on Unix), because that is the default behavior unless the IPV6_V6ONLY
+ // option is explicitly set by using setsockopt (sock, IPPROTO_IPV6, IPV6_ONLY)
+ //
public Socket (SocketType socketType, ProtocolType protocolType)
- : this (AddressFamily.InterNetwork, socketType, protocolType)
+ : this (AddressFamily.InterNetworkV6, socketType, protocolType)
{
+ DualMode = true;
}
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
this.address_family = addressFamily;
this.socket_type = socketType;
this.protocol_type = protocolType;
-
- int error;
- var handle = Socket_internal (addressFamily, socketType, protocolType, out error);
- this.safe_handle = new SafeSocketHandle (handle, true);
+ int error;
+ this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
if (error != 0)
throw new SocketException (error);
extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
#endregion
- static void AddSockets (List<Socket> sockets, IList list, string name)
- {
- if (list != null) {
- foreach (Socket sock in list) {
- if (sock == null) // MS throws a NullRef
- throw new ArgumentNullException ("name", "Contains a null element");
- sockets.Add (sock);
- }
- }
- sockets.Add (null);
+#region Properties
+
+ [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
+ public static bool SupportsIPv4 {
+ get { return ipv4_supported == 1; }
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Select_internal (ref Socket [] sockets,
- int microSeconds,
- out int error);
- public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
- {
- var list = new List<Socket> ();
- AddSockets (list, checkRead, "checkRead");
- AddSockets (list, checkWrite, "checkWrite");
- AddSockets (list, checkError, "checkError");
- if (list.Count == 3) {
- throw new ArgumentNullException ("checkRead, checkWrite, checkError",
- "All the lists are null or empty.");
- }
+ [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
+ public static bool SupportsIPv6 {
+ get { return ipv6_supported == 1; }
+ }
- int error;
- /*
- * The 'sockets' array contains: READ socket 0-n, null,
- * WRITE socket 0-n, null,
- * ERROR socket 0-n, null
- */
- Socket [] sockets = list.ToArray ();
- Select_internal (ref sockets, microSeconds, out error);
+#if NET_2_1
+ public static bool OSSupportsIPv4 {
+ get { return ipv4_supported == 1; }
+ }
+#else
+ public static bool OSSupportsIPv4 {
+ get {
+ NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
- if (error != 0)
- throw new SocketException (error);
+ foreach (NetworkInterface adapter in nics) {
+ if (adapter.Supports (NetworkInterfaceComponent.IPv4))
+ return true;
+ }
- if (sockets == null) {
- if (checkRead != null)
- checkRead.Clear ();
- if (checkWrite != null)
- checkWrite.Clear ();
- if (checkError != null)
- checkError.Clear ();
- return;
+ return false;
}
+ }
+#endif
- int mode = 0;
- int count = sockets.Length;
- IList currentList = checkRead;
- int currentIdx = 0;
- for (int i = 0; i < count; i++) {
- Socket sock = sockets [i];
- if (sock == null) { // separator
- if (currentList != null) {
- // Remove non-signaled sockets after the current one
- int to_remove = currentList.Count - currentIdx;
- for (int k = 0; k < to_remove; k++)
- currentList.RemoveAt (currentIdx);
- }
- currentList = (mode == 0) ? checkWrite : checkError;
- currentIdx = 0;
- mode++;
- continue;
- }
-
- if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
- if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
- sock.is_connected = true;
- }
+#if NET_2_1
+ public static bool OSSupportsIPv6 {
+ get { return ipv6_supported == 1; }
+ }
+#else
+ public static bool OSSupportsIPv6 {
+ get {
+ NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
- // Remove non-signaled sockets before the current one
- //int max = currentList.Count;
- while (((Socket) currentList [currentIdx]) != sock) {
- currentList.RemoveAt (currentIdx);
+ foreach (NetworkInterface adapter in nics) {
+ if (adapter.Supports (NetworkInterfaceComponent.IPv6))
+ return true;
}
- currentIdx++;
- }
- }
-
- // Returns the amount of data waiting to be read on socket
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int Available_internal(IntPtr socket, out int error);
- private static int Available_internal (SafeSocketHandle safeHandle, out int error)
- {
- bool release = false;
- try {
- safeHandle.DangerousAddRef (ref release);
- return Available_internal (safeHandle.DangerousGetHandle (), out error);
- } finally {
- if (release)
- safeHandle.DangerousRelease ();
+ return false;
}
}
+#endif
public int Available {
get {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
int ret, error;
-
ret = Available_internal (safe_handle, out error);
if (error != 0)
throw new SocketException (error);
- return(ret);
+ return ret;
+ }
+ }
+
+ static int Available_internal (SafeSocketHandle safeHandle, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ return Available_internal (safeHandle.DangerousGetHandle (), out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
}
}
+ /* Returns the amount of data waiting to be read on socket */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int Available_internal (IntPtr socket, out int error);
public bool DontFragment {
get {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
-
- bool dontfragment;
-
- if (address_family == AddressFamily.InterNetwork) {
- dontfragment = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
- } else if (address_family == AddressFamily.InterNetworkV6) {
- dontfragment = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
- } else {
+ ThrowIfDisposedAndClosed ();
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
+ case AddressFamily.InterNetworkV6:
+ return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
+ default:
throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
}
-
- return(dontfragment);
}
set {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
-
- if (address_family == AddressFamily.InterNetwork) {
- SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value?1:0);
- } else if (address_family == AddressFamily.InterNetworkV6) {
- SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value?1:0);
- } else {
+ ThrowIfDisposedAndClosed ();
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
+ break;
+ case AddressFamily.InterNetworkV6:
+ SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
+ break;
+ default:
throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
}
}
public bool EnableBroadcast {
get {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
+ ThrowIfDisposedAndClosed ();
- if (protocol_type != ProtocolType.Udp) {
- throw new SocketException ((int)SocketError.ProtocolOption);
- }
-
- return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0);
+ if (protocol_type != ProtocolType.Udp)
+ throw new SocketException ((int) SocketError.ProtocolOption);
+
+ return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
}
set {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
+ ThrowIfDisposedAndClosed ();
- if (protocol_type != ProtocolType.Udp) {
- throw new SocketException ((int)SocketError.ProtocolOption);
- }
+ if (protocol_type != ProtocolType.Udp)
+ throw new SocketException ((int) SocketError.ProtocolOption);
- SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value?1:0);
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
}
}
-
+
public bool ExclusiveAddressUse {
get {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
+ ThrowIfDisposedAndClosed ();
- return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0);
+ return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
}
set {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
- if (is_bound) {
+ ThrowIfDisposedAndClosed ();
+
+ if (is_bound)
throw new InvalidOperationException ("Bind has already been called for this socket");
- }
-
- SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value?1:0);
+
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
}
}
-
+
public bool IsBound {
get {
- return(is_bound);
+ return is_bound;
}
}
-
+
public LingerOption LingerState {
get {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
+ ThrowIfDisposedAndClosed ();
- return((LingerOption)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger));
+ return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
}
set {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
-
- SetSocketOption (SocketOptionLevel.Socket,
- SocketOptionName.Linger,
- value);
+ ThrowIfDisposedAndClosed ();
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
}
}
-
+
public bool MulticastLoopback {
get {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
-
- /* Even though this option can be set
- * for TCP sockets on Linux, throw
- * this exception anyway to be
- * compatible (the MSDN docs say
- * "Setting this property on a
- * Transmission Control Protocol (TCP)
- * socket will have no effect." but
- * the MS runtime throws the
- * exception...)
- */
- if (protocol_type == ProtocolType.Tcp) {
+ ThrowIfDisposedAndClosed ();
+
+ /* Even though this option can be set for TCP sockets on Linux, throw
+ * this exception anyway to be compatible (the MSDN docs say
+ * "Setting this property on a Transmission Control Protocol (TCP)
+ * socket will have no effect." but the MS runtime throws the
+ * exception...) */
+ if (protocol_type == ProtocolType.Tcp)
throw new SocketException ((int)SocketError.ProtocolOption);
- }
-
- bool multicastloopback;
-
- if (address_family == AddressFamily.InterNetwork) {
- multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
- } else if (address_family == AddressFamily.InterNetworkV6) {
- multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
- } else {
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
+ case AddressFamily.InterNetworkV6:
+ return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
+ default:
throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
}
-
- return(multicastloopback);
}
set {
- if (is_disposed && is_closed) {
- throw new ObjectDisposedException (GetType ().ToString ());
- }
-
- /* Even though this option can be set
- * for TCP sockets on Linux, throw
- * this exception anyway to be
- * compatible (the MSDN docs say
- * "Setting this property on a
- * Transmission Control Protocol (TCP)
- * socket will have no effect." but
- * the MS runtime throws the
- * exception...)
- */
- if (protocol_type == ProtocolType.Tcp) {
+ ThrowIfDisposedAndClosed ();
+
+ /* Even though this option can be set for TCP sockets on Linux, throw
+ * this exception anyway to be compatible (the MSDN docs say
+ * "Setting this property on a Transmission Control Protocol (TCP)
+ * socket will have no effect." but the MS runtime throws the
+ * exception...) */
+ if (protocol_type == ProtocolType.Tcp)
throw new SocketException ((int)SocketError.ProtocolOption);
- }
-
- if (address_family == AddressFamily.InterNetwork) {
- SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value?1:0);
- } else if (address_family == AddressFamily.InterNetworkV6) {
- SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value?1:0);
- } else {
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
+ break;
+ case AddressFamily.InterNetworkV6:
+ SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
+ break;
+ default:
throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
}
}
}
-
-
- [MonoTODO ("This doesn't do anything on Mono yet")]
- public bool UseOnlyOverlappedIO {
+
+ public bool DualMode {
get {
- return use_overlapped_io;
+ if (AddressFamily != AddressFamily.InterNetworkV6)
+ throw new NotSupportedException("This protocol version is not supported");
+
+ return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
}
set {
- use_overlapped_io = value;
+ if (AddressFamily != AddressFamily.InterNetworkV6)
+ throw new NotSupportedException("This protocol version is not supported");
+
+ SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
}
}
- public IntPtr Handle {
+ private bool IsDualMode {
get {
- return safe_handle.DangerousGetHandle ();
+ return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
}
}
- // Returns the local endpoint details in addr and port
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, int family, out int error);
+ [MonoTODO ("This doesn't do anything on Mono yet")]
+ public bool UseOnlyOverlappedIO {
+ get { return use_overlapped_io; }
+ set { use_overlapped_io = value; }
+ }
- private static SocketAddress LocalEndPoint_internal(SafeSocketHandle safeHandle, int family, out int error)
- {
- bool release = false;
- try {
- safeHandle.DangerousAddRef (ref release);
- return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
- } finally {
- if (release)
- safeHandle.DangerousRelease ();
- }
+ public IntPtr Handle {
+ get { return safe_handle.DangerousGetHandle (); }
}
// Wish: support non-IP endpoints.
public EndPoint LocalEndPoint {
get {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- /*
- * If the seed EndPoint is null, Connect, Bind,
- * etc has not yet been called. MS returns null
- * in this case.
- */
+ ThrowIfDisposedAndClosed ();
+
+ /* If the seed EndPoint is null, Connect, Bind, etc has not yet
+ * been called. MS returns null in this case. */
if (seed_endpoint == null)
return null;
-
- SocketAddress sa;
+
int error;
-
- sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
+ SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
if (error != 0)
throw new SocketException (error);
}
}
- public SocketType SocketType {
- get {
- return(socket_type);
+ static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
}
}
+ /* Returns the local endpoint details in addr and port */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
+
+ public SocketType SocketType {
+ get { return socket_type; }
+ }
+
public int SendTimeout {
get {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- return (int)GetSocketOption(
- SocketOptionLevel.Socket,
- SocketOptionName.SendTimeout);
+ return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
}
set {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
if (value < -1)
throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
- /* According to the MSDN docs we
- * should adjust values between 1 and
- * 499 to 500, but the MS runtime
- * doesn't do this.
- */
+ /* According to the MSDN docs we should adjust values between 1 and
+ * 499 to 500, but the MS runtime doesn't do this. */
if (value == -1)
value = 0;
- SetSocketOption(
- SocketOptionLevel.Socket,
- SocketOptionName.SendTimeout, value);
+ SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
}
}
public int ReceiveTimeout {
get {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- return (int)GetSocketOption(
- SocketOptionLevel.Socket,
- SocketOptionName.ReceiveTimeout);
+ return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
}
set {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
if (value < -1)
throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
- if (value == -1) {
+ if (value == -1)
value = 0;
- }
-
- SetSocketOption(
- SocketOptionLevel.Socket,
- SocketOptionName.ReceiveTimeout, value);
+
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
}
}
- public bool AcceptAsync (SocketAsyncEventArgs e)
- {
- // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
-
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
- if (!IsBound)
- throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
- if (!is_listening)
- throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
- if (e.BufferList != null)
- throw new ArgumentException ("Multiple buffers cannot be used with this method.");
- if (e.Count < 0)
- throw new ArgumentOutOfRangeException ("e.Count");
+ public AddressFamily AddressFamily {
+ get { return address_family; }
+ }
- Socket acceptSocket = e.AcceptSocket;
- if (acceptSocket != null) {
- if (acceptSocket.IsBound || acceptSocket.Connected)
- throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
- }
+ public bool Blocking {
+ get { return is_blocking; }
+ set {
+ ThrowIfDisposedAndClosed ();
- e.curSocket = this;
- SocketAsyncWorker w = e.Worker;
- w.Init (this, e, SocketOperation.Accept);
- int count;
- lock (readQ) {
- readQ.Enqueue (e.Worker);
- count = readQ.Count;
+ int error;
+ Blocking_internal (safe_handle, value, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ is_blocking = value;
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, w.result);
- return true;
}
- // Creates a new system socket, returning the handle
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
- private static SafeSocketHandle Accept_internal(SafeSocketHandle safeHandle, out int error, bool blocking)
+ static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
{
+ bool release = false;
try {
- safeHandle.RegisterForBlockingSyscall ();
- var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
- return new SafeSocketHandle (ret, true);
+ safeHandle.DangerousAddRef (ref release);
+ Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
} finally {
- safeHandle.UnRegisterForBlockingSyscall ();
+ if (release)
+ safeHandle.DangerousRelease ();
}
}
- public Socket Accept() {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
- int error = 0;
- var sock = Accept_internal(safe_handle, out error, is_blocking);
+ public bool Connected {
+ get { return is_connected; }
+ internal set { is_connected = value; }
+ }
- if (error != 0) {
- if (is_closed)
- error = SOCKET_CLOSED_CODE;
- throw new SocketException(error);
+ public ProtocolType ProtocolType {
+ get { return protocol_type; }
+ }
+
+ public bool NoDelay {
+ get {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfUdp ();
+
+ return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
}
- Socket accepted = new Socket(this.AddressFamily, this.SocketType,
- this.ProtocolType, sock);
+ set {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfUdp ();
- accepted.seed_endpoint = this.seed_endpoint;
- accepted.Blocking = this.Blocking;
- return(accepted);
+ SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
+ }
}
- internal void Accept (Socket acceptSocket)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- int error = 0;
- var sock = Accept_internal (safe_handle, out error, is_blocking);
-
- if (error != 0) {
- if (is_closed)
- error = SOCKET_CLOSED_CODE;
- throw new SocketException (error);
+ public int ReceiveBufferSize {
+ get {
+ ThrowIfDisposedAndClosed ();
+
+ return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
}
-
+ set {
+ ThrowIfDisposedAndClosed ();
+
+ if (value < 0)
+ throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
+
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
+ }
+ }
+
+ public int SendBufferSize {
+ get {
+ ThrowIfDisposedAndClosed ();
+
+ return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
+ }
+ set {
+ ThrowIfDisposedAndClosed ();
+
+ if (value < 0)
+ throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
+
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
+ }
+ }
+
+ public short Ttl {
+ get {
+ ThrowIfDisposedAndClosed ();
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
+ case AddressFamily.InterNetworkV6:
+ return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
+ default:
+ throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+ }
+ }
+ set {
+ ThrowIfDisposedAndClosed ();
+
+ if (value < 0)
+ throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
+
+ switch (address_family) {
+ case AddressFamily.InterNetwork:
+ SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
+ break;
+ case AddressFamily.InterNetworkV6:
+ SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
+ break;
+ default:
+ throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+ }
+ }
+ }
+
+ public EndPoint RemoteEndPoint {
+ get {
+ ThrowIfDisposedAndClosed ();
+
+ /* If the seed EndPoint is null, Connect, Bind, etc has
+ * not yet been called. MS returns null in this case. */
+ if (!is_connected || seed_endpoint == null)
+ return null;
+
+ int error;
+ SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ return seed_endpoint.Create (sa);
+ }
+ }
+
+ static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
+
+ /* Returns the remote endpoint details in addr and port */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
+
+#endregion
+
+#region Select
+
+ public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
+ {
+ var list = new List<Socket> ();
+ AddSockets (list, checkRead, "checkRead");
+ AddSockets (list, checkWrite, "checkWrite");
+ AddSockets (list, checkError, "checkError");
+
+ if (list.Count == 3)
+ throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
+
+ /* The 'sockets' array contains:
+ * - READ socket 0-n, null,
+ * - WRITE socket 0-n, null,
+ * - ERROR socket 0-n, null */
+ Socket [] sockets = list.ToArray ();
+
+ int error;
+ Select_internal (ref sockets, microSeconds, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ if (sockets == null) {
+ if (checkRead != null)
+ checkRead.Clear ();
+ if (checkWrite != null)
+ checkWrite.Clear ();
+ if (checkError != null)
+ checkError.Clear ();
+ return;
+ }
+
+ int mode = 0;
+ int count = sockets.Length;
+ IList currentList = checkRead;
+ int currentIdx = 0;
+ for (int i = 0; i < count; i++) {
+ Socket sock = sockets [i];
+ if (sock == null) { // separator
+ if (currentList != null) {
+ // Remove non-signaled sockets after the current one
+ int to_remove = currentList.Count - currentIdx;
+ for (int k = 0; k < to_remove; k++)
+ currentList.RemoveAt (currentIdx);
+ }
+ currentList = (mode == 0) ? checkWrite : checkError;
+ currentIdx = 0;
+ mode++;
+ continue;
+ }
+
+ if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
+ if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
+ sock.is_connected = true;
+ }
+
+ /* Remove non-signaled sockets before the current one */
+ while (((Socket) currentList [currentIdx]) != sock)
+ currentList.RemoveAt (currentIdx);
+
+ currentIdx++;
+ }
+ }
+
+ static void AddSockets (List<Socket> sockets, IList list, string name)
+ {
+ if (list != null) {
+ foreach (Socket sock in list) {
+ if (sock == null) // MS throws a NullRef
+ throw new ArgumentNullException ("name", "Contains a null element");
+ sockets.Add (sock);
+ }
+ }
+
+ sockets.Add (null);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
+
+#endregion
+
+#region Poll
+
+ public bool Poll (int time_us, SelectMode mode)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
+ throw new NotSupportedException ("'mode' parameter is not valid.");
+
+ int error;
+ bool result = Poll_internal (safe_handle, mode, time_us, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ if (mode == SelectMode.SelectWrite && result && !is_connected) {
+ /* Update the is_connected state; for non-blocking Connect()
+ * this is when we can find out that the connect succeeded. */
+ if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
+ is_connected = true;
+ }
+
+ return result;
+ }
+
+ static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
+
+#endregion
+
+#region Accept
+
+ public Socket Accept()
+ {
+ ThrowIfDisposedAndClosed ();
+
+ int error = 0;
+ SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
+
+ if (error != 0) {
+ if (is_closed)
+ error = SOCKET_CLOSED_CODE;
+ throw new SocketException(error);
+ }
+
+ Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
+ seed_endpoint = this.seed_endpoint,
+ Blocking = this.Blocking,
+ };
+
+ return accepted;
+ }
+
+ internal void Accept (Socket acceptSocket)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ int error = 0;
+ SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
+
+ if (error != 0) {
+ if (is_closed)
+ error = SOCKET_CLOSED_CODE;
+ throw new SocketException (error);
+ }
+
acceptSocket.address_family = this.AddressFamily;
acceptSocket.socket_type = this.SocketType;
acceptSocket.protocol_type = this.ProtocolType;
- acceptSocket.safe_handle = sock;
+ acceptSocket.safe_handle = safe_handle;
acceptSocket.is_connected = true;
acceptSocket.seed_endpoint = this.seed_endpoint;
acceptSocket.Blocking = this.Blocking;
- /* FIXME: figure out what if anything else
- * needs to be reset
- */
+ // FIXME: figure out what if anything else needs to be reset
+ }
+
+ public bool AcceptAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ ThrowIfDisposedAndClosed ();
+
+ if (!is_bound)
+ throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
+ if (!is_listening)
+ throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
+ if (e.BufferList != null)
+ throw new ArgumentException ("Multiple buffers cannot be used with this method.");
+ if (e.Count < 0)
+ throw new ArgumentOutOfRangeException ("e.Count");
+
+ Socket acceptSocket = e.AcceptSocket;
+ if (acceptSocket != null) {
+ if (acceptSocket.is_bound || acceptSocket.is_connected)
+ throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
+ }
+
+ InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
+
+ QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
+
+ return true;
+ }
+
+ static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+
+ try {
+ e.AcceptSocket = e.current_socket.EndAccept (ares);
+ } catch (SocketException ex) {
+ e.SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
+ } finally {
+ if (e.AcceptSocket == null)
+ e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
+ e.Complete ();
+ }
+ });
+
+ public IAsyncResult BeginAccept(AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (!is_bound || !is_listening)
+ throw new InvalidOperationException ();
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
+
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
+
+ return sockares;
+ }
+
+ static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ Socket socket = null;
+
+ try {
+ socket = sockares.socket.Accept ();
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
+
+ sockares.Complete (socket);
+ });
+
+ public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (receiveSize < 0)
+ throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
+ Buffer = new byte [receiveSize],
+ Offset = 0,
+ Size = receiveSize,
+ SockFlags = SocketFlags.None,
+ };
+
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
+
+ return sockares;
+ }
+
+ public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (receiveSize < 0)
+ throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+ if (acceptSocket != null) {
+ ThrowIfDisposedAndClosed (acceptSocket);
+
+ if (acceptSocket.IsBound)
+ throw new InvalidOperationException ();
+
+ /* For some reason the MS runtime
+ * barfs if the new socket is not TCP,
+ * even though it's just about to blow
+ * away all those parameters
+ */
+ if (acceptSocket.ProtocolType != ProtocolType.Tcp)
+ throw new SocketException ((int)SocketError.InvalidArgument);
+ }
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
+ Buffer = new byte [receiveSize],
+ Offset = 0,
+ Size = receiveSize,
+ SockFlags = SocketFlags.None,
+ AcceptSocket = acceptSocket,
+ };
+
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
+
+ return sockares;
+ }
+
+ static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ Socket acc_socket = null;
+
+ try {
+ if (sockares.AcceptSocket == null) {
+ acc_socket = sockares.socket.Accept ();
+ } else {
+ acc_socket = sockares.AcceptSocket;
+ sockares.socket.Accept (acc_socket);
+ }
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
+
+ /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
+ int total = 0;
+ if (sockares.Size > 0) {
+ try {
+ SocketError error;
+ total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
+ if (error != 0) {
+ sockares.Complete (new SocketException ((int) error));
+ return;
+ }
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
+ }
+
+ sockares.Complete (acc_socket, total);
+ });
+
+ public Socket EndAccept (IAsyncResult result)
+ {
+ int bytes;
+ byte[] buffer;
+ return EndAccept (out buffer, out bytes, result);
+ }
+
+ public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
+ {
+ int bytes;
+ return EndAccept (out buffer, out bytes, asyncResult);
+ }
+
+ public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
+
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne ();
+
+ sockares.CheckIfThrowDelayedException ();
+
+ buffer = sockares.Buffer;
+ bytesTransferred = sockares.Total;
+
+ return sockares.AcceptedSocket;
+ }
+
+ static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
+ {
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
+ return new SafeSocketHandle (ret, true);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
+ }
+ }
+
+ /* Creates a new system socket, returning the handle */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
+
+#endregion
+
+#region Bind
+
+ public void Bind (EndPoint local_end)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (local_end == null)
+ throw new ArgumentNullException("local_end");
+
+ int error;
+ Bind_internal (safe_handle, local_end.Serialize(), out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+ if (error == 0)
+ is_bound = true;
+
+ seed_endpoint = local_end;
+ }
+
+ private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
+
+ // Creates a new system socket, returning the handle
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
+
+#endregion
+
+#region Listen
+
+ public void Listen (int backlog)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (!is_bound)
+ throw new SocketException ((int) SocketError.InvalidArgument);
+
+ int error;
+ Listen_internal(safe_handle, backlog, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ is_listening = true;
+ }
+
+ static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void Listen_internal (IntPtr sock, int backlog, out int error);
+
+#endregion
+
+#region Connect
+
+ public void Connect (IPAddress address, int port)
+ {
+ Connect (new IPEndPoint (address, port));
+ }
+
+ public void Connect (string host, int port)
+ {
+ Connect (Dns.GetHostAddresses (host), port);
+ }
+
+ public void Connect (IPAddress[] addresses, int port)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (addresses == null)
+ throw new ArgumentNullException ("addresses");
+ if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
+ throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
+ if (is_listening)
+ throw new InvalidOperationException ();
+
+ // FIXME: do non-blocking sockets Poll here?
+ int error = 0;
+ foreach (IPAddress address in addresses) {
+ IPEndPoint iep = new IPEndPoint (address, port);
+
+ Connect_internal (safe_handle, iep.Serialize (), out error);
+ if (error == 0) {
+ is_connected = true;
+ is_bound = true;
+ seed_endpoint = iep;
+ return;
+ }
+ if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
+ continue;
+
+ if (!is_blocking) {
+ Poll (-1, SelectMode.SelectWrite);
+ error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+ if (error == 0) {
+ is_connected = true;
+ is_bound = true;
+ seed_endpoint = iep;
+ return;
+ }
+ }
+ }
+
+ if (error != 0)
+ throw new SocketException (error);
+ }
+
+
+ public void Connect (EndPoint remoteEP)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ IPEndPoint ep = remoteEP as IPEndPoint;
+ /* Dgram uses Any to 'disconnect' */
+ if (ep != null && socket_type != SocketType.Dgram) {
+ if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
+ throw new SocketException ((int) SocketError.AddressNotAvailable);
+ }
+
+ if (is_listening)
+ throw new InvalidOperationException ();
+
+ SocketAddress serial = remoteEP.Serialize ();
+
+ int error = 0;
+ Connect_internal (safe_handle, serial, out error);
+
+ if (error == 0 || error == 10035)
+ seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
+
+ if (error != 0) {
+ if (is_closed)
+ error = SOCKET_CLOSED_CODE;
+ throw new SocketException (error);
+ }
+
+ is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
+ is_bound = true;
+ }
+
+ public bool ConnectAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ ThrowIfDisposedAndClosed ();
+
+ if (is_listening)
+ throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
+ if (e.RemoteEndPoint == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ InitSocketAsyncEventArgs (e, ConnectAsyncCallback, e, SocketOperation.Connect);
+
+ try {
+ IPAddress [] addresses;
+ SocketAsyncResult ares;
+
+ if (!GetCheckedIPs (e, out addresses)) {
+ e.socket_async_result.EndPoint = e.RemoteEndPoint;
+ ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
+ } else {
+ DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
+ e.socket_async_result.Addresses = addresses;
+ e.socket_async_result.Port = dep.Port;
+ ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
+ }
+
+ if (ares.IsCompleted && ares.CompletedSynchronously) {
+ ares.CheckIfThrowDelayedException ();
+ return false;
+ }
+ } catch (Exception exc) {
+ e.socket_async_result.Complete (exc, true);
+ return false;
+ }
+
+ return true;
+ }
+
+ static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+
+ try {
+ e.current_socket.EndConnect (ares);
+ } catch (SocketException se) {
+ e.SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
+ } finally {
+ e.Complete ();
+ }
+ });
+
+ public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (address == null)
+ throw new ArgumentNullException ("address");
+ if (address.ToString ().Length == 0)
+ throw new ArgumentException ("The length of the IP address is zero");
+ if (port <= 0 || port > 65535)
+ throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+ if (is_listening)
+ throw new InvalidOperationException ();
+
+ return BeginConnect (new IPEndPoint (address, port), callback, state);
+ }
+
+ public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (host == null)
+ throw new ArgumentNullException ("host");
+ if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
+ throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
+ if (port <= 0 || port > 65535)
+ throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+ if (is_listening)
+ throw new InvalidOperationException ();
+
+ return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
+ }
+
+ public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (end_point == null)
+ throw new ArgumentNullException ("end_point");
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
+ EndPoint = end_point,
+ };
+
+ // Bug #75154: Connect() should not succeed for .Any addresses.
+ if (end_point is IPEndPoint) {
+ IPEndPoint ep = (IPEndPoint) end_point;
+ if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
+ sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
+ return sockares;
+ }
+ }
+
+ int error = 0;
+
+ if (connect_in_progress) {
+ // This could happen when multiple IPs are used
+ // Calling connect() again will reset the connection attempt and cause
+ // an error. Better to just close the socket and move on.
+ connect_in_progress = false;
+ safe_handle.Dispose ();
+ safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
+ if (error != 0)
+ throw new SocketException (error);
+ }
+
+ bool blk = is_blocking;
+ if (blk)
+ Blocking = false;
+ Connect_internal (safe_handle, end_point.Serialize (), out error);
+ if (blk)
+ Blocking = true;
+
+ if (error == 0) {
+ // succeeded synch
+ is_connected = true;
+ is_bound = true;
+ sockares.Complete (true);
+ return sockares;
+ }
+
+ if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
+ // error synch
+ is_connected = false;
+ is_bound = false;
+ sockares.Complete (new SocketException (error), true);
+ return sockares;
+ }
+
+ // continue asynch
+ is_connected = false;
+ is_bound = false;
+ connect_in_progress = true;
+
+ IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
+
+ return sockares;
+ }
+
+ public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (addresses == null)
+ throw new ArgumentNullException ("addresses");
+ if (addresses.Length == 0)
+ throw new ArgumentException ("Empty addresses list");
+ if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
+ throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
+ if (port <= 0 || port > 65535)
+ throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+ if (is_listening)
+ throw new InvalidOperationException ();
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
+ Addresses = addresses,
+ Port = port,
+ };
+
+ is_connected = false;
+
+ return BeginMConnect (sockares);
+ }
+
+ internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
+ {
+ SocketAsyncResult ares = null;
+ Exception exc = null;
+ AsyncCallback callback;
+
+ for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
+ try {
+ sockares.CurrentAddress++;
+
+ ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
+ if (ares.IsCompleted && ares.CompletedSynchronously) {
+ ares.CheckIfThrowDelayedException ();
+
+ callback = ares.AsyncCallback;
+ if (callback != null)
+ ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
+ }
+
+ break;
+ } catch (Exception e) {
+ exc = e;
+ ares = null;
+ }
+ }
+
+ if (ares == null)
+ throw exc;
+
+ return sockares;
+ }
+
+ static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+
+ if (sockares.EndPoint == null) {
+ sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
+ return;
+ }
+
+ SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
+ bool is_mconnect = mconnect != null && mconnect.Addresses != null;
+
+ try {
+ EndPoint ep = sockares.EndPoint;
+ int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+
+ if (error_code == 0) {
+ if (is_mconnect)
+ sockares = mconnect;
+
+ sockares.socket.seed_endpoint = ep;
+ sockares.socket.is_connected = true;
+ sockares.socket.is_bound = true;
+ sockares.socket.connect_in_progress = false;
+ sockares.error = 0;
+ sockares.Complete ();
+ return;
+ }
+
+ if (!is_mconnect) {
+ sockares.socket.connect_in_progress = false;
+ sockares.Complete (new SocketException (error_code));
+ return;
+ }
+
+ if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
+ mconnect.Complete (new SocketException (error_code));
+ return;
+ }
+
+ mconnect.socket.BeginMConnect (mconnect);
+ } catch (Exception e) {
+ sockares.socket.connect_in_progress = false;
+
+ if (is_mconnect)
+ sockares = mconnect;
+
+ sockares.Complete (e);
+ return;
+ }
+ });
+
+ public void EndConnect (IAsyncResult result)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
+
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne();
+
+ sockares.CheckIfThrowDelayedException();
+ }
+
+ static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
+ {
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
+ }
+ }
+
+ /* Connects to the remote address */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
+
+ /* Returns :
+ * - false when it is ok to use RemoteEndPoint
+ * - true when addresses must be used (and addresses could be null/empty) */
+ bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
+ {
+ addresses = null;
+
+ // Connect to the first address that match the host name, like:
+ // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
+ // while skipping entries that do not match the address family
+ DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
+ if (dep != null) {
+ addresses = Dns.GetHostAddresses (dep.Host);
+ return true;
+ } else {
+ e.ConnectByNameError = null;
+ return false;
+ }
+ }
+
+#endregion
+
+#region Disconnect
+
+ /* According to the docs, the MS runtime will throw PlatformNotSupportedException
+ * if the platform is newer than w2k. We should be able to cope... */
+ public void Disconnect (bool reuseSocket)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ int error = 0;
+ Disconnect_internal (safe_handle, reuseSocket, out error);
+
+ if (error != 0) {
+ if (error == 50) {
+ /* ERROR_NOT_SUPPORTED */
+ throw new PlatformNotSupportedException ();
+ } else {
+ throw new SocketException (error);
+ }
+ }
+
+ is_connected = false;
+ if (reuseSocket) {
+ /* Do managed housekeeping here... */
+ }
+ }
+
+ public bool DisconnectAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ ThrowIfDisposedAndClosed ();
+
+ InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
+
+ IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
+
+ return true;
+ }
+
+ static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+
+ try {
+ e.current_socket.EndDisconnect (ares);
+ } catch (SocketException ex) {
+ e.SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
+ } finally {
+ e.Complete ();
+ }
+ });
+
+ public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
+ ReuseSocket = reuseSocket,
+ };
+
+ IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
+
+ return sockares;
+ }
+
+ static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+
+ try {
+ sockares.socket.Disconnect (sockares.ReuseSocket);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
+
+ sockares.Complete ();
+ });
+
+ public void EndDisconnect (IAsyncResult asyncResult)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
+
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne ();
+
+ sockares.CheckIfThrowDelayedException ();
+ }
+
+ static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
+
+#endregion
+
+#region Receive
+
+ public int Receive (byte [] buffer)
+ {
+ return Receive (buffer, SocketFlags.None);
+ }
+
+ public int Receive (byte [] buffer, SocketFlags flags)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
+
+ SocketError error;
+ int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
+
+ if (error != SocketError.Success) {
+ if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
+ throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
+ throw new SocketException ((int) error);
+ }
+
+ return ret;
+ }
+
+ public int Receive (byte [] buffer, int size, SocketFlags flags)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, size);
+
+ SocketError error;
+ int ret = Receive_nochecks (buffer, 0, size, flags, out error);
+
+ if (error != SocketError.Success) {
+ if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
+ throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
+ throw new SocketException ((int) error);
+ }
+
+ return ret;
+ }
+
+ public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ SocketError error;
+ int ret = Receive_nochecks (buffer, offset, size, flags, out error);
+
+ if (error != SocketError.Success) {
+ if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
+ throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
+ throw new SocketException ((int) error);
+ }
+
+ return ret;
+ }
+
+ public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ return Receive_nochecks (buffer, offset, size, flags, out error);
+ }
+
+ public int Receive (IList<ArraySegment<byte>> buffers)
+ {
+ SocketError error;
+ int ret = Receive (buffers, SocketFlags.None, out error);
+
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
+
+ return ret;
+ }
+
+ [CLSCompliant (false)]
+ public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
+ {
+ SocketError error;
+ int ret = Receive (buffers, socketFlags, out error);
+
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
+
+ return(ret);
+ }
+
+ [CLSCompliant (false)]
+ public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (buffers == null || buffers.Count == 0)
+ throw new ArgumentNullException ("buffers");
+
+ int numsegments = buffers.Count;
+ int nativeError;
+ int ret;
+
+ /* Only example I can find of sending a byte array reference directly into an internal
+ * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
+ * so taking a lead from that... */
+ WSABUF[] bufarray = new WSABUF[numsegments];
+ GCHandle[] gch = new GCHandle[numsegments];
+
+ for (int i = 0; i < numsegments; i++) {
+ ArraySegment<byte> segment = buffers[i];
+
+ if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
+ throw new ArgumentOutOfRangeException ("segment");
+
+ gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+ bufarray[i].len = segment.Count;
+ bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+ }
+
+ try {
+ ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
+ } finally {
+ for (int i = 0; i < numsegments; i++) {
+ if (gch[i].IsAllocated)
+ gch[i].Free ();
+ }
+ }
+
+ errorCode = (SocketError) nativeError;
+
+ return ret;
+ }
+
+ public bool ReceiveAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ ThrowIfDisposedAndClosed ();
+
+ // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
+ // thrown when e.Buffer and e.BufferList are null (works fine when one is
+ // set to a valid object)
+ if (e.Buffer == null && e.BufferList == null)
+ throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
+
+ if (e.Buffer == null) {
+ InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
+
+ e.socket_async_result.Buffers = e.BufferList;
+
+ QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
+ } else {
+ InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
+
+ e.socket_async_result.Buffer = e.Buffer;
+ e.socket_async_result.Offset = e.Offset;
+ e.socket_async_result.Size = e.Count;
+
+ QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
+ }
+
+ return true;
+ }
+
+ static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+
+ try {
+ e.BytesTransferred = e.current_socket.EndReceive (ares);
+ } catch (SocketException se){
+ e.SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
+ } finally {
+ e.Complete ();
+ }
+ });
+
+ public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
+ Buffer = buffer,
+ Offset = offset,
+ Size = size,
+ SockFlags = socket_flags,
+ };
+
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
+
+ return sockares;
}
- public IAsyncResult BeginAccept(AsyncCallback callback, object state)
+ public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ /* As far as I can tell from the docs and from experimentation, a pointer to the
+ * SocketError parameter is not supposed to be saved for the async parts. And as we don't
+ * set any socket errors in the setup code, we just have to set it to Success. */
+ error = SocketError.Success;
+ return BeginReceive (buffer, offset, size, flags, callback, state);
+ }
- if (!is_bound || !is_listening)
- throw new InvalidOperationException ();
+ static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ int total = 0;
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
- int count;
- lock (readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
+ try {
+ total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
- }
- public IAsyncResult BeginAccept (int receiveSize,
- AsyncCallback callback,
- object state)
+ sockares.Complete (total);
+ });
+
+ [CLSCompliant (false)]
+ public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (receiveSize < 0)
- throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+ if (buffers == null)
+ throw new ArgumentNullException ("buffers");
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
- req.Buffer = new byte[receiveSize];
- req.Offset = 0;
- req.Size = receiveSize;
- req.SockFlags = SocketFlags.None;
- int count;
- lock (readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
+ Buffers = buffers,
+ SockFlags = socketFlags,
+ };
+
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
+
+ return sockares;
}
- public IAsyncResult BeginAccept (Socket acceptSocket,
- int receiveSize,
- AsyncCallback callback,
- object state)
+ [CLSCompliant (false)]
+ public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ /* I assume the same SocketError semantics as above */
+ errorCode = SocketError.Success;
+ return BeginReceive (buffers, socketFlags, callback, state);
+ }
- if (receiveSize < 0)
- throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+ static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ int total = 0;
- if (acceptSocket != null) {
- if (acceptSocket.is_disposed && acceptSocket.is_closed)
- throw new ObjectDisposedException (acceptSocket.GetType ().ToString ());
+ try {
+ total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
- if (acceptSocket.IsBound)
- throw new InvalidOperationException ();
+ sockares.Complete (total);
+ });
- /* For some reason the MS runtime
- * barfs if the new socket is not TCP,
- * even though it's just about to blow
- * away all those parameters
- */
- if (acceptSocket.ProtocolType != ProtocolType.Tcp)
- throw new SocketException ((int)SocketError.InvalidArgument);
- }
-
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
- req.Buffer = new byte[receiveSize];
- req.Offset = 0;
- req.Size = receiveSize;
- req.SockFlags = SocketFlags.None;
- req.AcceptSocket = acceptSocket;
- int count;
- lock (readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
+ public int EndReceive (IAsyncResult result)
+ {
+ SocketError error;
+ int bytesReceived = EndReceive (result, out error);
+
+ if (error != SocketError.Success) {
+ if (error != SocketError.WouldBlock && error != SocketError.InProgress)
+ is_connected = false;
+ throw new SocketException ((int)error);
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return(req);
+
+ return bytesReceived;
}
- public IAsyncResult BeginConnect (IPAddress address, int port,
- AsyncCallback callback,
- object state)
+ public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (address == null)
- throw new ArgumentNullException ("address");
+ ThrowIfDisposedAndClosed ();
- if (address.ToString ().Length == 0)
- throw new ArgumentException ("The length of the IP address is zero");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
- if (port <= 0 || port > 65535)
- throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne ();
- if (is_listening)
- throw new InvalidOperationException ();
+ // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
+ // kinds of exceptions that should be thrown.
+ if ((errorCode = sockares.ErrorCode) == SocketError.Success)
+ sockares.CheckIfThrowDelayedException();
- IPEndPoint iep = new IPEndPoint (address, port);
- return(BeginConnect (iep, callback, state));
+ return sockares.Total;
}
- public IAsyncResult BeginConnect (string host, int port,
- AsyncCallback callback,
- object state)
+ int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ int nativeError;
+ int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
- if (host == null)
- throw new ArgumentNullException ("host");
+ error = (SocketError) nativeError;
+ if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
+ is_connected = false;
+ is_bound = false;
+ } else {
+ is_connected = true;
+ }
- if (address_family != AddressFamily.InterNetwork &&
- address_family != AddressFamily.InterNetworkV6)
- throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
+ return ret;
+ }
- if (port <= 0 || port > 65535)
- throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+ static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
+ {
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
+ }
+ }
- if (is_listening)
- throw new InvalidOperationException ();
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
- return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
+ static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
+ {
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
+ }
}
- public IAsyncResult BeginDisconnect (bool reuseSocket,
- AsyncCallback callback,
- object state)
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
+
+#endregion
+
+#region ReceiveFrom
+
+ public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
- req.ReuseSocket = reuseSocket;
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return(req);
+ return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
}
- void CheckRange (byte[] buffer, int offset, int size)
+ public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
{
- if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
-
- if (offset > buffer.Length)
- throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
- if (size < 0)
- throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
-
- if (size > buffer.Length - offset)
- throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
+ return ReceiveFrom (buffer, 0, buffer.Length, flags, ref remoteEP);
}
-
- public IAsyncResult BeginReceive(byte[] buffer, int offset,
- int size,
- SocketFlags socket_flags,
- AsyncCallback callback,
- object state) {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, size);
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ return ReceiveFrom (buffer, 0, size, flags, ref remoteEP);
+ }
- CheckRange (buffer, offset, size);
+ public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive);
- req.Buffer = buffer;
- req.Offset = offset;
- req.Size = size;
- req.SockFlags = socket_flags;
- int count;
- lock (readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
- }
-
- public IAsyncResult BeginReceive (byte[] buffer, int offset,
- int size, SocketFlags flags,
- out SocketError error,
- AsyncCallback callback,
- object state)
- {
- /* As far as I can tell from the docs and from
- * experimentation, a pointer to the
- * SocketError parameter is not supposed to be
- * saved for the async parts. And as we don't
- * set any socket errors in the setup code, we
- * just have to set it to Success.
- */
- error = SocketError.Success;
- return (BeginReceive (buffer, offset, size, flags, callback, state));
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ int error;
+ return ReceiveFrom_nochecks_exc (buffer, offset, size, flags, ref remoteEP, true, out error);
}
- [CLSCompliant (false)]
- public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
- SocketFlags socketFlags,
- AsyncCallback callback,
- object state)
+ public bool ReceiveFromAsync (SocketAsyncEventArgs e)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (buffers == null)
- throw new ArgumentNullException ("buffers");
+ // We do not support recv into multiple buffers yet
+ if (e.BufferList != null)
+ throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
+ if (e.RemoteEndPoint == null)
+ throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
- req.Buffers = buffers;
- req.SockFlags = socketFlags;
- int count;
- lock(readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
- }
-
- [CLSCompliant (false)]
- public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
- SocketFlags socketFlags,
- out SocketError errorCode,
- AsyncCallback callback,
- object state)
- {
- /* I assume the same SocketError semantics as
- * above
- */
- errorCode = SocketError.Success;
- return (BeginReceive (buffers, socketFlags, callback, state));
+ InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
+
+ e.socket_async_result.Buffer = e.Buffer;
+ e.socket_async_result.Offset = e.Offset;
+ e.socket_async_result.Size = e.Count;
+ e.socket_async_result.EndPoint = e.RemoteEndPoint;
+ e.socket_async_result.SockFlags = e.SocketFlags;
+
+ QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
+
+ return true;
}
- public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
- int size,
- SocketFlags socket_flags,
- ref EndPoint remote_end,
- AsyncCallback callback,
- object state) {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+
+ try {
+ e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
+ } catch (SocketException ex) {
+ e.SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
+ } finally {
+ e.Complete ();
+ }
+ });
+
+ public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
if (remote_end == null)
throw new ArgumentNullException ("remote_end");
- CheckRange (buffer, offset, size);
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
+ Buffer = buffer,
+ Offset = offset,
+ Size = size,
+ SockFlags = socket_flags,
+ EndPoint = remote_end,
+ };
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom);
- req.Buffer = buffer;
- req.Offset = offset;
- req.Size = size;
- req.SockFlags = socket_flags;
- req.EndPoint = remote_end;
- int count;
- lock (readQ) {
- readQ.Enqueue (req.Worker);
- count = readQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
+ QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
+
+ return sockares;
}
- [MonoTODO]
- public IAsyncResult BeginReceiveMessageFrom (
- byte[] buffer, int offset, int size,
- SocketFlags socketFlags, ref EndPoint remoteEP,
- AsyncCallback callback, object state)
+ static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ int total = 0;
+
+ try {
+ int error;
+ total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
+
+ sockares.Complete (total);
+ });
+
+ public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ if (end_point == null)
+ throw new ArgumentNullException ("remote_end");
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
- CheckRange (buffer, offset, size);
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne();
- throw new NotImplementedException ();
+ sockares.CheckIfThrowDelayedException();
+
+ end_point = sockares.EndPoint;
+
+ return sockares.Total;
}
- public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
- AsyncCallback callback, object state)
+ internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ SocketAddress sockaddr = remote_end.Serialize();
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
+
+ SocketError err = (SocketError) error;
+ if (err != 0) {
+ if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
+ is_connected = false;
+ } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
+ if (throwOnError)
+ throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
+ error = (int) SocketError.TimedOut;
+ return 0;
+ }
- CheckRange (buffer, offset, size);
+ if (throwOnError)
+ throw new SocketException (error);
- if (!is_connected)
- throw new SocketException ((int)SocketError.NotConnected);
+ return 0;
+ }
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Send);
- req.Buffer = buffer;
- req.Offset = offset;
- req.Size = size;
- req.SockFlags = socket_flags;
- int count;
- lock (writeQ) {
- writeQ.Enqueue (req.Worker);
- count = writeQ.Count;
+ is_connected = true;
+ is_bound = true;
+
+ /* If sockaddr is null then we're a connection oriented protocol and should ignore the
+ * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
+ if (sockaddr != null) {
+ /* Stupidly, EndPoint.Create() is an instance method */
+ remote_end = remote_end.Create (sockaddr);
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
+
+ seed_endpoint = remote_end;
+
+ return cnt;
}
- public IAsyncResult BeginSend (byte[] buffer, int offset,
- int size,
- SocketFlags socketFlags,
- out SocketError errorCode,
- AsyncCallback callback,
- object state)
+ static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
{
- if (!is_connected) {
- errorCode = SocketError.NotConnected;
- throw new SocketException ((int)errorCode);
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
}
-
- errorCode = SocketError.Success;
-
- return (BeginSend (buffer, offset, size, socketFlags, callback,
- state));
}
- public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
- SocketFlags socketFlags,
- AsyncCallback callback,
- object state)
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
+
+#endregion
+
+#region ReceiveMessageFrom
+
+ [MonoTODO ("Not implemented")]
+ public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ // FIXME: figure out how we get hold of the IPPacketInformation
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented")]
+ public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
- if (buffers == null)
- throw new ArgumentNullException ("buffers");
+ ThrowIfDisposedAndClosed ();
- if (!is_connected)
- throw new SocketException ((int)SocketError.NotConnected);
+ throw new NotImplementedException ();
+ }
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
- req.Buffers = buffers;
- req.SockFlags = socketFlags;
- int count;
- lock (writeQ) {
- writeQ.Enqueue (req.Worker);
- count = writeQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
+ [MonoTODO]
+ public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ throw new NotImplementedException ();
}
- [CLSCompliant (false)]
- public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
- SocketFlags socketFlags,
- out SocketError errorCode,
- AsyncCallback callback,
- object state)
+ [MonoTODO]
+ public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
{
- if (!is_connected) {
- errorCode = SocketError.NotConnected;
- throw new SocketException ((int)errorCode);
- }
-
- errorCode = SocketError.Success;
- return (BeginSend (buffers, socketFlags, callback, state));
- }
+ ThrowIfDisposedAndClosed ();
- delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
+ if (endPoint == null)
+ throw new ArgumentNullException ("endPoint");
- sealed class SendFileAsyncResult : IAsyncResult {
- IAsyncResult ares;
- SendFileHandler d;
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
- public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
- {
- this.d = d;
- this.ares = ares;
- }
+ throw new NotImplementedException ();
+ }
- public object AsyncState {
- get { return ares.AsyncState; }
- }
+#endregion
- public WaitHandle AsyncWaitHandle {
- get { return ares.AsyncWaitHandle; }
- }
+#region Send
- public bool CompletedSynchronously {
- get { return ares.CompletedSynchronously; }
- }
+ public int Send (byte [] buffer)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
- public bool IsCompleted {
- get { return ares.IsCompleted; }
- }
+ SocketError error;
+ int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
- public SendFileHandler Delegate {
- get { return d; }
- }
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
- public IAsyncResult Original {
- get { return ares; }
- }
+ return ret;
}
- public IAsyncResult BeginSendFile (string fileName,
- AsyncCallback callback,
- object state)
+ public int Send (byte [] buffer, SocketFlags flags)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
- if (!is_connected)
- throw new NotSupportedException ();
+ SocketError error;
+ int ret = Send_nochecks (buffer, 0, buffer.Length, flags, out error);
- if (!File.Exists (fileName))
- throw new FileNotFoundException ();
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
- return BeginSendFile (fileName, null, null, 0, callback, state);
+ return ret;
}
- public IAsyncResult BeginSendFile (string fileName,
- byte[] preBuffer,
- byte[] postBuffer,
- TransmitFileOptions flags,
- AsyncCallback callback,
- object state)
+ public int Send (byte [] buffer, int size, SocketFlags flags)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, 0, size);
- if (!is_connected)
- throw new NotSupportedException ();
+ SocketError error;
+ int ret = Send_nochecks (buffer, 0, size, flags, out error);
- if (!File.Exists (fileName))
- throw new FileNotFoundException ();
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
- SendFileHandler d = new SendFileHandler (SendFile);
- return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => {
- SendFileAsyncResult sfar = new SendFileAsyncResult (d, ar);
- callback (sfar);
- }, state));
+ return ret;
}
- public IAsyncResult BeginSendTo(byte[] buffer, int offset,
- int size,
- SocketFlags socket_flags,
- EndPoint remote_end,
- AsyncCallback callback,
- object state) {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ public int Send (byte [] buffer, int offset, int size, SocketFlags flags)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ SocketError error;
+ int ret = Send_nochecks (buffer, offset, size, flags, out error);
- CheckRange (buffer, offset, size);
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
- SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo);
- req.Buffer = buffer;
- req.Offset = offset;
- req.Size = size;
- req.SockFlags = socket_flags;
- req.EndPoint = remote_end;
- int count;
- lock (writeQ) {
- writeQ.Enqueue (req.Worker);
- count = writeQ.Count;
- }
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
- return req;
+ return ret;
}
- // Creates a new system socket, returning the handle
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Bind_internal(IntPtr sock,
- SocketAddress sa,
- out int error);
-
- private static void Bind_internal (SafeSocketHandle safeHandle,
- SocketAddress sa,
- out int error)
+ public int Send (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
{
- bool release = false;
- try {
- safeHandle.DangerousAddRef (ref release);
- Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
- } finally {
- if (release)
- safeHandle.DangerousRelease ();
- }
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
+
+ return Send_nochecks (buffer, offset, size, flags, out error);
}
- public void Bind(EndPoint local_end) {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ public
+ int Send (IList<ArraySegment<byte>> buffers)
+ {
+ SocketError error;
+ int ret = Send (buffers, SocketFlags.None, out error);
- if (local_end == null)
- throw new ArgumentNullException("local_end");
-
- int error;
-
- Bind_internal (safe_handle, local_end.Serialize(), out error);
- if (error != 0)
- throw new SocketException (error);
- if (error == 0)
- is_bound = true;
-
- seed_endpoint = local_end;
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
+
+ return ret;
}
- public void Connect (IPAddress address, int port)
+ public
+ int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
{
- Connect (new IPEndPoint (address, port));
+ SocketError error;
+ int ret = Send (buffers, socketFlags, out error);
+
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
+
+ return ret;
}
-
- public void Connect (IPAddress[] addresses, int port)
+
+ [CLSCompliant (false)]
+ public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (addresses == null)
- throw new ArgumentNullException ("addresses");
+ if (buffers == null)
+ throw new ArgumentNullException ("buffers");
+ if (buffers.Count == 0)
+ throw new ArgumentException ("Buffer is empty", "buffers");
- if (this.AddressFamily != AddressFamily.InterNetwork &&
- this.AddressFamily != AddressFamily.InterNetworkV6)
- throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
+ int numsegments = buffers.Count;
+ int nativeError;
+ int ret;
- if (is_listening)
- throw new InvalidOperationException ();
+ WSABUF[] bufarray = new WSABUF[numsegments];
+ GCHandle[] gch = new GCHandle[numsegments];
- /* FIXME: do non-blocking sockets Poll here? */
- int error = 0;
- foreach (IPAddress address in addresses) {
- IPEndPoint iep = new IPEndPoint (address, port);
- SocketAddress serial = iep.Serialize ();
-
- Connect_internal (safe_handle, serial, out error);
- if (error == 0) {
- is_connected = true;
- is_bound = true;
- seed_endpoint = iep;
- return;
- } else if (error != (int)SocketError.InProgress &&
- error != (int)SocketError.WouldBlock) {
- continue;
- }
-
- if (!is_blocking) {
- Poll (-1, SelectMode.SelectWrite);
- error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
- if (error == 0) {
- is_connected = true;
- is_bound = true;
- seed_endpoint = iep;
- return;
+ for(int i = 0; i < numsegments; i++) {
+ ArraySegment<byte> segment = buffers[i];
+
+ if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
+ throw new ArgumentOutOfRangeException ("segment");
+
+ gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+ bufarray[i].len = segment.Count;
+ bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+ }
+
+ try {
+ ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
+ } finally {
+ for(int i = 0; i < numsegments; i++) {
+ if (gch[i].IsAllocated) {
+ gch[i].Free ();
}
}
}
- if (error != 0)
- throw new SocketException (error);
+
+ errorCode = (SocketError)nativeError;
+
+ return ret;
}
- public void Connect (string host, int port)
+ int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
{
- IPAddress [] addresses = Dns.GetHostAddresses (host);
- Connect (addresses, port);
+ if (size == 0) {
+ error = SocketError.Success;
+ return 0;
+ }
+
+ int nativeError;
+ int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
+
+ error = (SocketError)nativeError;
+
+ if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
+ is_connected = false;
+ is_bound = false;
+ } else {
+ is_connected = true;
+ }
+
+ return ret;
}
- public bool DisconnectAsync (SocketAsyncEventArgs e)
+ public bool SendAsync (SocketAsyncEventArgs e)
{
// NO check is made whether e != null in MS.NET (NRE is thrown in such case)
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
- e.curSocket = this;
- e.Worker.Init (this, e, SocketOperation.Disconnect);
- socket_pool_queue (SocketAsyncWorker.Dispatcher, e.Worker.result);
+ ThrowIfDisposedAndClosed ();
+
+ if (e.Buffer == null && e.BufferList == null)
+ throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
+
+ if (e.Buffer == null) {
+ InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
+
+ e.socket_async_result.Buffers = e.BufferList;
+
+ QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
+ } else {
+ InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
+
+ e.socket_async_result.Buffer = e.Buffer;
+ e.socket_async_result.Offset = e.Offset;
+ e.socket_async_result.Size = e.Count;
+
+ QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
+ }
+
return true;
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static void Disconnect_internal(IntPtr sock, bool reuse, out int error);
+ static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
- private static void Disconnect_internal(SafeSocketHandle safeHandle, bool reuse, out int error)
- {
- bool release = false;
try {
- safeHandle.DangerousAddRef (ref release);
- Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
+ e.BytesTransferred = e.current_socket.EndSend (ares);
+ } catch (SocketException se){
+ e.SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
} finally {
- if (release)
- safeHandle.DangerousRelease ();
+ e.Complete ();
}
- }
+ });
- /* According to the docs, the MS runtime will throw
- * PlatformNotSupportedException if the platform is
- * newer than w2k. We should be able to cope...
- */
- public void Disconnect (bool reuseSocket)
+ public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- int error = 0;
-
- Disconnect_internal (safe_handle, reuseSocket, out error);
-
- if (error != 0) {
- if (error == 50) {
- /* ERROR_NOT_SUPPORTED */
- throw new PlatformNotSupportedException ();
- } else {
- throw new SocketException (error);
- }
+ if (!is_connected) {
+ errorCode = SocketError.NotConnected;
+ throw new SocketException ((int) errorCode);
}
- is_connected = false;
-
- if (reuseSocket) {
- /* Do managed housekeeping here... */
- }
+ errorCode = SocketError.Success;
+ return BeginSend (buffer, offset, size, socketFlags, callback, state);
}
-#if !MOBILE
- [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
- public SocketInformation DuplicateAndClose (int targetProcessId)
+ public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
{
- var si = new SocketInformation ();
- si.Options =
- (is_listening ? SocketInformationOptions.Listening : 0) |
- (is_connected ? SocketInformationOptions.Connected : 0) |
- (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
- (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
- si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
- safe_handle = null;
+ if (!is_connected)
+ throw new SocketException ((int)SocketError.NotConnected);
- return si;
- }
-#endif
-
- public Socket EndAccept (IAsyncResult result)
- {
- int bytes;
- byte[] buffer;
-
- return(EndAccept (out buffer, out bytes, result));
- }
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
+ Buffer = buffer,
+ Offset = offset,
+ Size = size,
+ SockFlags = socket_flags,
+ };
- public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
- {
- int bytes;
- return(EndAccept (out buffer, out bytes, asyncResult));
+ QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
+
+ return sockares;
}
- public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
+ static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (asyncResult == null)
- throw new ArgumentNullException ("asyncResult");
-
- SocketAsyncResult req = asyncResult as SocketAsyncResult;
- if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+ int total = 0;
- if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
- throw InvalidAsyncOp ("EndAccept");
- if (!asyncResult.IsCompleted)
- asyncResult.AsyncWaitHandle.WaitOne ();
-
- req.CheckIfThrowDelayedException ();
-
- buffer = req.Buffer;
- bytesTransferred = req.Total;
-
- return(req.Socket);
- }
+ try {
+ total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
- public void EndConnect (IAsyncResult result)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ if (sockares.error == 0) {
+ sent_so_far += total;
+ sockares.Offset += total;
+ sockares.Size -= total;
- if (result == null)
- throw new ArgumentNullException ("result");
+ if (sockares.socket.is_disposed) {
+ sockares.Complete (total);
+ return;
+ }
- SocketAsyncResult req = result as SocketAsyncResult;
- if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "result");
+ if (sockares.Size > 0) {
+ IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
+ return; // Have to finish writing everything. See bug #74475.
+ }
- if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
- throw InvalidAsyncOp ("EndConnect");
- if (!result.IsCompleted)
- result.AsyncWaitHandle.WaitOne();
+ sockares.Total = sent_so_far;
+ }
- req.CheckIfThrowDelayedException();
+ sockares.Complete (total);
}
- public void EndDisconnect (IAsyncResult asyncResult)
+ public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (asyncResult == null)
- throw new ArgumentNullException ("asyncResult");
+ if (buffers == null)
+ throw new ArgumentNullException ("buffers");
+ if (!is_connected)
+ throw new SocketException ((int)SocketError.NotConnected);
- SocketAsyncResult req = asyncResult as SocketAsyncResult;
- if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
+ Buffers = buffers,
+ SockFlags = socketFlags,
+ };
- if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
- throw InvalidAsyncOp ("EndDisconnect");
- if (!asyncResult.IsCompleted)
- asyncResult.AsyncWaitHandle.WaitOne ();
+ QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
- req.CheckIfThrowDelayedException ();
+ return sockares;
}
- [MonoTODO]
- public int EndReceiveMessageFrom (IAsyncResult asyncResult,
- ref SocketFlags socketFlags,
- ref EndPoint endPoint,
- out IPPacketInformation ipPacketInformation)
+ [CLSCompliant (false)]
+ public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ if (!is_connected) {
+ errorCode = SocketError.NotConnected;
+ throw new SocketException ((int)errorCode);
+ }
- if (asyncResult == null)
- throw new ArgumentNullException ("asyncResult");
+ errorCode = SocketError.Success;
+ return BeginSend (buffers, socketFlags, callback, state);
+ }
- if (endPoint == null)
- throw new ArgumentNullException ("endPoint");
+ static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
+ SocketAsyncResult sockares = (SocketAsyncResult) ares;
+ int total = 0;
- SocketAsyncResult req = asyncResult as SocketAsyncResult;
- if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+ try {
+ total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
+ }
- if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
- throw InvalidAsyncOp ("EndReceiveMessageFrom");
- throw new NotImplementedException ();
- }
+ sockares.Complete (total);
+ });
- public void EndSendFile (IAsyncResult asyncResult)
+ public int EndSend (IAsyncResult result)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (asyncResult == null)
- throw new ArgumentNullException ("asyncResult");
+ SocketError error;
+ int bytesSent = EndSend (result, out error);
- SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
- if (ares == null)
- throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+ if (error != SocketError.Success) {
+ if (error != SocketError.WouldBlock && error != SocketError.InProgress)
+ is_connected = false;
+ throw new SocketException ((int)error);
+ }
- ares.Delegate.EndInvoke (ares.Original);
+ return bytesSent;
}
- public int EndSendTo (IAsyncResult result)
+ public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (result == null)
- throw new ArgumentNullException ("result");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
- SocketAsyncResult req = result as SocketAsyncResult;
- if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "result");
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne ();
- if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
- throw InvalidAsyncOp ("EndSendTo");
- if (!result.IsCompleted)
- result.AsyncWaitHandle.WaitOne();
+ /* If no socket error occurred, call CheckIfThrowDelayedException in
+ * case there are other kinds of exceptions that should be thrown.*/
+ if ((errorCode = sockares.ErrorCode) == SocketError.Success)
+ sockares.CheckIfThrowDelayedException ();
- req.CheckIfThrowDelayedException();
- return req.Total;
+ return sockares.Total;
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void GetSocketOption_arr_internal(IntPtr socket,
- SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
- out int error);
-
- private static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle,
- SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
- out int error)
+ static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
{
bool release = false;
try {
safeHandle.DangerousAddRef (ref release);
- GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
+ return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
} finally {
if (release)
safeHandle.DangerousRelease ();
}
}
- public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
+
+ static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
+ }
+ }
- if (optionValue == null)
- throw new SocketException ((int) SocketError.Fault,
- "Error trying to dereference an invalid pointer");
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
- int error;
+#endregion
- GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue,
- out error);
- if (error != 0)
- throw new SocketException (error);
- }
+#region SendTo
- public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
+ public int SendTo (byte [] buffer, EndPoint remote_end)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
- byte[] byte_val=new byte[length];
- int error;
+ return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
+ }
- GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val,
- out error);
- if (error != 0)
- throw new SocketException (error);
+ public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
+ {
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
- return(byte_val);
+ return SendTo (buffer, 0, buffer.Length, flags, remote_end);
}
- // See Socket.IOControl, WSAIoctl documentation in MSDN. The
- // common options between UNIX and Winsock are FIONREAD,
- // FIONBIO and SIOCATMARK. Anything else will depend on the
- // system except SIO_KEEPALIVE_VALS which is properly handled
- // on both windows and linux.
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input,
- byte [] output, out int error);
-
- private static int WSAIoctl (SafeSocketHandle safeHandle, int ioctl_code, byte [] input,
- byte [] output, out int error)
+ public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
{
- bool release = false;
- try {
- safeHandle.DangerousAddRef (ref release);
- return WSAIoctl (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
- } finally {
- if (release)
- safeHandle.DangerousRelease ();
- }
+ return SendTo (buffer, 0, size, flags, remote_end);
}
- public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
+ public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
{
- if (is_disposed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- int error;
- int result = WSAIoctl (safe_handle, ioctl_code, in_value, out_value,
- out error);
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
- if (error != 0)
- throw new SocketException (error);
-
- if (result == -1)
- throw new InvalidOperationException ("Must use Blocking property instead.");
+ if (remote_end == null)
+ throw new ArgumentNullException("remote_end");
- return result;
+ return SendTo_nochecks (buffer, offset, size, flags, remote_end);
}
- public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
+ public bool SendToAsync (SocketAsyncEventArgs e)
{
- return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ ThrowIfDisposedAndClosed ();
+
+ if (e.BufferList != null)
+ throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
+ if (e.RemoteEndPoint == null)
+ throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+
+ InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
+
+ e.socket_async_result.Buffer = e.Buffer;
+ e.socket_async_result.Offset = e.Offset;
+ e.socket_async_result.Size = e.Count;
+ e.socket_async_result.SockFlags = e.SocketFlags;
+ e.socket_async_result.EndPoint = e.RemoteEndPoint;
+
+ QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
+
+ return true;
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Listen_internal(IntPtr sock, int backlog, out int error);
+ static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
+ SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+ if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
- private static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
- {
- bool release = false;
try {
- safeHandle.DangerousAddRef (ref release);
- Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
+ e.BytesTransferred = e.current_socket.EndSendTo (ares);
+ } catch (SocketException ex) {
+ e.SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ e.SocketError = SocketError.OperationAborted;
} finally {
- if (release)
- safeHandle.DangerousRelease ();
+ e.Complete ();
}
- }
+ });
- public void Listen (int backlog)
+ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (!is_bound)
- throw new SocketException ((int)SocketError.InvalidArgument);
+ ThrowIfDisposedAndClosed ();
+ ThrowIfBufferNull (buffer);
+ ThrowIfBufferOutOfRange (buffer, offset, size);
- int error;
- Listen_internal(safe_handle, backlog, out error);
+ SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
+ Buffer = buffer,
+ Offset = offset,
+ Size = size,
+ SockFlags = socket_flags,
+ EndPoint = remote_end,
+ };
- if (error != 0)
- throw new SocketException (error);
+ QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
- is_listening = true;
+ return sockares;
}
- public bool Poll (int time_us, SelectMode mode)
+ static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (mode != SelectMode.SelectRead &&
- mode != SelectMode.SelectWrite &&
- mode != SelectMode.SelectError)
- throw new NotSupportedException ("'mode' parameter is not valid.");
+ int total = 0;
+ try {
+ total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
- int error;
- bool result = Poll_internal (safe_handle, mode, time_us, out error);
- if (error != 0)
- throw new SocketException (error);
+ if (sockares.error == 0) {
+ sent_so_far += total;
+ sockares.Offset += total;
+ sockares.Size -= total;
+ }
- if (mode == SelectMode.SelectWrite && result && !is_connected) {
- /* Update the is_connected state; for
- * non-blocking Connect()s this is
- * when we can find out that the
- * connect succeeded.
- */
- if ((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0) {
- is_connected = true;
+ if (sockares.Size > 0) {
+ IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
+ return; // Have to finish writing everything. See bug #74475.
}
+
+ sockares.Total = sent_so_far;
+ } catch (Exception e) {
+ sockares.Complete (e);
+ return;
}
-
- return result;
- }
- public int Receive (byte [] buffer)
- {
- return Receive (buffer, SocketFlags.None);
+ sockares.Complete ();
}
- public int Receive (byte [] buffer, SocketFlags flags)
+ public int EndSendTo (IAsyncResult result)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
- SocketError error;
+ if (!sockares.IsCompleted)
+ sockares.AsyncWaitHandle.WaitOne();
- int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
-
- if (error != SocketError.Success) {
- if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
- throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
- throw new SocketException ((int) error);
- }
+ sockares.CheckIfThrowDelayedException();
- return ret;
+ return sockares.Total;
}
- public int Receive (byte [] buffer, int size, SocketFlags flags)
+ int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
-
- CheckRange (buffer, 0, size);
-
- SocketError error;
+ int error;
+ int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
- int ret = Receive_nochecks (buffer, 0, size, flags, out error);
-
- if (error != SocketError.Success) {
- if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
- throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
- throw new SocketException ((int) error);
+ SocketError err = (SocketError) error;
+ if (err != 0) {
+ if (err != SocketError.WouldBlock && err != SocketError.InProgress)
+ is_connected = false;
+ throw new SocketException (error);
}
+ is_connected = true;
+ is_bound = true;
+ seed_endpoint = remote_end;
+
return ret;
}
- public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
+ static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
-
- CheckRange (buffer, offset, size);
-
- SocketError error;
-
- int ret = Receive_nochecks (buffer, offset, size, flags, out error);
-
- if (error != SocketError.Success) {
- if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
- throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
- throw new SocketException ((int) error);
+ try {
+ safeHandle.RegisterForBlockingSyscall ();
+ return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
+ } finally {
+ safeHandle.UnRegisterForBlockingSyscall ();
}
-
- return ret;
}
- public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+#endregion
- CheckRange (buffer, offset, size);
-
- return Receive_nochecks (buffer, offset, size, flags, out error);
- }
+#region SendFile
- public bool ReceiveFromAsync (SocketAsyncEventArgs e)
+ public void SendFile (string fileName)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- // We do not support recv into multiple buffers yet
- if (e.BufferList != null)
- throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
- if (e.RemoteEndPoint == null)
- throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+ if (!is_connected)
+ throw new NotSupportedException ();
+ if (!is_blocking)
+ throw new InvalidOperationException ();
+
+ SendFile (fileName, null, null, 0);
+ }
- e.curSocket = this;
- e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
- SocketAsyncResult res = e.Worker.result;
- res.Buffer = e.Buffer;
- res.Offset = e.Offset;
- res.Size = e.Count;
- res.EndPoint = e.RemoteEndPoint;
- res.SockFlags = e.SocketFlags;
- int count;
- lock (readQ) {
- readQ.Enqueue (e.Worker);
- count = readQ.Count;
+ public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
+ {
+ ThrowIfDisposedAndClosed ();
+
+ if (!is_connected)
+ throw new NotSupportedException ();
+ if (!is_blocking)
+ throw new InvalidOperationException ();
+
+ if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
+ SocketException exc = new SocketException ();
+ if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
+ throw new FileNotFoundException ();
+ throw exc;
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, res);
- return true;
}
- public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
+ public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ ThrowIfDisposedAndClosed ();
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+ if (!is_connected)
+ throw new NotSupportedException ();
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
- return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
+ return BeginSendFile (fileName, null, null, 0, callback, state);
}
- public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
+ public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ if (!is_connected)
+ throw new NotSupportedException ();
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+ SendFileHandler handler = new SendFileHandler (SendFile);
- return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
+ return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
}
- public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags,
- ref EndPoint remoteEP)
+ public void EndSendFile (IAsyncResult asyncResult)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ ThrowIfDisposedAndClosed ();
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
- if (size < 0 || size > buffer.Length)
- throw new ArgumentOutOfRangeException ("size");
+ SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
+ if (ares == null)
+ throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
- return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
+ ares.Delegate.EndInvoke (ares.Original);
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int RecvFrom_internal(IntPtr sock,
- byte[] buffer,
- int offset,
- int count,
- SocketFlags flags,
- ref SocketAddress sockaddr,
- out int error);
-
- private static int RecvFrom_internal (SafeSocketHandle safeHandle,
- byte[] buffer,
- int offset,
- int count,
- SocketFlags flags,
- ref SocketAddress sockaddr,
- out int error)
+ static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return RecvFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
+ return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
- public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags,
- ref EndPoint remoteEP)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+ sealed class SendFileAsyncResult : IAsyncResult {
+ IAsyncResult ares;
+ SendFileHandler d;
- CheckRange (buffer, offset, size);
+ public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
+ {
+ this.d = d;
+ this.ares = ares;
+ }
- return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
- }
+ public object AsyncState {
+ get { return ares.AsyncState; }
+ }
- internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
- ref EndPoint remote_end)
- {
- int error;
- return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
- }
+ public WaitHandle AsyncWaitHandle {
+ get { return ares.AsyncWaitHandle; }
+ }
- internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags,
- ref EndPoint remote_end, bool throwOnError, out int error)
- {
- SocketAddress sockaddr = remote_end.Serialize();
- int cnt = RecvFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
- SocketError err = (SocketError) error;
- if (err != 0) {
- if (err != SocketError.WouldBlock && err != SocketError.InProgress)
- is_connected = false;
- else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
- if (throwOnError)
- throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
- error = (int) SocketError.TimedOut;
- return 0;
- }
+ public bool CompletedSynchronously {
+ get { return ares.CompletedSynchronously; }
+ }
- if (throwOnError)
- throw new SocketException (error);
- return 0;
+ public bool IsCompleted {
+ get { return ares.IsCompleted; }
}
- is_connected = true;
- is_bound = true;
+ public SendFileHandler Delegate {
+ get { return d; }
+ }
- // If sockaddr is null then we're a connection
- // oriented protocol and should ignore the
- // remote_end parameter (see MSDN
- // documentation for Socket.ReceiveFrom(...) )
-
- if ( sockaddr != null ) {
- // Stupidly, EndPoint.Create() is an
- // instance method
- remote_end = remote_end.Create (sockaddr);
+ public IAsyncResult Original {
+ get { return ares; }
}
-
- seed_endpoint = remote_end;
-
- return cnt;
}
+#endregion
+
+#region SendPackets
+
[MonoTODO ("Not implemented")]
- public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
+ public bool SendPacketsAsync (SocketAsyncEventArgs e)
{
// NO check is made whether e != null in MS.NET (NRE is thrown in such case)
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
+
+ ThrowIfDisposedAndClosed ();
+
throw new NotImplementedException ();
}
-
- [MonoTODO ("Not implemented")]
- public int ReceiveMessageFrom (byte[] buffer, int offset,
- int size,
- ref SocketFlags socketFlags,
- ref EndPoint remoteEP,
- out IPPacketInformation ipPacketInformation)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+#endregion
- if (remoteEP == null)
- throw new ArgumentNullException ("remoteEP");
+#region DuplicateAndClose
- CheckRange (buffer, offset, size);
+#if !MOBILE
+ [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
+ public SocketInformation DuplicateAndClose (int targetProcessId)
+ {
+ var si = new SocketInformation ();
+ si.Options =
+ (is_listening ? SocketInformationOptions.Listening : 0) |
+ (is_connected ? SocketInformationOptions.Connected : 0) |
+ (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
+ (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
- /* FIXME: figure out how we get hold of the
- * IPPacketInformation
- */
- throw new NotImplementedException ();
+ si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
+ safe_handle = null;
+
+ return si;
}
+#endif
- [MonoTODO ("Not implemented")]
- public bool SendPacketsAsync (SocketAsyncEventArgs e)
+#endregion
+
+#region GetSocketOption
+
+ public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
{
- // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
-
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- throw new NotImplementedException ();
+ ThrowIfDisposedAndClosed ();
+
+ if (optionValue == null)
+ throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
+
+ int error;
+ GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
}
- public int Send (byte [] buf)
+ public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
+
+ int error;
+ byte[] byte_val = new byte [length];
+ GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (error != 0)
+ throw new SocketException (error);
- SocketError error;
+ return byte_val;
+ }
- int ret = Send_nochecks (buf, 0, buf.Length, SocketFlags.None, out error);
+ public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
+ {
+ ThrowIfDisposedAndClosed ();
- if (error != SocketError.Success)
- throw new SocketException ((int) error);
+ int error;
+ object obj_val;
+ GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
- return ret;
+ if (error != 0)
+ throw new SocketException (error);
+
+ if (optionName == SocketOptionName.Linger)
+ return (LingerOption) obj_val;
+ else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
+ return (MulticastOption) obj_val;
+ else if (obj_val is int)
+ return (int) obj_val;
+ else
+ return obj_val;
}
- public int Send (byte [] buf, SocketFlags flags)
+ static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
- SocketError error;
+ static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
+ }
+ }
- int ret = Send_nochecks (buf, 0, buf.Length, flags, out error);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
- if (error != SocketError.Success)
- throw new SocketException ((int) error);
+#endregion
- return ret;
- }
+#region SetSocketOption
- public int Send (byte [] buf, int size, SocketFlags flags)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ ThrowIfDisposedAndClosed ();
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ // I'd throw an ArgumentNullException, but this is what MS does.
+ if (optionValue == null)
+ throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
- CheckRange (buf, 0, size);
+ int error;
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
- SocketError error;
+ if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
+ throw new SocketException (error);
+ }
+ }
- int ret = Send_nochecks (buf, 0, size, flags, out error);
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
+ {
+ ThrowIfDisposedAndClosed ();
- if (error != SocketError.Success)
- throw new SocketException ((int) error);
+ // NOTE: if a null is passed, the byte[] overload is used instead...
+ if (optionValue == null)
+ throw new ArgumentNullException("optionValue");
- return ret;
+ int error;
+
+ if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
+ LingerOption linger = optionValue as LingerOption;
+ if (linger == null)
+ throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
+ } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
+ MulticastOption multicast = optionValue as MulticastOption;
+ if (multicast == null)
+ throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
+ } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
+ IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
+ if (multicast == null)
+ throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
+ } else {
+ throw new ArgumentException ("Invalid value specified.", "optionValue");
+ }
+
+ if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
+ throw new SocketException (error);
+ }
}
- public int Send (byte [] buf, int offset, int size, SocketFlags flags)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buf == null)
- throw new ArgumentNullException ("buffer");
-
- CheckRange (buf, offset, size);
-
- SocketError error;
+ ThrowIfDisposedAndClosed ();
- int ret = Send_nochecks (buf, offset, size, flags, out error);
-
- if (error != SocketError.Success)
- throw new SocketException ((int) error);
+ int error;
+ int int_val = optionValue ? 1 : 0;
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
- return ret;
+ if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
+ throw new SocketException (error);
+ }
}
- public int Send (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (buf == null)
- throw new ArgumentNullException ("buffer");
+ ThrowIfDisposedAndClosed ();
- CheckRange (buf, offset, size);
+ int error;
+ SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
- return Send_nochecks (buf, offset, size, flags, out error);
+ if (error != 0) {
+ throw new SocketException (error);
+ }
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static bool SendFile (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
-
- private static bool SendFile (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
+ static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
{
+ bool release = false;
try {
- safeHandle.RegisterForBlockingSyscall ();
- return SendFile (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
+ safeHandle.DangerousAddRef (ref release);
+ SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
} finally {
- safeHandle.UnRegisterForBlockingSyscall ();
+ if (release)
+ safeHandle.DangerousRelease ();
}
}
- public void SendFile (string fileName)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- if (!is_connected)
- throw new NotSupportedException ();
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
- if (!is_blocking)
- throw new InvalidOperationException ();
+#endregion
- SendFile (fileName, null, null, 0);
- }
+#region IOControl
- public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
+ public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
{
- if (is_disposed && is_closed)
+ if (is_disposed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (!is_connected)
- throw new NotSupportedException ();
+ int error;
+ int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
- if (!is_blocking)
- throw new InvalidOperationException ();
+ if (error != 0)
+ throw new SocketException (error);
+ if (result == -1)
+ throw new InvalidOperationException ("Must use Blocking property instead.");
- if (!SendFile (safe_handle, fileName, preBuffer, postBuffer, flags)) {
- SocketException exc = new SocketException ();
- if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
- throw new FileNotFoundException ();
- throw exc;
- }
+ return result;
}
- public bool SendToAsync (SocketAsyncEventArgs e)
+ public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
{
- // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
-
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
- if (e.BufferList != null)
- throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
- if (e.RemoteEndPoint == null)
- throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+ return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
+ }
- e.curSocket = this;
- e.Worker.Init (this, e, SocketOperation.SendTo);
- SocketAsyncResult res = e.Worker.result;
- res.Buffer = e.Buffer;
- res.Offset = e.Offset;
- res.Size = e.Count;
- res.SockFlags = e.SocketFlags;
- res.EndPoint = e.RemoteEndPoint;
- int count;
- lock (writeQ) {
- writeQ.Enqueue (e.Worker);
- count = writeQ.Count;
+ static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
+ {
+ bool release = false;
+ try {
+ safeHandle.DangerousAddRef (ref release);
+ return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
+ } finally {
+ if (release)
+ safeHandle.DangerousRelease ();
}
- if (count == 1)
- socket_pool_queue (SocketAsyncWorker.Dispatcher, res);
- return true;
}
-
- public int SendTo (byte [] buffer, EndPoint remote_end)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
+ * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
+ * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+#endregion
- return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
+#region Close
+
+ public void Close ()
+ {
+ linger_timeout = 0;
+ Dispose ();
}
- public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
+ public void Close (int timeout)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ linger_timeout = timeout;
+ Dispose ();
+ }
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern static void Close_internal (IntPtr socket, out int error);
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
-
- return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
- }
+#endregion
- public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
- {
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+#region Shutdown
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ public void Shutdown (SocketShutdown how)
+ {
+ ThrowIfDisposedAndClosed ();
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (!is_connected)
+ throw new SocketException (10057); // Not connected
- CheckRange (buffer, 0, size);
+ int error;
+ Shutdown_internal (safe_handle, how, out error);
- return SendTo_nochecks (buffer, 0, size, flags, remote_end);
+ if (error != 0)
+ throw new SocketException (error);
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int SendTo_internal(IntPtr sock,
- byte[] buffer,
- int offset,
- int count,
- SocketFlags flags,
- SocketAddress sa,
- out int error);
-
- private static int SendTo_internal (SafeSocketHandle safeHandle,
- byte[] buffer,
- int offset,
- int count,
- SocketFlags flags,
- SocketAddress sa,
- out int error)
+ static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
{
+ bool release = false;
try {
- safeHandle.RegisterForBlockingSyscall ();
- return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
+ safeHandle.DangerousAddRef (ref release);
+ Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
} finally {
- safeHandle.UnRegisterForBlockingSyscall ();
+ if (release)
+ safeHandle.DangerousRelease ();
}
}
- public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags,
- EndPoint remote_end)
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
+
+#endregion
+
+#region Dispose
+
+ protected virtual void Dispose (bool disposing)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ if (is_disposed)
+ return;
- if (buffer == null)
- throw new ArgumentNullException ("buffer");
+ is_disposed = true;
+ bool was_connected = is_connected;
+ is_connected = false;
- if (remote_end == null)
- throw new ArgumentNullException("remote_end");
+ if (safe_handle != null) {
+ is_closed = true;
+ IntPtr x = Handle;
- CheckRange (buffer, offset, size);
+ if (was_connected)
+ Linger (x);
- return SendTo_nochecks (buffer, offset, size, flags, remote_end);
+ safe_handle.Dispose ();
+ }
}
- internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
- EndPoint remote_end)
+ public void Dispose ()
{
- SocketAddress sockaddr = remote_end.Serialize ();
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
- int ret, error;
+ void Linger (IntPtr handle)
+ {
+ if (!is_connected || linger_timeout <= 0)
+ return;
- ret = SendTo_internal (safe_handle, buffer, offset, size, flags, sockaddr, out error);
+ /* We don't want to receive any more data */
+ int error;
+ Shutdown_internal (handle, SocketShutdown.Receive, out error);
- SocketError err = (SocketError) error;
- if (err != 0) {
- if (err != SocketError.WouldBlock && err != SocketError.InProgress)
- is_connected = false;
+ if (error != 0)
+ return;
- throw new SocketException (error);
+ int seconds = linger_timeout / 1000;
+ int ms = linger_timeout % 1000;
+ if (ms > 0) {
+ /* If the other end closes, this will return 'true' with 'Available' == 0 */
+ Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
+ if (error != 0)
+ return;
}
- is_connected = true;
- is_bound = true;
- seed_endpoint = remote_end;
-
- return ret;
+ if (seconds > 0) {
+ LingerOption linger = new LingerOption (true, seconds);
+ SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
+ /* Not needed, we're closing upon return */
+ //if (error != 0)
+ // return;
+ }
}
- public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
+#endregion
+
+ void ThrowIfDisposedAndClosed (Socket socket)
+ {
+ if (socket.is_disposed && socket.is_closed)
+ throw new ObjectDisposedException (socket.GetType ().ToString ());
+ }
+
+ void ThrowIfDisposedAndClosed ()
{
if (is_disposed && is_closed)
throw new ObjectDisposedException (GetType ().ToString ());
+ }
- // I'd throw an ArgumentNullException, but this is what MS does.
- if (optionValue == null)
- throw new SocketException ((int) SocketError.Fault,
- "Error trying to dereference an invalid pointer");
-
- int error;
-
- SetSocketOption_internal (safe_handle, optionLevel, optionName, null,
- optionValue, 0, out error);
+ void ThrowIfBufferNull (byte[] buffer)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+ }
- if (error != 0) {
- if (error == (int) SocketError.InvalidArgument)
- throw new ArgumentException ();
- throw new SocketException (error);
- }
+ void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
+ {
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
+ if (offset > buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
+ if (size < 0)
+ throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
+ if (size > buffer.Length - offset)
+ throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
}
- public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
+ void ThrowIfUdp ()
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+#if !NET_2_1 || MOBILE
+ if (protocol_type == ProtocolType.Udp)
+ throw new SocketException ((int)SocketError.ProtocolOption);
+#endif
+ }
- // NOTE: if a null is passed, the byte[] overload is used instead...
- if (optionValue == null)
- throw new ArgumentNullException("optionValue");
-
- int error;
+ SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
+ {
+ if (ares == null)
+ throw new ArgumentNullException (argName);
- if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
- LingerOption linger = optionValue as LingerOption;
- if (linger == null)
- throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
- SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
- } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
- MulticastOption multicast = optionValue as MulticastOption;
- if (multicast == null)
- throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
- SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
- } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
- IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
- if (multicast == null)
- throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
- SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
- } else {
- throw new ArgumentException ("Invalid value specified.", "optionValue");
- }
+ SocketAsyncResult sockares = ares as SocketAsyncResult;
+ if (sockares == null)
+ throw new ArgumentException ("Invalid IAsyncResult", argName);
+ if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
+ throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
- if (error != 0) {
- if (error == (int) SocketError.InvalidArgument)
- throw new ArgumentException ();
- throw new SocketException (error);
- }
+ return sockares;
}
- public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
+ void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
{
- if (is_disposed && is_closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ int count;
+ lock (queue) {
+ queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
+ count = queue.Count;
+ }
- int error;
- int int_val = (optionValue) ? 1 : 0;
- SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
- if (error != 0) {
- if (error == (int) SocketError.InvalidArgument)
- throw new ArgumentException ();
- throw new SocketException (error);
+ if (count == 1)
+ IOSelector.Add (handle, job);
+ }
+
+ void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
+ {
+ e.socket_async_result.Init (this, callback, state, operation);
+
+ e.current_socket = this;
+ e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
+ e.SocketError = SocketError.Success;
+ e.BytesTransferred = 0;
+ }
+
+ SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
+ {
+ switch (op) {
+ case SocketOperation.Connect:
+ return SocketAsyncOperation.Connect;
+ case SocketOperation.Accept:
+ return SocketAsyncOperation.Accept;
+ case SocketOperation.Disconnect:
+ return SocketAsyncOperation.Disconnect;
+ case SocketOperation.Receive:
+ case SocketOperation.ReceiveGeneric:
+ return SocketAsyncOperation.Receive;
+ case SocketOperation.ReceiveFrom:
+ return SocketAsyncOperation.ReceiveFrom;
+ case SocketOperation.Send:
+ case SocketOperation.SendGeneric:
+ return SocketAsyncOperation.Send;
+ case SocketOperation.SendTo:
+ return SocketAsyncOperation.SendTo;
+ default:
+ throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
}
}
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct WSABUF {
+ public int len;
+ public IntPtr buf;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern void cancel_blocking_socket_operation (Thread thread);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern bool SupportsPortReuse ();
}
}