Skip to content

Commit 97f093d

Browse files
committed
works
1 parent 2e09d49 commit 97f093d

File tree

3 files changed

+184
-1
lines changed

3 files changed

+184
-1
lines changed

lib_eio_linux/eio_linux.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,25 @@ module Low_level = struct
858858

859859
external eio_getdents : Unix.file_descr -> string list = "caml_eio_getdents"
860860

861+
(* keep in sync with eio_stubs.c *)
862+
type gai_error =
863+
| EAI_ADDRFAMILY
864+
| EAI_AGAIN
865+
| EAI_BADFLAGS
866+
| EAI_BADHINTS
867+
| EAI_FAIL
868+
| EAI_FAMILY
869+
| EAI_MEMORY
870+
| EAI_NODATA
871+
| EAI_NONAME
872+
| EAI_SERVICE
873+
| EAI_SOCKTYPE
874+
| EAI_SYSTEM
875+
876+
external eio_getaddrinfo : string -> string -> Unix.getaddrinfo_option list ->
877+
(Unix.addr_info list, gai_error) result
878+
= "caml_eio_getaddrinfo"
879+
861880
let getrandom { Cstruct.buffer; off; len } =
862881
let rec loop n =
863882
if n = len then

lib_eio_linux/eio_linux.mli

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,21 @@ module Low_level : sig
251251
(** [getaddrinfo host] returns a list of IP addresses for [host]. [host] is either a domain name or
252252
an ipaddress. *)
253253

254+
type gai_error =
255+
| EAI_ADDRFAMILY
256+
| EAI_AGAIN
257+
| EAI_BADFLAGS
258+
| EAI_BADHINTS
259+
| EAI_FAIL
260+
| EAI_FAMILY
261+
| EAI_MEMORY
262+
| EAI_NODATA
263+
| EAI_NONAME
264+
| EAI_SERVICE
265+
| EAI_SOCKTYPE
266+
| EAI_SYSTEM
267+
268+
val eio_getaddrinfo : string -> string -> Unix.getaddrinfo_option list -> (Unix.addr_info list, gai_error) result
269+
270+
254271
end

lib_eio_linux/eio_stubs.c

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <sys/stat.h>
22
#include <sys/types.h>
3+
#include <sys/socket.h>
34
#include <sys/eventfd.h>
45
#include <sys/random.h>
56
#include <sys/syscall.h>
@@ -8,14 +9,15 @@
89
#include <dirent.h>
910
#include <fcntl.h>
1011
#include <unistd.h>
11-
12+
#include <netdb.h>
1213

1314
#include <caml/mlvalues.h>
1415
#include <caml/memory.h>
1516
#include <caml/alloc.h>
1617
#include <caml/signals.h>
1718
#include <caml/unixsupport.h>
1819
#include <caml/bigarray.h>
20+
#include <caml/socketaddr.h>
1921

2022
// Make sure we have enough space for at least one entry.
2123
#define DIRENT_BUF_SIZE (PATH_MAX + sizeof(struct dirent64))
@@ -99,3 +101,148 @@ CAMLprim value caml_eio_getdents(value v_fd) {
99101

100102
CAMLreturn(result);
101103
}
104+
105+
static value caml_unix_cst_to_constr(int n, int *tbl, int size, int deflt)
106+
{
107+
int i;
108+
for (i = 0; i < size; i++)
109+
if (n == tbl[i]) return Val_int(i);
110+
return Val_int(deflt);
111+
}
112+
113+
extern int caml_unix_socket_domain_table[]; /* from socket.c */
114+
extern int caml_unix_socket_type_table[]; /* from socket.c */
115+
116+
static value convert_addrinfo(struct addrinfo * a)
117+
{
118+
CAMLparam0();
119+
CAMLlocal3(vres,vaddr,vcanonname);
120+
union sock_addr_union sa;
121+
socklen_param_type len;
122+
123+
len = a->ai_addrlen;
124+
if (len > sizeof(sa)) len = sizeof(sa);
125+
memcpy(&sa.s_gen, a->ai_addr, len);
126+
vaddr = caml_unix_alloc_sockaddr(&sa, len, -1);
127+
vcanonname = caml_copy_string(a->ai_canonname == NULL ? "" : a->ai_canonname);
128+
vres = caml_alloc_small(5, 0);
129+
Field(vres, 0) =
130+
caml_unix_cst_to_constr(a->ai_family, caml_unix_socket_domain_table, 3, 0);
131+
Field(vres, 1) =
132+
caml_unix_cst_to_constr(a->ai_socktype, caml_unix_socket_type_table, 4, 0);
133+
Field(vres, 2) = Val_int(a->ai_protocol);
134+
Field(vres, 3) = vaddr;
135+
Field(vres, 4) = vcanonname;
136+
CAMLreturn(vres);
137+
}
138+
139+
/* glibc doesn't define a bunch of EAI_, so fake one since code gets copied around */
140+
141+
#ifndef EAI_ADDRFAMILY
142+
#define EAI_ADDRFAMILY -3000
143+
#endif /* EAI_ADDRFAMILY */
144+
145+
#ifndef EAI_BADHINTS
146+
#define EAI_BADHINTS -3013
147+
#endif /* EAI_BADHINTS */
148+
149+
#ifndef EAI_NODATA
150+
#define EAI_NODATA -3007
151+
#endif /* EAI_NODATA */
152+
153+
static int gai_errors[] = {
154+
EAI_ADDRFAMILY,
155+
EAI_AGAIN,
156+
EAI_BADFLAGS,
157+
EAI_BADHINTS,
158+
EAI_FAIL,
159+
EAI_FAMILY,
160+
EAI_MEMORY,
161+
EAI_NODATA,
162+
EAI_NONAME,
163+
EAI_SERVICE,
164+
EAI_SOCKTYPE,
165+
EAI_SYSTEM
166+
};
167+
168+
CAMLprim value caml_eio_getaddrinfo(value vnode, value vserv, value vopts)
169+
{
170+
CAMLparam3(vnode, vserv, vopts);
171+
CAMLlocal3(vres, v, vret);
172+
char * node, * serv;
173+
struct addrinfo hints;
174+
struct addrinfo * res, * r;
175+
int retcode, i;
176+
177+
if (! (caml_string_is_c_safe(vnode) && caml_string_is_c_safe(vserv)))
178+
CAMLreturn (Val_emptylist);
179+
180+
/* Extract "node" parameter */
181+
if (caml_string_length(vnode) == 0) {
182+
node = NULL;
183+
} else {
184+
node = caml_stat_strdup(String_val(vnode));
185+
}
186+
/* Extract "service" parameter */
187+
if (caml_string_length(vserv) == 0) {
188+
serv = NULL;
189+
} else {
190+
serv = caml_stat_strdup(String_val(vserv));
191+
}
192+
/* Parse options, set hints */
193+
memset(&hints, 0, sizeof(hints));
194+
hints.ai_family = PF_UNSPEC;
195+
for (/*nothing*/; vopts != Val_emptylist; vopts = Field(vopts, 1)) {
196+
v = Field(vopts, 0);
197+
if (Is_block(v))
198+
switch (Tag_val(v)) {
199+
case 0: /* AI_FAMILY of socket_domain */
200+
hints.ai_family = caml_unix_socket_domain_table[Int_val(Field(v, 0))];
201+
break;
202+
case 1: /* AI_SOCKTYPE of socket_type */
203+
hints.ai_socktype = caml_unix_socket_type_table[Int_val(Field(v, 0))];
204+
break;
205+
case 2: /* AI_PROTOCOL of int */
206+
hints.ai_protocol = Int_val(Field(v, 0));
207+
break;
208+
}
209+
else
210+
switch (Int_val(v)) {
211+
case 0: /* AI_NUMERICHOST */
212+
hints.ai_flags |= AI_NUMERICHOST; break;
213+
case 1: /* AI_CANONNAME */
214+
hints.ai_flags |= AI_CANONNAME; break;
215+
case 2: /* AI_PASSIVE */
216+
hints.ai_flags |= AI_PASSIVE; break;
217+
}
218+
}
219+
/* Do the call */
220+
caml_enter_blocking_section();
221+
retcode = getaddrinfo(node, serv, &hints, &res);
222+
caml_leave_blocking_section();
223+
if (node != NULL) caml_stat_free(node);
224+
if (serv != NULL) caml_stat_free(serv);
225+
/* Convert result */
226+
vres = Val_emptylist;
227+
if (retcode == 0) {
228+
for (r = res; r != NULL; r = r->ai_next) {
229+
v = caml_alloc_small(2, Tag_cons);
230+
Field(v, 0) = convert_addrinfo(r);
231+
Field(v, 1) = vres;
232+
vres = v;
233+
}
234+
vret = caml_alloc_small(1, 0); /* 0 = Ok */
235+
Field(vret, 0) = vres;
236+
freeaddrinfo(res);
237+
} else {
238+
for (i = 0; i < (sizeof(gai_errors) / sizeof(int)); i++)
239+
if (gai_errors[i] == retcode)
240+
break;
241+
if (i == (sizeof(gai_errors) / sizeof(int)))
242+
uerror("invalid gai_error", Nothing);
243+
vret = caml_alloc_small(1, 1); /* 1 = Error */
244+
Field(vret, 0) = Val_int(i);
245+
}
246+
247+
CAMLreturn(vret);
248+
}

0 commit comments

Comments
 (0)