const string TIMEOUT_EXCEPTION_MSG = "A connection attempt failed because the connected party did not properly respond" +
"after a period of time, or established connection failed because connected host has failed to respond";
- /*
- * These two fields are looked up by name by the runtime, don't change
- * their name without also updating the runtime code.
- */
- static int ipv4_supported = -1;
- static int ipv6_supported = -1;
-
/* true if we called Close_internal */
bool is_closed;
*/
internal EndPoint seed_endpoint = null;
- 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 SemaphoreSlim ReadSem = new SemaphoreSlim (1, 1);
+ internal SemaphoreSlim WriteSem = new SemaphoreSlim (1, 1);
internal bool is_blocking = true;
internal bool is_bound;
int m_IntCleanedUp;
internal bool connect_in_progress;
- private static volatile bool s_LoggingEnabled = Logging.On;
-
#region Constructors
- static Socket ()
- {
- 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 !MOBILE
-#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;
- }
- }
- }
- }
-
- public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
- {
- this.addressFamily = addressFamily;
- this.socketType = socketType;
- this.protocolType = protocolType;
-
- int error;
- this.m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
-
- if (error != 0)
- throw new SocketException (error);
-
- SocketDefaults ();
- }
public Socket (SocketInformation socketInformation)
{
this.is_bound = (ProtocolType) (int) result [3] != 0;
this.m_Handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
+ InitializeSockets ();
+
SocketDefaults ();
}
this.m_Handle = safe_handle;
this.is_connected = true;
+
+ InitializeSockets ();
}
void SocketDefaults ()
#region Properties
- [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
- public static bool SupportsIPv4 {
- get { return ipv4_supported == 1; }
- }
-
- [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
- public static bool SupportsIPv6 {
- get { return ipv6_supported == 1; }
- }
-
-#if MOBILE
- public static bool OSSupportsIPv4 {
- get { return ipv4_supported == 1; }
- }
-#else
- public static bool OSSupportsIPv4 {
- get {
- NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
-
- foreach (NetworkInterface adapter in nics) {
- if (adapter.Supports (NetworkInterfaceComponent.IPv4))
- return true;
- }
-
- return false;
- }
- }
-#endif
-
-#if MOBILE
- public static bool OSSupportsIPv6 {
- get { return ipv6_supported == 1; }
- }
-#else
- public static bool OSSupportsIPv6 {
- get {
- NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
-
- foreach (NetworkInterface adapter in nics) {
- if (adapter.Supports (NetworkInterfaceComponent.IPv6))
- return true;
- }
-
- return false;
- }
- }
-#endif
-
public int Available {
get {
ThrowIfDisposedAndClosed ();
if (list != null) {
foreach (Socket sock in list) {
if (sock == null) // MS throws a NullRef
- throw new ArgumentNullException ("name", "Contains a null element");
+ throw new ArgumentNullException (name, "Contains a null element");
sockets.Add (sock);
}
}
InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
- QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
+ QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
return true;
}
SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
- QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
+ QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
return sockares;
}
AcceptSocket = acceptSocket,
};
- QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
+ QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
return sockares;
}
sockares.Complete (acc_socket, total);
});
- public Socket EndAccept (IAsyncResult result)
+ public Socket EndAccept (IAsyncResult asyncResult)
{
int bytes;
byte[] buffer;
- return EndAccept (out buffer, out bytes, result);
+ return EndAccept (out buffer, out bytes, asyncResult);
}
public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
public void Bind (EndPoint localEP)
{
+#if FEATURE_NO_BSD_SOCKETS
+ throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
+#else
ThrowIfDisposedAndClosed ();
if (localEP == null)
is_bound = true;
seed_endpoint = localEP;
+#endif // FEATURE_NO_BSD_SOCKETS
}
private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
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);
-
- iep = RemapIPEndPoint (iep);
-
- Connect_internal (m_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 ();
SocketAddress serial = remoteEP.Serialize ();
int error = 0;
- Connect_internal (m_Handle, serial, out error);
+ Connect_internal (m_Handle, serial, out error, is_blocking);
if (error == 0 || error == 10035)
seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
SocketAsyncResult ares;
if (!GetCheckedIPs (e, out addresses)) {
- e.socket_async_result.EndPoint = e.RemoteEndPoint;
+ //NOTE: DualMode may cause Socket's RemoteEndpoint to differ in AddressFamily from the
+ // SocketAsyncEventArgs, but the SocketAsyncEventArgs itself is not changed
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;
+ DnsEndPoint dep = (DnsEndPoint)e.RemoteEndPoint;
ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
}
return true;
}
- public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
- {
- var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
- return sock.ConnectAsync (e);
- }
-
public static void CancelConnectAsync (SocketAsyncEventArgs e)
{
if (e == null)
}
});
- public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
+ public IAsyncResult BeginConnect (string host, int port, AsyncCallback requestCallback, object state)
{
ThrowIfDisposedAndClosed ();
if (is_listening)
throw new InvalidOperationException ();
- return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
+ return BeginConnect (Dns.GetHostAddresses (host), port, requestCallback, state);
}
- public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
+ public IAsyncResult BeginConnect (EndPoint remoteEP, AsyncCallback callback, object state)
{
ThrowIfDisposedAndClosed ();
- if (end_point == null)
- throw new ArgumentNullException ("end_point");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
if (is_listening)
throw new InvalidOperationException ();
SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
- EndPoint = end_point,
+ EndPoint = remoteEP,
};
- // 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;
- }
-
- end_point = RemapIPEndPoint (ep);
- }
-
- 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;
- m_Handle.Dispose ();
- m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
- if (error != 0)
- throw new SocketException (error);
- }
-
- bool blk = is_blocking;
- if (blk)
- Blocking = false;
- Connect_internal (m_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));
-
+ BeginSConnect (sockares);
return sockares;
}
- public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
+ public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
{
ThrowIfDisposedAndClosed ();
if (is_listening)
throw new InvalidOperationException ();
- SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
+ SocketAsyncResult sockares = new SocketAsyncResult (this, requestCallback, state, SocketOperation.Connect) {
Addresses = addresses,
Port = port,
};
is_connected = false;
- return BeginMConnect (sockares);
+ BeginMConnect (sockares);
+ return sockares;
}
- internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
+ static void BeginMConnect (SocketAsyncResult sockares)
{
- SocketAsyncResult ares = null;
Exception exc = null;
- AsyncCallback callback;
for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
try {
sockares.CurrentAddress++;
+ sockares.EndPoint = new IPEndPoint (sockares.Addresses [i], sockares.Port);
- 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;
+ BeginSConnect (sockares);
+ return;
} catch (Exception e) {
exc = e;
- ares = null;
}
}
- if (ares == null)
- throw exc;
+ throw exc;
+ }
- return sockares;
+ static void BeginSConnect (SocketAsyncResult sockares)
+ {
+ EndPoint remoteEP = sockares.EndPoint;
+ // Bug #75154: Connect() should not succeed for .Any addresses.
+ if (remoteEP is IPEndPoint) {
+ IPEndPoint ep = (IPEndPoint) remoteEP;
+ if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
+ sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
+ return;
+ }
+
+ sockares.EndPoint = remoteEP = sockares.socket.RemapIPEndPoint (ep);
+ }
+
+ int error = 0;
+
+ if (sockares.socket.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.
+ sockares.socket.connect_in_progress = false;
+ sockares.socket.m_Handle.Dispose ();
+ sockares.socket.m_Handle = new SafeSocketHandle (sockares.socket.Socket_internal (sockares.socket.addressFamily, sockares.socket.socketType, sockares.socket.protocolType, out error), true);
+ if (error != 0)
+ throw new SocketException (error);
+ }
+
+ bool blk = sockares.socket.is_blocking;
+ if (blk)
+ sockares.socket.Blocking = false;
+ Connect_internal (sockares.socket.m_Handle, remoteEP.Serialize (), out error, false);
+ if (blk)
+ sockares.socket.Blocking = true;
+
+ if (error == 0) {
+ // succeeded synch
+ sockares.socket.is_connected = true;
+ sockares.socket.is_bound = true;
+ sockares.Complete (true);
+ return;
+ }
+
+ if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
+ // error synch
+ sockares.socket.is_connected = false;
+ sockares.socket.is_bound = false;
+ sockares.Complete (new SocketException (error), true);
+ return;
+ }
+
+ // continue asynch
+ sockares.socket.is_connected = false;
+ sockares.socket.is_bound = false;
+ sockares.socket.connect_in_progress = true;
+
+ IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
}
static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
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);
+ int error = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
- if (error_code == 0) {
- if (is_mconnect)
- sockares = mconnect;
-
- sockares.socket.seed_endpoint = ep;
+ if (error == 0) {
+ sockares.socket.seed_endpoint = sockares.EndPoint;
sockares.socket.is_connected = true;
sockares.socket.is_bound = true;
sockares.socket.connect_in_progress = false;
return;
}
- if (!is_mconnect) {
+ if (sockares.Addresses == null) {
sockares.socket.connect_in_progress = false;
- sockares.Complete (new SocketException (error_code));
+ sockares.Complete (new SocketException (error));
return;
}
- if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
- mconnect.Complete (new SocketException (error_code));
+ if (sockares.CurrentAddress >= sockares.Addresses.Length) {
+ sockares.Complete (new SocketException (error));
return;
}
- mconnect.socket.BeginMConnect (mconnect);
+ BeginMConnect (sockares);
} catch (Exception e) {
sockares.socket.connect_in_progress = false;
-
- if (is_mconnect)
- sockares = mconnect;
-
sockares.Complete (e);
- return;
}
});
- public void EndConnect (IAsyncResult result)
+ public void EndConnect (IAsyncResult asyncResult)
{
ThrowIfDisposedAndClosed ();
- SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndConnect", "asyncResult");
if (!sockares.IsCompleted)
sockares.AsyncWaitHandle.WaitOne();
sockares.CheckIfThrowDelayedException();
}
- static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
+ static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
+ Connect_internal (safeHandle.DangerousGetHandle (), sa, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
/* Connects to the remote address */
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
+ extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error, bool blocking);
/* Returns :
* - false when it is ok to use RemoteEndPoint
ThrowIfBufferOutOfRange (buffer, offset, size);
int nativeError;
- int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError);
+ int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
errorCode = (SocketError) nativeError;
if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
}
try {
- ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError);
+ ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
} finally {
for (int i = 0; i < numsegments; i++) {
if (gch[i].IsAllocated)
e.socket_async_result.Buffers = e.BufferList;
- QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
+ QueueIOSelectorJob (ReadSem, 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.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));
+ QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
}
return true;
SockFlags = socketFlags,
};
- QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
+ QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
return sockares;
}
int total = 0;
try {
- total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+ total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
} catch (Exception e) {
sockares.Complete (e);
return;
SockFlags = socketFlags,
};
- QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
+ QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
return sockares;
}
return sockares.Total;
}
- static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
+ static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
+ return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
+ extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
- static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
+ static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
+ return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
+ extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
#endregion
SocketAddress sockaddr = remoteEP.Serialize();
int nativeError;
- int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError);
+ int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
errorCode = (SocketError) nativeError;
if (errorCode != SocketError.Success) {
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));
+ QueueIOSelectorJob (ReadSem, 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)
+ public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
{
ThrowIfDisposedAndClosed ();
ThrowIfBufferNull (buffer);
ThrowIfBufferOutOfRange (buffer, offset, size);
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
Buffer = buffer,
Offset = offset,
Size = size,
- SockFlags = socket_flags,
- EndPoint = remote_end,
+ SockFlags = socketFlags,
+ EndPoint = remoteEP,
};
- QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
+ QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
return sockares;
}
sockares.Complete (total);
});
- public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
+ public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint)
{
ThrowIfDisposedAndClosed ();
- if (end_point == null)
- throw new ArgumentNullException ("remote_end");
+ if (endPoint == null)
+ throw new ArgumentNullException ("endPoint");
- SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveFrom", "asyncResult");
if (!sockares.IsCompleted)
sockares.AsyncWaitHandle.WaitOne();
sockares.CheckIfThrowDelayedException();
- end_point = sockares.EndPoint;
+ endPoint = sockares.EndPoint;
return sockares.Total;
}
- static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
+ static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
+ return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
+ extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
#endregion
if (endPoint == null)
throw new ArgumentNullException ("endPoint");
- SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
+ /*SocketAsyncResult sockares =*/ ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
throw new NotImplementedException ();
}
int sent = 0;
do {
sent += Send_internal (
-m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError);
+m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
errorCode = (SocketError)nativeError;
if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
is_connected = false;
}
try {
- ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError);
+ ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
} finally {
for(int i = 0; i < numsegments; i++) {
if (gch[i].IsAllocated) {
e.socket_async_result.Buffers = e.BufferList;
- QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
+ QueueIOSelectorJob (WriteSem, 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.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));
+ QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
}
return true;
SockFlags = socketFlags,
};
- QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
+ QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
return sockares;
}
int total = 0;
try {
- total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+ total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
} catch (Exception e) {
sockares.Complete (e);
return;
SockFlags = socketFlags,
};
- QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
+ QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
return sockares;
}
return sockares.Total;
}
- static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
+ static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
{
- bool release = false;
try {
- safeHandle.DangerousAddRef (ref release);
- return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
+ safeHandle.RegisterForBlockingSyscall ();
+ return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
} finally {
- if (release)
- safeHandle.DangerousRelease ();
+ safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
+ extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
- static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
+ static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
+ return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
+ extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
#endregion
throw new ArgumentNullException("remoteEP");
int error;
- int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error);
+ int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
SocketError err = (SocketError) error;
if (err != 0) {
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));
+ QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
return true;
}
}
});
- public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
+ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, object state)
{
ThrowIfDisposedAndClosed ();
ThrowIfBufferNull (buffer);
Buffer = buffer,
Offset = offset,
Size = size,
- SockFlags = socket_flags,
- EndPoint = remote_end,
+ SockFlags = socketFlags,
+ EndPoint = remoteEP,
};
- QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
+ QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
return sockares;
}
sockares.Complete ();
}
- public int EndSendTo (IAsyncResult result)
+ public int EndSendTo (IAsyncResult asyncResult)
{
ThrowIfDisposedAndClosed ();
- SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
+ SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSendTo", "result");
if (!sockares.IsCompleted)
sockares.AsyncWaitHandle.WaitOne();
return sockares.Total;
}
- static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
+ static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
+ return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
+ extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
#endregion
if (!is_blocking)
throw new InvalidOperationException ();
- if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags)) {
- SocketException exc = new SocketException ();
+ int error = 0;
+ if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags, out error, is_blocking) || error != 0) {
+ SocketException exc = new SocketException (error);
if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
throw new FileNotFoundException ();
throw exc;
ares.Delegate.EndInvoke (ares.Original);
}
- static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
+ static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking)
{
try {
safeHandle.RegisterForBlockingSyscall ();
- return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
+ return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags, out error, blocking);
} finally {
safeHandle.UnRegisterForBlockingSyscall ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
+ extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking);
delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
#region DuplicateAndClose
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ static extern bool Duplicate_internal(IntPtr handle, int targetProcessId, out IntPtr duplicateHandle, out MonoIOError error);
+
[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)
{
(is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
(useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
- si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
- m_Handle = null;
+ IntPtr duplicateHandle;
+ if (!Duplicate_internal (Handle, targetProcessId, out duplicateHandle, out MonoIOError error))
+ throw MonoIO.GetException (error);
- return si;
+ si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)duplicateHandle);
+ m_Handle = null;
+
+ return si;
}
#endregion
{
ThrowIfDisposedAndClosed ();
- if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
- throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times.");
-
int error;
SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
return sockares;
}
- void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
+ void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
{
- int count;
- lock (queue) {
- queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
- count = queue.Count;
- }
-
- if (count == 1)
+ var task = sem.WaitAsync();
+ // fast path without Task<Action> allocation.
+ if (task.IsCompleted) {
+ if (CleanedUp) {
+ job.MarkDisposed ();
+ return;
+ }
IOSelector.Add (handle, job);
+ }
+ else
+ {
+ task.ContinueWith( t => {
+ if (CleanedUp) {
+ job.MarkDisposed ();
+ return;
+ }
+ IOSelector.Add(handle, job);
+ });
+ }
}
void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool SupportsPortReuse (ProtocolType proto);
+
+ internal static int FamilyHint {
+ get {
+ // Returns one of
+ // MONO_HINT_UNSPECIFIED = 0,
+ // MONO_HINT_IPV4 = 1,
+ // MONO_HINT_IPV6 = 2,
+
+ int hint = 0;
+ if (OSSupportsIPv4) {
+ hint = 1;
+ }
+
+ if (OSSupportsIPv6) {
+ hint = hint == 0 ? 2 : 0;
+ }
+
+ return hint;
+ }
+ }
+
+ static bool IsProtocolSupported (NetworkInterfaceComponent networkInterface)
+ {
+#if MOBILE
+ return true;
+#else
+ var nics = NetworkInterface.GetAllNetworkInterfaces ();
+ foreach (var adapter in nics) {
+ if (adapter.Supports (networkInterface))
+ return true;
+ }
+
+ return false;
+#endif
+ }
}
}