Add support for Abstract namespace sockets
Lubomir Rintel [Tue, 25 Aug 2009 15:09:53 +0000 (17:09 +0200)]
Abstract namespace sockets are Linux-specific socket type that live in
AF_UNIX family, slightly abusing it to be able to use arbitrary
character arrays as addresses: They start with nul byte and are not
terminated by nul byte, but with the length passed to the socket()
system call.

Added regression test for the correct address length computation.

Signed-off-by: Lubomir Rintel <lkundrak@fedoraproject.org>

ext/Socket/Socket.xs
ext/Socket/t/Socket.t

index 75d0f33..d46a6b9 100644 (file)
@@ -303,6 +303,7 @@ pack_sockaddr_un(pathname)
        struct sockaddr_un sun_ad; /* fear using sun */
        STRLEN len;
        char * pathname_pv;
+       int addr_len;
 
        Zero( &sun_ad, sizeof sun_ad, char );
        sun_ad.sun_family = AF_UNIX;
@@ -336,7 +337,17 @@ pack_sockaddr_un(pathname)
        Copy( pathname_pv, sun_ad.sun_path, len, char );
 #  endif
        if (0) not_here("dummy");
-       ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, sizeof sun_ad));
+       if (len > 1 && sun_ad.sun_path[0] == '\0') {
+               /* Linux-style abstract-namespace socket.
+                * The name is not a file name, but an array of arbitrary
+                * character, starting with \0 and possibly including \0s,
+                * therefore the length of the structure must denote the
+                * end of that character array */
+               addr_len = (void *)&sun_ad.sun_path - (void *)&sun_ad + len;
+       } else {
+               addr_len = sizeof sun_ad;
+       }
+       ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, addr_len));
 #else
        ST(0) = (SV *) not_here("pack_sockaddr_un");
 #endif
index aeeb2a0..09d25f9 100644 (file)
@@ -14,7 +14,7 @@ BEGIN {
        
 use Socket qw(:all);
 
-print "1..20\n";
+print "1..21\n";
 
 $has_echo = $^O ne 'MSWin32';
 $alarmed = 0;
@@ -163,16 +163,26 @@ if ($^O eq 'linux') {
        print "# got <$path>\n";
         print "not ok 17\n";
     }
+
+    # see if we calculate the address structure length correctly
+    if (length ($test_abstract_socket) + 2 == length $addr) {
+        print "ok 18\n";
+    } else {
+       print "# got ".(length $addr)."\n";
+        print "not ok 18\n";
+    }
+
 } else {
     # doesn't have abstract socket support
     print "ok 17 - skipped on this platform\n";
+    print "ok 18 - skipped on this platform\n";
 }
 
 if($Config{d_inetntop} && $Config{d_inetaton}){
-    print ((inet_ntop(AF_INET, inet_pton(AF_INET, "10.20.30.40")) eq "10.20.30.40") ? "ok 18\n" : "not ok 18\n");
-    print ((inet_ntop(AF_INET, inet_aton("10.20.30.40")) eq "10.20.30.40") ? "ok 19\n" : "not ok 19\n");
-    print (lc(inet_ntop(AF_INET6, inet_pton(AF_INET6, "2001:503:BA3E::2:30")) eq "2001:503:ba3e::2:30") ? "ok 20\n" : "not ok 20\n");
+    print ((inet_ntop(AF_INET, inet_pton(AF_INET, "10.20.30.40")) eq "10.20.30.40") ? "ok 19\n" : "not ok 19\n");
+    print ((inet_ntop(AF_INET, inet_aton("10.20.30.40")) eq "10.20.30.40") ? "ok 20\n" : "not ok 20\n");
+    print (lc(inet_ntop(AF_INET6, inet_pton(AF_INET6, "2001:503:BA3E::2:30")) eq "2001:503:ba3e::2:30") ? "ok 21\n" : "not ok 21\n");
 } else {
     # no IPv6 
-    print "ok $_ - skipped on this platform\n" for 18 .. 20;
+    print "ok $_ - skipped on this platform\n" for 19 .. 21;
 }