Add inet_pton() and inet_ntop() to Socket.
Steve Peters [Fri, 27 Mar 2009 00:59:23 +0000 (19:59 -0500)]
ext/Socket/Socket.pm
ext/Socket/Socket.xs
ext/Socket/t/Socket.t

index ad5e618..8ef4fb3 100644 (file)
@@ -1,11 +1,11 @@
 package Socket;
 
 our($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
-$VERSION = "1.81";
+$VERSION = "1.90";
 
 =head1 NAME
 
-Socket, sockaddr_in, sockaddr_un, inet_aton, inet_ntoa - load the C socket.h defines and structure manipulators 
+Socket, sockaddr_in, sockaddr_un, inet_aton, inet_ntoa, inet_pton, inet_ntop - load the C socket.h defines and structure manipulators 
 
 =head1 SYNOPSIS
 
@@ -171,6 +171,21 @@ Takes a sockaddr_un structure (as returned by pack_sockaddr_un())
 and returns the pathname.  Will croak if the structure does not
 have AF_UNIX in the right place.
 
+=item inet_pton ADDRESS_FAMILY, HOSTNAME
+
+Takes an address family, either AF_INET or AF_INET6, and a string giving
+the name of a host, and translates that to an opaque string
+(if programming in C, struct in_addr or struct in6_addr depending on the 
+address family passed in).  The host string may be a string hostname, such
+as 'www.perl.org', or an IP address.  If using an IP address, the type of
+IP address must be consistant with the address family passed into the function.
+
+=item inet_ntop ADDRESS_FAMILY, IP_ADDRESS
+
+Takes an address family, either AF_INET or AF_INET6, and a string 
+(an opaque string as returned by inet_aton() or inet_pton()) and
+translates it to an IPv4 or IPv6 address string.
+
 =back
 
 =cut
index 076297f..064de2e 100644 (file)
@@ -442,3 +442,53 @@ unpack_sockaddr_in(sin_sv)
        PUSHs(sv_2mortal(newSViv((IV) port)));
        PUSHs(sv_2mortal(newSVpvn((char *)&ip_address, sizeof ip_address)));
        }
+
+void
+inet_ntop(af, ip_address_sv)
+        int     af
+        SV *    ip_address_sv
+        CODE:
+#ifdef HAS_INETNTOP
+       STRLEN addrlen, struct_size;
+       struct in6_addr addr;
+       char str[INET6_ADDRSTRLEN];
+       char *ip_address = SvPV(ip_address_sv, addrlen);
+
+        if(af == AF_INET) {
+            struct_size = sizeof(struct in_addr);
+        } else if(af == AF_INET6) {
+            struct_size = sizeof(struct in6_addr);
+        } else {
+           croak("Bad address family for Socket::inet_ntop, got %d, should be either AF_INET or AF_INET6",
+               af);
+        }
+
+       Copy( ip_address, &addr, sizeof addr, char );
+       inet_ntop(af, &addr, str, INET6_ADDRSTRLEN);
+
+       ST(0) = sv_2mortal(newSVpv(str, strlen(str)));
+#else
+        ST(0) = (SV *)not_here("inet_ntop");
+#endif
+
+void
+inet_pton(af, host)
+        int           af
+        const char *  host
+        CODE:
+#ifdef HAS_INETPTON
+        struct in6_addr ip_address;
+        if(af != AF_INET && af != AF_INET6) {
+           croak("Bad address family for %s, got %d, should be either AF_INET or AF_INET6",
+                        "Socket::inet_pton",
+                        af);
+        }
+        int ok = (*host != '\0') && inet_pton(af, host, &ip_address);
+
+        ST(0) = sv_newmortal();
+        if (ok) {
+                sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address );
+        }
+#else
+        ST(0) = (SV *)not_here("inet_pton");
+#endif
index f707999..cec72e7 100755 (executable)
@@ -14,7 +14,7 @@ BEGIN {
        
 use Socket qw(:all);
 
-print "1..17\n";
+print "1..20\n";
 
 $has_echo = $^O ne 'MSWin32';
 $alarmed = 0;
@@ -167,3 +167,13 @@ if ($^O eq 'linux') {
     # doesn't have abstract socket support
     print "ok 17 - 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");
+} else {
+    # no IPv6 
+    print "ok 18 - skipped on this platform\n";
+    print "ok 19 - skipped on this platform\n";
+}