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