using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
-using System.Reflection;
using System.IO;
using System.Security;
using System.Text;
using System.Collections.Generic;
#if !NET_2_1
using System.Net.NetworkInformation;
-using System.Timers;
#endif
#endif
* These two fields are looked up by name by the runtime, don't change
* their name without also updating the runtime code.
*/
- private static int ipv4Supported = -1;
- /* MonoTouch doesn't support System.Configuration, and the ipv6 check raises an uncatchable exception
- * so we unfortunately need to disable ipv6 here.
- */
-#if MONOTOUCH
- private static int ipv6Supported = 0;
-#else
- private static int ipv6Supported = -1;
-#endif
+ private static int ipv4Supported = -1, ipv6Supported = -1;
+ int linger_timeout;
static Socket ()
{
bool block,
out int error);
#endif
+
public bool Blocking {
get {
return(blocking);
}
}
+ void Linger (IntPtr handle)
+ {
+ if (!connected || linger_timeout <= 0)
+ return;
+
+ // We don't want to receive any more data
+ int error;
+ Shutdown_internal (handle, SocketShutdown.Receive, out error);
+ if (error != 0)
+ return;
+
+ 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;
+
+ }
+ 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; */
+ }
+ }
+
protected virtual void Dispose (bool explicitDisposing)
{
if (disposed)
return;
disposed = true;
+ bool was_connected = connected;
connected = false;
if ((int) socket != -1) {
int error;
closed = true;
IntPtr x = socket;
socket = (IntPtr) (-1);
- Close_internal (x, out error);
- if (blocking_thread != null) {
- blocking_thread.Abort ();
+ Thread th = blocking_thread;
+ if (th != null) {
+ th.Abort ();
blocking_thread = null;
}
+
+ if (was_connected)
+ Linger (x);
+ //DateTime start = DateTime.UtcNow;
+ Close_internal (x, out error);
+ //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
if (error != 0)
throw new SocketException (error);
}
public void Close ()
{
+ linger_timeout = 0;
((IDisposable) this).Dispose ();
}
+#if NET_2_0
+ public void Close (int timeout)
+ {
+ linger_timeout = timeout;
+ ((IDisposable) this).Dispose ();
+ }
+#endif
+
// Connects to the remote address
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static void Connect_internal(IntPtr sock,
if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
throw new SocketException ((int) SocketError.AddressNotAvailable);
-#if NET_2_1 && !MONOTOUCH
+#if MOONLIGHT
if (protocol_type != ProtocolType.Tcp)
throw new SocketException ((int) SocketError.AccessDenied);
-
- DnsEndPoint dep = (remoteEP as DnsEndPoint);
- if (dep != null)
- serial = dep.AsIPEndPoint ().Serialize ();
- else
- serial = remoteEP.Serialize ();
#elif NET_2_0
/* TODO: check this for the 1.1 profile too */
if (islistening)
throw new InvalidOperationException ();
-
- serial = remoteEP.Serialize ();
-#else
- serial = remoteEP.Serialize ();
#endif
+ serial = remoteEP.Serialize ();
int error = 0;
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
+ if (!connected)
+ throw new SocketException (10057); // Not connected
+
int error;
Shutdown_internal (socket, how, out error);
-
if (error != 0)
throw new SocketException (error);
}
#endif
}
-#if NET_2_1 && !MONOTOUCH
- static MethodInfo check_socket_policy;
-
- static void CheckConnect (SocketAsyncEventArgs e, bool checkPolicy)
+#if MOONLIGHT
+ static void CheckConnect (SocketAsyncEventArgs e)
{
// NO check is made whether e != null in MS.NET (NRE is thrown in such case)
throw new ArgumentNullException ("remoteEP");
if (e.BufferList != null)
throw new ArgumentException ("Multiple buffers cannot be used with this method.");
-
- if (!checkPolicy)
- return;
-
- e.SocketError = SocketError.AccessDenied;
- if (check_socket_policy == null) {
- Type type = Type.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
- check_socket_policy = type.GetMethod ("CheckEndPoint");
- if (check_socket_policy == null)
- throw new SecurityException ();
- }
- if ((bool) check_socket_policy.Invoke (null, new object [1] { e.RemoteEndPoint }))
- e.SocketError = SocketError.Success;
}
- // only _directly_ used (with false) to download the socket policy
- internal bool ConnectAsync (SocketAsyncEventArgs e, bool checkPolicy)
+ public bool ConnectAsync (SocketAsyncEventArgs e)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- CheckConnect (e, checkPolicy);
+ CheckConnect (e);
e.DoOperation (SocketAsyncOperation.Connect, this);
return true;
}
- public bool ConnectAsync (SocketAsyncEventArgs e)
- {
- return ConnectAsync (e, true);
- }
-
public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
{
- CheckConnect (e, true);
+ // exception ordering requires to check before creating the socket (good thing resource wise too)
+ CheckConnect (e);
Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
e.DoOperation (SocketAsyncOperation.Connect, s);