// Phillip Pearson (pp@myelin.co.nz)
// Dick Porter <dick@ximian.com>
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Sridhar Kulkarni (sridharkulkarni@gmail.com)
+// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
// http://www.myelin.co.nz
-// (c) 2004 Novell, Inc. (http://www.novell.com)
+// (c) 2004-2006 Novell, Inc. (http://www.novell.com)
//
//
using System.Reflection;
using System.IO;
using System.Net.Configuration;
+using System.Text;
+
+#if NET_2_0
+using System.Collections.Generic;
+using System.Net.NetworkInformation;
+#if !NET_2_1
+using System.Timers;
+#endif
+#endif
namespace System.Net.Sockets
{
- public class Socket : IDisposable
+ public partial class Socket : IDisposable
{
enum SocketOperation {
Accept,
UsedInManaged1,
UsedInManaged2,
UsedInProcess,
- UsedInConsole2
+ UsedInConsole2,
+ Disconnect,
+ AcceptReceive,
+ ReceiveGeneric,
+ SendGeneric
}
[StructLayout (LayoutKind.Sequential)]
- private sealed class SocketAsyncResult: IAsyncResult
+ struct WSABUF
+ {
+ public int len;
+ public IntPtr buf;
+ };
+
+ [StructLayout (LayoutKind.Sequential)]
+ private sealed class SocketAsyncResult: IAsyncResult
{
/* Same structure in the runtime */
+ /*
+ Keep this in sync with MonoSocketAsyncResult in
+ metadata/socket-io.h and ProcessAsyncReader
+ in System.Diagnostics/Process.cs.
+ */
+
public Socket Sock;
public IntPtr handle;
object state;
public int Offset; // Receive,ReceiveFrom,Send,SendTo
public int Size; // Receive,ReceiveFrom,Send,SendTo
public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
+ public Socket AcceptSocket; // AcceptReceive
+ public IPAddress[] Addresses; // Connect
+ public int Port; // Connect
+#if NET_2_0
+ public IList<ArraySegment<byte>> Buffers; // Receive, Send
+#else
+ public object Buffers; // Reserve this slot in older profiles
+#endif
+ public bool ReuseSocket; // Disconnect
// Return values
Socket acc_socket;
internal int error;
SocketOperation operation;
public object ares;
+ public int EndCalled;
public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
{
public void CheckIfThrowDelayedException ()
{
- if (delayedException != null)
+ if (delayedException != null) {
+ Sock.connected = false;
throw delayedException;
+ }
if (error != 0) {
+ Sock.connected = false;
throw new SocketException (error);
}
}
cb = new WaitCallback (ares.CompleteDisposed);
ThreadPool.QueueUserWorkItem (cb, null);
}
+ if (pending.Length == 0)
+ Buffer = null;
}
void CompleteDisposed (object unused)
if (callback != null)
callback (this);
+ Buffer = null;
}
SocketAsyncCall GetDelegate (Worker worker, SocketOperation op)
Complete ();
}
+ public void Complete (Socket s, int total)
+ {
+ acc_socket = s;
+ this.total = total;
+ Complete ();
+ }
+
public object AsyncState {
get {
return state;
get { return total; }
set { total = value; }
}
+
+ public SocketError ErrorCode
+ {
+ get {
+#if NET_2_0
+ SocketException ex = delayedException as SocketException;
+
+ if (ex != null)
+ return(ex.SocketErrorCode);
+
+ if (error != 0)
+ return((SocketError)error);
+#endif
+ return(SocketError.Success);
+ }
+ }
}
private sealed class Worker
result.Complete (acc_socket);
}
- public void Connect ()
+ /* only used in 2.0 profile and newer, but
+ * leave in older profiles to keep interface
+ * to runtime consistent
+ */
+ public void AcceptReceive ()
{
+ Socket acc_socket = null;
+
try {
- if (!result.Sock.Blocking) {
- int success;
- result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
- if (success == 0) {
- result.Sock.connected = true;
+ if (result.AcceptSocket == null) {
+ acc_socket = result.Sock.Accept ();
+ } else {
+ acc_socket = result.AcceptSocket;
+ result.Sock.Accept (acc_socket);
+ }
+ } catch (Exception e) {
+ result.Complete (e);
+ return;
+ }
+
+ /* It seems the MS runtime
+ * special-cases 0-length requested
+ * receive data. See bug 464201.
+ */
+ int total = 0;
+ if (result.Size > 0) {
+ try {
+ SocketError error;
+
+ total = acc_socket.Receive_nochecks (result.Buffer,
+ result.Offset,
+ result.Size,
+ result.SockFlags,
+ out error);
+ } catch (Exception e) {
+ result.Complete (e);
+ return;
+ }
+ }
+
+ result.Complete (acc_socket, total);
+ }
+
+ public void Connect ()
+ {
+ /* If result.EndPoint is non-null,
+ * this is the standard one-address
+ * connect attempt. Otherwise
+ * Addresses must be non-null and
+ * contain a list of addresses to try
+ * to connect to; the first one to
+ * succeed causes the rest of the list
+ * to be ignored.
+ */
+ if (result.EndPoint != null) {
+ try {
+ if (!result.Sock.Blocking) {
+ int success;
+ result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
+ if (success == 0) {
+ result.Sock.connected = true;
+ } else {
+ result.Complete (new SocketException (success));
+ return;
+ }
} else {
- result.Complete (new SocketException (success));
+ result.Sock.seed_endpoint = result.EndPoint;
+ result.Sock.Connect (result.EndPoint);
+ result.Sock.connected = true;
+ }
+ } catch (Exception e) {
+ result.Complete (e);
+ return;
+ }
+
+ result.Complete ();
+ } else if (result.Addresses != null) {
+ int error = (int) SocketError.InProgress; // why?
+ foreach(IPAddress address in result.Addresses) {
+ IPEndPoint iep = new IPEndPoint (address, result.Port);
+ SocketAddress serial = iep.Serialize ();
+
+ Socket.Connect_internal (result.Sock.socket, serial, out error);
+ if (error == 0) {
+ result.Sock.connected = true;
+ result.Sock.seed_endpoint = iep;
+ result.Complete ();
return;
+ } else if (error != (int)SocketError.InProgress &&
+ error != (int)SocketError.WouldBlock) {
+ continue;
+ }
+
+ if (!result.Sock.Blocking) {
+ int success;
+ result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
+ if (success == 0) {
+ result.Sock.connected = true;
+ result.Sock.seed_endpoint = iep;
+ result.Complete ();
+ return;
+ }
}
- } else {
- result.Sock.Connect (result.EndPoint);
- result.Sock.connected = true;
}
+
+ result.Complete (new SocketException (error));
+ } else {
+ result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
+ }
+ }
+
+ /* Also only used in 2.0 profile and newer */
+ public void Disconnect ()
+ {
+#if NET_2_0
+ try {
+ result.Sock.Disconnect (result.ReuseSocket);
} catch (Exception e) {
result.Complete (e);
return;
}
-
result.Complete ();
+#else
+ result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
}
public void Receive ()
result.Complete (total);
}
+ public void ReceiveGeneric ()
+ {
+#if NET_2_0
+ int total = 0;
+ try {
+ SocketError error;
+
+ total = result.Sock.Receive (result.Buffers, result.SockFlags, out error);
+ } catch (Exception e) {
+ result.Complete (e);
+ return;
+ }
+
+ result.Complete (total);
+#else
+ result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
+ }
+
int send_so_far;
void UpdateSendValues (int last_sent)
result.Complete ();
}
+
+ public void SendGeneric ()
+ {
+#if NET_2_0
+ int total = 0;
+ try {
+ SocketError error;
+
+ total = result.Sock.Send (result.Buffers, result.SockFlags, out error);
+ } catch (Exception e) {
+ result.Complete (e);
+ return;
+ }
+
+ result.Complete (total);
+#else
+ result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
+ }
}
- /* the field "socket" is looked up by name by the runtime */
- private IntPtr socket;
- private AddressFamily address_family;
- private SocketType socket_type;
- private ProtocolType protocol_type;
- internal bool blocking=true;
+
private Queue readQ = new Queue (2);
private Queue writeQ = new Queue (2);
delegate void SocketAsyncCall ();
- /*
- * 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, ipv6Supported = -1;
-
- /* When true, the socket was connected at the time of
- * the last IO operation
- */
- private bool connected=false;
- /* true if we called Close_internal */
- private bool closed;
- internal bool disposed;
-
- /* Used in LocalEndPoint and RemoteEndPoint if the
- * Mono.Posix assembly is available
- */
- private static object unixendpoint=null;
- private static Type unixendpointtype=null;
+#if NET_2_0
+ private bool islistening;
+ private bool useoverlappedIO;
+#endif
static void AddSockets (ArrayList 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");
+ throw new ArgumentNullException ("name", "Contains a null element");
sockets.Add (sock);
}
}
if (error != 0)
throw new SocketException (error);
- if (checkRead != null)
- checkRead.Clear ();
-
- if (checkWrite != null)
- checkWrite.Clear ();
-
- if (checkError != null)
- checkError.Clear ();
-
- if (sockets == null)
+ 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 cur_sock;
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 (currentList != null) {
- if (currentList == checkWrite) {
- if ((int)sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0) {
- sock.connected = true;
- }
- }
-
- currentList.Add (sock);
+ if (mode == 1 && currentList == checkWrite && !sock.connected) {
+ if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
+ sock.connected = true;
}
- }
- }
- static Socket() {
- Assembly ass;
-
- try {
- ass = Assembly.Load (Consts.AssemblyMono_Posix);
- } catch (FileNotFoundException) {
- return;
+ // Remove non-signaled sockets before the current one
+ int max = currentList.Count;
+ while ((cur_sock = (Socket) currentList [currentIdx]) != sock) {
+ currentList.RemoveAt (currentIdx);
+ }
+ currentIdx++;
}
-
- unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
-
- /* The endpoint Create() method is an instance
- * method :-(
- */
- Type[] arg_types=new Type[1];
- arg_types[0]=typeof(string);
- ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
-
- object[] args=new object[1];
- args[0]="nothing";
-
- unixendpoint=cons.Invoke(args);
}
// private constructor used by Accept, which already
// has a socket handle to use
private Socket(AddressFamily family, SocketType type,
- ProtocolType proto, IntPtr sock) {
+ ProtocolType proto, IntPtr sock)
+ {
address_family=family;
socket_type=type;
protocol_type=proto;
socket=sock;
connected=true;
}
-#if !TARGET_JVM
- // Creates a new system socket, returning the handle
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern IntPtr Socket_internal(AddressFamily family,
- SocketType type,
- ProtocolType proto,
- out int error);
-#endif
- public Socket(AddressFamily family, SocketType type,
- ProtocolType proto) {
- address_family=family;
- socket_type=type;
- protocol_type=proto;
+
+ private void SocketDefaults ()
+ {
+#if NET_2_0
+ try {
+ if (address_family == AddressFamily.InterNetwork /* Need to test IPv6 further ||
+ address_family == AddressFamily.InterNetworkV6 */) {
+ /* This is the default, but it
+ * probably has nasty side
+ * effects on Linux, as the
+ * socket option is kludged by
+ * turning on or off PMTU
+ * discovery...
+ */
+ this.DontFragment = false;
+ }
+
+ //
+ // Microsoft sets these to 8192, but we are going to keep them
+ // both to the OS defaults as these have a big performance impact.
+ // on WebClient performance.
+ //
+ //this.ReceiveBufferSize = 8192;
+ //this.SendBufferSize = 8192;
+ } catch (SocketException) {
+ }
+#endif
+ }
+
+
+#if NET_2_0
+ [MonoTODO]
+ public Socket (SocketInformation socketInformation)
+ {
+ throw new NotImplementedException ("SocketInformation not figured out yet");
+
+ // ifdef to avoid the warnings.
+#if false
+ //address_family = socketInformation.address_family;
+ //socket_type = socketInformation.socket_type;
+ //protocol_type = socketInformation.protocol_type;
+ address_family = AddressFamily.InterNetwork;
+ socket_type = SocketType.Stream;
+ protocol_type = ProtocolType.IP;
int error;
-
- socket=Socket_internal(family, type, proto, out error);
- if (error != 0) {
+ socket = Socket_internal (address_family, socket_type, protocol_type, out error);
+ if (error != 0)
throw new SocketException (error);
- }
- }
- public AddressFamily AddressFamily {
- get {
- return(address_family);
- }
+ SocketDefaults ();
+#endif
}
+#endif
+
#if !TARGET_JVM
// 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 extern static int Available_internal(IntPtr socket, out int error);
#endif
-
+
public int Available {
get {
if (disposed && closed)
ret = Available_internal(socket, out error);
- if (error != 0) {
+ if (error != 0)
throw new SocketException (error);
- }
return(ret);
}
}
-#if !TARGET_JVM
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Blocking_internal(IntPtr socket,
- bool block,
- out int error);
-#endif
- public bool Blocking {
+
+
+#if NET_2_0
+ public bool DontFragment {
get {
- return(blocking);
- }
- set {
- if (disposed && closed)
+ if (disposed && closed) {
throw new ObjectDisposedException (GetType ().ToString ());
+ }
- int error;
+ bool dontfragment;
- Blocking_internal(socket, value, out error);
-
- if (error != 0) {
- throw new SocketException (error);
+ 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 {
+ throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
}
- blocking=value;
+ return(dontfragment);
}
- }
+ set {
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
+ }
- public bool Connected {
- get {
- return(connected);
+ 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 {
+ throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+ }
}
}
- public IntPtr Handle {
+ public bool EnableBroadcast {
get {
- return(socket);
- }
- }
-#if !TARGET_JVM
- // Returns the local endpoint details in addr and port
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
-#endif
- // Wish: support non-IP endpoints.
- public EndPoint LocalEndPoint {
- get {
- if (disposed && closed)
+ if (disposed && closed) {
throw new ObjectDisposedException (GetType ().ToString ());
+ }
- SocketAddress sa;
- int error;
+ if (protocol_type != ProtocolType.Udp) {
+ throw new SocketException ((int)SocketError.ProtocolOption);
+ }
- sa=LocalEndPoint_internal(socket, out error);
-
- if (error != 0) {
- throw new SocketException (error);
+ return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0);
+ }
+ set {
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
}
- if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
- // Stupidly, EndPoint.Create() is an
- // instance method
- return new IPEndPoint(0, 0).Create(sa);
- } else if (sa.Family==AddressFamily.Unix &&
- unixendpoint!=null) {
- return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
- } else {
- throw new NotImplementedException();
+ if (protocol_type != ProtocolType.Udp) {
+ throw new SocketException ((int)SocketError.ProtocolOption);
}
- }
- }
- public ProtocolType ProtocolType {
- get {
- return(protocol_type);
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value?1:0);
}
}
-
- // Returns the remote endpoint details in addr and port
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
-
- //
- // Wish: Support non-IP endpoints
- //
- public EndPoint RemoteEndPoint {
+
+ public bool ExclusiveAddressUse {
get {
- if (disposed && closed)
+ if (disposed && closed) {
throw new ObjectDisposedException (GetType ().ToString ());
-
- SocketAddress sa;
- int error;
-
- sa=RemoteEndPoint_internal(socket, out error);
-
- if (error != 0) {
- throw new SocketException (error);
}
- if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
- // Stupidly, EndPoint.Create() is an
- // instance method
- return new IPEndPoint(0, 0).Create(sa);
- } else if (sa.Family==AddressFamily.Unix &&
- unixendpoint!=null) {
- return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
- } else {
- throw new NotImplementedException();
+ return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0);
+ }
+ set {
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
+ }
+ if (isbound) {
+ throw new InvalidOperationException ("Bind has already been called for this socket");
}
+
+ SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value?1:0);
}
}
-
- public SocketType SocketType {
+
+ public bool IsBound {
get {
- return(socket_type);
+ return(isbound);
}
}
-
- public static bool SupportsIPv4 {
+
+ public LingerOption LingerState {
get {
- CheckProtocolSupport();
- return ipv4Supported == 1;
- }
- }
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
+ }
- public static bool SupportsIPv6 {
- get {
- CheckProtocolSupport();
- return ipv6Supported == 1;
+ return((LingerOption)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger));
+ }
+ set {
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
+ }
+
+ SetSocketOption (SocketOptionLevel.Socket,
+ SocketOptionName.Linger,
+ value);
}
}
-
-#if NET_2_0
- public int SendTimeout {
+
+ public bool MulticastLoopback {
+ get {
+ if (disposed && 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) {
+ 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 {
+ throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+ }
+
+ return(multicastloopback);
+ }
+ set {
+ if (disposed && 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) {
+ 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 {
+ 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 {
+ get {
+ return(useoverlappedIO);
+ }
+ set {
+ useoverlappedIO = value;
+ }
+ }
+#endif
+
+ public IntPtr Handle {
+ get {
+ return(socket);
+ }
+ }
+
+#if !TARGET_JVM
+ // Returns the local endpoint details in addr and port
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
+#endif
+
+ // Wish: support non-IP endpoints.
+ public EndPoint LocalEndPoint {
+ get {
+ if (disposed && 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.
+ */
+ if (seed_endpoint == null)
+ return null;
+
+ SocketAddress sa;
+ int error;
+
+ sa=LocalEndPoint_internal(socket, out error);
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ return seed_endpoint.Create (sa);
+ }
+ }
+
+ public SocketType SocketType {
+ get {
+ return(socket_type);
+ }
+ }
+
+#if NET_2_0
+ public int SendTimeout {
get {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
return (int)GetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.SendTimeout);
}
set {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ 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.
+ */
+ if (value == -1)
+ value = 0;
+
SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, value);
public int ReceiveTimeout {
get {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
return (int)GetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout);
}
set {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (value < -1)
+ throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
+
+ if (value == -1) {
+ value = 0;
+ }
+
SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, value);
}
}
- public bool NoDelay {
- get {
- return (int)(GetSocketOption (
- SocketOptionLevel.Tcp,
- SocketOptionName.NoDelay)) != 0;
- }
-
- set {
- SetSocketOption (
- SocketOptionLevel.Tcp,
- SocketOptionName.NoDelay, value ? 1 : 0);
- }
- }
-#endif
-
- internal static void CheckProtocolSupport()
+ public bool AcceptAsync (SocketAsyncEventArgs e)
{
- if(ipv4Supported == -1) {
- try {
- Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- tmp.Close();
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+ if (!IsBound)
+ throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
+ if (!islistening)
+ 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.IsBound || acceptSocket.Connected)
+ throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
+ } else
+ e.AcceptSocket = new Socket (AddressFamily, SocketType, ProtocolType);
- ipv4Supported = 1;
- }
- catch {
- ipv4Supported = 0;
- }
+ try {
+ e.DoOperation (SocketAsyncOperation.Accept, this);
+ } catch {
+ ((IDisposable)e).Dispose ();
+ throw;
}
- if(ipv6Supported == -1) {
-#if NET_2_0 && CONFIGURATION_DEP
- SettingsSection config;
- config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
- if (config != null)
- ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
-#else
- NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");
-
- if(config != null)
- ipv6Supported = config.ipv6Enabled?-1:0;
-#endif
- if(ipv6Supported != 0) {
- try {
- Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
- tmp.Close();
-
- ipv6Supported = 1;
- }
- catch { }
- }
- }
+ // We always return true for now
+ return true;
}
-
+#endif
+
// Creates a new system socket, returning the handle
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static IntPtr Accept_internal(IntPtr sock,
- out int error);
+ private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
- Thread blocking_thread;
public Socket Accept() {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
IntPtr sock = (IntPtr) (-1);
blocking_thread = Thread.CurrentThread;
try {
- sock = Accept_internal(socket, out error);
+ sock = Accept_internal(socket, out error, blocking);
} catch (ThreadAbortException) {
if (disposed) {
+#if !NET_2_1
Thread.ResetAbort ();
+#endif
error = (int) SocketError.Interrupted;
}
} finally {
blocking_thread = null;
}
- if (error != 0) {
+ if (error != 0)
throw new SocketException (error);
- }
- Socket accepted = new Socket(this.AddressFamily,
- this.SocketType,
- this.ProtocolType, sock);
+ Socket accepted = new Socket(this.AddressFamily, this.SocketType,
+ this.ProtocolType, sock);
+ accepted.seed_endpoint = this.seed_endpoint;
accepted.Blocking = this.Blocking;
return(accepted);
}
- public IAsyncResult BeginAccept(AsyncCallback callback,
- object state) {
+ internal void Accept (Socket acceptSocket)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ int error = 0;
+ IntPtr sock = (IntPtr)(-1);
+ blocking_thread = Thread.CurrentThread;
+
+ try {
+ sock = Accept_internal (socket, out error, blocking);
+ } catch (ThreadAbortException) {
+ if (disposed) {
+#if !NET_2_1
+ Thread.ResetAbort ();
+#endif
+ error = (int)SocketError.Interrupted;
+ }
+ } finally {
+ blocking_thread = null;
+ }
+
+ if (error != 0)
+ throw new SocketException (error);
+
+ acceptSocket.address_family = this.AddressFamily;
+ acceptSocket.socket_type = this.SocketType;
+ acceptSocket.protocol_type = this.ProtocolType;
+ acceptSocket.socket = sock;
+ acceptSocket.connected = true;
+ acceptSocket.seed_endpoint = this.seed_endpoint;
+ acceptSocket.Blocking = this.Blocking;
+
+ /* FIXME: figure out what if anything else
+ * needs to be reset
+ */
+ }
+ public IAsyncResult BeginAccept(AsyncCallback callback,
+ object state)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
+#if NET_2_0
+ /* FIXME: check the 1.1 docs for this too */
+ if (!isbound || !islistening)
+ throw new InvalidOperationException ();
+#endif
+
SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
Worker worker = new Worker (req);
SocketAsyncCall sac = new SocketAsyncCall (worker.Accept);
return(req);
}
+#if NET_2_0
+ public IAsyncResult BeginAccept (int receiveSize,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (receiveSize < 0)
+ throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+ SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.AcceptReceive);
+
+ req.Buffer = new byte[receiveSize];
+ req.Offset = 0;
+ req.Size = receiveSize;
+ req.SockFlags = SocketFlags.None;
+
+ sac.BeginInvoke (null, req);
+ return(req);
+ }
+
+ public IAsyncResult BeginAccept (Socket acceptSocket,
+ int receiveSize,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (receiveSize < 0)
+ throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+ if (acceptSocket != null) {
+ if (acceptSocket.disposed && acceptSocket.closed)
+ throw new ObjectDisposedException (acceptSocket.GetType ().ToString ());
+
+ 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 req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.AcceptReceive);
+
+ req.Buffer = new byte[receiveSize];
+ req.Offset = 0;
+ req.Size = receiveSize;
+ req.SockFlags = SocketFlags.None;
+ req.AcceptSocket = acceptSocket;
+
+ sac.BeginInvoke (null, req);
+ return(req);
+ }
+#endif
+
public IAsyncResult BeginConnect(EndPoint end_point,
AsyncCallback callback,
object state) {
return(req);
}
+#if NET_2_0
+ public IAsyncResult BeginConnect (IPAddress address, int port,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (address == null)
+ throw new ArgumentNullException ("address");
+
+ if (address.ToString ().Length == 0)
+ throw new ArgumentException ("The length of the IP address is zero");
+
+ if (islistening)
+ throw new InvalidOperationException ();
+
+ IPEndPoint iep = new IPEndPoint (address, port);
+ return(BeginConnect (iep, callback, state));
+ }
+
+ public IAsyncResult BeginConnect (IPAddress[] addresses,
+ int port,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ 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 (islistening)
+ throw new InvalidOperationException ();
+
+ SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
+ req.Addresses = addresses;
+ req.Port = port;
+
+ connected = false;
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.Connect);
+ sac.BeginInvoke (null, req);
+
+ return(req);
+ }
+
+ public IAsyncResult BeginConnect (string host, int port,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ 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 (islistening)
+ throw new InvalidOperationException ();
+
+ IPAddress [] addresses = Dns.GetHostAddresses (host);
+ return (BeginConnect (addresses, port, callback, state));
+ }
+
+ public IAsyncResult BeginDisconnect (bool reuseSocket,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
+ req.ReuseSocket = reuseSocket;
+
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.Disconnect);
+ sac.BeginInvoke (null, req);
+
+ return(req);
+ }
+#endif
+
public IAsyncResult BeginReceive(byte[] buffer, int offset,
int size,
SocketFlags socket_flags,
return req;
}
+#if NET_2_0
+ 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));
+ }
+
+ [CLSCompliant (false)]
+ public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (buffers == null)
+ throw new ArgumentNullException ("buffers");
+
+ SocketAsyncResult req;
+ lock(readQ) {
+ req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
+ req.Buffers = buffers;
+ req.SockFlags = socketFlags;
+ readQ.Enqueue (req);
+ if (readQ.Count == 1) {
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.ReceiveGeneric);
+ sac.BeginInvoke (null, 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));
+ }
+#endif
public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
int size,
throw new ArgumentNullException ("buffer");
if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset must be >= 0");
+ throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
if (size < 0)
- throw new ArgumentOutOfRangeException ("size must be >= 0");
+ throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
if (offset + size > buffer.Length)
- throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+ throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
SocketAsyncResult req;
lock (readQ) {
return req;
}
+#if NET_2_0
+ [MonoTODO]
+ public IAsyncResult BeginReceiveMessageFrom (
+ byte[] buffer, int offset, int size,
+ SocketFlags socketFlags, ref EndPoint remoteEP,
+ AsyncCallback callback, object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ if (offset < 0 || offset > buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ if (size < 0 || offset + size > buffer.Length)
+ throw new ArgumentOutOfRangeException ("size");
+
+ throw new NotImplementedException ();
+ }
+#endif
+
public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
AsyncCallback callback, object state)
{
throw new ArgumentNullException ("buffer");
if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset must be >= 0");
+ throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
if (size < 0)
- throw new ArgumentOutOfRangeException ("size must be >= 0");
+ throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
if (offset + size > buffer.Length)
- throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+ throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
+
+#if NET_2_0
+ /* TODO: Check this exception in the 1.1 profile */
+ if (!connected)
+ throw new SocketException ((int)SocketError.NotConnected);
+#endif
SocketAsyncResult req;
lock (writeQ) {
return req;
}
+#if NET_2_0
+ public IAsyncResult BeginSend (byte[] buffer, int offset,
+ int size,
+ SocketFlags socketFlags,
+ out SocketError errorCode,
+ AsyncCallback callback,
+ object state)
+ {
+ if (!connected) {
+ errorCode = SocketError.NotConnected;
+ throw new SocketException ((int)errorCode);
+ }
+
+ errorCode = SocketError.Success;
+
+ return (BeginSend (buffer, offset, size, socketFlags, callback,
+ state));
+ }
+
+ public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (buffers == null)
+ throw new ArgumentNullException ("buffers");
+
+ if (!connected)
+ throw new SocketException ((int)SocketError.NotConnected);
+
+ SocketAsyncResult req;
+ lock (writeQ) {
+ req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
+ req.Buffers = buffers;
+ req.SockFlags = socketFlags;
+ writeQ.Enqueue (req);
+ if (writeQ.Count == 1) {
+ Worker worker = new Worker (req);
+ SocketAsyncCall sac = new SocketAsyncCall (worker.SendGeneric);
+ sac.BeginInvoke (null, req);
+ }
+ }
+
+ return(req);
+ }
+
+ [CLSCompliant (false)]
+ public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags,
+ out SocketError errorCode,
+ AsyncCallback callback,
+ object state)
+ {
+ if (!connected) {
+ errorCode = SocketError.NotConnected;
+ throw new SocketException ((int)errorCode);
+ }
+
+ errorCode = SocketError.Success;
+ return (BeginSend (buffers, socketFlags, callback, state));
+ }
+
+ [MonoTODO ("Not implemented")]
+ public IAsyncResult BeginSendFile (string fileName,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (!connected)
+ throw new NotSupportedException ();
+
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
+
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented")]
+ public IAsyncResult BeginSendFile (string fileName,
+ byte[] preBuffer,
+ byte[] postBuffer,
+ TransmitFileOptions flags,
+ AsyncCallback callback,
+ object state)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (!connected)
+ throw new NotSupportedException ();
+
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
+
+ throw new NotImplementedException ();
+ }
+#endif
+
public IAsyncResult BeginSendTo(byte[] buffer, int offset,
int size,
SocketFlags socket_flags,
throw new ArgumentNullException ("buffer");
if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset must be >= 0");
+ throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
if (size < 0)
- throw new ArgumentOutOfRangeException ("size must be >= 0");
+ throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
if (offset + size > buffer.Length)
- throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+ throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
SocketAsyncResult req;
lock (writeQ) {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if(local_end==null) {
+ if (local_end == null)
throw new ArgumentNullException("local_end");
- }
int error;
- Bind_internal(socket, local_end.Serialize(),
- out error);
+ Bind_internal(socket, local_end.Serialize(), out error);
+ if (error != 0)
+ throw new SocketException (error);
+#if NET_2_0
+ if (error == 0)
+ isbound = true;
+#endif
+
+ seed_endpoint = local_end;
+ }
+
+#if NET_2_0 && !NET_2_1
+ public void Close (int timeout)
+ {
+ System.Timers.Timer close_timer = new System.Timers.Timer ();
+ close_timer.Elapsed += new ElapsedEventHandler (OnTimeoutClose);
+ close_timer.Interval = timeout * 1000;
+ close_timer.AutoReset = false;
+ close_timer.Enabled = true;
+ }
+
+ private void OnTimeoutClose (object source, ElapsedEventArgs e)
+ {
+ this.Close ();
+ }
+
+ public bool ConnectAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+ if (islistening)
+ throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
+ if (e.RemoteEndPoint == null)
+ throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+ if (e.BufferList != null)
+ throw new ArgumentException ("Multiple buffers cannot be used with this method.");
+
+ e.DoOperation (SocketAsyncOperation.Connect, this);
+
+ // We always return true for now
+ return true;
+ }
+#endif
+
+#if NET_2_0
+ public void Connect (IPAddress address, int port)
+ {
+ Connect (new IPEndPoint (address, port));
+ }
+
+ public void Connect (IPAddress[] addresses, int port)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ 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 (islistening)
+ throw new InvalidOperationException ();
+
+ /* FIXME: do non-blocking sockets Poll here? */
+ foreach (IPAddress address in addresses) {
+ IPEndPoint iep = new IPEndPoint (address,
+ port);
+ SocketAddress serial = iep.Serialize ();
+ int error = 0;
+
+ Connect_internal (socket, serial, out error);
+ if (error == 0) {
+ connected = true;
+ seed_endpoint = iep;
+ return;
+ } else if (error != (int)SocketError.InProgress &&
+ error != (int)SocketError.WouldBlock) {
+ continue;
+ }
+
+ if (!blocking) {
+ Poll (-1, SelectMode.SelectWrite);
+ int success = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+ if (success == 0) {
+ connected = true;
+ seed_endpoint = iep;
+ return;
+ }
+ }
+ }
+ }
+
+ public void Connect (string host, int port)
+ {
+ IPAddress [] addresses = Dns.GetHostAddresses (host);
+ Connect (addresses, port);
+ }
+
+#if NET_2_0
+ public bool DisconnectAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ e.DoOperation (SocketAsyncOperation.Disconnect, this);
+
+ return true;
+ }
+#endif
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private extern static void Disconnect_internal(IntPtr sock,
+ bool reuse,
+ out int error);
+
+ /* 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)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ int error = 0;
+
+ Disconnect_internal (socket, reuseSocket, out error);
+
+ if (error != 0) {
+ if (error == 50) {
+ /* ERROR_NOT_SUPPORTED */
+ throw new PlatformNotSupportedException ();
+ } else {
+ throw new SocketException (error);
+ }
+ }
- if (error != 0) {
- throw new SocketException (error);
+ connected = false;
+
+ if (reuseSocket) {
+ /* Do managed housekeeping here... */
}
}
- // Closes the socket
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Close_internal(IntPtr socket,
- out int error);
+ [MonoTODO ("Not implemented")]
+ public SocketInformation DuplicateAndClose (int targetProcessId)
+ {
+ /* Need to serialize this socket into a
+ * SocketInformation struct, but must study
+ * the MS implementation harder to figure out
+ * behaviour as documentation is lacking
+ */
+ throw new NotImplementedException ();
+ }
+#endif
- public void Close() {
- ((IDisposable) this).Dispose ();
+ public Socket EndAccept (IAsyncResult result)
+ {
+ int bytes;
+ byte[] buffer;
+
+ return(EndAccept (out buffer, out bytes, result));
}
- // Connects to the remote address
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Connect_internal(IntPtr sock,
- SocketAddress sa,
- out int error);
+#if NET_2_0
+ public Socket EndAccept (out byte[] buffer,
+ IAsyncResult asyncResult)
+ {
+ int bytes;
+
+ return(EndAccept (out buffer, out bytes, asyncResult));
+ }
+#endif
- public void Connect(EndPoint remote_end) {
+#if NET_2_0
+ public
+#else
+ private
+#endif
+ Socket EndAccept (out byte[] buffer, out int bytesTransferred,
+ IAsyncResult asyncResult)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if(remote_end==null) {
- throw new ArgumentNullException("remote_end");
- }
-
- if (remote_end is IPEndPoint) {
- IPEndPoint ep = (IPEndPoint) remote_end;
- if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
- throw new SocketException ((int) SocketError.AddressNotAvailable);
- }
-
- SocketAddress serial = remote_end.Serialize ();
- int error = 0;
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ SocketAsyncResult req = asyncResult as SocketAsyncResult;
+ if (req == null)
+ throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
- blocking_thread = Thread.CurrentThread;
- try {
- Connect_internal (socket, serial, out error);
- } catch (ThreadAbortException) {
- if (disposed) {
- Thread.ResetAbort ();
- error = (int) SocketError.Interrupted;
- }
- } finally {
- blocking_thread = null;
- }
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndAccept");
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
- if (error != 0) {
- throw new SocketException (error);
- }
+ req.CheckIfThrowDelayedException ();
- connected=true;
+ buffer = req.Buffer;
+ bytesTransferred = req.Total;
+
+ return(req.Socket);
}
-
- public Socket EndAccept(IAsyncResult result) {
+
+ public void EndConnect (IAsyncResult result)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
if (req == null)
throw new ArgumentException ("Invalid IAsyncResult", "result");
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndConnect");
if (!result.IsCompleted)
result.AsyncWaitHandle.WaitOne();
req.CheckIfThrowDelayedException();
- return req.Socket;
}
- public void EndConnect(IAsyncResult result) {
+#if NET_2_0
+ public void EndDisconnect (IAsyncResult asyncResult)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (result == null)
- throw new ArgumentNullException ("result");
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
- SocketAsyncResult req = result as SocketAsyncResult;
+ SocketAsyncResult req = asyncResult as SocketAsyncResult;
if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "result");
+ throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
- if (!result.IsCompleted)
- result.AsyncWaitHandle.WaitOne();
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndDisconnect");
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
- req.CheckIfThrowDelayedException();
+ req.CheckIfThrowDelayedException ();
+ }
+#endif
+
+ public int EndReceive (IAsyncResult result)
+ {
+ SocketError error;
+
+ return (EndReceive (result, out error));
}
- public int EndReceive(IAsyncResult result) {
+#if NET_2_0
+ public
+#else
+ private
+#endif
+ int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (result == null)
- throw new ArgumentNullException ("result");
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
- SocketAsyncResult req = result as SocketAsyncResult;
+ SocketAsyncResult req = asyncResult as SocketAsyncResult;
if (req == null)
- throw new ArgumentException ("Invalid IAsyncResult", "result");
+ throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
- if (!result.IsCompleted)
- result.AsyncWaitHandle.WaitOne();
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndReceive");
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
- req.CheckIfThrowDelayedException();
- return req.Total;
+ errorCode = req.ErrorCode;
+ req.CheckIfThrowDelayedException ();
+
+ return(req.Total);
}
- public int EndReceiveFrom(IAsyncResult result,
- ref EndPoint end_point) {
+ public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
if (req == null)
throw new ArgumentException ("Invalid IAsyncResult", "result");
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndReceiveFrom");
if (!result.IsCompleted)
result.AsyncWaitHandle.WaitOne();
return req.Total;
}
- public int EndSend(IAsyncResult result) {
+#if NET_2_0
+ [MonoTODO]
+ public int EndReceiveMessageFrom (IAsyncResult asyncResult,
+ ref SocketFlags socketFlags,
+ ref EndPoint endPoint,
+ out IPPacketInformation ipPacketInformation)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (result == null)
- throw new ArgumentNullException ("result");
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
- SocketAsyncResult req = result as SocketAsyncResult;
+ if (endPoint == null)
+ throw new ArgumentNullException ("endPoint");
+
+ SocketAsyncResult req = asyncResult as SocketAsyncResult;
+ if (req == null)
+ throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndReceiveMessageFrom");
+ throw new NotImplementedException ();
+ }
+#endif
+
+ public int EndSend (IAsyncResult result)
+ {
+ SocketError error;
+
+ return(EndSend (result, out error));
+ }
+
+#if NET_2_0
+ public
+#else
+ private
+#endif
+ int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
+ {
+ if (disposed && 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", "result");
- if (!result.IsCompleted)
- result.AsyncWaitHandle.WaitOne();
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndSend");
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
- req.CheckIfThrowDelayedException();
- return req.Total;
+ errorCode = req.ErrorCode;
+ req.CheckIfThrowDelayedException ();
+
+ return(req.Total);
+ }
+
+#if NET_2_0
+ [MonoTODO]
+ public void EndSendFile (IAsyncResult asyncResult)
+ {
+ if (disposed && 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");
+
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndSendFile");
+ throw new NotImplementedException ();
+ }
+#endif
+
+ Exception InvalidAsyncOp (string method)
+ {
+ return new InvalidOperationException (method + " can only be called once per asynchronous operation");
}
- public int EndSendTo(IAsyncResult result) {
+ public int EndSendTo (IAsyncResult result)
+ {
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
if (req == null)
throw new ArgumentException ("Invalid IAsyncResult", "result");
+ if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+ throw InvalidAsyncOp ("EndSendTo");
if (!result.IsCompleted)
result.AsyncWaitHandle.WaitOne();
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
+ private extern static void GetSocketOption_arr_internal(IntPtr socket,
+ SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
+ out int error);
- public object GetSocketOption (SocketOptionLevel level, SocketOptionName name)
+ public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- object obj_val;
- int error;
-
- GetSocketOption_obj_internal(socket, level, name,
- out obj_val, out error);
-
- if (error != 0) {
- throw new SocketException (error);
- }
-
- if(name==SocketOptionName.Linger) {
- return((LingerOption)obj_val);
- } else if (name==SocketOptionName.AddMembership ||
- name==SocketOptionName.DropMembership) {
- return((MulticastOption)obj_val);
- } else if (obj_val is int) {
- return((int)obj_val);
- } else {
- return(obj_val);
- }
- }
-
- public void GetSocketOption (SocketOptionLevel level, SocketOptionName name, byte [] opt_value)
- {
- if (disposed && closed)
- throw new ObjectDisposedException (GetType ().ToString ());
+ if (optionValue == null)
+ throw new SocketException ((int) SocketError.Fault,
+ "Error trying to dereference an invalid pointer");
int error;
-
- GetSocketOption_arr_internal(socket, level, name,
- ref opt_value, out error);
- if (error != 0) {
+ GetSocketOption_arr_internal (socket, optionLevel, optionName, ref optionValue,
+ out error);
+ if (error != 0)
throw new SocketException (error);
- }
}
- public byte [] GetSocketOption (SocketOptionLevel level, SocketOptionName name, int length)
+ public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
byte[] byte_val=new byte[length];
int error;
-
- GetSocketOption_arr_internal(socket, level, name,
- ref byte_val, out error);
- if (error != 0) {
+ GetSocketOption_arr_internal (socket, optionLevel, optionName, ref byte_val,
+ out error);
+ if (error != 0)
throw new SocketException (error);
- }
return(byte_val);
}
// FIONBIO and SIOCATMARK. Anything else will depend on the
// system.
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static int WSAIoctl (IntPtr sock, int ioctl_code,
- byte [] input, byte [] output,
- out int error);
+ extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input,
+ byte [] output, out int error);
public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
{
throw new ObjectDisposedException (GetType ().ToString ());
int error;
- int result = WSAIoctl (socket, ioctl_code, in_value,
- out_value, out error);
+ int result = WSAIoctl (socket, ioctl_code, in_value, out_value,
+ out error);
- if (error != 0) {
+ if (error != 0)
throw new SocketException (error);
- }
if (result == -1)
throw new InvalidOperationException ("Must use Blocking property instead.");
return result;
}
+#if NET_2_0
+ [MonoTODO]
+ public int IOControl (IOControlCode ioControlCode,
+ byte[] optionInValue,
+ byte[] optionOutValue)
+ {
+ /* Probably just needs to mirror the int
+ * overload, but more investigation needed.
+ */
+ throw new NotImplementedException ();
+ }
+#endif
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Listen_internal(IntPtr sock,
- int backlog,
- out int error);
+ private extern static void Listen_internal(IntPtr sock, int backlog,
+ out int error);
public void Listen (int backlog)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
+#if NET_2_0
+ /* TODO: check if this should be thrown in the
+ * 1.1 profile too
+ */
+ if (!isbound)
+ throw new SocketException ((int)SocketError.InvalidArgument);
+#endif
+
int error;
Listen_internal(socket, backlog, out error);
- if (error != 0) {
+ if (error != 0)
throw new SocketException (error);
- }
- }
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
+#if NET_2_0
+ islistening = true;
+#endif
+ }
public bool Poll (int time_us, SelectMode mode)
{
if (error != 0)
throw new SocketException (error);
- if (mode == SelectMode.SelectWrite && result == true) {
+ if (mode == SelectMode.SelectWrite && result && !connected) {
/* Update the connected state; for
* non-blocking Connect()s this is
* when we can find out that the
return result;
}
- /* This overload is needed as the async Connect method
- * also needs to check the socket error status, but
- * getsockopt(..., SO_ERROR) clears the error.
- */
- private bool Poll (int time_us, SelectMode mode,
- out int socket_error)
+ public int Receive (byte [] buffer)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (mode != SelectMode.SelectRead &&
- mode != SelectMode.SelectWrite &&
- mode != SelectMode.SelectError)
- throw new NotSupportedException ("'mode' parameter is not valid.");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
- int error;
- bool result = Poll_internal (socket, mode, time_us, out error);
- if (error != 0)
- throw new SocketException (error);
+ SocketError error;
- socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
-
- if (mode == SelectMode.SelectWrite && result == true) {
- /* Update the connected state; for
- * non-blocking Connect()s this is
- * when we can find out that the
- * connect succeeded.
- */
- if (socket_error == 0) {
- connected = true;
- }
- }
+ int ret = Receive_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
- return result;
+ if (error != SocketError.Success)
+ throw new SocketException ((int) error);
+
+ return ret;
}
-
- public int Receive (byte [] buf)
+
+ public int Receive (byte [] buffer, SocketFlags flags)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
SocketError error;
- int ret = Receive_nochecks (buf, 0, buf.Length, SocketFlags.None, out error);
+ int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
- if (error != SocketError.Success)
+ if (error != SocketError.Success) {
+ if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
+ throw new SocketException ((int) error, "Operation timed out.");
throw new SocketException ((int) error);
+ }
return ret;
}
- public int Receive (byte [] buf, SocketFlags flags)
+ public int Receive (byte [] buffer, int size, SocketFlags flags)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (size < 0 || size > buffer.Length)
+ throw new ArgumentOutOfRangeException ("size");
SocketError error;
- int ret = Receive_nochecks (buf, 0, buf.Length, flags, out error);
+ int ret = Receive_nochecks (buffer, 0, size, flags, out error);
if (error != SocketError.Success) {
if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
return ret;
}
- public int Receive (byte [] buf, int size, SocketFlags flags)
+ public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
- if (size < 0 || size > buf.Length)
- throw new ArgumentOutOfRangeException ("size");
+ if (offset < 0 || offset > buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+ if (size < 0 || offset + size > buffer.Length)
+ throw new ArgumentOutOfRangeException ("size");
+
SocketError error;
- int ret = Receive_nochecks (buf, 0, size, flags, out error);
+ int ret = Receive_nochecks (buffer, offset, size, flags, out error);
if (error != SocketError.Success) {
if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
throw new SocketException ((int) error, "Operation timed out.");
throw new SocketException ((int) error);
}
-
- return ret;
+
+ return ret;
+ }
+
+#if NET_2_0
+ public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (offset < 0 || offset > buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ if (size < 0 || offset + size > buffer.Length)
+ throw new ArgumentOutOfRangeException ("size");
+
+ return Receive_nochecks (buffer, offset, size, flags, out error);
+ }
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static int Receive_internal (IntPtr sock,
+ WSABUF[] bufarray,
+ SocketFlags flags,
+ out int error);
+
+ public int Receive (IList<ArraySegment<byte>> buffers)
+ {
+ int ret;
+ SocketError error;
+
+ 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)
+ {
+ int ret;
+ SocketError error;
+
+ ret = Receive (buffers, socketFlags, out error);
+ if (error != SocketError.Success) {
+ throw new SocketException ((int)error);
+ }
+
+ return(ret);
}
- public int Receive (byte [] buf, int offset, int size, SocketFlags flags)
+ [CLSCompliant (false)]
+ public int Receive (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags,
+ out SocketError errorCode)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffers == null ||
+ buffers.Count == 0) {
+ throw new ArgumentNullException ("buffers");
+ }
- if (offset < 0 || offset > buf.Length)
- throw new ArgumentOutOfRangeException ("offset");
+ int numsegments = buffers.Count;
+ int nativeError;
+ int ret;
- if (size < 0 || offset + size > buf.Length)
- throw new ArgumentOutOfRangeException ("size");
-
- SocketError error;
+ /* 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];
- int ret = Receive_nochecks (buf, offset, size, flags, out error);
+ for(int i = 0; i < numsegments; i++) {
+ ArraySegment<byte> segment = buffers[i];
+ gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+ bufarray[i].len = segment.Count;
+ bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+ }
- if (error != SocketError.Success) {
- if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
- throw new SocketException ((int) error, "Operation timed out.");
- throw new SocketException ((int) error);
+ try {
+ ret = Receive_internal (socket, bufarray,
+ socketFlags,
+ out nativeError);
+ } finally {
+ for(int i = 0; i < numsegments; i++) {
+ if (gch[i].IsAllocated) {
+ gch[i].Free ();
+ }
+ }
}
- return ret;
+ errorCode = (SocketError)nativeError;
+ return(ret);
}
+#endif
#if NET_2_0
- public int Receive (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+ public bool ReceiveFromAsync (SocketAsyncEventArgs e)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ // 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 (offset < 0 || offset > buf.Length)
- throw new ArgumentOutOfRangeException ("offset");
+ e.DoOperation (SocketAsyncOperation.ReceiveFrom, this);
- if (size < 0 || offset + size > buf.Length)
- throw new ArgumentOutOfRangeException ("size");
-
- return Receive_nochecks (buf, offset, size, flags, out error);
+ // We always return true for now
+ return true;
}
#endif
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int Receive_internal(IntPtr sock,
- byte[] buffer,
- int offset,
- int count,
- SocketFlags flags,
- out int error);
-
- int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
- {
- int nativeError;
- int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
- error = (SocketError) nativeError;
- if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
- connected = false;
- else
- connected = true;
-
- return ret;
- }
-
- public int ReceiveFrom (byte [] buf, ref EndPoint remote_end)
+ public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
- return ReceiveFrom_nochecks (buf, 0, buf.Length, SocketFlags.None, ref remote_end);
+ return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
}
- public int ReceiveFrom (byte [] buf, SocketFlags flags, ref EndPoint remote_end)
+ public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
-
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
- return ReceiveFrom_nochecks (buf, 0, buf.Length, flags, ref remote_end);
+ return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
}
- public int ReceiveFrom (byte [] buf, int size, SocketFlags flags,
- ref EndPoint remote_end)
+ public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags,
+ ref EndPoint remoteEP)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
- if (size < 0 || size > buf.Length)
+ if (size < 0 || size > buffer.Length)
throw new ArgumentOutOfRangeException ("size");
- return ReceiveFrom_nochecks (buf, 0, size, flags, ref remote_end);
+ return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
}
-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static int RecvFrom_internal(IntPtr sock,
byte[] buffer,
ref SocketAddress sockaddr,
out int error);
- public int ReceiveFrom (byte [] buf, int offset, int size, SocketFlags flags,
- ref EndPoint remote_end)
+ public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags,
+ ref EndPoint remoteEP)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (buf == null)
- throw new ArgumentNullException ("buf");
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
- if (remote_end == null)
- throw new ArgumentNullException ("remote_end");
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
- if (offset < 0 || offset > buf.Length)
+ if (offset < 0 || offset > buffer.Length)
throw new ArgumentOutOfRangeException ("offset");
- if (size < 0 || offset + size > buf.Length)
+ if (size < 0 || offset + size > buffer.Length)
throw new ArgumentOutOfRangeException ("size");
- return ReceiveFrom_nochecks (buf, offset, size, flags, ref remote_end);
+ return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
}
- int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
- ref EndPoint remote_end)
+ internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
+ ref EndPoint remote_end)
{
- SocketAddress sockaddr = remote_end.Serialize();
- int cnt, error;
-
- cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
+ int error;
+ return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
+ }
+ 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 (socket, buf, offset, size, flags, ref sockaddr, out error);
SocketError err = (SocketError) error;
if (err != 0) {
if (err != SocketError.WouldBlock && err != SocketError.InProgress)
connected = false;
- else if (err == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
- throw new SocketException (error, "Operation timed out.");
+ else if (err == SocketError.WouldBlock && blocking) { // This might happen when ReceiveTimeout is set
+ if (throwOnError)
+ throw new SocketException ((int) SocketError.TimedOut, "Operation timed out");
+ error = (int) SocketError.TimedOut;
+ return 0;
+ }
- throw new SocketException (error);
+ if (throwOnError)
+ throw new SocketException (error);
+ return 0;
}
connected = true;
+#if NET_2_0
+ isbound = true;
+#endif
+
// If sockaddr is null then we're a connection
// oriented protocol and should ignore the
// remote_end parameter (see MSDN
// instance method
remote_end = remote_end.Create (sockaddr);
}
-
+
+ seed_endpoint = remote_end;
+
return cnt;
}
+#if NET_2_0
+ [MonoTODO ("Not implemented")]
+ public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ 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 (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (remoteEP == null)
+ throw new ArgumentNullException ("remoteEP");
+
+ if (offset < 0 || offset > buffer.Length)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ if (size < 0 || offset + size > buffer.Length)
+ throw new ArgumentOutOfRangeException ("size");
+
+ /* FIXME: figure out how we get hold of the
+ * IPPacketInformation
+ */
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented")]
+ public bool SendPacketsAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ throw new NotImplementedException ();
+ }
+
+#endif
+
public int Send (byte [] buf)
{
if (disposed && closed)
return Send_nochecks (buf, offset, size, flags, out error);
}
-#endif
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int Send_internal(IntPtr sock,
- byte[] buf, int offset,
- int count,
- SocketFlags flags,
- out int error);
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static int Send_internal (IntPtr sock,
+ WSABUF[] bufarray,
+ SocketFlags flags,
+ out int error);
- int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+ public int Send (IList<ArraySegment<byte>> buffers)
{
- if (size == 0) {
- error = SocketError.Success;
- return 0;
+ int ret;
+ SocketError error;
+
+ ret = Send (buffers, SocketFlags.None, out error);
+ if (error != SocketError.Success) {
+ throw new SocketException ((int)error);
+ }
+
+ return(ret);
+ }
+
+ public int Send (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags)
+ {
+ int ret;
+ SocketError error;
+
+ ret = Send (buffers, socketFlags, out error);
+ if (error != SocketError.Success) {
+ throw new SocketException ((int)error);
}
+
+ return(ret);
+ }
+ [CLSCompliant (false)]
+ public int Send (IList<ArraySegment<byte>> buffers,
+ SocketFlags socketFlags,
+ out SocketError errorCode)
+ {
+ if (disposed && closed) {
+ throw new ObjectDisposedException (GetType ().ToString ());
+ }
+
+ if (buffers == null) {
+ throw new ArgumentNullException ("buffers");
+ }
+
+ if (buffers.Count == 0) {
+ throw new ArgumentException ("Buffer is empty", "buffers");
+ }
+
+ int numsegments = buffers.Count;
int nativeError;
+ int ret;
+
+ WSABUF[] bufarray = new WSABUF[numsegments];
+ GCHandle[] gch = new GCHandle[numsegments];
+
+ for(int i = 0; i < numsegments; i++) {
+ ArraySegment<byte> segment = buffers[i];
+ 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 (socket, bufarray,
+ socketFlags,
+ out nativeError);
+ } finally {
+ for(int i = 0; i < numsegments; i++) {
+ if (gch[i].IsAllocated) {
+ gch[i].Free ();
+ }
+ }
+ }
+
+ errorCode = (SocketError)nativeError;
+ return(ret);
+ }
+
+ [MonoTODO ("Not implemented")]
+ public void SendFile (string fileName)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
- int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
+ if (!connected)
+ throw new NotSupportedException ();
- error = (SocketError)nativeError;
+ if (!blocking)
+ throw new InvalidOperationException ();
- if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
- connected = false;
- else
- connected = true;
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
- return ret;
+ /* FIXME: Implement TransmitFile */
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO ("Not implemented")]
+ public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
+ {
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+
+ if (!connected)
+ throw new NotSupportedException ();
+
+ if (!blocking)
+ throw new InvalidOperationException ();
+
+ if (!File.Exists (fileName))
+ throw new FileNotFoundException ();
+
+ /* FIXME: Implement TransmitFile */
+ throw new NotImplementedException ();
}
+ public bool SendToAsync (SocketAsyncEventArgs e)
+ {
+ // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
+
+ if (disposed && closed)
+ throw new ObjectDisposedException (GetType ().ToString ());
+ if (e.RemoteEndPoint == null)
+ throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+
+ e.DoOperation (SocketAsyncOperation.SendTo, this);
+
+ // We always return true for now
+ return true;
+ }
+#endif
+
public int SendTo (byte [] buffer, EndPoint remote_end)
{
if (disposed && closed)
return SendTo_nochecks (buffer, offset, size, flags, remote_end);
}
- int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
- EndPoint remote_end)
+ internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
+ EndPoint remote_end)
{
SocketAddress sockaddr = remote_end.Serialize ();
connected = true;
+#if NET_2_0
+ isbound = true;
+#endif
+
+ seed_endpoint = remote_end;
+
return ret;
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
- SocketOptionName name, object obj_val,
- byte [] byte_val, int int_val,
- out int error);
-
- public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, byte[] opt_value)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- int error;
+ // 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");
- SetSocketOption_internal(socket, level, name, null,
- opt_value, 0, out error);
-
- if (error != 0) {
- throw new SocketException (error);
- }
- }
-
- public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, int opt_value)
- {
- if (disposed && closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
int error;
-
- SetSocketOption_internal(socket, level, name, null,
- null, opt_value, out error);
+
+ SetSocketOption_internal (socket, optionLevel, optionName, null,
+ optionValue, 0, out error);
if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
throw new SocketException (error);
}
}
- public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, object opt_value)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
{
-
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
- if(opt_value==null) {
- throw new ArgumentNullException();
- }
+ // NOTE: if a null is passed, the byte[] overload is used instead...
+ if (optionValue == null)
+ throw new ArgumentNullException("optionValue");
int error;
- /* From MS documentation on SetSocketOption: "For an
- * option with a Boolean data type, specify a nonzero
- * value to enable the option, and a zero value to
- * disable the option."
- * Booleans are only handled in 2.0
- */
- if (opt_value is System.Boolean) {
+ if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
+ LingerOption linger = optionValue as LingerOption;
+ if (linger == null)
#if NET_2_0
- bool bool_val = (bool) opt_value;
- int int_val = (bool_val) ? 1 : 0;
-
- SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
+ throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
+#else
+ throw new ArgumentException ("optionValue");
+#endif
+ SetSocketOption_internal (socket, 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)
+#if NET_2_0
+ throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
#else
- throw new ArgumentException ("Use an integer 1 (true) or 0 (false) instead of a boolean.", "opt_value");
+ throw new ArgumentException ("optionValue");
#endif
+ SetSocketOption_internal (socket, 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)
+#if NET_2_0
+ throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
+#else
+ throw new ArgumentException ("optionValue");
+#endif
+ SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error);
} else {
- SetSocketOption_internal (socket, level, name, opt_value, null, 0, out error);
+#if NET_2_0
+ throw new ArgumentException ("Invalid value specified.", "optionValue");
+#else
+ throw new ArgumentException ("optionValue");
+#endif
}
- if (error != 0)
+ if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
throw new SocketException (error);
+ }
}
#if NET_2_0
- public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, bool optionValue)
+ public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
{
if (disposed && closed)
throw new ObjectDisposedException (GetType ().ToString ());
int error;
int int_val = (optionValue) ? 1 : 0;
- SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
- if (error != 0)
- throw new SocketException (error);
- }
-#endif
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how, out int error);
-
- public void Shutdown (SocketShutdown how)
- {
- if (disposed && closed)
- throw new ObjectDisposedException (GetType ().ToString ());
-
- int error;
-
- Shutdown_internal(socket, how, out error);
-
+ SetSocketOption_internal (socket, optionLevel, optionName, null, null, int_val, out error);
if (error != 0) {
+ if (error == (int) SocketError.InvalidArgument)
+ throw new ArgumentException ();
throw new SocketException (error);
}
}
+#endif
+#if ONLY_1_1
public override int GetHashCode ()
- {
- return (int) socket;
- }
-
- protected virtual void Dispose (bool explicitDisposing)
- {
- if (disposed)
- return;
-
- disposed = true;
- 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 ();
- blocking_thread = null;
- }
-
- if (error != 0)
- throw new SocketException (error);
- }
- }
-
- void IDisposable.Dispose ()
{
- Dispose (true);
- GC.SuppressFinalize (this);
- }
-
- ~Socket () {
- Dispose(false);
+ // LAMESPEC:
+ // The socket is not suitable to serve as a hash code,
+ // because it will change during its lifetime, but
+ // this is how MS.NET 1.1 implemented this method.
+ return (int) socket;
}
+#endif
}
}
-