2003-02-16 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
1 // System.Net.Sockets.Socket.cs
2 //
3 // Authors:
4 //    Phillip Pearson (pp@myelin.co.nz)
5 //    Dick Porter <dick@ximian.com>
6 //
7 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
8 //    http://www.myelin.co.nz
9 //
10
11 using System;
12 using System.Net;
13 using System.Collections;
14 using System.Runtime.CompilerServices;
15 using System.Threading;
16
17 namespace System.Net.Sockets 
18 {
19         public class Socket : IDisposable 
20         {
21                 private sealed class SocketAsyncResult: IAsyncResult 
22                 {
23                         private object state;
24                         private WaitHandle waithandle;
25                         private bool completed_sync, completed;
26                         private Worker worker;
27
28                         public SocketAsyncResult(object state) {
29                                 this.state=state;
30                                 waithandle=new ManualResetEvent(false);
31                                 completed_sync=completed=false;
32                         }
33
34                         public object AsyncState {
35                                 get {
36                                         return(state);
37                                 }
38                         }
39
40                         public WaitHandle AsyncWaitHandle {
41                                 get {
42                                         return(waithandle);
43                                 }
44                                 set {
45                                         waithandle=value;
46                                 }
47                         }
48
49                         public bool CompletedSynchronously {
50                                 get {
51                                         return(completed_sync);
52                                 }
53                         }
54
55                         public bool IsCompleted {
56                                 get {
57                                         return(completed);
58                                 }
59                                 set {
60                                         completed=value;
61                                 }
62                         }
63                         
64                         public Worker Worker {
65                                 get {
66                                         return(worker);
67                                 }
68                                 set {
69                                         worker=value;
70                                 }
71                         }
72                 }
73
74                 private sealed class Worker 
75                 {
76                         private AsyncCallback callback;
77                         private SocketAsyncResult result;
78                         private Socket socket;
79
80                         // Parameters
81                         private EndPoint endpoint;      // Connect,ReceiveFrom,SendTo
82                         private byte[] buffer;          // Receive,ReceiveFrom,Send,SendTo
83                         private int offset;             // Receive,ReceiveFrom,Send,SendTo
84                         private int size;               // Receive,ReceiveFrom,Send,SendTo
85                         private SocketFlags sockflags;  // Receive,ReceiveFrom,Send,SendTo
86
87                         // Return values
88                         private Socket acc_socket;
89                         private int total;
90                         
91
92                         // For Accept
93                         public Worker(Socket req_sock,
94                                       AsyncCallback req_callback,
95                                       SocketAsyncResult req_result)
96                                 : this(req_sock, null, 0, 0, SocketFlags.None,
97                                        null, req_callback, req_result) {}
98
99                         // For Connect
100                         public Worker(Socket req_sock, EndPoint req_endpoint,
101                                       AsyncCallback req_callback,
102                                       SocketAsyncResult req_result)
103                                 : this(req_sock, null, 0, 0, SocketFlags.None,
104                                        req_endpoint, req_callback,
105                                        req_result) {}
106
107                         // For Receive and Send
108                         public Worker(Socket req_sock, byte[] req_buffer,
109                                       int req_offset, int req_size,
110                                       SocketFlags req_sockflags,
111                                       AsyncCallback req_callback,
112                                       SocketAsyncResult req_result)
113                                 : this(req_sock, req_buffer, req_offset,
114                                        req_size, req_sockflags, null,
115                                        req_callback, req_result) {}
116
117                         // For ReceiveFrom and SendTo
118                         public Worker(Socket req_sock, byte[] req_buffer,
119                                       int req_offset, int req_size,
120                                       SocketFlags req_sockflags,
121                                       EndPoint req_endpoint,
122                                       AsyncCallback req_callback,
123                                       SocketAsyncResult req_result) {
124                                 socket=req_sock;
125                                 buffer=req_buffer;
126                                 offset=req_offset;
127                                 size=req_size;
128                                 sockflags=req_sockflags;
129                                 endpoint=req_endpoint;
130                                 callback=req_callback;
131                                 result=req_result;
132                         }
133
134                         private void End() {
135                                 ((ManualResetEvent)result.AsyncWaitHandle).Set();
136                                 result.IsCompleted=true;
137                                 callback(result);
138                         }
139                         
140                         public void Accept() {
141                                 lock(result) {
142                                         acc_socket=socket.Accept();
143                                         End();
144                                 }
145                         }
146
147                         public void Connect() {
148                                 lock(result) {
149                                         if (socket.Blocking) {
150                                                 socket.Connect(endpoint);
151                                                 End ();
152                                                 return;
153                                         }
154
155                                         SocketException rethrow = null;
156                                         try {
157                                                 socket.Connect (endpoint);
158                                         } catch (SocketException e) {
159                                                 //WSAEINPROGRESS
160                                                 if (e.NativeErrorCode != 10036)
161                                                         throw;
162
163                                                 socket.Poll (-1, SelectMode.SelectWrite);
164                                                 try {
165                                                         socket.Connect (endpoint);
166                                                 } catch (SocketException e2) {
167                                                         rethrow = e2;
168                                                 }
169                                         }
170                                         End ();
171                                         if (rethrow != null)
172                                                 throw rethrow;
173                                 }
174                         }
175
176                         public void Receive() {
177                                 lock(result) {
178                                         if (socket.Blocking) {
179                                                 total=socket.Receive(buffer, offset,
180                                                                      size, sockflags);
181                                                 End();
182                                                 return;
183                                         }
184
185                                         SocketException rethrow = null;
186                                         try {
187                                                 total = socket.Receive (buffer, offset, size, sockflags);
188                                         } catch (SocketException e) {
189                                                 //WSAEWOULDBLOCK
190                                                 if (e.NativeErrorCode != 10035)
191                                                         throw;
192
193                                                 socket.Poll (-1, SelectMode.SelectRead);
194                                                 try {
195                                                         total = socket.Receive (buffer, offset, size, sockflags);
196                                                 } catch (SocketException e2) {
197                                                         rethrow = e2;
198                                                 }
199                                         }
200                                         End ();
201                                         if (rethrow != null)
202                                                 throw rethrow;
203                                 }
204                         }
205
206                         public void ReceiveFrom() {
207                                 lock(result) {
208                                         total=socket.ReceiveFrom(buffer,
209                                                                  offset, size,
210                                                                  sockflags,
211                                                                  ref endpoint);
212                                         End();
213                                 }
214                         }
215
216                         public void Send() {
217                                 lock(result) {
218                                         total=socket.Send(buffer, offset, size,
219                                                           sockflags);
220                                         End();
221                                 }
222                         }
223
224                         public void SendTo() {
225                                 lock(result) {
226                                         total=socket.SendTo(buffer, offset,
227                                                             size, sockflags,
228                                                             endpoint);
229                                         End();
230                                 }
231                         }
232
233                         public EndPoint EndPoint {
234                                 get {
235                                         return(endpoint);
236                                 }
237                         }
238
239                         public Socket Socket {
240                                 get {
241                                         return(acc_socket);
242                                 }
243                         }
244
245                         public int Total {
246                                 get {
247                                         return(total);
248                                 }
249                         }
250                 }
251                         
252                 /* the field "socket" is looked up by name by the runtime */
253                 private IntPtr socket;
254                 private AddressFamily address_family;
255                 private SocketType socket_type;
256                 private ProtocolType protocol_type;
257                 private bool blocking=true;
258
259                 /* When true, the socket was connected at the time of
260                  * the last IO operation
261                  */
262                 private bool connected=false;
263                 
264                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
265                 private extern static void Select_internal(ref Socket[] read,
266                                                            ref Socket[] write,
267                                                            ref Socket[] err,
268                                                            int timeout);
269
270                 public static void Select(IList read_list, IList write_list,
271                                           IList err_list, int time_us) {
272                         if(read_list==null &&
273                            write_list==null &&
274                            err_list==null) {
275                                 throw new ArgumentNullException();
276                         }
277
278                         int read_count, write_count, err_count;
279
280                         if(read_list!=null) {
281                                 read_count=read_list.Count;
282                         } else {
283                                 read_count=0;
284                         }
285
286                         if(write_list!=null) {
287                                 write_count=write_list.Count;
288                         } else {
289                                 write_count=0;
290                         }
291
292                         if(err_list!=null) {
293                                 err_count=err_list.Count;
294                         } else {
295                                 err_count=0;
296                         }
297                         
298                         Socket[] read_arr=new Socket[read_count];
299                         Socket[] write_arr=new Socket[write_count];
300                         Socket[] err_arr=new Socket[err_count];
301
302                         int i;
303
304                         if(read_list!=null) {
305                                 i=0;
306                                 
307                                 foreach (Socket s in read_list) {
308                                         read_arr[i]=s;
309                                         i++;
310                                 }
311                         }
312
313                         if(write_list!=null) {
314                                 i=0;
315                                 foreach (Socket s in write_list) {
316                                         write_arr[i]=s;
317                                         i++;
318                                 }
319                         }
320                         
321                         if(err_list!=null) {
322                                 i=0;
323                                 foreach (Socket s in err_list) {
324                                         err_arr[i]=s;
325                                         i++;
326                                 }
327                         }
328
329                         Select_internal(ref read_arr, ref write_arr,
330                                         ref err_arr, time_us);
331
332                         if(read_list!=null) {
333                                 read_list.Clear();
334                                 for(i=0; i<read_arr.Length; i++) {
335                                         read_list.Add(read_arr[i]);
336                                 }
337                         }
338                         
339                         if(write_list!=null) {
340                                 write_list.Clear();
341                                 for(i=0; i<write_arr.Length; i++) {
342                                         write_list.Add(write_arr[i]);
343                                 }
344                         }
345                         
346                         if(err_list!=null) {
347                                 err_list.Clear();
348                                 for(i=0; i<err_arr.Length; i++) {
349                                         err_list.Add(err_arr[i]);
350                                 }
351                         }
352                 }
353
354                 // private constructor used by Accept, which already
355                 // has a socket handle to use
356                 private Socket(AddressFamily family, SocketType type,
357                                ProtocolType proto, IntPtr sock) {
358                         address_family=family;
359                         socket_type=type;
360                         protocol_type=proto;
361                         
362                         socket=sock;
363                         connected=true;
364                 }
365                 
366                 // Creates a new system socket, returning the handle
367                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
368                 private extern IntPtr Socket_internal(AddressFamily family,
369                                                       SocketType type,
370                                                       ProtocolType proto);
371                 
372                 public Socket(AddressFamily family, SocketType type,
373                               ProtocolType proto) {
374                         address_family=family;
375                         socket_type=type;
376                         protocol_type=proto;
377                         
378                         socket=Socket_internal(family, type, proto);
379                 }
380
381                 public AddressFamily AddressFamily {
382                         get {
383                                 return(address_family);
384                         }
385                 }
386
387                 // Returns the amount of data waiting to be read on socket
388                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
389                 private extern static int Available_internal(IntPtr socket);
390                 
391                 public int Available {
392                         get {
393                                 return(Available_internal(socket));
394                         }
395                 }
396
397                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
398                 private extern static void Blocking_internal(IntPtr socket,
399                                                             bool block);
400
401                 public bool Blocking {
402                         get {
403                                 return(blocking);
404                         }
405                         set {
406                                 Blocking_internal(socket, value);
407                                 blocking=value;
408                         }
409                 }
410
411                 public bool Connected {
412                         get {
413                                 return(connected);
414                         }
415                 }
416
417                 public IntPtr Handle {
418                         get {
419                                 return(socket);
420                         }
421                 }
422
423                 // Returns the local endpoint details in addr and port
424                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
425                 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
426
427                 [MonoTODO("Support non-IP endpoints")]
428                 public EndPoint LocalEndPoint {
429                         get {
430                                 SocketAddress sa;
431                                 
432                                 sa=LocalEndPoint_internal(socket);
433
434                                 if(sa.Family==AddressFamily.InterNetwork) {
435                                         // Stupidly, EndPoint.Create() is an
436                                         // instance method
437                                         return new IPEndPoint(0, 0).Create(sa);
438                                 } else {
439                                         throw new NotImplementedException();
440                                 }
441                         }
442                 }
443
444                 public ProtocolType ProtocolType {
445                         get {
446                                 return(protocol_type);
447                         }
448                 }
449
450                 // Returns the remote endpoint details in addr and port
451                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
452                 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
453
454                 [MonoTODO("Support non-IP endpoints")]
455                 public EndPoint RemoteEndPoint {
456                         get {
457                                 SocketAddress sa;
458                                 
459                                 sa=RemoteEndPoint_internal(socket);
460
461                                 if(sa.Family==AddressFamily.InterNetwork) {
462                                         // Stupidly, EndPoint.Create() is an
463                                         // instance method
464                                         return new IPEndPoint(0, 0).Create(sa);
465                                 } else {
466                                         throw new NotImplementedException();
467                                 }
468                         }
469                 }
470
471                 public SocketType SocketType {
472                         get {
473                                 return(socket_type);
474                         }
475                 }
476
477                 // Creates a new system socket, returning the handle
478                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
479                 private extern static IntPtr Accept_internal(IntPtr sock);
480                 
481                 public Socket Accept() {
482                         IntPtr sock=Accept_internal(socket);
483                         
484                         return(new Socket(this.AddressFamily, this.SocketType,
485                                           this.ProtocolType, sock));
486                 }
487
488                 public IAsyncResult BeginAccept(AsyncCallback callback,
489                                                 object state) {
490                         SocketAsyncResult req=new SocketAsyncResult(state);
491                         Worker worker=new Worker(this, callback, req);
492                         req.Worker=worker;
493                         Thread child=new Thread(new ThreadStart(worker.Accept));
494                         child.Start();
495                         return(req);
496                 }
497
498                 public IAsyncResult BeginConnect(EndPoint end_point,
499                                                  AsyncCallback callback,
500                                                  object state) {
501                         SocketAsyncResult req=new SocketAsyncResult(state);
502                         Worker worker=new Worker(this, end_point, callback,
503                                                  req);
504                         req.Worker=worker;
505                         Thread child=new Thread(new ThreadStart(worker.Connect));
506                         child.Start();
507                         return(req);
508                 }
509
510                 public IAsyncResult BeginReceive(byte[] buffer, int offset,
511                                                  int size,
512                                                  SocketFlags socket_flags,
513                                                  AsyncCallback callback,
514                                                  object state) {
515                         SocketAsyncResult req=new SocketAsyncResult(state);
516                         Worker worker=new Worker(this, buffer, offset, size,
517                                                  socket_flags, callback, req);
518                         req.Worker=worker;
519                         Thread child=new Thread(new ThreadStart(worker.Receive));
520                         child.Start();
521                         return(req);
522                 }
523
524                 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
525                                                      int size,
526                                                      SocketFlags socket_flags,
527                                                      ref EndPoint remote_end,
528                                                      AsyncCallback callback,
529                                                      object state) {
530                         SocketAsyncResult req=new SocketAsyncResult(state);
531                         Worker worker=new Worker(this, buffer, offset, size,
532                                                  socket_flags, remote_end,
533                                                  callback, req);
534                         req.Worker=worker;
535                         Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
536                         child.Start();
537                         return(req);
538                 }
539
540                 public IAsyncResult BeginSend(byte[] buffer, int offset,
541                                               int size,
542                                               SocketFlags socket_flags,
543                                               AsyncCallback callback,
544                                               object state) {
545                         SocketAsyncResult req=new SocketAsyncResult(state);
546                         Worker worker=new Worker(this, buffer, offset, size,
547                                                  socket_flags, callback, req);
548                         req.Worker=worker;
549                         Thread child=new Thread(new ThreadStart(worker.Send));
550                         child.Start();
551                         return(req);
552                 }
553
554                 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
555                                                 int size,
556                                                 SocketFlags socket_flags,
557                                                 EndPoint remote_end,
558                                                 AsyncCallback callback,
559                                                 object state) {
560                         SocketAsyncResult req=new SocketAsyncResult(state);
561                         Worker worker=new Worker(this, buffer, offset, size,
562                                                  socket_flags, remote_end,
563                                                  callback, req);
564                         req.Worker=worker;
565                         Thread child=new Thread(new ThreadStart(worker.SendTo));
566                         child.Start();
567                         return(req);
568                 }
569
570                 // Creates a new system socket, returning the handle
571                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
572                 private extern static void Bind_internal(IntPtr sock,
573                                                          SocketAddress sa);
574
575                 public void Bind(EndPoint local_end) {
576                         if(local_end==null) {
577                                 throw new ArgumentNullException();
578                         }
579                         
580                         Bind_internal(socket, local_end.Serialize());
581                 }
582
583                 // Closes the socket
584                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
585                 private extern static void Close_internal(IntPtr socket);
586                 
587                 public void Close() {
588                         this.Dispose();
589                 }
590
591                 // Connects to the remote address
592                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593                 private extern static void Connect_internal(IntPtr sock,
594                                                             SocketAddress sa);
595
596                 public void Connect(EndPoint remote_end) {
597                         if(remote_end==null) {
598                                 throw new ArgumentNullException();
599                         }
600                         
601                         Connect_internal(socket, remote_end.Serialize());
602                         connected=true;
603                 }
604                 
605                 public Socket EndAccept(IAsyncResult result) {
606                         SocketAsyncResult req=(SocketAsyncResult)result;
607
608                         result.AsyncWaitHandle.WaitOne();
609                         return(req.Worker.Socket);
610                 }
611
612                 public void EndConnect(IAsyncResult result) {
613                         SocketAsyncResult req=(SocketAsyncResult)result;
614
615                         result.AsyncWaitHandle.WaitOne();
616                 }
617
618                 public int EndReceive(IAsyncResult result) {
619                         SocketAsyncResult req=(SocketAsyncResult)result;
620
621                         result.AsyncWaitHandle.WaitOne();
622                         return(req.Worker.Total);
623                 }
624
625                 public int EndReceiveFrom(IAsyncResult result,
626                                           ref EndPoint end_point) {
627                         SocketAsyncResult req=(SocketAsyncResult)result;
628
629                         result.AsyncWaitHandle.WaitOne();
630                         end_point=req.Worker.EndPoint;
631                         return(req.Worker.Total);
632                 }
633
634                 public int EndSend(IAsyncResult result) {
635                         SocketAsyncResult req=(SocketAsyncResult)result;
636
637                         result.AsyncWaitHandle.WaitOne();
638                         return(req.Worker.Total);
639                 }
640
641                 public int EndSendTo(IAsyncResult result) {
642                         SocketAsyncResult req=(SocketAsyncResult)result;
643
644                         result.AsyncWaitHandle.WaitOne();
645                         return(req.Worker.Total);
646                 }
647
648                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
649                 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
650                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
651                 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
652
653                 public object GetSocketOption(SocketOptionLevel level,
654                                               SocketOptionName name) {
655                         object obj_val;
656                         
657                         GetSocketOption_obj_internal(socket, level, name,
658                                                      out obj_val);
659                         
660                         if(name==SocketOptionName.Linger) {
661                                 return((LingerOption)obj_val);
662                         } else if (name==SocketOptionName.AddMembership ||
663                                    name==SocketOptionName.DropMembership) {
664                                 return((MulticastOption)obj_val);
665                         } else {
666                                 return((int)obj_val);
667                         }
668                 }
669
670                 public void GetSocketOption(SocketOptionLevel level,
671                                             SocketOptionName name,
672                                             byte[] opt_value) {
673                         int opt_value_len=opt_value.Length;
674                         
675                         GetSocketOption_arr_internal(socket, level, name,
676                                                      ref opt_value);
677                 }
678
679                 public byte[] GetSocketOption(SocketOptionLevel level,
680                                               SocketOptionName name,
681                                               int length) {
682                         byte[] byte_val=new byte[length];
683                         
684                         GetSocketOption_arr_internal(socket, level, name,
685                                                      ref byte_val);
686
687                         return(byte_val);
688                 }
689
690                 [MonoTODO("Totally undocumented")]
691                 public int IOControl(int ioctl_code, byte[] in_value,
692                                      byte[] out_value) {
693                         throw new NotImplementedException();
694                 }
695
696                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
697                 private extern static void Listen_internal(IntPtr sock,
698                                                            int backlog);
699
700                 public void Listen(int backlog) {
701                         Listen_internal(socket, backlog);
702                 }
703
704                 /* The docs for Poll() are a bit lightweight too, but
705                  * it seems to be just a simple wrapper around Select.
706                  */
707                 public bool Poll(int time_us, SelectMode mode) {
708                         ArrayList socketlist=new ArrayList(1);
709
710                         socketlist.Add(this);
711                         
712                         switch(mode) {
713                         case SelectMode.SelectError:
714                                 Select(null, null, socketlist, time_us);
715                                 break;
716                         case SelectMode.SelectRead:
717                                 Select(socketlist, null, null, time_us);
718                                 break;
719                         case SelectMode.SelectWrite:
720                                 Select(null, socketlist, null, time_us);
721                                 break;
722                         default:
723                                 throw new NotSupportedException();
724                         }
725
726                         if(socketlist.Contains(this)) {
727                                 return(true);
728                         } else {
729                                 return(false);
730                         }
731                 }
732                 
733                 public int Receive(byte[] buf) {
734                         return(Receive(buf, 0, buf.Length, SocketFlags.None));
735                 }
736
737                 public int Receive(byte[] buf, SocketFlags flags) {
738                         return(Receive(buf, 0, buf.Length, flags));
739                 }
740
741                 public int Receive(byte[] buf, int size, SocketFlags flags) {
742                         return(Receive(buf, 0, size, flags));
743                 }
744
745                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
746                 private extern static int Receive_internal(IntPtr sock,
747                                                            byte[] buffer,
748                                                            int offset,
749                                                            int count,
750                                                            SocketFlags flags);
751
752                 public int Receive(byte[] buf, int offset, int size,
753                                    SocketFlags flags) {
754                         if(buf==null) {
755                                 throw new ArgumentNullException("buffer is null");
756                         }
757                         if(offset<0 || offset >= buf.Length) {
758                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
759                         }
760                         if(offset+size<0 || offset+size > buf.Length) {
761                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
762                         }
763                         
764                         int ret;
765                         
766                         try {
767                                 ret=Receive_internal(socket, buf, offset,
768                                                      size, flags);
769                         } catch(SocketException) {
770                                 connected=false;
771                                 throw;
772                         }
773                         connected=true;
774
775                         return(ret);
776                 }
777                 
778                 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
779                         return(ReceiveFrom(buf, 0, buf.Length,
780                                            SocketFlags.None, ref remote_end));
781                 }
782
783                 public int ReceiveFrom(byte[] buf, SocketFlags flags,
784                                        ref EndPoint remote_end) {
785                         return(ReceiveFrom(buf, 0, buf.Length, flags,
786                                            ref remote_end));
787                 }
788
789                 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
790                                        ref EndPoint remote_end) {
791                         return(ReceiveFrom(buf, 0, size, flags,
792                                            ref remote_end));
793                 }
794
795
796                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
797                 private extern static int RecvFrom_internal(IntPtr sock,
798                                                             byte[] buffer,
799                                                             int offset,
800                                                             int count,
801                                                             SocketFlags flags,
802                                                             ref SocketAddress sockaddr);
803
804                 public int ReceiveFrom(byte[] buf, int offset, int size,
805                                        SocketFlags flags,
806                                        ref EndPoint remote_end) {
807                         if(buf==null) {
808                                 throw new ArgumentNullException("buffer is null");
809                         }
810                         if(remote_end==null) {
811                                 throw new ArgumentNullException("remote endpoint is null");
812                         }
813                         if(offset<0 || offset>=buf.Length) {
814                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
815                         }
816                         if(offset+size<0 || offset+size>buf.Length) {
817                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
818                         }
819
820                         SocketAddress sockaddr=remote_end.Serialize();
821                         int count;
822
823                         try {
824                                 count=RecvFrom_internal(socket, buf, offset,
825                                                         size, flags,
826                                                         ref sockaddr);
827                         } catch(SocketException) {
828                                 connected=false;
829                                 throw;
830                         }
831                         connected=true;
832                         
833                         // Stupidly, EndPoint.Create() is an
834                         // instance method
835                         remote_end=remote_end.Create(sockaddr);
836
837                         return(count);
838                 }
839
840                 public int Send(byte[] buf) {
841                         return(Send(buf, 0, buf.Length, SocketFlags.None));
842                 }
843
844                 public int Send(byte[] buf, SocketFlags flags) {
845                         return(Send(buf, 0, buf.Length, flags));
846                 }
847
848                 public int Send(byte[] buf, int size, SocketFlags flags) {
849                         return(Send(buf, 0, size, flags));
850                 }
851
852                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
853                 private extern static int Send_internal(IntPtr sock,
854                                                         byte[] buf, int offset,
855                                                         int count,
856                                                         SocketFlags flags);
857
858                 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
859                 {
860                         if (buf == null)
861                                 throw new ArgumentNullException ("buffer");
862
863                         if (offset < 0 || offset > buf.Length)
864                                 throw new ArgumentOutOfRangeException ("offset");
865
866                         if (size < 0 || offset + size > buf.Length)
867                                 throw new ArgumentOutOfRangeException ("size");
868
869                         if (size == 0)
870                                 return 0;
871
872                         int ret;
873
874                         try {
875                                 ret = Send_internal (socket, buf, offset, size, flags);
876                         } catch (SocketException) {
877                                 connected = false;
878                                 throw;
879                         }
880                         connected = true;
881
882                         return ret;
883                 }
884
885                 public int SendTo(byte[] buffer, EndPoint remote_end) {
886                         return(SendTo(buffer, 0, buffer.Length,
887                                       SocketFlags.None, remote_end));
888                 }
889
890                 public int SendTo(byte[] buffer, SocketFlags flags,
891                                   EndPoint remote_end) {
892                         return(SendTo(buffer, 0, buffer.Length, flags,
893                                       remote_end));
894                 }
895
896                 public int SendTo(byte[] buffer, int size, SocketFlags flags,
897                                   EndPoint remote_end) {
898                         return(SendTo(buffer, size, buffer.Length, flags,
899                                       remote_end));
900                 }
901
902
903                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
904                 private extern static int SendTo_internal(IntPtr sock,
905                                                           byte[] buffer,
906                                                           int offset,
907                                                           int count,
908                                                           SocketFlags flags,
909                                                           SocketAddress sa);
910
911                 public int SendTo(byte[] buffer, int offset, int size,
912                                   SocketFlags flags, EndPoint remote_end) {
913                         if(buffer==null) {
914                                 throw new ArgumentNullException("buffer is null");
915                         }
916                         if(remote_end==null) {
917                                 throw new ArgumentNullException("remote endpoint is null");
918                         }
919                         if(offset<0 || offset>=buffer.Length) {
920                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
921                         }
922                         if(offset+size<0 || offset+size>buffer.Length) {
923                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
924                         }
925
926                         SocketAddress sockaddr=remote_end.Serialize();
927
928                         int ret;
929
930                         try {
931                                 ret=SendTo_internal(socket, buffer, offset,
932                                                     size, flags, sockaddr);
933                         }
934                         catch(SocketException) {
935                                 connected=false;
936                                 throw;
937                         }
938                         connected=true;
939
940                         return(ret);
941                 }
942
943                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
944                 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
945
946                 public void SetSocketOption(SocketOptionLevel level,
947                                             SocketOptionName name,
948                                             byte[] opt_value) {
949                         SetSocketOption_internal(socket, level, name, null,
950                                                  opt_value, 0);
951                 }
952
953                 public void SetSocketOption(SocketOptionLevel level,
954                                             SocketOptionName name,
955                                             int opt_value) {
956                         SetSocketOption_internal(socket, level, name, null,
957                                                  null, opt_value);
958                 }
959
960                 public void SetSocketOption(SocketOptionLevel level,
961                                             SocketOptionName name,
962                                             object opt_value) {
963                         if(opt_value==null) {
964                                 throw new ArgumentNullException();
965                         }
966                         
967                         /* Passing a bool as the third parameter to
968                          * SetSocketOption causes this overload to be
969                          * used when in fact we want to pass the value
970                          * to the runtime as an int.
971                          */
972                         if(opt_value is System.Boolean) {
973                                 bool bool_val=(bool)opt_value;
974                                 
975                                 /* Stupid casting rules :-( */
976                                 if(bool_val==true) {
977                                         SetSocketOption_internal(socket, level,
978                                                                  name, null,
979                                                                  null, 1);
980                                 } else {
981                                         SetSocketOption_internal(socket, level,
982                                                                  name, null,
983                                                                  null, 0);
984                                 }
985                         } else {
986                                 SetSocketOption_internal(socket, level, name,
987                                                          opt_value, null, 0);
988                         }
989                 }
990
991                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
992                 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
993                 
994                 public void Shutdown(SocketShutdown how) {
995                         Shutdown_internal(socket, how);
996                 }
997
998                 private bool disposed = false;
999                 
1000                 protected virtual void Dispose(bool explicitDisposing) {
1001                         // Check to see if Dispose has already been called
1002                         if(!this.disposed) {
1003                                 // If this is a call to Dispose,
1004                                 // dispose all managed resources.
1005                                 if(explicitDisposing) {
1006                                         // Free up stuff here
1007                                 }
1008
1009                                 // Release unmanaged resources
1010                                 this.disposed=true;
1011                         
1012                                 connected=false;
1013                                 Close_internal(socket);
1014                         }
1015                 }
1016
1017                 public void Dispose() {
1018                         Dispose(true);
1019                         // Take yourself off the Finalization queue
1020                         GC.SuppressFinalize(this);
1021                 }
1022
1023                 ~Socket () {
1024                         Dispose(false);
1025                 }
1026         }
1027 }