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