// System.Net.Sockets.Socket.cs // // Authors: // Phillip Pearson (pp@myelin.co.nz) // Dick Porter // // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc. // http://www.myelin.co.nz // using System; using System.Net; using System.Collections; using System.Runtime.CompilerServices; using System.Threading; namespace System.Net.Sockets { public class Socket : IDisposable { private sealed class SocketAsyncResult: IAsyncResult { private object state; private WaitHandle waithandle; private bool completed_sync, completed; private Worker worker; public SocketAsyncResult(object state) { this.state=state; waithandle=new ManualResetEvent(false); completed_sync=completed=false; } public object AsyncState { get { return(state); } } public WaitHandle AsyncWaitHandle { get { return(waithandle); } set { waithandle=value; } } public bool CompletedSynchronously { get { return(completed_sync); } } public bool IsCompleted { get { return(completed); } set { completed=value; } } public Worker Worker { get { return(worker); } set { worker=value; } } } private sealed class Worker { private AsyncCallback callback; private SocketAsyncResult result; private Socket socket; // Parameters private EndPoint endpoint; // Connect,ReceiveFrom,SendTo private byte[] buffer; // Receive,ReceiveFrom,Send,SendTo private int offset; // Receive,ReceiveFrom,Send,SendTo private int size; // Receive,ReceiveFrom,Send,SendTo private SocketFlags sockflags; // Receive,ReceiveFrom,Send,SendTo // Return values private Socket acc_socket; private int total; // For Accept public Worker(Socket req_sock, AsyncCallback req_callback, SocketAsyncResult req_result) : this(req_sock, null, 0, 0, SocketFlags.None, null, req_callback, req_result) {} // For Connect public Worker(Socket req_sock, EndPoint req_endpoint, AsyncCallback req_callback, SocketAsyncResult req_result) : this(req_sock, null, 0, 0, SocketFlags.None, req_endpoint, req_callback, req_result) {} // For Receive and Send public Worker(Socket req_sock, byte[] req_buffer, int req_offset, int req_size, SocketFlags req_sockflags, AsyncCallback req_callback, SocketAsyncResult req_result) : this(req_sock, req_buffer, req_offset, req_size, req_sockflags, null, req_callback, req_result) {} // For ReceiveFrom and SendTo public Worker(Socket req_sock, byte[] req_buffer, int req_offset, int req_size, SocketFlags req_sockflags, EndPoint req_endpoint, AsyncCallback req_callback, SocketAsyncResult req_result) { socket=req_sock; buffer=req_buffer; offset=req_offset; size=req_size; sockflags=req_sockflags; endpoint=req_endpoint; callback=req_callback; result=req_result; } private void End() { ((ManualResetEvent)result.AsyncWaitHandle).Set(); callback(result); result.IsCompleted=true; } public void Accept() { lock(result) { acc_socket=socket.Accept(); End(); } } public void Connect() { lock(result) { socket.Connect(endpoint); End(); } } public void Receive() { lock(result) { total=socket.Receive(buffer, offset, size, sockflags); End(); } } public void ReceiveFrom() { lock(result) { total=socket.ReceiveFrom(buffer, offset, size, sockflags, ref endpoint); End(); } } public void Send() { lock(result) { total=socket.Send(buffer, offset, size, sockflags); End(); } } public void SendTo() { lock(result) { total=socket.SendTo(buffer, offset, size, sockflags, endpoint); End(); } } public EndPoint EndPoint { get { return(endpoint); } } public Socket Socket { get { return(acc_socket); } } public int Total { get { return(total); } } } /* 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; private bool blocking=true; /* When true, the socket was connected at the time of * the last IO operation */ private bool connected=false; [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static void Select_internal(ref Socket[] read, ref Socket[] write, ref Socket[] err, int timeout); public static void Select(IList read_list, IList write_list, IList err_list, int time_us) { if(read_list==null && write_list==null && err_list==null) { throw new ArgumentNullException(); } int read_count, write_count, err_count; if(read_list!=null) { read_count=read_list.Count; } else { read_count=0; } if(write_list!=null) { write_count=write_list.Count; } else { write_count=0; } if(err_list!=null) { err_count=err_list.Count; } else { err_count=0; } Socket[] read_arr=new Socket[read_count]; Socket[] write_arr=new Socket[write_count]; Socket[] err_arr=new Socket[err_count]; int i; if(read_list!=null) { i=0; foreach (Socket s in read_list) { read_arr[i]=s; i++; } } if(write_list!=null) { i=0; foreach (Socket s in write_list) { write_arr[i]=s; i++; } } if(err_list!=null) { i=0; foreach (Socket s in err_list) { err_arr[i]=s; i++; } } Select_internal(ref read_arr, ref write_arr, ref err_arr, time_us); if(read_list!=null) { read_list.Clear(); for(i=0; ibuf.Length) { throw new ArgumentException(); } int ret; try { ret=Receive_internal(socket, buf, offset, size, flags); } catch(SocketException) { connected=false; throw; } connected=true; return(ret); } public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) { return(ReceiveFrom(buf, 0, buf.Length, SocketFlags.None, ref remote_end)); } public int ReceiveFrom(byte[] buf, SocketFlags flags, ref EndPoint remote_end) { return(ReceiveFrom(buf, 0, buf.Length, flags, ref remote_end)); } public int ReceiveFrom(byte[] buf, int size, SocketFlags flags, ref EndPoint remote_end) { return(ReceiveFrom(buf, 0, size, flags, ref remote_end)); } [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static int RecvFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr); public int ReceiveFrom(byte[] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end) { if(buf==null || remote_end==null) { throw new ArgumentNullException(); } if(offset+size>buf.Length) { throw new ArgumentException(); } SocketAddress sockaddr=remote_end.Serialize(); int count; try { count=RecvFrom_internal(socket, buf, offset, size, flags, ref sockaddr); } catch(SocketException) { connected=false; throw; } connected=true; // Stupidly, EndPoint.Create() is an // instance method remote_end=remote_end.Create(sockaddr); return(count); } public int Send(byte[] buf) { return(Send(buf, 0, buf.Length, SocketFlags.None)); } public int Send(byte[] buf, SocketFlags flags) { return(Send(buf, 0, buf.Length, flags)); } public int Send(byte[] buf, int size, SocketFlags flags) { return(Send(buf, 0, size, flags)); } [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags); public int Send(byte[] buf, int offset, int size, SocketFlags flags) { if(buf==null) { throw new ArgumentNullException(); } if(offset+size>buf.Length) { throw new ArgumentException(); } int ret; try { ret=Send_internal(socket, buf, offset, size, flags); } catch(SocketException) { connected=false; throw; } connected=true; return(ret); } public int SendTo(byte[] buffer, EndPoint remote_end) { return(SendTo(buffer, 0, buffer.Length, SocketFlags.None, remote_end)); } public int SendTo(byte[] buffer, SocketFlags flags, EndPoint remote_end) { return(SendTo(buffer, 0, buffer.Length, flags, remote_end)); } public int SendTo(byte[] buffer, int size, SocketFlags flags, EndPoint remote_end) { return(SendTo(buffer, size, buffer.Length, flags, remote_end)); } [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static int SendTo_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa); public int SendTo(byte[] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end) { if(buffer==null || remote_end==null) { throw new ArgumentNullException(); } if(offset+size>buffer.Length) { throw new ArgumentException(); } SocketAddress sockaddr=remote_end.Serialize(); int ret; try { ret=SendTo_internal(socket, buffer, offset, size, flags, sockaddr); } catch(SocketException) { connected=false; throw; } connected=true; 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); public void SetSocketOption(SocketOptionLevel level, SocketOptionName name, byte[] opt_value) { SetSocketOption_internal(socket, level, name, null, opt_value, 0); } public void SetSocketOption(SocketOptionLevel level, SocketOptionName name, int opt_value) { SetSocketOption_internal(socket, level, name, null, null, opt_value); } public void SetSocketOption(SocketOptionLevel level, SocketOptionName name, object opt_value) { if(opt_value==null) { throw new ArgumentNullException(); } /* Passing a bool as the third parameter to * SetSocketOption causes this overload to be * used when in fact we want to pass the value * to the runtime as an int. */ if(opt_value is System.Boolean) { bool bool_val=(bool)opt_value; /* Stupid casting rules :-( */ if(bool_val==true) { SetSocketOption_internal(socket, level, name, null, null, 1); } else { SetSocketOption_internal(socket, level, name, null, null, 0); } } else { SetSocketOption_internal(socket, level, name, opt_value, null, 0); } } [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how); public void Shutdown(SocketShutdown how) { Shutdown_internal(socket, how); } private bool disposed = false; protected virtual void Dispose(bool explicitDisposing) { // Check to see if Dispose has already been called if(!this.disposed) { // If this is a call to Dispose, // dispose all managed resources. if(explicitDisposing) { // Free up stuff here } // Release unmanaged resources this.disposed=true; this.Close(); } } public void Dispose() { Dispose(true); // Take yourself off the Finalization queue GC.SuppressFinalize(this); } ~Socket () { Dispose(false); } } }