--- /dev/null 2003-01-30 11:24:37.000000000 +0100 +++ ./config/auto-aux/gethostbyname2.c 2003-09-29 22:23:34.000000000 +0200 @@ -0,0 +1,15 @@ + +#include +#include + +int main(int argc, char ** argv) +{ + struct hostent *hp; + struct hostent h; + char buffer[1000]; + int h_errno; + int rc; + rc = gethostbyname2_r("www.caml.org", AF_INET, + &h, buffer, 10, &hp, &h_errno); + return 0; +} --- ./otherlibs/threads/unix.ml.ipv6 2003-03-20 17:24:03.000000000 +0100 +++ ./otherlibs/threads/unix.ml 2003-09-29 22:23:34.000000000 +0200 @@ -481,17 +481,32 @@ external getgrgid : int -> group_entry = "unix_getgrgid" type inet_addr +type inet_addr_family = + | AF_INET + | AF_INET6 external inet_addr_of_string : string -> inet_addr = "unix_inet_addr_of_string" external string_of_inet_addr : inet_addr -> string = "unix_string_of_inet_addr" +external inet_addr_family : inet_addr -> inet_addr_family + = "unix_inet_addr_type" let inet_addr_any = inet_addr_of_string "0.0.0.0" +let inet6_addr_any = inet_addr_of_string "::" + +external in6_is_addr_unspecified : inet_addr -> bool = "unix_in6_is_addr_unspecified" +external in6_is_addr_loopback : inet_addr -> bool = "unix_in6_is_addr_loopback" +external in6_is_addr_multicast : inet_addr -> bool = "unix_in6_is_addr_multicast" +external in6_is_addr_linklocal : inet_addr -> bool = "unix_in6_is_addr_linklocal" +external in6_is_addr_sitelocal : inet_addr -> bool = "unix_in6_is_addr_sitelocal" +external in6_is_addr_v4mapped : inet_addr -> bool = "unix_in6_is_addr_v4mapped" +external in6_is_addr_v4compat : inet_addr -> bool = "unix_in6_is_addr_v4compat" type socket_domain = PF_UNIX | PF_INET + | PF_INET6 type socket_type = SOCK_STREAM @@ -661,6 +676,8 @@ external gethostname : unit -> string = "unix_gethostname" external gethostbyname : string -> host_entry = "unix_gethostbyname" +external gethostbyname2 : string -> inet_addr_family -> host_entry + = "unix_gethostbyname2" external gethostbyaddr : inet_addr -> host_entry = "unix_gethostbyaddr" external getprotobyname : string -> protocol_entry = "unix_getprotobyname" @@ -670,6 +687,37 @@ = "unix_getservbyname" external getservbyport : int -> string -> service_entry = "unix_getservbyport" +type addrinfo = { + ai_family : socket_domain ; + ai_socktype : socket_type ; + ai_protocol : int ; + ai_canonname : string ; + ai_addr : sockaddr ; + } + +type addrinfo_flags = + AI_PASSIVE + | AI_CANONNAME + | AI_NUMERICHOST + +external getaddrinfo : string -> string -> + ?family:socket_domain -> + ?socktype:socket_type -> + ?protocol:int -> + addrinfo_flags list -> addrinfo list + = "unix_getaddrinfo_bc" "unix_getaddrinfo" + +type nameinfo_flags = + NI_NOFQDN + | NI_NUMERICHOST + | NI_NAMEREQD + | NI_NUMERICSERV + | NI_DGRAM + +external getnameinfo : sockaddr -> nameinfo_flags list -> string * string + = "unix_getnameinfo" + + type terminal_io = { mutable c_ignbrk: bool; mutable c_brkint: bool; @@ -888,9 +936,16 @@ (* High-level network functions *) +let sockdomain_of_sockaddr = function + ADDR_UNIX _ -> PF_UNIX + | ADDR_INET (a,_) -> + match inet_addr_family a with + AF_INET -> PF_INET + | AF_INET6 -> PF_INET6 + + let open_connection sockaddr = - let domain = - match sockaddr with ADDR_UNIX _ -> PF_UNIX | ADDR_INET(_,_) -> PF_INET in + let domain = sockdomain_of_sockaddr sockaddr in let sock = socket domain SOCK_STREAM 0 in try @@ -903,8 +958,7 @@ shutdown (descr_of_in_channel inchan) SHUTDOWN_SEND let establish_server server_fun sockaddr = - let domain = - match sockaddr with ADDR_UNIX _ -> PF_UNIX | ADDR_INET(_,_) -> PF_INET in + let domain = sockdomain_of_sockaddr sockaddr in let sock = socket domain SOCK_STREAM 0 in setsockopt sock SO_REUSEADDR true; --- ./otherlibs/unix/socketaddr.c.ipv6 2001-12-07 14:40:35.000000000 +0100 +++ ./otherlibs/unix/socketaddr.c 2003-09-29 22:23:34.000000000 +0200 @@ -18,6 +18,7 @@ #include #include #include +#include #include "unixsupport.h" #ifdef HAS_SOCKETS @@ -39,6 +40,17 @@ return res; } +value alloc_inet6_addr(struct in6_addr *a) +{ + value res; + /* Use a string rather than an abstract block so that it can be + marshaled safely. Remember that a is in network byte order, + hence can be marshaled safely. */ + res = alloc_string(sizeof (a->s6_addr)); + memcpy(String_val(res), a, sizeof(a->s6_addr)); + return res; +} + void get_sockaddr(value mladr, union sock_addr_union * adr /*out*/, socklen_param_type * adr_len /*out*/) @@ -63,20 +75,53 @@ #endif case 1: /* ADDR_INET */ { - char * p; - int n; - for (p = (char *) &adr->s_inet, n = sizeof(adr->s_inet); - n > 0; p++, n--) - *p = 0; - adr->s_inet.sin_family = AF_INET; - adr->s_inet.sin_addr.s_addr = GET_INET_ADDR(Field(mladr, 0)); - adr->s_inet.sin_port = htons(Int_val(Field(mladr, 1))); - *adr_len = sizeof(struct sockaddr_in); - break; + switch(string_length(Field(mladr, 0))) { + case 4: { /* IN_ADDR */ + char * p; + int n; + for (p = (char *) &adr->s_inet, n = sizeof(adr->s_inet); + n > 0; p++, n--) + *p = 0; + adr->s_inet.sin_family = AF_INET; + adr->s_inet.sin_addr.s_addr = GET_INET_ADDR(Field(mladr, 0)); + adr->s_inet.sin_port = htons(Int_val(Field(mladr, 1))); + *adr_len = sizeof(struct sockaddr_in); + break; + } + case 16: { /* IN6_ADDR */ + memset(&adr->s_inet6, 0, sizeof(adr->s_inet6)); + adr->s_inet6.sin6_family = AF_INET6; + memcpy(adr->s_inet6.sin6_addr.s6_addr, + String_val(Field(mladr, 0)), + sizeof(adr->s_inet6.sin6_addr.s6_addr)); + adr->s_inet6.sin6_port = htons(Int_val(Field(mladr, 1))); + *adr_len = sizeof(struct sockaddr_in6); + break; + } + default: + failwith("get_sockaddr"); + } } } } +void get_in_addr(value mladdr, + union in_addr_union *addr /*out*/, + size_t *addr_len /*out*/) +{ + switch(string_length(mladdr)) { + case 4: + addr->a_in.s_addr = GET_INET_ADDR(mladdr); + *addr_len = 4; + return; + case 16: + memcpy(addr->a_in6.s6_addr, String_val(mladdr), 16); + *addr_len = 16; + return; + } + failwith("get_in_addr"); +} + value alloc_sockaddr(union sock_addr_union * adr /*in*/, socklen_param_type adr_len) { @@ -101,6 +146,15 @@ End_roots(); break; } + case AF_INET6: + { value a = alloc_inet6_addr( &(adr->s_inet6.sin6_addr) ); + Begin_root (a); + res = alloc_small(2, 1); + Field(res,0) = a; + Field(res,1) = Val_int(ntohs(adr->s_inet6.sin6_port)); + End_roots(); + break; + } default: unix_error(EAFNOSUPPORT, "", Nothing); } --- ./otherlibs/unix/addrofstr.c.ipv6 2001-12-07 14:40:24.000000000 +0100 +++ ./otherlibs/unix/addrofstr.c 2003-09-29 22:23:34.000000000 +0200 @@ -23,7 +23,19 @@ CAMLprim value unix_inet_addr_of_string(value s) { -#ifdef HAS_INET_ATON +#ifdef HAS_INET_PTON + union in_addr_union address; + int retcode; + retcode = inet_pton(AF_INET, String_val(s), &address); + if (retcode > 0) + return alloc_inet_addr(address.a_in.s_addr); + retcode = inet_pton(AF_INET6, String_val(s), &address); + if (retcode > 0) + return alloc_inet6_addr(&address.a_in6); + failwith("inet_addr_of_string"); + return Nothing; + +#elif defined (HAS_INET_ATON) struct in_addr address; if (inet_aton(String_val(s), &address) == 0) failwith("inet_addr_of_string"); --- ./otherlibs/unix/socket.c.ipv6 2001-12-07 14:40:35.000000000 +0100 +++ ./otherlibs/unix/socket.c 2003-09-29 22:23:34.000000000 +0200 @@ -22,7 +22,7 @@ #include int socket_domain_table[] = { - PF_UNIX, PF_INET + PF_UNIX, PF_INET, PF_INET6 }; int socket_type_table[] = { --- ./otherlibs/unix/socketaddr.h.ipv6 2001-12-07 14:40:35.000000000 +0100 +++ ./otherlibs/unix/socketaddr.h 2003-09-29 22:23:34.000000000 +0200 @@ -20,10 +20,16 @@ #include #include +union in_addr_union { + struct in_addr a_in; + struct in6_addr a_in6; +}; + union sock_addr_union { struct sockaddr s_gen; struct sockaddr_un s_unix; struct sockaddr_in s_inet; + struct sockaddr_in6 s_inet6; }; extern union sock_addr_union sock_addr; @@ -37,8 +43,12 @@ void get_sockaddr (value mladdr, union sock_addr_union * addr /*out*/, socklen_param_type * addr_len /*out*/); +void get_in_addr(value mladdr, + union in_addr_union *addr /*out*/, + size_t *addr_len /*out*/); CAMLprim value alloc_sockaddr (union sock_addr_union * addr /*in*/, socklen_param_type addr_len); CAMLprim value alloc_inet_addr (uint32 inaddr); +CAMLprim value alloc_inet6_addr (struct in6_addr *); #define GET_INET_ADDR(v) (*((uint32 *) (v))) --- ./otherlibs/unix/strofaddr.c.ipv6 2001-12-07 14:40:36.000000000 +0100 +++ ./otherlibs/unix/strofaddr.c 2003-09-29 22:23:34.000000000 +0200 @@ -15,6 +15,7 @@ #include #include +#include #include "unixsupport.h" #ifdef HAS_SOCKETS @@ -23,9 +24,31 @@ CAMLprim value unix_string_of_inet_addr(value a) { - struct in_addr address; - address.s_addr = GET_INET_ADDR(a); - return copy_string(inet_ntoa(address)); + union in_addr_union address; + size_t addrlen; + get_in_addr(a, &address, &addrlen); +#ifdef HAS_INET_NTOP + switch(addrlen) { + case 4: { /* IN_ADDR */ + char host[INET_ADDRSTRLEN+ 1]; + return copy_string(inet_ntop(AF_INET, &address, host, sizeof(host))); + } + case 16: { /* IN6_ADDR */ + char host[INET6_ADDRSTRLEN+ 1]; + return copy_string(inet_ntop(AF_INET6, &address, host, sizeof(host))); + } +#else + switch(addrlen) { + case 4: { /* IN_ADDR */ + return copy_string(inet_ntoa(address.a_in)); + } + case 16: /* IN6_ADDR */ + invalid_argument("string_of_inet_addr not implemented for IPv6"); +#endif + default: + failwith("string_of_inet_addr"); + } + return Nothing; } #else @@ -34,3 +57,16 @@ { invalid_argument("string_of_inet_addr not implemented"); } #endif + +CAMLprim value unix_inet_addr_type(value a) +{ + switch(string_length(a)) { + case 4: /* IN_ADDR */ + return Val_int(0); + case 16: /* IN6_ADDR */ + return Val_int(1); + default: + failwith("inet_addr_type"); + } + return Nothing; +} --- ./otherlibs/unix/unix.ml.ipv6 2002-07-12 11:47:54.000000000 +0200 +++ ./otherlibs/unix/unix.ml 2003-09-29 22:23:35.000000000 +0200 @@ -374,17 +374,33 @@ external getgrgid : int -> group_entry = "unix_getgrgid" type inet_addr +type inet_addr_family = + | AF_INET + | AF_INET6 external inet_addr_of_string : string -> inet_addr = "unix_inet_addr_of_string" external string_of_inet_addr : inet_addr -> string = "unix_string_of_inet_addr" +external inet_addr_family : inet_addr -> inet_addr_family + = "unix_inet_addr_type" + let inet_addr_any = inet_addr_of_string "0.0.0.0" +let inet6_addr_any = inet_addr_of_string "::" + +external in6_is_addr_unspecified : inet_addr -> bool = "unix_in6_is_addr_unspecified" +external in6_is_addr_loopback : inet_addr -> bool = "unix_in6_is_addr_loopback" +external in6_is_addr_multicast : inet_addr -> bool = "unix_in6_is_addr_multicast" +external in6_is_addr_linklocal : inet_addr -> bool = "unix_in6_is_addr_linklocal" +external in6_is_addr_sitelocal : inet_addr -> bool = "unix_in6_is_addr_sitelocal" +external in6_is_addr_v4mapped : inet_addr -> bool = "unix_in6_is_addr_v4mapped" +external in6_is_addr_v4compat : inet_addr -> bool = "unix_in6_is_addr_v4compat" type socket_domain = PF_UNIX | PF_INET + | PF_INET6 type socket_type = SOCK_STREAM @@ -508,6 +524,8 @@ external gethostname : unit -> string = "unix_gethostname" external gethostbyname : string -> host_entry = "unix_gethostbyname" +external gethostbyname2 : string -> inet_addr_family -> host_entry + = "unix_gethostbyname2" external gethostbyaddr : inet_addr -> host_entry = "unix_gethostbyaddr" external getprotobyname : string -> protocol_entry = "unix_getprotobyname" @@ -517,6 +535,37 @@ = "unix_getservbyname" external getservbyport : int -> string -> service_entry = "unix_getservbyport" + +type addrinfo = { + ai_family : socket_domain ; + ai_socktype : socket_type ; + ai_protocol : int ; + ai_canonname : string ; + ai_addr : sockaddr ; + } + +type addrinfo_flags = + AI_PASSIVE + | AI_CANONNAME + | AI_NUMERICHOST + +external getaddrinfo : string -> string -> + ?family:socket_domain -> + ?socktype:socket_type -> + ?protocol:int -> + addrinfo_flags list -> addrinfo list + = "unix_getaddrinfo_bc" "unix_getaddrinfo" + +type nameinfo_flags = + NI_NOFQDN + | NI_NUMERICHOST + | NI_NAMEREQD + | NI_NUMERICSERV + | NI_DGRAM + +external getnameinfo : sockaddr -> nameinfo_flags list -> string * string + = "unix_getnameinfo" + type terminal_io = { mutable c_ignbrk: bool; mutable c_brkint: bool; @@ -735,9 +784,15 @@ (* High-level network functions *) +let sockdomain_of_sockaddr = function + ADDR_UNIX _ -> PF_UNIX + | ADDR_INET (a,_) -> + match inet_addr_family a with + AF_INET -> PF_INET + | AF_INET6 -> PF_INET6 + let open_connection sockaddr = - let domain = - match sockaddr with ADDR_UNIX _ -> PF_UNIX | ADDR_INET(_,_) -> PF_INET in + let domain = sockdomain_of_sockaddr sockaddr in let sock = socket domain SOCK_STREAM 0 in try @@ -750,8 +805,7 @@ shutdown (descr_of_in_channel inchan) SHUTDOWN_SEND let establish_server server_fun sockaddr = - let domain = - match sockaddr with ADDR_UNIX _ -> PF_UNIX | ADDR_INET(_,_) -> PF_INET in + let domain = sockdomain_of_sockaddr sockaddr in let sock = socket domain SOCK_STREAM 0 in setsockopt sock SO_REUSEADDR true; --- ./otherlibs/unix/unix.mli.ipv6 2003-09-14 18:46:31.000000000 +0200 +++ ./otherlibs/unix/unix.mli 2003-09-29 22:23:35.000000000 +0200 @@ -834,6 +834,10 @@ type inet_addr (** The abstract type of Internet addresses. *) +type inet_addr_family = + | AF_INET + | AF_INET6 + val inet_addr_of_string : string -> inet_addr (** Conversions between string with the format [XXX.YYY.ZZZ.TTT] and Internet addresses. [inet_addr_of_string] raises [Failure] @@ -842,10 +846,25 @@ val string_of_inet_addr : inet_addr -> string (** See {!Unix.inet_addr_of_string}. *) +val inet_addr_family : inet_addr -> inet_addr_family + val inet_addr_any : inet_addr (** A special Internet address, for use only with [bind], representing all the Internet addresses that the host machine possesses. *) +val inet6_addr_any : inet_addr +(** A special IPv6 address, for use only with [bind], representing + all the Internet addresses that the host machine possesses. *) + +(** {7 IPv6 address testing functions} *) + +val in6_is_addr_unspecified : inet_addr -> bool +val in6_is_addr_loopback : inet_addr -> bool +val in6_is_addr_multicast : inet_addr -> bool +val in6_is_addr_linklocal : inet_addr -> bool +val in6_is_addr_sitelocal : inet_addr -> bool +val in6_is_addr_v4mapped : inet_addr -> bool +val in6_is_addr_v4compat : inet_addr -> bool (** {6 Sockets} *) @@ -853,6 +872,7 @@ type socket_domain = PF_UNIX (** Unix domain *) | PF_INET (** Internet domain *) + | PF_INET6 (** IPv6 protoccol *) (** The type of socket domains. *) type socket_type = @@ -1013,6 +1033,8 @@ (** {6 High-level network connection functions} *) +val sockdomain_of_sockaddr : sockaddr -> socket_domain +(** Returns the appropriate socket_domain for the given address *) val open_connection : sockaddr -> in_channel * out_channel (** Connect to a server at the given address. @@ -1066,6 +1088,10 @@ (** Find an entry in [hosts] with the given name, or raise [Not_found]. *) +val gethostbyname2 : string -> inet_addr_family -> host_entry +(** Find an entry in [hosts] with the given name and address + family, or raise [Not_found]. *) + val gethostbyaddr : inet_addr -> host_entry (** Find an entry in [hosts] with the given address, or raise [Not_found]. *) @@ -1086,7 +1112,33 @@ (** Find an entry in [services] with the given service number, or raise [Not_found]. *) +type addrinfo = { + ai_family : socket_domain ; + ai_socktype : socket_type ; + ai_protocol : int ; + ai_canonname : string ; + ai_addr : sockaddr ; + } + +type addrinfo_flags = + AI_PASSIVE + | AI_CANONNAME + | AI_NUMERICHOST + +val getaddrinfo : string -> string -> + ?family:socket_domain -> + ?socktype:socket_type -> + ?protocol:int -> + addrinfo_flags list -> addrinfo list + +type nameinfo_flags = + NI_NOFQDN + | NI_NUMERICHOST + | NI_NAMEREQD + | NI_NUMERICSERV + | NI_DGRAM +val getnameinfo : sockaddr -> nameinfo_flags list -> string * string (** {6 Terminal interface} *) --- ./otherlibs/unix/gethost.c.ipv6 2002-06-07 11:49:40.000000000 +0200 +++ ./otherlibs/unix/gethost.c 2003-09-29 22:23:35.000000000 +0200 @@ -42,9 +42,21 @@ static value alloc_one_addr(char const *a) { - struct in_addr addr; - memmove (&addr, a, entry_h_length); - return alloc_inet_addr(addr.s_addr); + switch(entry_h_length) { + case 4: { /* IN_ADDR */ + struct in_addr addr; + memmove (&addr, a, entry_h_length); + return alloc_inet_addr(addr.s_addr); + } + case 16: { /* IN6_ADDR */ + struct in6_addr addr; + memmove (&addr, a, entry_h_length); + return alloc_inet6_addr(&addr); + } + default: + failwith("alloc_one_addr"); + } + return Nothing; } static value alloc_host_entry(struct hostent *entry) @@ -67,22 +79,35 @@ res = alloc_small(4, 0); Field(res, 0) = name; Field(res, 1) = aliases; - Field(res, 2) = entry->h_addrtype == PF_UNIX ? Val_int(0) : Val_int(1); Field(res, 3) = addr_list; + switch(entry->h_addrtype) { + case AF_UNIX: + Field(res, 2) = Val_int(0); break; + case AF_INET: + Field(res, 2) = Val_int(1); break; + case AF_INET6: + Field(res, 2) = Val_int(2); break; + default: + abort(); + } End_roots(); return res; } CAMLprim value unix_gethostbyaddr(value a) { - uint32 adr = GET_INET_ADDR(a); + union in_addr_union adr; struct hostent * hp; + size_t adr_len; + int adr_family; + get_in_addr(a, &adr, &adr_len); + adr_family = adr_len == 4 ? AF_INET : AF_INET6; #if HAS_GETHOSTBYADDR_R == 7 struct hostent h; char buffer[NETDB_BUFFER_SIZE]; int h_errnop; enter_blocking_section(); - hp = gethostbyaddr_r((char *) &adr, 4, AF_INET, + hp = gethostbyaddr_r((char *) &adr, adr_len, adr_family, &h, buffer, sizeof(buffer), &h_errnop); leave_blocking_section(); #elif HAS_GETHOSTBYADDR_R == 8 @@ -90,7 +115,7 @@ char buffer[NETDB_BUFFER_SIZE]; int h_errnop, rc; enter_blocking_section(); - rc = gethostbyaddr_r((char *) &adr, 4, AF_INET, + rc = gethostbyaddr_r((char *) &adr, adr_len, adr_family, &h, buffer, sizeof(buffer), &hp, &h_errnop); leave_blocking_section(); if (rc != 0) hp = NULL; @@ -98,7 +123,7 @@ #ifdef GETHOSTBYADDR_IS_REENTRANT enter_blocking_section(); #endif - hp = gethostbyaddr((char *) &adr, 4, AF_INET); + hp = gethostbyaddr((char *) &adr, adr_len, adr_family); #ifdef GETHOSTBYADDR_IS_REENTRANT leave_blocking_section(); #endif @@ -165,3 +190,35 @@ { invalid_argument("gethostbyname not implemented"); } #endif + +#ifdef HAS_GETHOSTBYNAME2_R +CAMLprim value unix_gethostbyname2(value name, value family) +{ + struct hostent * hp; + char * hostname; + int adr_family = Int_val(family) == 0 ? AF_INET : AF_INET6; + + hostname = stat_alloc(string_length(name) + 1); + strcpy(hostname, String_val(name)); + { + struct hostent h; + char buffer[NETDB_BUFFER_SIZE]; + int h_errno, rc; + enter_blocking_section(); + rc = gethostbyname2_r(hostname, adr_family, + &h, buffer, sizeof(buffer), &hp, &h_errno); + leave_blocking_section(); + if (rc != 0) hp = NULL; + } + stat_free(hostname); + + if (hp == (struct hostent *) NULL) raise_not_found(); + return alloc_host_entry(hp); +} + +#else + +CAMLprim value unix_gethostbyname2(value name, value family) +{ invalid_argument("gethostbyname not implemented"); } + +#endif --- ./otherlibs/unix/Makefile.ipv6 2002-06-27 13:36:02.000000000 +0200 +++ ./otherlibs/unix/Makefile 2003-09-29 22:23:35.000000000 +0200 @@ -28,11 +28,11 @@ OBJS=accept.o access.o addrofstr.o alarm.o bind.o chdir.o chmod.o \ chown.o chroot.o close.o closedir.o connect.o cst2constr.o cstringv.o \ dup.o dup2.o envir.o errmsg.o execv.o execve.o execvp.o exit.o \ - fchmod.o fchown.o fcntl.o fork.o ftruncate.o getcwd.o getegid.o \ - geteuid.o getgid.o getgr.o getgroups.o gethost.o gethostname.o \ - getlogin.o getpeername.o getpid.o getppid.o getproto.o getpw.o \ - gettimeofday.o getserv.o getsockname.o getuid.o \ - gmtime.o itimer.o kill.o link.o listen.o lockf.o lseek.o mkdir.o \ + fchmod.o fchown.o fcntl.o fork.o ftruncate.o getaddrinfo.o \ + getcwd.o getegid.o geteuid.o getgid.o getgr.o getgroups.o gethost.o \ + gethostname.o getlogin.o getpeername.o getpid.o getppid.o getproto.o \ + getpw.o gettimeofday.o getserv.o getsockname.o getuid.o \ + gmtime.o ipv6macros.o itimer.o kill.o link.o listen.o lockf.o lseek.o mkdir.o \ mkfifo.o nice.o open.o opendir.o pipe.o putenv.o read.o \ readdir.o readlink.o rename.o rewinddir.o rmdir.o select.o sendrecv.o \ setgid.o setsid.o setuid.o shutdown.o signals.o \ --- /dev/null 2003-01-30 11:24:37.000000000 +0100 +++ ./otherlibs/unix/ipv6macros.c 2003-09-29 22:23:35.000000000 +0200 @@ -0,0 +1,106 @@ + +#include +#include + +#include +#include + +#include "socketaddr.h" + +CAMLprim value unix_in6_is_addr_unspecified(value a) +{ +#ifdef IN6_IS_ADDR_UNSPECIFIED + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_UNSPECIFIED(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_loopback(value a) +{ +#ifdef IN6_IS_ADDR_LOOPBACK + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_LOOPBACK(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_multicast(value a) +{ +#ifdef IN6_IS_ADDR_MULTICAST + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_MULTICAST(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_linklocal(value a) +{ +#ifdef IN6_IS_ADDR_LINKLOCAL + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_LINKLOCAL(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_sitelocal(value a) +{ +#ifdef IN6_IS_ADDR_SITELOCAL + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_SITELOCAL(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_v4mapped(value a) +{ +#ifdef IN6_IS_ADDR_V4MAPPED + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_V4MAPPED(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} + +CAMLprim value unix_in6_is_addr_v4compat(value a) +{ +#ifdef IN6_IS_ADDR_V4COMPAT + union in_addr_union addr; + size_t addr_len; + get_in_addr(a, &addr, &addr_len); + if(addr_len != 16) + invalid_argument("not an AF_INET6 address"); + return Val_bool(IN6_IS_ADDR_V4COMPAT(&addr.a_in6)); +#else + invalid_argument("not implemented"); +#endif +} --- /dev/null 2003-01-30 11:24:37.000000000 +0100 +++ ./otherlibs/unix/getaddrinfo.c 2003-09-29 22:23:35.000000000 +0200 @@ -0,0 +1,178 @@ +#include + +#include +#include +#include +#include +#include +#include "unixsupport.h" + +#ifdef HAS_SOCKETS + +#include "socketaddr.h" +#include + +extern int socket_domain_table[]; +extern int socket_type_table[]; + +static void gai_fail(const char *, int) Noreturn; + +#define MSG_BUFFER_SIZE 1024 + +static void gai_fail(const char *msg1, int gai_errcode) +{ + switch (gai_errcode) { + case EAI_NONAME: + raise_not_found(); + default: { + char msg[MSG_BUFFER_SIZE]; + const char *msg2 = gai_strerror(gai_errcode); + snprintf(msg, MSG_BUFFER_SIZE, "%s (%s)", msg1, msg2); + failwith(msg); + } + } +} + +#ifdef HAS_GETADDRINFO +CAMLprim value unix_getaddrinfo(value nodename, value servname, + value ofamily, value osocktype, + value oprotocol, value flags) +{ + struct addrinfo *res, *hints, cnv; + char *node, *serv; + int rc; + + if (Is_block(ofamily) || Is_block(osocktype) || + Is_block(oprotocol) || Is_block(flags)) { + memset(&cnv, 0, sizeof cnv); + hints = &cnv; + } else + hints = NULL; + if (Is_block(ofamily)) + hints->ai_family = socket_domain_table[ Int_val(Field(ofamily, 0)) ]; + if (Is_block(osocktype)) + hints->ai_socktype = socket_type_table[ Int_val(Field(osocktype, 0)) ]; + if (Is_block(oprotocol)) + hints->ai_protocol = Int_val(Field(oprotocol, 0)); + if (Is_block(flags)) { + int ai_flags_table[] = { AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, } ; + hints->ai_flags = convert_flag_list(flags, ai_flags_table); + } + if (string_length(nodename)) { + node = stat_alloc(string_length(nodename) +1); + strcpy(node, String_val(nodename)); + } + else node = NULL; + if (string_length(servname)) { + serv = stat_alloc(string_length(servname) +1); + strcpy(serv, String_val(servname)); + } + else serv = NULL; + + enter_blocking_section(); + rc = getaddrinfo(node, serv, hints, &res); + leave_blocking_section(); + + if (node) stat_free(node); + if (serv) stat_free(serv); + if (rc == 0) { + CAMLparam0(); + CAMLlocal5(vli, vtmp, vcell, vcanon, vaddr); + struct addrinfo *cell = res; + vli = Val_unit; + while (cell) { + vcanon = cell->ai_canonname ? + copy_string(cell->ai_canonname) : copy_string(""); + vaddr = alloc_sockaddr((union sock_addr_union *)(cell->ai_addr), + cell->ai_addrlen); + vcell = alloc_small(5, 0); + switch(cell->ai_family) { + case PF_UNIX: Field(vcell, 0) = Val_int(0); break; + case PF_INET: Field(vcell, 0) = Val_int(1); break; + case PF_INET6: Field(vcell, 0) = Val_int(2); break; + } + switch(cell->ai_socktype) { + case SOCK_STREAM: Field(vcell, 1) = Val_int(0); break; + case SOCK_DGRAM: Field(vcell, 1) = Val_int(1); break; + case SOCK_RAW: Field(vcell, 1) = Val_int(2); break; + case SOCK_SEQPACKET: Field(vcell, 1) = Val_int(3); break; + } + Field(vcell, 2) = Val_int(cell->ai_protocol); + Field(vcell, 3) = vcanon; + Field(vcell, 4) = vaddr; + vtmp = vli; + vli = alloc_small(2, 0); + Field(vli, 0) = vcell; + Field(vli, 1) = vtmp; + cell = cell->ai_next; + } + freeaddrinfo(res); + CAMLreturn(vli); + } + else + gai_fail("Unix.getaddrinfo: ", rc); +} + +CAMLprim value unix_getaddrinfo_bc(value argv[], int argc) +{ + return unix_getaddrinfo(argv[0], argv[1], + argv[2], argv[3], + argv[4], argv[5]); +} + +#else + +CAMLprim value unix_getaddrinfo(value nodename, value servname, + value ofamily, value osocktype, + value oprotocol, value flags) +{ invalid_argument("getaddrinfo not implemented"); } + +CAMLprim value unix_getaddrinfo_bc(value argv[], int argc) +{ invalid_argument("getaddrinfo not implemented"); } +#endif /* HAS_GETADDRINFO */ + + + +#ifdef HAS_GETNAMEINFO +CAMLprim value unix_getnameinfo(value mladdress, value flags) +{ + union sock_addr_union addr; + socklen_param_type addr_len; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + int c_flags, rc, release_lock; + { + int ni_flags_table[] = { + NI_NOFQDN, NI_NUMERICHOST, NI_NAMEREQD, + NI_NUMERICSERV, NI_DGRAM, } ; + c_flags = convert_flag_list(flags, ni_flags_table); + } + get_sockaddr(mladdress, &addr, &addr_len); + + enter_blocking_section(); + rc = getnameinfo(&addr.s_gen, addr_len, + host, sizeof host, + serv, sizeof serv, c_flags); + leave_blocking_section(); + + if (rc == 0) { + CAMLparam0(); + CAMLlocal3(s1, s2, v); + s1 = copy_string(host); + s2 = copy_string(serv); + v = alloc_small(2, 0); + Field(v, 0) = s1; + Field(v, 1) = s2; + CAMLreturn(v); + } + else + gai_fail("Unix.getnameinfo: ", rc); +} + +#else + +CAMLprim value unix_getnameinfo(value mladdress, value flags) +{ invalid_argument("getnameinfo not implemented"); } + +#endif /* HAS_GETNAMEINFO */ + +#endif /* HAS_SOCKETS */ --- ./otherlibs/unix/unixLabels.mli.ipv6 2002-05-27 18:06:31.000000000 +0200 +++ ./otherlibs/unix/unixLabels.mli 2003-09-29 22:23:35.000000000 +0200 @@ -852,6 +852,10 @@ type inet_addr = Unix.inet_addr (** The abstract type of Internet addresses. *) +type inet_addr_family = + | AF_INET + | AF_INET6 + val inet_addr_of_string : string -> inet_addr (** Conversions between string with the format [XXX.YYY.ZZZ.TTT] and Internet addresses. [inet_addr_of_string] raises [Failure] @@ -860,10 +864,25 @@ val string_of_inet_addr : inet_addr -> string (** See {!UnixLabels.inet_addr_of_string}. *) +val inet_addr_family : inet_addr -> inet_addr_family + val inet_addr_any : inet_addr (** A special Internet address, for use only with [bind], representing all the Internet addresses that the host machine possesses. *) +val inet6_addr_any : inet_addr +(** A special IPv6 address, for use only with [bind], representing + all the Internet addresses that the host machine possesses. *) + +(** {7 IPv6 address testing functions} *) + +val in6_is_addr_unspecified : inet_addr -> bool +val in6_is_addr_loopback : inet_addr -> bool +val in6_is_addr_multicast : inet_addr -> bool +val in6_is_addr_linklocal : inet_addr -> bool +val in6_is_addr_sitelocal : inet_addr -> bool +val in6_is_addr_v4mapped : inet_addr -> bool +val in6_is_addr_v4compat : inet_addr -> bool (** {6 Sockets} *) @@ -872,6 +891,7 @@ Unix.socket_domain = PF_UNIX (** Unix domain *) | PF_INET (** Internet domain *) + | PF_INET6 (** The type of socket domains. *) type socket_type = @@ -1044,6 +1064,8 @@ (** {6 High-level network connection functions} *) +val sockdomain_of_sockaddr : sockaddr -> socket_domain +(** Returns the appropriate socket_domain for the given address *) val open_connection : sockaddr -> in_channel * out_channel (** Connect to a server at the given address. @@ -1102,6 +1124,10 @@ (** Find an entry in [hosts] with the given name, or raise [Not_found]. *) +val gethostbyname2 : string -> inet_addr_family -> host_entry +(** Find an entry in [hosts] with the given name and address + family, or raise [Not_found]. *) + val gethostbyaddr : inet_addr -> host_entry (** Find an entry in [hosts] with the given address, or raise [Not_found]. *) @@ -1122,7 +1148,33 @@ (** Find an entry in [services] with the given service number, or raise [Not_found]. *) +type addrinfo = { + ai_family : socket_domain ; + ai_socktype : socket_type ; + ai_protocol : int ; + ai_canonname : string ; + ai_addr : sockaddr ; + } + +type addrinfo_flags = + AI_PASSIVE + | AI_CANONNAME + | AI_NUMERICHOST + +val getaddrinfo : string -> string -> + ?family:socket_domain -> + ?socktype:socket_type -> + ?protocol:int -> + addrinfo_flags list -> addrinfo list + +type nameinfo_flags = + NI_NOFQDN + | NI_NUMERICHOST + | NI_NAMEREQD + | NI_NUMERICSERV + | NI_DGRAM +val getnameinfo : sockaddr -> nameinfo_flags list -> string * string (** {6 Terminal interface} *) --- ./configure.ipv6 2003-09-25 10:17:13.000000000 +0200 +++ ./configure 2003-09-29 22:23:35.000000000 +0200 @@ -780,6 +780,26 @@ echo "#define HAS_INET_ATON" >> s.h fi +if sh ./hasgot inet_pton; then + echo "inet_pton() found." + echo "#define HAS_INET_PTON" >> s.h +fi + +if sh ./hasgot inet_ntop; then + echo "inet_ntop() found." + echo "#define HAS_INET_NTOP" >> s.h +fi + +if sh ./hasgot getaddrinfo; then + echo "getaddrinfo() found." + echo "#define HAS_GETADDRINFO" >> s.h +fi + +if sh ./hasgot getnameinfo; then + echo "getnameinfo() found." + echo "#define HAS_GETNAMEINFO" >> s.h +fi + if sh ./hasgot -i unistd.h; then echo "unistd.h found." echo "#define HAS_UNISTD" >> s.h @@ -988,6 +1008,15 @@ fi nargs=none +for i in 7; do + if sh ./trycompile -DNUM_ARGS=${i} gethostbyname2.c; then nargs=$i; break; fi +done +if test $nargs != "none"; then + echo "gethostbyname2_r() found (with ${nargs} arguments)." + echo "#define HAS_GETHOSTBYNAME2_R $nargs" >> s.h +fi + +nargs=none for i in 7 8; do if sh ./trycompile -DNUM_ARGS=${i} gethostbyaddr.c; then nargs=$i; break; fi done