Merge pull request #3796 from ntherning/windows-backend-for-MemoryMappedFile
[mono.git] / mcs / class / Mono.Posix / Test / Mono.Unix.Native / SocketTest.cs
1 //
2 // socket-related test cases
3 //
4 // Authors:
5 //  Steffen Kiess (s-kiess@web.de)
6 //
7 // Copyright (C) 2015 Steffen Kiess
8 //
9
10 using System;
11 using System.IO;
12 using System.Net;
13 using System.Net.Sockets;
14 using System.Runtime.InteropServices;
15
16 using Mono.Unix;
17 using Mono.Unix.Native;
18
19 using NUnit.Framework;
20
21 namespace MonoTests.Mono.Unix.Native
22 {
23         [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")]
24         public class SocketTest {
25
26                 string TempFolder;
27
28                 [SetUp]
29                 public void SetUp ()
30                 {
31                         TempFolder = Path.Combine (Path.GetTempPath (), this.GetType ().FullName);
32
33                         if (Directory.Exists (TempFolder))
34                                 Directory.Delete (TempFolder, true);
35
36                         Directory.CreateDirectory (TempFolder);
37                 }
38
39                 [TearDown]
40                 public void TearDown()
41                 {
42                         if (Directory.Exists (TempFolder))
43                                 Directory.Delete (TempFolder, true);
44                 }
45
46                 // Set a timeout on all sockets to make sure that if a test fails it
47                 // won't cause the program to hang
48                 void SetTimeout (int socket)
49                 {
50                         var timeout = new Timeval {
51                                 tv_sec = 0,
52                                 tv_usec = 500000,
53                         };
54                         if (Syscall.setsockopt (socket, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_RCVTIMEO, timeout) < 0 ||
55                                         Syscall.setsockopt (socket, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_SNDTIMEO, timeout) < 0)
56                                 UnixMarshal.ThrowExceptionForLastError ();
57                 }
58
59                 void WithSocketPair (Action<int, int> f)
60                 {
61                         int socket1, socket2;
62                         if (Syscall.socketpair (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, out socket1, out socket2) < 0)
63                                 UnixMarshal.ThrowExceptionForLastError ();
64                         try {
65                                 SetTimeout (socket1);
66                                 SetTimeout (socket2);
67
68                                 f (socket1, socket2);
69                         } finally {
70                                 int r0 = Syscall.close (socket1);
71                                 int r1 = Syscall.close (socket2);
72                                 if (r0 < 0 || r1 < 0)
73                                         UnixMarshal.ThrowExceptionForLastError ();
74                         }
75                 }
76
77                 void WithSockets (UnixAddressFamily af, UnixSocketType type, UnixSocketProtocol protocol, Action<int, int> f)
78                 {
79                         int so1, so2;
80                         if ((so1 = Syscall.socket (af, type, protocol)) < 0)
81                                 UnixMarshal.ThrowExceptionForLastError ();
82                         try {
83                                 if ((so2 = Syscall.socket (af, type, protocol)) < 0)
84                                         UnixMarshal.ThrowExceptionForLastError ();
85                                 try {
86                                         SetTimeout (so1);
87                                         SetTimeout (so2);
88
89                                         f (so1, so2);
90                                 } finally {
91                                         if (Syscall.close (so2) < 0)
92                                                 UnixMarshal.ThrowExceptionForLastError ();
93                                 }
94                         } finally {
95                                 if (Syscall.close (so1) < 0)
96                                         UnixMarshal.ThrowExceptionForLastError ();
97                         }
98                 }
99
100                 [Test]
101                 public void TestSocket ()
102                 {
103                         int socket;
104                         if ((socket = Syscall.socket (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0)) < 0)
105                                 UnixMarshal.ThrowExceptionForLastError ();
106
107                         if (Syscall.close (socket) < 0)
108                                 UnixMarshal.ThrowExceptionForLastError ();
109                 }
110
111                 [Test]
112                 public void SocketPair ()
113                 {
114                         int socket1, socket2;
115                         if (Syscall.socketpair (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, out socket1, out socket2) < 0)
116                                 UnixMarshal.ThrowExceptionForLastError ();
117
118                         int r0 = Syscall.close (socket1);
119                         int r1 = Syscall.close (socket2);
120                         if (r0 < 0 || r1 < 0)
121                                 UnixMarshal.ThrowExceptionForLastError ();
122                 }
123
124                 [Test]
125                 public void SendRecv ()
126                 {
127                         WithSocketPair ((so1, so2) => {
128                                 long ret;
129                                 var buffer1 = new byte[] { 42, 43, 44 };
130                                 ret = Syscall.send (so1, buffer1, (ulong) buffer1.Length, 0);
131                                 if (ret < 0)
132                                         UnixMarshal.ThrowExceptionForLastError ();
133
134                                 var buffer2 = new byte[1024];
135                                 ret = Syscall.recv (so2, buffer2, (ulong) buffer2.Length, 0);
136                                 if (ret < 0)
137                                         UnixMarshal.ThrowExceptionForLastError ();
138
139                                 Assert.AreEqual (buffer1.Length, ret);
140                                 for (int i = 0; i < buffer1.Length; i++)
141                                         Assert.AreEqual (buffer1[i], buffer2[i]);
142                         });
143                 }
144
145                 [Test]
146                 public void SockOpt ()
147                 {
148                         WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
149                                 int value;
150                                 if (Syscall.getsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, out value) < 0)
151                                         UnixMarshal.ThrowExceptionForLastError ();
152                                 Assert.AreEqual (0, value);
153
154                                 // Set SO_REUSEADDR to 1
155                                 if (Syscall.setsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, 1) < 0)
156                                         UnixMarshal.ThrowExceptionForLastError ();
157
158                                 // Get and check SO_REUSEADDR
159                                 if (Syscall.getsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, out value) < 0)
160                                         UnixMarshal.ThrowExceptionForLastError ();
161                                 Assert.AreNotEqual (0, value);
162
163                                 // Set SO_REUSEADDR to 0
164                                 if (Syscall.setsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, new byte[10], 4) < 0)
165                                         UnixMarshal.ThrowExceptionForLastError ();
166
167                                 // Get and check SO_REUSEADDR
168                                 var buffer = new byte[15];
169                                 long size = 12;
170                                 if (Syscall.getsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, buffer, ref size) < 0)
171                                         UnixMarshal.ThrowExceptionForLastError ();
172                                 Assert.AreEqual (size, 4);
173                                 for (int i = 0; i < size; i++)
174                                         Assert.AreEqual (buffer[i], 0);
175                         });
176                 }
177
178                 [Test]
179                 public void SockOptLinger ()
180                 {
181                         WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_STREAM, UnixSocketProtocol.IPPROTO_TCP, (so1, so2) => {
182                                 Linger linger = new Linger {
183                                         l_onoff = 1,
184                                         l_linger = 42,
185                                 };
186                                 // Set SO_LINGER
187                                 if (Syscall.setsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_LINGER, linger) < 0)
188                                         UnixMarshal.ThrowExceptionForLastError ();
189
190                                 // Get and check SO_LINGER
191                                 Linger value;
192                                 if (Syscall.getsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_LINGER, out value) < 0)
193                                         UnixMarshal.ThrowExceptionForLastError ();
194                                 if (value.l_onoff == 0)
195                                         Assert.Fail ("Linger not enabled");
196                                 Assert.AreEqual (linger.l_linger, value.l_linger);
197                         });
198                 }
199
200                 [Test]
201                 public void Shutdown ()
202                 {
203                         WithSocketPair ((so1, so2) => {
204                                 if (Syscall.shutdown (so1, ShutdownOption.SHUT_WR) < 0)
205                                         UnixMarshal.ThrowExceptionForLastError ();
206
207                                 var buffer2 = new byte[1024];
208                                 long ret = Syscall.recv (so2, buffer2, (ulong) buffer2.Length, 0);
209                                 if (ret < 0)
210                                         UnixMarshal.ThrowExceptionForLastError ();
211
212                                 Assert.AreEqual (ret, 0);
213                         });
214                 }
215
216                 [Test]
217                 public unsafe void ByteOrder ()
218                 {
219                         ushort val1 = Syscall.htons (0x1234);
220                         byte* ptr1 = (byte*) &val1;
221                         Assert.AreEqual (ptr1[0], 0x12);
222                         Assert.AreEqual (ptr1[1], 0x34);
223
224                         uint val2 = Syscall.htonl (0x6789abcd);
225                         byte* ptr2 = (byte*) &val2;
226                         Assert.AreEqual (ptr2[0], 0x67);
227                         Assert.AreEqual (ptr2[1], 0x89);
228                         Assert.AreEqual (ptr2[2], 0xab);
229                         Assert.AreEqual (ptr2[3], 0xcd);
230
231                         ptr1[0] = 0xfe;
232                         ptr1[1] = 0xdc;
233                         Assert.AreEqual (Syscall.ntohs (val1), 0xfedc);
234
235                         ptr2[0] = 0x76;
236                         ptr2[1] = 0x54;
237                         ptr2[2] = 0x32;
238                         ptr2[3] = 0x10;
239                         Assert.AreEqual (Syscall.ntohl (val2), 0x76543210);
240                 }
241
242                 [Test]
243                 public void InAddr ()
244                 {
245                         var ip = IPAddress.Loopback;
246                         var inAddr = NativeConvert.ToInAddr (ip);
247                         Assert.AreEqual (ip, NativeConvert.ToIPAddress (inAddr));
248                         Assert.AreEqual (0x7f000001, Syscall.ntohl (inAddr.s_addr));
249
250                         Assert.AreEqual ("127.0.0.1", inAddr.ToString ());
251                 }
252
253                 [Test]
254                 public void In6Addr ()
255                 {
256                         if (!Socket.OSSupportsIPv6)
257                                 Assert.Ignore ("OS does not support IPv6.");
258
259                         var ip6 = IPAddress.IPv6Loopback;
260                         var in6Addr = NativeConvert.ToIn6Addr (ip6);
261                         Assert.AreEqual (ip6, NativeConvert.ToIPAddress (in6Addr));
262                         Assert.AreEqual (1, in6Addr[15]);
263
264                         Assert.AreEqual ("::1", in6Addr.ToString ());
265                 }
266
267                 [Test]
268                 public void SockaddrUnTest ()
269                 {
270                         var address1 = new SockaddrUn ("/tmp/foo");
271                         Assert.AreEqual (address1.Path, "/tmp/foo");
272                         Assert.IsFalse (address1.IsLinuxAbstractNamespace);
273
274                         var storage = address1.ToSockaddrStorage ();
275                         var address2 = SockaddrUn.FromSockaddrStorage (storage);
276                         Assert.AreEqual (address1, address2);
277
278                         var sockaddr = Sockaddr.FromSockaddrStorage (storage);
279                         Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
280
281                         var address3 = new SockaddrUn ("/tmp/bar", linuxAbstractNamespace:true);
282                         Assert.AreEqual (address3.Path, "/tmp/bar");
283                         Assert.IsTrue (address3.IsLinuxAbstractNamespace);
284
285                         var address4 = new SockaddrUn (new string ('X', 9000));
286                         Assert.AreEqual (address4.Path, new string ('X', 9000));
287                         Assert.IsFalse (address4.IsLinuxAbstractNamespace);
288                         var storage2 = address4.ToSockaddrStorage ();
289                         var address5 = SockaddrUn.FromSockaddrStorage (storage2);
290                         Assert.AreEqual (address4, address5);
291                         // Test the malloc() path for long SockaddrUn adresses (the syscalls will fail because the fd is invalid and because the path is too long)
292                         Syscall.bind (-1, address4);
293                         Syscall.getsockname (-1, address4);
294
295                         Assert.AreEqual ("{sa_family=AF_UNIX, sun_path=\"/tmp/foo\"}", address1.ToString ());
296                         Assert.AreEqual ("{sa_family=AF_UNIX, sun_path=\"\\0/tmp/bar\"}", address3.ToString ());
297                 }
298
299                 [Test]
300                 public void SockaddrInTest ()
301                 {
302                         var address1 = new SockaddrIn {
303                                 sin_family = UnixAddressFamily.AF_INET,
304                                 sin_port = Syscall.htons (5678),
305                                 sin_addr = NativeConvert.ToInAddr (IPAddress.Loopback),
306                         };
307
308                         var storage = address1.ToSockaddrStorage ();
309                         var address2 = SockaddrIn.FromSockaddrStorage (storage);
310                         Assert.AreEqual (address1, address2);
311
312                         var sockaddr = Sockaddr.FromSockaddrStorage (storage);
313                         Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
314
315                         var storage2 = storage.ToSockaddrStorage ();
316                         Assert.AreEqual (storage, storage2);
317
318                         var storage3 = new SockaddrStorage (123);
319                         storage2.CopyTo (storage3);
320                         Assert.AreEqual (storage, storage3);
321
322                         Assert.AreEqual ("{sin_family=AF_INET, sin_port=htons(5678), sin_addr=127.0.0.1}", address1.ToString ());
323                 }
324
325                 [Test]
326                 public void SockaddrIn6Test ()
327                 {
328                         if (!Socket.OSSupportsIPv6)
329                                 Assert.Ignore ("OS does not support IPv6.");
330
331                         var address1 = new SockaddrIn6 {
332                                 sin6_family = UnixAddressFamily.AF_INET6,
333                                 sin6_port = Syscall.htons (1234),
334                                 sin6_flowinfo = 2,
335                                 sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
336                                 sin6_scope_id = 3
337                         };
338
339                         var storage = address1.ToSockaddrStorage ();
340                         var address2 = SockaddrIn6.FromSockaddrStorage (storage);
341                         Assert.AreEqual (address1, address2);
342
343                         var sockaddr = Sockaddr.FromSockaddrStorage (storage);
344                         Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
345
346                         Assert.AreEqual ("{sin6_family=AF_INET6, sin6_port=htons(1234), sin6_flowinfo=2, sin6_addr=::1, sin6_scope_id=3}", address1.ToString ());
347                 }
348
349                 [Test]
350                 public void BindConnect ()
351                 {
352                         WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
353                                 // Bind UDP socket so1 to 127.0.0.1 with dynamic port
354                                 var address = new SockaddrIn {
355                                         sin_family = UnixAddressFamily.AF_INET,
356                                         sin_port = Syscall.htons (0),
357                                         sin_addr = new InAddr (127, 0, 0, 1),
358                                 };
359                                 if (Syscall.bind (so1, address) < 0)
360                                         UnixMarshal.ThrowExceptionForLastError ();
361
362                                 // Get actual port number using getsockname()
363                                 var actualAddress = new SockaddrIn ();
364                                 if (Syscall.getsockname (so1, actualAddress) < 0)
365                                         UnixMarshal.ThrowExceptionForLastError ();
366                                 Assert.AreEqual (actualAddress.sa_family, UnixAddressFamily.AF_INET);
367                                 var port = Syscall.ntohs (actualAddress.sin_port);
368                                 Assert.IsTrue (port != 0);
369
370
371                                 // Connect so2 to so1
372                                 var remoteAddress = new SockaddrIn {
373                                         sin_family = UnixAddressFamily.AF_INET,
374                                         sin_port = Syscall.htons (port),
375                                         sin_addr = new InAddr (127, 0, 0, 1),
376                                 };
377                                 if (Syscall.connect (so2, remoteAddress) < 0)
378                                         UnixMarshal.ThrowExceptionForLastError ();
379
380                                 // Verify peer address using getpeername()
381                                 var address2 = new SockaddrIn ();
382                                 if (Syscall.getpeername (so2, address2) < 0)
383                                         UnixMarshal.ThrowExceptionForLastError ();
384                                 Assert.AreEqual (address2.sa_family, UnixAddressFamily.AF_INET);
385                                 Assert.AreEqual (remoteAddress.sin_port, address2.sin_port);
386                                 Assert.AreEqual (remoteAddress.sin_addr, address2.sin_addr);
387
388                                 // Send and receive a few bytes
389                                 long ret;
390                                 var buffer1 = new byte[] { 42, 43, 44 };
391                                 ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
392                                 if (ret < 0)
393                                         UnixMarshal.ThrowExceptionForLastError ();
394
395                                 var buffer2 = new byte[1024];
396                                 ret = Syscall.recv (so1, buffer2, (ulong) buffer2.Length, 0);
397                                 if (ret < 0)
398                                         UnixMarshal.ThrowExceptionForLastError ();
399
400                                 Assert.AreEqual (buffer1.Length, ret);
401                                 for (int i = 0; i < buffer1.Length; i++)
402                                         Assert.AreEqual (buffer1[i], buffer2[i]);
403                         });
404                 }
405
406                 [Test]
407                 public void IPv6 ()
408                 {
409                         if (!Socket.OSSupportsIPv6)
410                                 Assert.Ignore ("OS does not support IPv6.");
411
412                         var address = new SockaddrIn6 {
413                                 sin6_family = UnixAddressFamily.AF_INET6,
414                                 sin6_port = Syscall.htons (0),
415                                 sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
416                         };
417                         WithSockets (UnixAddressFamily.AF_INET6, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
418                                 if (Syscall.bind (so1, address) < 0)
419                                         UnixMarshal.ThrowExceptionForLastError ();
420
421                                 var address1Stor = new SockaddrStorage ();
422                                 if (Syscall.getsockname (so1, address1Stor) < 0)
423                                         UnixMarshal.ThrowExceptionForLastError ();
424                                 var address1 = new SockaddrIn6 ();
425                                 address1Stor.CopyTo (address1);
426
427                                 // Check getsockname(socket, null)
428                                 if (Syscall.getsockname (so1, null) < 0)
429                                         UnixMarshal.ThrowExceptionForLastError ();
430
431                                 var address2 = new SockaddrIn6 ();
432                                 if (Syscall.getsockname (so1, address2) < 0)
433                                         UnixMarshal.ThrowExceptionForLastError ();
434
435                                 Assert.AreEqual (address1, address2);
436                                 Assert.IsTrue (Syscall.ntohs (address1.sin6_port) != 0);
437                                 address1.sin6_port = 0;
438                                 Assert.AreEqual (address, address1);
439
440                                 var address3 = new Sockaddr ();
441                                 if (Syscall.getsockname (so1, address3) < 0)
442                                         UnixMarshal.ThrowExceptionForLastError ();
443                                 Assert.AreEqual (address.sa_family, address3.sa_family);
444
445                                 // Try to store a sockaddr_in6 into a Sockaddr. Should fail because sockaddr_in6 should be larger than sockaddr_in
446                                 var address4 = new SockaddrIn ();
447                                 if (Syscall.getsockname (so1, address4) == 0)
448                                         Assert.Fail ("getsockname() should have failed");
449                                 Assert.AreEqual (Errno.ENOBUFS, Stdlib.GetLastError ());
450                         });
451                 }
452
453                 [Test]
454                 public void UnixAccept ()
455                 {
456                         var address = new SockaddrUn (TempFolder + "/socket1");
457                         var address2 = SockaddrUn.FromSockaddrStorage (address.ToSockaddrStorage ());
458                         Assert.AreEqual (address, address2);
459
460                         WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
461                                 if (Syscall.bind (so1, address) < 0)
462                                         UnixMarshal.ThrowExceptionForLastError ();
463
464                                 if (Syscall.listen (so1, 5) < 0)
465                                         UnixMarshal.ThrowExceptionForLastError ();
466
467                                 if (Syscall.connect (so2, address) < 0)
468                                         UnixMarshal.ThrowExceptionForLastError ();
469
470                                 var address3 = new SockaddrUn ();
471                                 if (Syscall.getsockname (so1, address3) < 0)
472                                         UnixMarshal.ThrowExceptionForLastError ();
473                                 Assert.AreEqual (address, address3);
474
475                                 var address4 = new SockaddrStorage ();
476                                 if (Syscall.getsockname (so1, address4) < 0)
477                                         UnixMarshal.ThrowExceptionForLastError ();
478                                 Assert.AreEqual (UnixAddressFamily.AF_UNIX, address4.sa_family);
479                                 Assert.AreEqual (address3, SockaddrUn.FromSockaddrStorage (address4));
480
481                                 var address5 = new SockaddrUn ();
482                                 if (Syscall.getsockname (so1, address5) < 0)
483                                         UnixMarshal.ThrowExceptionForLastError ();
484                                 Assert.AreEqual (UnixAddressFamily.AF_UNIX, address5.sa_family);
485
486                                 // Check getsockname(socket, null)
487                                 if (Syscall.getsockname (so1, null) < 0)
488                                         UnixMarshal.ThrowExceptionForLastError ();
489
490                                 int so3;
491                                 var remote = new SockaddrUn ();
492                                 if ((so3 = Syscall.accept (so1, remote)) < 0)
493                                         UnixMarshal.ThrowExceptionForLastError ();
494                                 try {
495                                         // Send and receive a few bytes
496                                         long ret;
497                                         var buffer1 = new byte[] { 42, 43, 44 };
498                                         ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
499                                         if (ret < 0)
500                                                 UnixMarshal.ThrowExceptionForLastError ();
501
502                                         var buffer2 = new byte[1024];
503                                         ret = Syscall.recv (so3, buffer2, (ulong) buffer2.Length, 0);
504                                         if (ret < 0)
505                                                 UnixMarshal.ThrowExceptionForLastError ();
506
507                                         Assert.AreEqual (buffer1.Length, ret);
508                                         for (int i = 0; i < buffer1.Length; i++)
509                                                 Assert.AreEqual (buffer1[i], buffer2[i]);
510                                 } finally {
511                                         if (Syscall.close (so3) < 0)
512                                                 UnixMarshal.ThrowExceptionForLastError ();
513                                 }
514                         });
515                 }
516
517                 [Test]
518                 [Category ("NotOnMac")]
519                 public void Accept4 ()
520                 {
521                         WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
522                                 var address = new SockaddrUn (TempFolder + "/socket2");
523                                 if (Syscall.bind (so1, address) < 0)
524                                         UnixMarshal.ThrowExceptionForLastError ();
525                                 if (Syscall.listen (so1, 5) < 0)
526                                         UnixMarshal.ThrowExceptionForLastError ();
527                                 if (Syscall.connect (so2, address) < 0)
528                                         UnixMarshal.ThrowExceptionForLastError ();
529
530                                 int so3;
531                                 var remote = new SockaddrUn ();
532                                 if ((so3 = Syscall.accept4 (so1, remote, UnixSocketFlags.SOCK_CLOEXEC | UnixSocketFlags.SOCK_NONBLOCK)) < 0)
533                                         UnixMarshal.ThrowExceptionForLastError ();
534                                 try {
535                                         int _flags;
536                                         if ((_flags = Syscall.fcntl (so3, FcntlCommand.F_GETFL)) < 0)
537                                                 UnixMarshal.ThrowExceptionForLastError ();
538                                         var flags = NativeConvert.ToOpenFlags (_flags);
539                                         Assert.IsTrue ((flags & OpenFlags.O_NONBLOCK) != 0);
540
541                                         int _flagsFD;
542                                         if ((_flagsFD = Syscall.fcntl (so3, FcntlCommand.F_GETFD)) < 0)
543                                                 UnixMarshal.ThrowExceptionForLastError ();
544                                         // FD_CLOEXEC must be set
545                                         //var flagsFD = NativeConvert.ToFdFlags (_flagsFD);
546                                         //Assert.IsTrue ((flagsFD & FdFlags.FD_CLOEXEC) != 0);
547                                         Assert.IsTrue (_flagsFD != 0);
548                                 } finally {
549                                         if (Syscall.close (so3) < 0)
550                                                 UnixMarshal.ThrowExceptionForLastError ();
551                                 }
552                         });
553                 }
554
555                 [Test]
556                 public void SendToRecvFrom ()
557                 {
558                         WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
559                                 // Bind UDP socket so1 to 127.0.0.1 with dynamic port
560                                 var address = new SockaddrIn { sin_family = UnixAddressFamily.AF_INET, sin_port = Syscall.htons (0), sin_addr = new InAddr (127, 0, 0, 1) };
561                                 if (Syscall.bind (so1, address) < 0)
562                                         UnixMarshal.ThrowExceptionForLastError ();
563
564                                 // Get actual port number using getsockname()
565                                 var actualAddress = new SockaddrIn ();
566                                 if (Syscall.getsockname (so1, actualAddress) < 0)
567                                         UnixMarshal.ThrowExceptionForLastError ();
568                                 Assert.AreEqual (actualAddress.sa_family, UnixAddressFamily.AF_INET);
569                                 var port = Syscall.ntohs (actualAddress.sin_port);
570                                 Assert.IsTrue (port != 0);
571
572
573                                 var remoteAddress = new SockaddrIn {
574                                         sin_family = UnixAddressFamily.AF_INET,
575                                         sin_port = Syscall.htons (port),
576                                         sin_addr = new InAddr (127, 0, 0, 1),
577                                 };
578
579                                 // Send and receive a few bytes
580                                 long ret;
581                                 var buffer1 = new byte[] { 42, 43, 44 };
582                                 ret = Syscall.sendto (so2, buffer1, (ulong) buffer1.Length, 0, remoteAddress);
583                                 if (ret < 0)
584                                         UnixMarshal.ThrowExceptionForLastError ();
585
586                                 var senderAddress = new SockaddrIn ();
587                                 var buffer2 = new byte[1024];
588                                 ret = Syscall.recvfrom (so1, buffer2, (ulong) buffer2.Length, 0, senderAddress);
589                                 if (ret < 0)
590                                         UnixMarshal.ThrowExceptionForLastError ();
591                                 Assert.AreEqual (senderAddress.sa_family, UnixAddressFamily.AF_INET);
592                                 Assert.AreEqual (senderAddress.sin_addr, new InAddr (127, 0, 0, 1));
593
594                                 Assert.AreEqual (buffer1.Length, ret);
595                                 for (int i = 0; i < buffer1.Length; i++)
596                                         Assert.AreEqual (buffer1[i], buffer2[i]);
597                         });
598                 }
599
600                 [Test]
601                 public unsafe void SendMsgRecvMsg ()
602                 {
603                         WithSocketPair ((so1, so2) => {
604                                 long ret;
605                                 var buffer1 = new byte[] { 42, 43, 44 };
606                                 fixed (byte* ptr_buffer1 = buffer1) {
607                                         var iovecs1 = new Iovec[] {
608                                                 new Iovec {
609                                                         iov_base = (IntPtr) ptr_buffer1,
610                                                         iov_len = (ulong) buffer1.Length,
611                                                 },
612                                         };
613                                         var msghdr1 = new Msghdr {
614                                                 msg_iov = iovecs1,
615                                                 msg_iovlen = 1,
616                                         };
617                                         ret = Syscall.sendmsg (so1, msghdr1, 0);
618                                 }
619                                 if (ret < 0)
620                                         UnixMarshal.ThrowExceptionForLastError ();
621
622                                 var buffer2 = new byte[1024];
623                                 fixed (byte* ptr_buffer2 = buffer2) {
624                                         var iovecs2 = new Iovec[] {
625                                                 new Iovec {
626                                                         iov_base = (IntPtr) ptr_buffer2,
627                                                         iov_len = (ulong) buffer2.Length,
628                                                 },
629                                         };
630                                         var msghdr2 = new Msghdr {
631                                                 msg_iov = iovecs2,
632                                                 msg_iovlen = 1,
633                                         };
634                                         ret = Syscall.recvmsg (so2, msghdr2, 0);
635                                 }
636                                 if (ret < 0)
637                                         UnixMarshal.ThrowExceptionForLastError ();
638
639                                 Assert.AreEqual (buffer1.Length, ret);
640                                 for (int i = 0; i < buffer1.Length; i++)
641                                         Assert.AreEqual (buffer1[i], buffer2[i]);
642                         });
643                 }
644
645                 [Test]
646                 public unsafe void SendMsgRecvMsgAddress ()
647                 {
648                         WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
649                                 // Bind UDP socket so1 to 127.0.0.1 with dynamic port
650                                 var address = new SockaddrIn {
651                                         sin_family = UnixAddressFamily.AF_INET,
652                                         sin_port = Syscall.htons (0),
653                                         sin_addr = new InAddr (127, 0, 0, 1),
654                                 };
655                                 if (Syscall.bind (so1, address) < 0)
656                                         UnixMarshal.ThrowExceptionForLastError ();
657
658                                 // Get actual port number using getsockname()
659                                 var actualAddress = new SockaddrIn ();
660                                 if (Syscall.getsockname (so1, actualAddress) < 0)
661                                         UnixMarshal.ThrowExceptionForLastError ();
662                                 Assert.AreEqual (actualAddress.sa_family, UnixAddressFamily.AF_INET);
663                                 var port = Syscall.ntohs (actualAddress.sin_port);
664                                 Assert.IsTrue (port != 0);
665
666
667                                 var remoteAddress = new SockaddrIn {
668                                         sin_family = UnixAddressFamily.AF_INET,
669                                         sin_port = Syscall.htons (port),
670                                         sin_addr = new InAddr (127, 0, 0, 1),
671                                 };
672
673                                 // Send and receive a few bytes
674                                 long ret;
675                                 var buffer1 = new byte[] { 42, 43, 44 };
676                                 fixed (byte* ptr_buffer1 = buffer1) {
677                                         var iovecs1 = new Iovec[] {
678                                                 new Iovec {
679                                                         iov_base = (IntPtr) ptr_buffer1,
680                                                         iov_len = (ulong) buffer1.Length,
681                                                 },
682                                         };
683                                         var msghdr1 = new Msghdr {
684                                                 msg_name = remoteAddress,
685                                                 msg_iov = iovecs1,
686                                                 msg_iovlen = 1,
687                                         };
688                                         ret = Syscall.sendmsg (so2, msghdr1, 0);
689                                         msghdr1.msg_name = remoteAddress.ToSockaddrStorage ();
690                                         if (ret >= 0)
691                                                 ret = Syscall.sendmsg (so2, msghdr1, 0);
692                                 }
693                                 if (ret < 0)
694                                         UnixMarshal.ThrowExceptionForLastError ();
695
696                                 var senderAddress = new SockaddrIn ();
697                                 var senderAddressStorage = new SockaddrStorage ();
698                                 var buffer2 = new byte[1024];
699                                 var buffer3 = new byte[1024];
700                                 fixed (byte* ptr_buffer2 = buffer2, ptr_buffer3 = buffer3) {
701                                         var iovecs2 = new Iovec[] {
702                                                 new Iovec {
703                                                         iov_base = (IntPtr) ptr_buffer2,
704                                                         iov_len = (ulong) buffer2.Length,
705                                                 },
706                                         };
707                                         var msghdr2 = new Msghdr {
708                                                 msg_name = senderAddress,
709                                                 msg_iov = iovecs2,
710                                                 msg_iovlen = 1,
711                                         };
712                                         ret = Syscall.recvmsg (so1, msghdr2, 0);
713                                         msghdr2.msg_name = senderAddressStorage;
714                                         iovecs2[0].iov_base = (IntPtr) ptr_buffer3;
715                                         if (ret >= 0)
716                                                 ret = Syscall.recvmsg (so1, msghdr2, 0);
717                                 }
718                                 if (ret < 0)
719                                         UnixMarshal.ThrowExceptionForLastError ();
720                                 Assert.AreEqual (senderAddress.sa_family, UnixAddressFamily.AF_INET);
721                                 Assert.AreEqual (senderAddress.sin_addr, new InAddr (127, 0, 0, 1));
722                                 var senderAddress2 = SockaddrIn.FromSockaddrStorage (senderAddressStorage);
723                                 Assert.AreEqual (senderAddress2.sa_family, UnixAddressFamily.AF_INET);
724                                 Assert.AreEqual (senderAddress2.sin_addr, new InAddr (127, 0, 0, 1));
725
726                                 Assert.AreEqual (buffer1.Length, ret);
727                                 for (int i = 0; i < buffer1.Length; i++)
728                                         Assert.AreEqual (buffer1[i], buffer2[i]);
729                                 for (int i = 0; i < buffer1.Length; i++)
730                                         Assert.AreEqual (buffer1[i], buffer3[i]);
731                         });
732                 }
733
734                 public unsafe void ControlMsg (bool useMultipleControlMessages)
735                 {
736                         // Create two socket pairs and send inner_so1 and inner_so2 over the other socket pair using SCM_RIGHTS
737                         WithSocketPair ((inner_so1, inner_so2) => {
738                                 WithSocketPair ((so1, so2) => {
739                                         byte[] cmsg;
740                                         Msghdr msghdr1;
741                                         long offset;
742                                         if (useMultipleControlMessages) {
743                                                 // Create two SCM_RIGHTS control messages
744                                                 cmsg = new byte[2 * Syscall.CMSG_SPACE (sizeof (int))];
745                                                 var hdr = new Cmsghdr {
746                                                         cmsg_len = (long) Syscall.CMSG_LEN (sizeof (int)),
747                                                         cmsg_level = UnixSocketProtocol.SOL_SOCKET,
748                                                         cmsg_type = UnixSocketControlMessage.SCM_RIGHTS,
749                                                 };
750                                                 msghdr1 = new Msghdr {
751                                                         msg_control = cmsg,
752                                                         msg_controllen = cmsg.Length,
753                                                 };
754                                                 offset = 0;
755                                                 hdr.WriteToBuffer (msghdr1, offset);
756                                                 var dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
757                                                 fixed (byte* ptr = msghdr1.msg_control) {
758                                                         ((int*) (ptr + dataOffset))[0] = inner_so1;
759                                                 }
760                                                 offset = (long) Syscall.CMSG_SPACE (sizeof (int));
761                                                 hdr.WriteToBuffer (msghdr1, offset);
762                                                 dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
763                                                 fixed (byte* ptr = msghdr1.msg_control) {
764                                                         ((int*) (ptr + dataOffset))[0] = inner_so2;
765                                                 }
766                                         } else {
767                                                 // Create one SCM_RIGHTS control message
768                                                 cmsg = new byte[Syscall.CMSG_SPACE (2 * sizeof (int))];
769                                                 var hdr = new Cmsghdr {
770                                                         cmsg_len = (long) Syscall.CMSG_LEN (2 * sizeof (int)),
771                                                         cmsg_level = UnixSocketProtocol.SOL_SOCKET,
772                                                         cmsg_type = UnixSocketControlMessage.SCM_RIGHTS,
773                                                 };
774                                                 msghdr1 = new Msghdr {
775                                                         msg_control = cmsg,
776                                                         msg_controllen = cmsg.Length,
777                                                 };
778                                                 offset = 0;
779                                                 hdr.WriteToBuffer (msghdr1, offset);
780                                                 var dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
781                                                 fixed (byte* ptr = msghdr1.msg_control) {
782                                                         ((int*) (ptr + dataOffset))[0] = inner_so1;
783                                                         ((int*) (ptr + dataOffset))[1] = inner_so2;
784                                                 }
785                                         }
786
787                                         long ret;
788                                         var buffer1 = new byte[] { 42, 43, 44 };
789                                         fixed (byte* ptr_buffer1 = buffer1) {
790                                                 var iovecs1 = new Iovec[] {
791                                                         new Iovec {
792                                                                 iov_base = (IntPtr) ptr_buffer1,
793                                                                 iov_len = (ulong) buffer1.Length,
794                                                         },
795                                                 };
796                                                 msghdr1.msg_iov = iovecs1;
797                                                 msghdr1.msg_iovlen = 1;
798                                                 // Send message twice
799                                                 ret = Syscall.sendmsg (so1, msghdr1, 0);
800                                                 if (ret < 0)
801                                                         UnixMarshal.ThrowExceptionForLastError ();
802                                                 ret = Syscall.sendmsg (so1, msghdr1, 0);
803                                                 if (ret < 0)
804                                                         UnixMarshal.ThrowExceptionForLastError ();
805                                         }
806
807                                         // Receive without control message buffer
808                                         var buffer2 = new byte[1024];
809                                         var msghdr2 = new Msghdr { };
810                                         fixed (byte* ptr_buffer2 = buffer2) {
811                                                 var iovecs2 = new Iovec[] {
812                                                         new Iovec {
813                                                                 iov_base = (IntPtr) ptr_buffer2,
814                                                                 iov_len = (ulong) buffer2.Length,
815                                                         },
816                                                 };
817                                                 msghdr2.msg_iov = iovecs2;
818                                                 msghdr2.msg_iovlen = 1;
819                                                 ret = Syscall.recvmsg (so2, msghdr2, 0);
820                                         }
821                                         if (ret < 0)
822                                                 UnixMarshal.ThrowExceptionForLastError ();
823
824                                         if (useMultipleControlMessages) // This assertion fails on OSX for some reason
825                                                 Assert.IsTrue ((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) != 0); // Control message has been truncated
826
827                                         Assert.AreEqual (buffer1.Length, ret);
828                                         for (int i = 0; i < buffer1.Length; i++)
829                                                 Assert.AreEqual (buffer1[i], buffer2[i]);
830
831                                         // Receive with control message buffer
832                                         buffer2 = new byte[1024];
833                                         var cmsg2 = new byte[1024];
834                                         msghdr2 = new Msghdr {
835                                                 msg_control = cmsg2,
836                                                 msg_controllen = cmsg2.Length,
837                                         };
838                                         fixed (byte* ptr_buffer2 = buffer2) {
839                                                 var iovecs2 = new Iovec[] {
840                                                         new Iovec {
841                                                                 iov_base = (IntPtr) ptr_buffer2,
842                                                                 iov_len = (ulong) buffer2.Length,
843                                                         },
844                                                 };
845                                                 msghdr2.msg_iov = iovecs2;
846                                                 msghdr2.msg_iovlen = 1;
847                                                 ret = Syscall.recvmsg (so2, msghdr2, 0);
848                                         }
849                                         if (ret < 0)
850                                                 UnixMarshal.ThrowExceptionForLastError ();
851
852                                         var fds = new global::System.Collections.Generic.List<int> ();
853                                         for (offset = Syscall.CMSG_FIRSTHDR (msghdr2); offset != -1; offset = Syscall.CMSG_NXTHDR (msghdr2, offset)) {
854                                                 var recvHdr = Cmsghdr.ReadFromBuffer (msghdr2, offset);
855                                                 var recvDataOffset = Syscall.CMSG_DATA (msghdr2, offset);
856                                                 var bytes = recvHdr.cmsg_len - (recvDataOffset - offset);
857                                                 Assert.AreEqual (bytes % sizeof (int), 0);
858                                                 var fdCount = bytes / sizeof (int);
859                                                 fixed (byte* ptr = msghdr2.msg_control)
860                                                         for (int i = 0; i < fdCount; i++)
861                                                                 fds.Add (((int*) (ptr + recvDataOffset))[i]);
862                                         }
863                                         try {
864                                                 Assert.IsTrue ((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) == 0); // Control message has not been truncated
865
866                                                 Assert.AreEqual (buffer1.Length, ret);
867                                                 for (int i = 0; i < buffer1.Length; i++)
868                                                         Assert.AreEqual (buffer1[i], buffer2[i]);
869
870                                                 Assert.AreEqual (fds.Count, 2);
871
872                                                 // Send message over the first received fd and receive it over inner_so2
873                                                 var buffer3 = new byte[] { 16, 17 };
874                                                 ret = Syscall.send (fds[0], buffer3, (ulong) buffer3.Length, 0);
875                                                 if (ret < 0)
876                                                         UnixMarshal.ThrowExceptionForLastError ();
877
878                                                 var buffer4 = new byte[1024];
879                                                 ret = Syscall.recv (inner_so2, buffer4, (ulong) buffer4.Length, 0);
880                                                 if (ret < 0)
881                                                         UnixMarshal.ThrowExceptionForLastError ();
882
883                                                 Assert.AreEqual (buffer3.Length, ret);
884                                                 for (int i = 0; i < buffer3.Length; i++)
885                                                         Assert.AreEqual (buffer3[i], buffer4[i]);
886
887                                                 // Send message over inner_so1 and receive it second received fd
888                                                 var buffer5 = new byte[] { 10, 40, 0, 1 };
889                                                 ret = Syscall.send (inner_so1, buffer5, (ulong) buffer5.Length, 0);
890                                                 if (ret < 0)
891                                                         UnixMarshal.ThrowExceptionForLastError ();
892
893                                                 var buffer6 = new byte[1024];
894                                                 ret = Syscall.recv (fds[1], buffer6, (ulong) buffer6.Length, 0);
895                                                 if (ret < 0)
896                                                         UnixMarshal.ThrowExceptionForLastError ();
897
898                                                 Assert.AreEqual (buffer5.Length, ret);
899                                                 for (int i = 0; i < buffer5.Length; i++)
900                                                         Assert.AreEqual (buffer5[i], buffer6[i]);
901                                         } finally {
902                                                 foreach (var fd in fds)
903                                                         if (Syscall.close (fd) < 0)
904                                                                 UnixMarshal.ThrowExceptionForLastError ();
905                                         }
906                                 });
907                         });
908                 }
909
910                 [Test]
911                 public unsafe void ControlMsgOneCmsg ()
912                 {
913                         ControlMsg (useMultipleControlMessages: false);
914                 }
915
916                 [Test]
917                 [Category ("NotOnMac")]
918                 public unsafe void ControlMsgMultipleCMsgs ()
919                 {
920                         ControlMsg (useMultipleControlMessages: true);
921                 }
922         }
923 }
924
925 // vim: noexpandtab
926 // Local Variables: 
927 // tab-width: 4
928 // c-basic-offset: 4
929 // indent-tabs-mode: t
930 // End: