Skip to content

Commit

Permalink
Support Unix domain sockets on Windows
Browse files Browse the repository at this point in the history
Unix domain sockets were introduced in Insider Build 17063 [1]. There are some caveats, as only SOCK_STREAM is supported and abstract sockets are
not implemented. The header file <afunix.h> declares the `struct sockaddr_un` type, but hasn't been picked by mingw-w64. The struct definition is
embedded if the header wasn't found. The curl [3] project has taken that approach too.

It is expected that users get runtime errors if the system doesn't have support for Unix domain sockets.

Fixes ocaml#8863.

[1]: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
[2]: microsoft/WSL#4240 (comment)
[3]: https://github.com/curl/curl/blob/curl-7_74_0/lib/config-win32.h#L725-L734
  • Loading branch information
MisterDA committed Jan 26, 2021
1 parent f7ac1b1 commit 5855ce5
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 19 deletions.
21 changes: 21 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,12 @@ AC_CHECK_TYPE(

AC_CHECK_FUNC([inet_aton], [AC_DEFINE([HAS_INET_ATON])])

## Unix domain sockets support on Windows

AS_CASE([$host],
[*-*-mingw32|*-pc-windows],
[AC_CHECK_HEADERS([afunix.h], [AC_DEFINE([HAS_AFUNIX_H])])])

## IPv6 support

ipv6=true
Expand Down
2 changes: 1 addition & 1 deletion manual/manual/library/libunix.etex
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ processes}
\entree{"getpwnam", "getpwuid"}{always raise "Not_found"}
\entree{"getgrnam", "getgrgid"}{always raise "Not_found"}
\entree{type "socket_domain"}{"PF_INET" is fully supported;
"PF_INET6" is fully supported (since 4.01.0); "PF_UNIX" is not supported }
"PF_INET6" is fully supported (since 4.01.0); "PF_UNIX" is supported since Windows 10 17063.}
\entree{"establish_server"}{not implemented; use threads}
\entree{terminal functions ("tc*")}{not implemented}
\entree{"setsid"}{not implemented}
Expand Down
6 changes: 0 additions & 6 deletions otherlibs/unix/socketaddr.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ void get_sockaddr(value mladr,
socklen_param_type * adr_len /*out*/)
{
switch(Tag_val(mladr)) {
#ifndef _WIN32
case 0: /* ADDR_UNIX */
{ value path;
mlsize_t len;
Expand All @@ -75,7 +74,6 @@ void get_sockaddr(value mladr,
+ len;
break;
}
#endif
case 1: /* ADDR_INET */
#ifdef HAS_IPV6
if (caml_string_length(Field(mladr, 0)) == 16) {
Expand Down Expand Up @@ -114,16 +112,13 @@ value alloc_sockaddr(union sock_addr_union * adr /*in*/,
socklen_param_type adr_len, int close_on_error)
{
value res;
#ifndef _WIN32
if (adr_len < offsetof(struct sockaddr, sa_data)) {
// Only possible for an unnamed AF_UNIX socket, in
// which case sa_family might be uninitialized.
return alloc_unix_sockaddr(caml_alloc_string(0));
}
#endif

switch(adr->s_gen.sa_family) {
#ifndef _WIN32
case AF_UNIX:
{ /* Based on recommendation in section BUGS of Linux unix(7). See
http://man7.org/linux/man-pages/man7/unix.7.html. */
Expand All @@ -147,7 +142,6 @@ value alloc_sockaddr(union sock_addr_union * adr /*in*/,
);
break;
}
#endif
case AF_INET:
{ value a = alloc_inet_addr(&adr->s_inet.sin_addr);
Begin_root (a);
Expand Down
21 changes: 18 additions & 3 deletions otherlibs/unix/socketaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,24 @@
#define CAML_SOCKETADDR_H

#include "caml/misc.h"
#ifndef _WIN32

#ifdef _WIN32
#ifdef HAS_AFUNIX_H
#include <afunix.h>
#else
#define UNIX_PATH_MAX 108

typedef struct sockaddr_un
{
ADDRESS_FAMILY sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
} SOCKADDR_UN, *PSOCKADDR_UN;

#define SIO_AF_UNIX_GETPEERPID _WSAIOR(IOC_VENDOR, 256) // Returns ULONG PID of the connected peer process

#endif

#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
Expand All @@ -27,9 +44,7 @@

union sock_addr_union {
struct sockaddr s_gen;
#ifndef _WIN32
struct sockaddr_un s_unix;
#endif
struct sockaddr_in s_inet;
#ifdef HAS_IPV6
struct sockaddr_in6 s_inet6;
Expand Down
2 changes: 1 addition & 1 deletion otherlibs/unix/unix.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1383,7 +1383,7 @@ type socket_domain =
(** The type of socket domains. Not all platforms support
IPv6 sockets (type [PF_INET6]).
On Windows: [PF_UNIX] not implemented. *)
On Windows: [PF_UNIX] supported since Windows 10 17063. *)

type socket_type =
SOCK_STREAM (** Stream socket *)
Expand Down
2 changes: 1 addition & 1 deletion otherlibs/unix/unixLabels.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1383,7 +1383,7 @@ type socket_domain = Unix.socket_domain =
(** The type of socket domains. Not all platforms support
IPv6 sockets (type [PF_INET6]).
On Windows: [PF_UNIX] not implemented. *)
On Windows: [PF_UNIX] supported since Windows 10 17063. *)

type socket_type = Unix.socket_type =
SOCK_STREAM (** Stream socket *)
Expand Down
4 changes: 4 additions & 0 deletions runtime/caml/s.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
/* Define HAS_SOCKLEN_T if the type socklen_t is defined in
/usr/include/sys/socket.h. */

#undef HAS_AFUNIX_H

/* Define HAS_AFUNIX_H if you have <afunix.h>. */

#undef HAS_INET_ATON

#undef HAS_IPV6
Expand Down
18 changes: 11 additions & 7 deletions runtime/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ CAMLexport void caml_debugger_cleanup_fork(void)
#define ATOM ATOM_WS
#include <winsock.h>
#undef ATOM
#ifdef HAS_AFUNIX_H
#include <afunix.h>
#else
struct sockaddr_un
{
ADDRESS_FAMILY sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
#endif /* HAS_AFUNIX_H */
#endif /* _WIN32 */
#include <process.h>
#endif

Expand All @@ -85,9 +95,7 @@ static value marshal_flags = Val_emptylist;
static int sock_domain; /* Socket domain for the debugger */
static union { /* Socket address for the debugger */
struct sockaddr s_gen;
#ifndef _WIN32
struct sockaddr_un s_unix;
#endif
struct sockaddr_in s_inet;
} sock_addr;
static int sock_addr_len; /* Length of sock_addr */
Expand Down Expand Up @@ -181,7 +189,6 @@ void caml_debugger_init(void)
{
char * address;
char_os * a;
size_t a_len;
char * port, * p;
struct hostent * host;
int n;
Expand Down Expand Up @@ -216,7 +223,7 @@ void caml_debugger_init(void)
if (*p == ':') { *p = 0; port = p+1; break; }
}
if (port == NULL) {
#ifndef _WIN32
size_t a_len;
/* Unix domain */
sock_domain = PF_UNIX;
sock_addr.s_unix.sun_family = AF_UNIX;
Expand All @@ -233,9 +240,6 @@ void caml_debugger_init(void)
sock_addr_len =
((char *)&(sock_addr.s_unix.sun_path) - (char *)&(sock_addr.s_unix))
+ a_len;
#else
caml_fatal_error("unix sockets not supported");
#endif
} else {
/* Internet domain */
sock_domain = PF_INET;
Expand Down

0 comments on commit 5855ce5

Please sign in to comment.