Skip to content

unix: add Cstruct_unix.{read,write,writev,send,recv} #302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions unix/dune
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
(name cstruct_unix)
(wrapped false)
(public_name cstruct-unix)
(foreign_stubs
(language c)
(names read_stubs write_stubs writev_stubs send_stubs recv_stubs
recvfrom_stubs sendto_stubs))
(libraries cstruct unix))
76 changes: 76 additions & 0 deletions unix/read_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#include <caml/threads.h>

#include <stdio.h>
#include <errno.h>

CAMLprim value stub_cstruct_read(value val_fd, value val_c)
{
CAMLparam2(val_fd, val_c);
CAMLlocal3(val_buf, val_ofs, val_len);
uint8_t *buf;
size_t len;
ssize_t n = 0;
#ifdef WIN32
int win32err = 0;
SOCKET s;
HANDLE h;
DWORD numread;
int ok;
#endif
val_buf = Field(val_c, 0);
val_ofs = Field(val_c, 1);
val_len = Field(val_c, 2);

buf = (uint8_t *)Caml_ba_data_val(val_buf) + Long_val(val_ofs);
len = (size_t)Long_val(val_len);

#ifdef WIN32
switch (Descr_kind_val(val_fd))
{
case KIND_SOCKET:
s = Socket_val(val_fd);

caml_release_runtime_system();
n = recv(s, buf, len, 0);
win32err = WSAGetLastError();
caml_acquire_runtime_system();

if (n == SOCKET_ERROR)
{
win32_maperr(win32err);
uerror("stub_cstruct_read", Nothing);
}
break;
case KIND_HANDLE:
h = Handle_val(val_fd);
caml_release_runtime_system();
ok = ReadFile(h, buf, len, &numread, NULL);
win32err = GetLastError();
n = numread;
caml_acquire_runtime_system();

if (!ok)
{
win32_maperr(win32err);
uerror("stub_cstruct_read", Nothing);
}
break;
default:
caml_failwith("unknown Descr_kind_val");
}
#else
caml_release_runtime_system();
n = read(Int_val(val_fd), buf, len);
caml_acquire_runtime_system();
if (n < 0)
uerror("stub_cstruct_read", Nothing);
#endif
CAMLreturn(Val_int(n));
}
70 changes: 70 additions & 0 deletions unix/recv_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#include <caml/threads.h>

#include <stdio.h>

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <NTSecAPI.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#endif

static int msg_flag_table[] = {
MSG_OOB, MSG_DONTROUTE, MSG_PEEK /* XXX */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the XXX for here? Incomplete flags?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause we assume how stdlib ordered things and also because we redefine them, would be nice if stdlib exposed them as not static so we could just use caml_msg_flag_table or something

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stdlib does expose them -- as OCaml values. Just add a type definition in unix_cstruct.mli instead and get rid of the XXX:

type msg_flag = Unix.msg_flag = MSG_OOB | MSG_DONTROUTE | MSG_PEEK

This will create an alias to Unix.msg_flag that also checks that it's exactly the same as what is specified there.
Try for example, swapping two of the flags:

type t = Unix.msg_flag = MSG_OOB | MSG_PEEK | MSG_DONTROUTE;;
Error: This variant or record definition does not match that of type
         Unix.msg_flag
       Constructors MSG_DONTROUTE and MSG_PEEK have been swapped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's smart ! yes we should do that.

};

CAMLprim value stub_cstruct_recv(value val_fd, value val_c, value val_flags)
{
CAMLparam3(val_fd, val_c, val_flags);
CAMLlocal3(val_buf, val_ofs, val_len);
uint8_t *buf;
size_t len;
ssize_t n = 0;
int cv_flags;
#ifdef WIN32
int win32err = 0;
SOCKET s = Socket_val(val_fd);
#endif

val_buf = Field(val_c, 0);
val_ofs = Field(val_c, 1);
val_len = Field(val_c, 2);

buf = (uint8_t *)Caml_ba_data_val(val_buf) + Long_val(val_ofs);
len = (size_t)Long_val(val_len);
cv_flags = caml_convert_flag_list(val_flags, msg_flag_table);
#ifdef WIN32
if (Descr_kind_val(val_fd) != KIND_SOCKET)
unix_error(EINVAL, "stub_cstruct_recv", Nothing);

caml_release_runtime_system();
n = recv(s, buf, len, cv_flags);
win32err = WSAGetLastError();
caml_acquire_runtime_system();

if (n == SOCKET_ERROR)
{
win32_maperr(win32err);
uerror("stub_cstruct_recv", Nothing);
}
#else
caml_release_runtime_system();
n = recv(Int_val(val_fd), buf, len, cv_flags);
caml_acquire_runtime_system();

if (n < 0)
uerror("stub_cstruct_recv", Nothing);
#endif
CAMLreturn(Val_int(n));
}
74 changes: 74 additions & 0 deletions unix/recvfrom_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#include <caml/threads.h>
#include <caml/socketaddr.h>

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif

static int msg_flag_table[] = {
MSG_OOB, MSG_DONTROUTE, MSG_PEEK /* XXX */
};

CAMLprim value stub_cstruct_recvfrom(value val_fd, value val_c, value val_flags)
{
CAMLparam3(val_fd, val_c, val_flags);
CAMLlocal5(val_buf, val_ofs, val_len, val_addr, val_res);
uint8_t *buf;
size_t len;
ssize_t n;
int cv_flags;
union sock_addr_union addr;
socklen_param_type addr_len;
#ifdef WIN32
int win32err = 0;
SOCKET s = Socket_val(val_fd);
#endif

val_buf = Field(val_c, 0);
val_ofs = Field(val_c, 1);
val_len = Field(val_c, 2);
cv_flags = caml_convert_flag_list(val_flags, msg_flag_table);

buf = (uint8_t *)Caml_ba_data_val(val_buf) + Long_val(val_ofs);
len = Long_val(val_len);
addr_len = sizeof(addr);
#ifdef WIN32
if (Descr_kind_val(val_fd) != KIND_SOCKET)
unix_error(EINVAL, "stub_cstruct_recvfrom", Nothing);

caml_release_runtime_system();
n = recvfrom(s, buf, len, cv_flags, &addr.s_gen, &addr_len);
win32err = WSAGetLastError();
caml_acquire_runtime_system();

if (n == SOCKET_ERROR)
{
win32_maperr(win32err);
uerror("stub_cstruct_recvfrom", Nothing);
}
#else
caml_release_runtime_system();
n = recvfrom(Int_val(val_fd), buf, len, cv_flags, &addr.s_gen, &addr_len);
caml_acquire_runtime_system();

if (n == -1)
uerror("stub_cstruct_recvfrom", Nothing);
#endif

val_addr = alloc_sockaddr(&addr, addr_len, -1);
val_res = caml_alloc_small(2, 0);
Field(val_res, 0) = Val_int(n);
Field(val_res, 1) = val_addr;

CAMLreturn (val_res);
}
69 changes: 69 additions & 0 deletions unix/send_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#include <caml/threads.h>

#include <stdio.h>

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <NTSecAPI.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#endif

static int msg_flag_table[] = {
MSG_OOB, MSG_DONTROUTE, MSG_PEEK /* XXX */
};

CAMLprim value stub_cstruct_send(value val_fd, value val_c, value val_flags)
{
CAMLparam3(val_fd, val_c, val_flags);
CAMLlocal3(val_buf, val_ofs, val_len);
uint8_t *buf;
size_t len;
ssize_t n = 0;
int cv_flags = caml_convert_flag_list(val_flags, msg_flag_table);
#ifdef WIN32
int win32err = 0;
SOCKET s = Socket_val(val_fd);
#endif

val_buf = Field(val_c, 0);
val_ofs = Field(val_c, 1);
val_len = Field(val_c, 2);

buf = (uint8_t *)Caml_ba_data_val(val_buf) + Long_val(val_ofs);
len = (size_t)Long_val(val_len);

#ifdef WIN32
if (Descr_kind_val(val_fd) != KIND_SOCKET)
unix_error(EINVAL, "stub_cstruct_send", Nothing);

caml_release_runtime_system();
n = send(s, buf, len, cv_flags);
win32err = WSAGetLastError();
caml_acquire_runtime_system();

if (n == SOCKET_ERROR)
{
win32_maperr(win32err);
uerror("stub_cstruct_send", Nothing);
}
#else
caml_release_runtime_system();
n = send(Int_val(val_fd), buf, len, cv_flags);
caml_acquire_runtime_system();
if (n < 0)
uerror("stub_cstruct_send", Nothing);
#endif
CAMLreturn(Val_int(n));
}
69 changes: 69 additions & 0 deletions unix/sendto_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/unixsupport.h>
#include <caml/bigarray.h>
#include <caml/threads.h>
#include <caml/socketaddr.h>

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif

static int msg_flag_table[] = { /* XXX */
MSG_OOB, MSG_DONTROUTE, MSG_PEEK
};

CAMLprim value stub_cstruct_sendto(value val_fd, value val_c, value val_flags, value val_daddr)
{
CAMLparam4(val_fd, val_c, val_flags, val_daddr);
CAMLlocal5(val_buf, val_ofs, val_len, val_addr, val_res);
union sock_addr_union addr;
socklen_param_type addr_len;
uint8_t *buf;
size_t len;
ssize_t n;
int cv_flags;
#ifdef WIN32
int win32err = 0;
SOCKET s = Socket_val(val_fd);
#endif

val_buf = Field(val_c, 0);
val_ofs = Field(val_c, 1);
val_len = Field(val_c, 2);

buf = (uint8_t *)Caml_ba_data_val(val_buf) + Long_val(val_ofs);
len = Long_val(val_len);
get_sockaddr(val_daddr, &addr, &addr_len);
cv_flags = caml_convert_flag_list(val_flags, msg_flag_table);

#ifdef WIN32
if (Descr_kind_val(val_fd) != KIND_SOCKET)
unix_error(EINVAL, "stub_cstruct_sendto", Nothing);

caml_release_runtime_system();
n = sendto(s, buf, len, cv_flags, &addr.s_gen, addr_len);
win32err = WSAGetLastError();
caml_acquire_runtime_system();

if (n == SOCKET_ERROR)
{
win32_maperr(win32err);
uerror("stub_cstruct_sendto", Nothing);
}
#else
caml_release_runtime_system();
n = sendto(Int_val(val_fd), buf, len, cv_flags, &addr.s_gen, addr_len);
caml_acquire_runtime_system();

if (n == -1)
uerror("stub_cstruct_sendto", Nothing);
#endif
CAMLreturn (Val_int(n));
}
Loading