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