2002-10-08 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("buffer is null");
713                         }
714                         if(offset<0 || offset >= buf.Length) {
715                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
716                         }
717                         if(offset+size<0 || offset+size > buf.Length) {
718                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
719                         }
720                         
721                         int ret;
722                         
723                         try {
724                                 ret=Receive_internal(socket, buf, offset,
725                                                      size, flags);
726                         } catch(SocketException) {
727                                 connected=false;
728                                 throw;
729                         }
730                         connected=true;
731
732                         return(ret);
733                 }
734                 
735                 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
736                         return(ReceiveFrom(buf, 0, buf.Length,
737                                            SocketFlags.None, ref remote_end));
738                 }
739
740                 public int ReceiveFrom(byte[] buf, SocketFlags flags,
741                                        ref EndPoint remote_end) {
742                         return(ReceiveFrom(buf, 0, buf.Length, flags,
743                                            ref remote_end));
744                 }
745
746                 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
747                                        ref EndPoint remote_end) {
748                         return(ReceiveFrom(buf, 0, size, flags,
749                                            ref remote_end));
750                 }
751
752
753                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
754                 private extern static int RecvFrom_internal(IntPtr sock,
755                                                             byte[] buffer,
756                                                             int offset,
757                                                             int count,
758                                                             SocketFlags flags,
759                                                             ref SocketAddress sockaddr);
760
761                 public int ReceiveFrom(byte[] buf, int offset, int size,
762                                        SocketFlags flags,
763                                        ref EndPoint remote_end) {
764                         if(buf==null) {
765                                 throw new ArgumentNullException("buffer is null");
766                         }
767                         if(remote_end==null) {
768                                 throw new ArgumentNullException("remote endpoint is null");
769                         }
770                         if(offset<0 || offset>=buf.Length) {
771                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
772                         }
773                         if(offset+size<0 || offset+size>buf.Length) {
774                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
775                         }
776
777                         SocketAddress sockaddr=remote_end.Serialize();
778                         int count;
779
780                         try {
781                                 count=RecvFrom_internal(socket, buf, offset,
782                                                         size, flags,
783                                                         ref sockaddr);
784                         } catch(SocketException) {
785                                 connected=false;
786                                 throw;
787                         }
788                         connected=true;
789                         
790                         // Stupidly, EndPoint.Create() is an
791                         // instance method
792                         remote_end=remote_end.Create(sockaddr);
793
794                         return(count);
795                 }
796
797                 public int Send(byte[] buf) {
798                         return(Send(buf, 0, buf.Length, SocketFlags.None));
799                 }
800
801                 public int Send(byte[] buf, SocketFlags flags) {
802                         return(Send(buf, 0, buf.Length, flags));
803                 }
804
805                 public int Send(byte[] buf, int size, SocketFlags flags) {
806                         return(Send(buf, 0, size, flags));
807                 }
808
809                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
810                 private extern static int Send_internal(IntPtr sock,
811                                                         byte[] buf, int offset,
812                                                         int count,
813                                                         SocketFlags flags);
814
815                 public int Send(byte[] buf, int offset, int size,
816                                 SocketFlags flags) {
817                         if(buf==null) {
818                                 throw new ArgumentNullException("buffer is null");
819                         }
820                         if(offset<0 || offset>=buf.Length) {
821                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
822                         }
823                         if(offset+size<0 || offset+size>buf.Length) {
824                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
825                         }
826
827                         int ret;
828
829                         try {
830                                 ret=Send_internal(socket, buf, offset, size,
831                                                   flags);
832                         } catch(SocketException) {
833                                 connected=false;
834                                 throw;
835                         }
836                         connected=true;
837
838                         return(ret);
839                 }
840
841                 public int SendTo(byte[] buffer, EndPoint remote_end) {
842                         return(SendTo(buffer, 0, buffer.Length,
843                                       SocketFlags.None, remote_end));
844                 }
845
846                 public int SendTo(byte[] buffer, SocketFlags flags,
847                                   EndPoint remote_end) {
848                         return(SendTo(buffer, 0, buffer.Length, flags,
849                                       remote_end));
850                 }
851
852                 public int SendTo(byte[] buffer, int size, SocketFlags flags,
853                                   EndPoint remote_end) {
854                         return(SendTo(buffer, size, buffer.Length, flags,
855                                       remote_end));
856                 }
857
858
859                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
860                 private extern static int SendTo_internal(IntPtr sock,
861                                                           byte[] buffer,
862                                                           int offset,
863                                                           int count,
864                                                           SocketFlags flags,
865                                                           SocketAddress sa);
866
867                 public int SendTo(byte[] buffer, int offset, int size,
868                                   SocketFlags flags, EndPoint remote_end) {
869                         if(buffer==null) {
870                                 throw new ArgumentNullException("buffer is null");
871                         }
872                         if(remote_end==null) {
873                                 throw new ArgumentNullException("remote endpoint is null");
874                         }
875                         if(offset<0 || offset>=buffer.Length) {
876                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
877                         }
878                         if(offset+size<0 || offset+size>buffer.Length) {
879                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
880                         }
881
882                         SocketAddress sockaddr=remote_end.Serialize();
883
884                         int ret;
885
886                         try {
887                                 ret=SendTo_internal(socket, buffer, offset,
888                                                     size, flags, sockaddr);
889                         }
890                         catch(SocketException) {
891                                 connected=false;
892                                 throw;
893                         }
894                         connected=true;
895
896                         return(ret);
897                 }
898
899                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
900                 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
901
902                 public void SetSocketOption(SocketOptionLevel level,
903                                             SocketOptionName name,
904                                             byte[] opt_value) {
905                         SetSocketOption_internal(socket, level, name, null,
906                                                  opt_value, 0);
907                 }
908
909                 public void SetSocketOption(SocketOptionLevel level,
910                                             SocketOptionName name,
911                                             int opt_value) {
912                         SetSocketOption_internal(socket, level, name, null,
913                                                  null, opt_value);
914                 }
915
916                 public void SetSocketOption(SocketOptionLevel level,
917                                             SocketOptionName name,
918                                             object opt_value) {
919                         if(opt_value==null) {
920                                 throw new ArgumentNullException();
921                         }
922                         
923                         /* Passing a bool as the third parameter to
924                          * SetSocketOption causes this overload to be
925                          * used when in fact we want to pass the value
926                          * to the runtime as an int.
927                          */
928                         if(opt_value is System.Boolean) {
929                                 bool bool_val=(bool)opt_value;
930                                 
931                                 /* Stupid casting rules :-( */
932                                 if(bool_val==true) {
933                                         SetSocketOption_internal(socket, level,
934                                                                  name, null,
935                                                                  null, 1);
936                                 } else {
937                                         SetSocketOption_internal(socket, level,
938                                                                  name, null,
939                                                                  null, 0);
940                                 }
941                         } else {
942                                 SetSocketOption_internal(socket, level, name,
943                                                          opt_value, null, 0);
944                         }
945                 }
946
947                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
948                 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
949                 
950                 public void Shutdown(SocketShutdown how) {
951                         Shutdown_internal(socket, how);
952                 }
953
954                 private bool disposed = false;
955                 
956                 protected virtual void Dispose(bool explicitDisposing) {
957                         // Check to see if Dispose has already been called
958                         if(!this.disposed) {
959                                 // If this is a call to Dispose,
960                                 // dispose all managed resources.
961                                 if(explicitDisposing) {
962                                         // Free up stuff here
963                                 }
964
965                                 // Release unmanaged resources
966                                 this.disposed=true;
967                                 this.Close();
968                         }
969                 }
970
971                 public void Dispose() {
972                         Dispose(true);
973                         // Take yourself off the Finalization queue
974                         GC.SuppressFinalize(this);
975                 }
976
977                 ~Socket () {
978                         Dispose(false);
979                 }
980         }
981 }