summaryrefslogtreecommitdiffstats
path: root/otherlibs/unix/getaddrinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'otherlibs/unix/getaddrinfo.c')
-rw-r--r--otherlibs/unix/getaddrinfo.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/otherlibs/unix/getaddrinfo.c b/otherlibs/unix/getaddrinfo.c
new file mode 100644
index 000000000..104f55c49
--- /dev/null
+++ b/otherlibs/unix/getaddrinfo.c
@@ -0,0 +1,133 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 2004 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include <string.h>
+#include <mlvalues.h>
+#include <alloc.h>
+#include <memory.h>
+#include <fail.h>
+#include <signals.h>
+#include "unixsupport.h"
+#include "cst2constr.h"
+
+#if defined(HAS_SOCKETS) && defined(HAS_IPV6)
+
+#include "socketaddr.h"
+#ifndef _WIN32
+#include <sys/types.h>
+#include <netdb.h>
+#endif
+
+extern int socket_domain_table[]; /* from socket.c */
+extern int socket_type_table[]; /* from socket.c */
+
+static value convert_addrinfo(struct addrinfo * a)
+{
+ CAMLparam0();
+ CAMLlocal3(vres,vaddr,vcanonname);
+ union sock_addr_union sa;
+
+ memcpy(&sa.s_gen, a->ai_addr, sizeof(struct sockaddr));
+ vaddr = alloc_sockaddr(&sa, sizeof(struct sockaddr));
+ vcanonname = copy_string(a->ai_canonname == NULL ? "" : a->ai_canonname);
+ vres = alloc_small(5, 0);
+ Field(vres, 0) = cst_to_constr(a->ai_family, socket_domain_table, 3, 0);
+ Field(vres, 1) = cst_to_constr(a->ai_socktype, socket_type_table, 4, 0);
+ Field(vres, 2) = Val_int(a->ai_protocol);
+ Field(vres, 3) = vaddr;
+ Field(vres, 4) = vcanonname;
+ CAMLreturn(vres);
+}
+
+CAMLprim value unix_getaddrinfo(value vnode, value vserv, value vopts)
+{
+ CAMLparam3(vnode, vserv, vopts);
+ CAMLlocal3(vres, v, e);
+ mlsize_t len;
+ char * node, * serv;
+ struct addrinfo hints;
+ struct addrinfo * res, * r;
+ int retcode;
+
+ /* Extract "node" parameter */
+ len = string_length(vnode);
+ if (len == 0) {
+ node = NULL;
+ } else {
+ node = stat_alloc(len + 1);
+ strcpy(node, String_val(vnode));
+ }
+ /* Extract "service" parameter */
+ len = string_length(vserv);
+ if (len == 0) {
+ serv = NULL;
+ } else {
+ serv = stat_alloc(len + 1);
+ strcpy(serv, String_val(vserv));
+ }
+ /* Parse options, set hints */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ for (/*nothing*/; Is_block(vopts); vopts = Field(vopts, 1)) {
+ v = Field(vopts, 0);
+ if (Is_block(v))
+ switch (Tag_val(v)) {
+ case 0: /* AI_FAMILY of socket_domain */
+ hints.ai_family = socket_domain_table[Int_val(Field(v, 0))];
+ break;
+ case 1: /* AI_SOCKTYPE of socket_type */
+ hints.ai_socktype = socket_type_table[Int_val(Field(v, 0))];
+ break;
+ case 2: /* AI_PROTOCOL of int */
+ hints.ai_protocol = Int_val(Field(v, 0));
+ break;
+ }
+ else
+ switch (Int_val(v)) {
+ case 0: /* AI_NUMERICHOST */
+ hints.ai_flags |= AI_NUMERICHOST; break;
+ case 1: /* AI_CANONNAME */
+ hints.ai_flags |= AI_CANONNAME; break;
+ case 2: /* AI_PASSIVE */
+ hints.ai_flags |= AI_PASSIVE; break;
+ }
+ }
+ /* Do the call */
+ enter_blocking_section();
+ retcode = getaddrinfo(node, serv, &hints, &res);
+ leave_blocking_section();
+ if (node != NULL) stat_free(node);
+ if (serv != NULL) stat_free(serv);
+ /* Convert result */
+ vres = Val_int(0);
+ if (retcode == 0) {
+ for (r = res; r != NULL; r = r->ai_next) {
+ e = convert_addrinfo(r);
+ v = alloc_small(2, 0);
+ Field(v, 0) = e;
+ Field(v, 1) = vres;
+ vres = v;
+ }
+ freeaddrinfo(res);
+ }
+ CAMLreturn(vres);
+}
+
+#else
+
+CAMLprim value unix_getaddrinfo(value vnode, value vserv, value vopts)
+{ invalid_argument("getaddrinfo not implemented"); }
+
+#endif