2 // socket-related test cases
5 // Steffen Kiess (s-kiess@web.de)
7 // Copyright (C) 2015 Steffen Kiess
13 using System.Net.Sockets;
14 using System.Runtime.InteropServices;
17 using Mono.Unix.Native;
19 using NUnit.Framework;
21 namespace MonoTests.Mono.Unix.Native
23 [TestFixture, Category ("NotDotNet")]
24 public class SocketTest {
31 TempFolder = Path.Combine (Path.GetTempPath (), this.GetType ().FullName);
33 if (Directory.Exists (TempFolder))
34 Directory.Delete (TempFolder, true);
36 Directory.CreateDirectory (TempFolder);
40 public void TearDown()
42 if (Directory.Exists (TempFolder))
43 Directory.Delete (TempFolder, true);
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)
50 var timeout = new Timeval {
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 ();
59 void WithSocketPair (Action<int, int> f)
62 if (Syscall.socketpair (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, out socket1, out socket2) < 0)
63 UnixMarshal.ThrowExceptionForLastError ();
70 int r0 = Syscall.close (socket1);
71 int r1 = Syscall.close (socket2);
73 UnixMarshal.ThrowExceptionForLastError ();
77 void WithSockets (UnixAddressFamily af, UnixSocketType type, UnixSocketProtocol protocol, Action<int, int> f)
80 if ((so1 = Syscall.socket (af, type, protocol)) < 0)
81 UnixMarshal.ThrowExceptionForLastError ();
83 if ((so2 = Syscall.socket (af, type, protocol)) < 0)
84 UnixMarshal.ThrowExceptionForLastError ();
91 if (Syscall.close (so2) < 0)
92 UnixMarshal.ThrowExceptionForLastError ();
95 if (Syscall.close (so1) < 0)
96 UnixMarshal.ThrowExceptionForLastError ();
101 public void TestSocket ()
104 if ((socket = Syscall.socket (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0)) < 0)
105 UnixMarshal.ThrowExceptionForLastError ();
107 if (Syscall.close (socket) < 0)
108 UnixMarshal.ThrowExceptionForLastError ();
112 public void SocketPair ()
114 int socket1, socket2;
115 if (Syscall.socketpair (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, out socket1, out socket2) < 0)
116 UnixMarshal.ThrowExceptionForLastError ();
118 int r0 = Syscall.close (socket1);
119 int r1 = Syscall.close (socket2);
120 if (r0 < 0 || r1 < 0)
121 UnixMarshal.ThrowExceptionForLastError ();
125 public void SendRecv ()
127 WithSocketPair ((so1, so2) => {
129 var buffer1 = new byte[] { 42, 43, 44 };
130 ret = Syscall.send (so1, buffer1, (ulong) buffer1.Length, 0);
132 UnixMarshal.ThrowExceptionForLastError ();
134 var buffer2 = new byte[1024];
135 ret = Syscall.recv (so2, buffer2, (ulong) buffer2.Length, 0);
137 UnixMarshal.ThrowExceptionForLastError ();
139 Assert.AreEqual (buffer1.Length, ret);
140 for (int i = 0; i < buffer1.Length; i++)
141 Assert.AreEqual (buffer1[i], buffer2[i]);
146 public void SockOpt ()
148 WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
150 if (Syscall.getsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, out value) < 0)
151 UnixMarshal.ThrowExceptionForLastError ();
152 Assert.AreEqual (0, value);
154 // Set SO_REUSEADDR to 1
155 if (Syscall.setsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_REUSEADDR, 1) < 0)
156 UnixMarshal.ThrowExceptionForLastError ();
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);
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 ();
167 // Get and check SO_REUSEADDR
168 var buffer = new byte[15];
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);
179 public void SockOptLinger ()
181 WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_STREAM, UnixSocketProtocol.IPPROTO_TCP, (so1, so2) => {
182 Linger linger = new Linger {
187 if (Syscall.setsockopt (so1, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_LINGER, linger) < 0)
188 UnixMarshal.ThrowExceptionForLastError ();
190 // Get and check SO_LINGER
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);
201 public void Shutdown ()
203 WithSocketPair ((so1, so2) => {
204 if (Syscall.shutdown (so1, ShutdownOption.SHUT_WR) < 0)
205 UnixMarshal.ThrowExceptionForLastError ();
207 var buffer2 = new byte[1024];
208 long ret = Syscall.recv (so2, buffer2, (ulong) buffer2.Length, 0);
210 UnixMarshal.ThrowExceptionForLastError ();
212 Assert.AreEqual (ret, 0);
217 public unsafe void ByteOrder ()
219 ushort val1 = Syscall.htons (0x1234);
220 byte* ptr1 = (byte*) &val1;
221 Assert.AreEqual (ptr1[0], 0x12);
222 Assert.AreEqual (ptr1[1], 0x34);
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);
233 Assert.AreEqual (Syscall.ntohs (val1), 0xfedc);
239 Assert.AreEqual (Syscall.ntohl (val2), 0x76543210);
243 public void InAddr ()
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));
250 Assert.AreEqual ("127.0.0.1", inAddr.ToString ());
254 public void In6Addr ()
256 if (!Socket.OSSupportsIPv6)
257 Assert.Ignore ("OS does not support IPv6.");
259 var ip6 = IPAddress.IPv6Loopback;
260 var in6Addr = NativeConvert.ToIn6Addr (ip6);
261 Assert.AreEqual (ip6, NativeConvert.ToIPAddress (in6Addr));
262 Assert.AreEqual (1, in6Addr[15]);
264 Assert.AreEqual ("::1", in6Addr.ToString ());
268 public void SockaddrUnTest ()
270 var address1 = new SockaddrUn ("/tmp/foo");
271 Assert.AreEqual (address1.Path, "/tmp/foo");
272 Assert.IsFalse (address1.IsLinuxAbstractNamespace);
274 var storage = address1.ToSockaddrStorage ();
275 var address2 = SockaddrUn.FromSockaddrStorage (storage);
276 Assert.AreEqual (address1, address2);
278 var sockaddr = Sockaddr.FromSockaddrStorage (storage);
279 Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
281 var address3 = new SockaddrUn ("/tmp/bar", linuxAbstractNamespace:true);
282 Assert.AreEqual (address3.Path, "/tmp/bar");
283 Assert.IsTrue (address3.IsLinuxAbstractNamespace);
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);
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 ());
300 public void SockaddrInTest ()
302 var address1 = new SockaddrIn {
303 sin_family = UnixAddressFamily.AF_INET,
304 sin_port = Syscall.htons (5678),
305 sin_addr = NativeConvert.ToInAddr (IPAddress.Loopback),
308 var storage = address1.ToSockaddrStorage ();
309 var address2 = SockaddrIn.FromSockaddrStorage (storage);
310 Assert.AreEqual (address1, address2);
312 var sockaddr = Sockaddr.FromSockaddrStorage (storage);
313 Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
315 var storage2 = storage.ToSockaddrStorage ();
316 Assert.AreEqual (storage, storage2);
318 var storage3 = new SockaddrStorage (123);
319 storage2.CopyTo (storage3);
320 Assert.AreEqual (storage, storage3);
322 Assert.AreEqual ("{sin_family=AF_INET, sin_port=htons(5678), sin_addr=127.0.0.1}", address1.ToString ());
326 public void SockaddrIn6Test ()
328 if (!Socket.OSSupportsIPv6)
329 Assert.Ignore ("OS does not support IPv6.");
331 var address1 = new SockaddrIn6 {
332 sin6_family = UnixAddressFamily.AF_INET6,
333 sin6_port = Syscall.htons (1234),
335 sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
339 var storage = address1.ToSockaddrStorage ();
340 var address2 = SockaddrIn6.FromSockaddrStorage (storage);
341 Assert.AreEqual (address1, address2);
343 var sockaddr = Sockaddr.FromSockaddrStorage (storage);
344 Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
346 Assert.AreEqual ("{sin6_family=AF_INET6, sin6_port=htons(1234), sin6_flowinfo=2, sin6_addr=::1, sin6_scope_id=3}", address1.ToString ());
350 public void BindConnect ()
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),
359 if (Syscall.bind (so1, address) < 0)
360 UnixMarshal.ThrowExceptionForLastError ();
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);
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),
377 if (Syscall.connect (so2, remoteAddress) < 0)
378 UnixMarshal.ThrowExceptionForLastError ();
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);
388 // Send and receive a few bytes
390 var buffer1 = new byte[] { 42, 43, 44 };
391 ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
393 UnixMarshal.ThrowExceptionForLastError ();
395 var buffer2 = new byte[1024];
396 ret = Syscall.recv (so1, buffer2, (ulong) buffer2.Length, 0);
398 UnixMarshal.ThrowExceptionForLastError ();
400 Assert.AreEqual (buffer1.Length, ret);
401 for (int i = 0; i < buffer1.Length; i++)
402 Assert.AreEqual (buffer1[i], buffer2[i]);
409 if (!Socket.OSSupportsIPv6)
410 Assert.Ignore ("OS does not support IPv6.");
412 var address = new SockaddrIn6 {
413 sin6_family = UnixAddressFamily.AF_INET6,
414 sin6_port = Syscall.htons (0),
415 sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
417 WithSockets (UnixAddressFamily.AF_INET6, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
418 if (Syscall.bind (so1, address) < 0)
419 UnixMarshal.ThrowExceptionForLastError ();
421 var address1Stor = new SockaddrStorage ();
422 if (Syscall.getsockname (so1, address1Stor) < 0)
423 UnixMarshal.ThrowExceptionForLastError ();
424 var address1 = new SockaddrIn6 ();
425 address1Stor.CopyTo (address1);
427 // Check getsockname(socket, null)
428 if (Syscall.getsockname (so1, null) < 0)
429 UnixMarshal.ThrowExceptionForLastError ();
431 var address2 = new SockaddrIn6 ();
432 if (Syscall.getsockname (so1, address2) < 0)
433 UnixMarshal.ThrowExceptionForLastError ();
435 Assert.AreEqual (address1, address2);
436 Assert.IsTrue (Syscall.ntohs (address1.sin6_port) != 0);
437 address1.sin6_port = 0;
438 Assert.AreEqual (address, address1);
440 var address3 = new Sockaddr ();
441 if (Syscall.getsockname (so1, address3) < 0)
442 UnixMarshal.ThrowExceptionForLastError ();
443 Assert.AreEqual (address.sa_family, address3.sa_family);
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 ());
454 public void UnixAccept ()
456 var address = new SockaddrUn (TempFolder + "/socket1");
457 var address2 = SockaddrUn.FromSockaddrStorage (address.ToSockaddrStorage ());
458 Assert.AreEqual (address, address2);
460 WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
461 if (Syscall.bind (so1, address) < 0)
462 UnixMarshal.ThrowExceptionForLastError ();
464 if (Syscall.listen (so1, 5) < 0)
465 UnixMarshal.ThrowExceptionForLastError ();
467 if (Syscall.connect (so2, address) < 0)
468 UnixMarshal.ThrowExceptionForLastError ();
470 var address3 = new SockaddrUn ();
471 if (Syscall.getsockname (so1, address3) < 0)
472 UnixMarshal.ThrowExceptionForLastError ();
473 Assert.AreEqual (address, address3);
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));
481 var address5 = new SockaddrUn ();
482 if (Syscall.getsockname (so1, address5) < 0)
483 UnixMarshal.ThrowExceptionForLastError ();
484 Assert.AreEqual (UnixAddressFamily.AF_UNIX, address5.sa_family);
486 // Check getsockname(socket, null)
487 if (Syscall.getsockname (so1, null) < 0)
488 UnixMarshal.ThrowExceptionForLastError ();
491 var remote = new SockaddrUn ();
492 if ((so3 = Syscall.accept (so1, remote)) < 0)
493 UnixMarshal.ThrowExceptionForLastError ();
495 // Send and receive a few bytes
497 var buffer1 = new byte[] { 42, 43, 44 };
498 ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
500 UnixMarshal.ThrowExceptionForLastError ();
502 var buffer2 = new byte[1024];
503 ret = Syscall.recv (so3, buffer2, (ulong) buffer2.Length, 0);
505 UnixMarshal.ThrowExceptionForLastError ();
507 Assert.AreEqual (buffer1.Length, ret);
508 for (int i = 0; i < buffer1.Length; i++)
509 Assert.AreEqual (buffer1[i], buffer2[i]);
511 if (Syscall.close (so3) < 0)
512 UnixMarshal.ThrowExceptionForLastError ();
518 public void Accept4 ()
520 WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
521 var address = new SockaddrUn (TempFolder + "/socket2");
522 if (Syscall.bind (so1, address) < 0)
523 UnixMarshal.ThrowExceptionForLastError ();
524 if (Syscall.listen (so1, 5) < 0)
525 UnixMarshal.ThrowExceptionForLastError ();
526 if (Syscall.connect (so2, address) < 0)
527 UnixMarshal.ThrowExceptionForLastError ();
530 var remote = new SockaddrUn ();
531 if ((so3 = Syscall.accept4 (so1, remote, UnixSocketFlags.SOCK_CLOEXEC | UnixSocketFlags.SOCK_NONBLOCK)) < 0)
532 UnixMarshal.ThrowExceptionForLastError ();
535 if ((_flags = Syscall.fcntl (so3, FcntlCommand.F_GETFL)) < 0)
536 UnixMarshal.ThrowExceptionForLastError ();
537 var flags = NativeConvert.ToOpenFlags (_flags);
538 Assert.IsTrue ((flags & OpenFlags.O_NONBLOCK) != 0);
541 if ((_flagsFD = Syscall.fcntl (so3, FcntlCommand.F_GETFD)) < 0)
542 UnixMarshal.ThrowExceptionForLastError ();
543 // FD_CLOEXEC must be set
544 //var flagsFD = NativeConvert.ToFdFlags (_flagsFD);
545 //Assert.IsTrue ((flagsFD & FdFlags.FD_CLOEXEC) != 0);
546 Assert.IsTrue (_flagsFD != 0);
548 if (Syscall.close (so3) < 0)
549 UnixMarshal.ThrowExceptionForLastError ();
555 public void SendToRecvFrom ()
557 WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
558 // Bind UDP socket so1 to 127.0.0.1 with dynamic port
559 var address = new SockaddrIn { sin_family = UnixAddressFamily.AF_INET, sin_port = Syscall.htons (0), sin_addr = new InAddr (127, 0, 0, 1) };
560 if (Syscall.bind (so1, address) < 0)
561 UnixMarshal.ThrowExceptionForLastError ();
563 // Get actual port number using getsockname()
564 var actualAddress = new SockaddrIn ();
565 if (Syscall.getsockname (so1, actualAddress) < 0)
566 UnixMarshal.ThrowExceptionForLastError ();
567 Assert.AreEqual (actualAddress.sa_family, UnixAddressFamily.AF_INET);
568 var port = Syscall.ntohs (actualAddress.sin_port);
569 Assert.IsTrue (port != 0);
572 var remoteAddress = new SockaddrIn {
573 sin_family = UnixAddressFamily.AF_INET,
574 sin_port = Syscall.htons (port),
575 sin_addr = new InAddr (127, 0, 0, 1),
578 // Send and receive a few bytes
580 var buffer1 = new byte[] { 42, 43, 44 };
581 ret = Syscall.sendto (so2, buffer1, (ulong) buffer1.Length, 0, remoteAddress);
583 UnixMarshal.ThrowExceptionForLastError ();
585 var senderAddress = new SockaddrIn ();
586 var buffer2 = new byte[1024];
587 ret = Syscall.recvfrom (so1, buffer2, (ulong) buffer2.Length, 0, senderAddress);
589 UnixMarshal.ThrowExceptionForLastError ();
590 Assert.AreEqual (senderAddress.sa_family, UnixAddressFamily.AF_INET);
591 Assert.AreEqual (senderAddress.sin_addr, new InAddr (127, 0, 0, 1));
593 Assert.AreEqual (buffer1.Length, ret);
594 for (int i = 0; i < buffer1.Length; i++)
595 Assert.AreEqual (buffer1[i], buffer2[i]);
605 // indent-tabs-mode: t