Skip to content

Commit

Permalink
Fix #2255: complete socket.h; simplify & shorten code paths (#2766)
Browse files Browse the repository at this point in the history
* Fix #2255: complete socket.h; simplify & shorten code paths

* First round of OS specific fixes

* Remove some Windows warnings

* Remove Windows failures

* Remove more Windows warnings

* Good morning CI! Healthy yet?

* Is it safe to go back into the water? Are the sharks gone?

* Fix defect discovered by multiarch
  • Loading branch information
LeeTibbert committed Aug 31, 2022
1 parent 66df18b commit 7c947a5
Show file tree
Hide file tree
Showing 3 changed files with 786 additions and 32 deletions.
260 changes: 257 additions & 3 deletions posixlib/src/main/resources/scala-native/sys/socket.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <string.h>
#include <stddef.h>
#include <stdio.h>
//#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

Expand All @@ -15,7 +15,7 @@ typedef SSIZE_T ssize_t;
#ifndef SCALANATIVE_SUPPRESS_STRUCT_CHECK_WARNING
#warning "Size and order of C structures are not checked when -std < c11."
#endif
#else
#else // POSIX
/* POSIX defines the name and type of required fields. Size of fields
* and any internal or tail padding are left unspecified. This section
* verifies that the C and Scala Native definitions match in each compilation
Expand Down Expand Up @@ -63,8 +63,108 @@ _Static_assert(offsetof(struct scalanative_sockaddr, sa_data) ==

_Static_assert(sizeof(struct sockaddr_storage) == 128,
"unexpected size for sockaddr_storage");

// struct msghdr - POSIX 48 byte (padding) on 64 bit machines, 28 on 32 bit.
struct scalanative_msghdr {
void *msg_name;
uint32_t msg_namelen;
struct iovec *msg_iov;
uint32_t msg_iovlen;
void *msg_control;
uint32_t msg_controllen;
int msg_flags;
};

#if !defined(__LP64__) && !defined(__ILP32__)
#error "Unknown hardware memory model, not __ILP32__, not __LP64__"
#endif
#endif

#if defined(__ILP32__)
_Static_assert(sizeof(struct msghdr) == 28,
"Unexpected size: struct msghdr, expected 28");
_Static_assert(sizeof(struct msghdr) == sizeof(struct scalanative_msghdr),
"sizeof mismatch: OS & SN msghdr");
#elif defined(__linux__) // __LP64__
// Only do a rough check, will use conversion mapping routines in C code.
_Static_assert(sizeof(struct msghdr) == 56,
"Unexpected size: struct msghdr, expected 56");
#else // 64 bit POSIX - macOS, FreeBSD

// Will use direct passthru to C, so check all fields.
_Static_assert(sizeof(struct msghdr) == 48,
"Unexpected size: struct msghdr, expected 48");

_Static_assert(sizeof(struct msghdr) == sizeof(struct scalanative_msghdr),
"sizeof mismatch: OS & SN msghdr");

_Static_assert(offsetof(struct msghdr, msg_name) ==
offsetof(struct scalanative_msghdr, msg_name),
"offset mismatch: OS & SN msg_name expected 0");

_Static_assert(offsetof(struct msghdr, msg_namelen) ==
offsetof(struct scalanative_msghdr, msg_namelen),
"offset mismatch: OS & SN msg_namelen expected 8");

_Static_assert(offsetof(struct msghdr, msg_iov) ==
offsetof(struct scalanative_msghdr, msg_iov),
"offset mismatch: OS & SN msg_iov expected 16");

_Static_assert(offsetof(struct msghdr, msg_iovlen) ==
offsetof(struct scalanative_msghdr, msg_iovlen),
"offset mismatch: OS & SN msg_iovlen expected 24");

_Static_assert(offsetof(struct msghdr, msg_control) ==
offsetof(struct scalanative_msghdr, msg_control),
"offset mismatch: OS & SN msg_control expected 32");

_Static_assert(offsetof(struct msghdr, msg_controllen) ==
offsetof(struct scalanative_msghdr, msg_controllen),
"offset mismatch: OS & SN msg_controllen expected 40");

_Static_assert(offsetof(struct msghdr, msg_flags) ==
offsetof(struct scalanative_msghdr, msg_flags),
"offset mismatch: OS & SN msg_flags expected 44");
#endif // POSIX msghdr

// POSIX 2018 & prior 12 byte definition, Linux uses 16 bytes.
struct scalanative_cmsghdr {
socklen_t cmsg_len;
int cmsg_level;
int cmsg_type;
};

#if defined(__ILP32__)
_Static_assert(sizeof(struct cmsghdr) == 12,
"Unexpected size: struct cmsghdr, expected 12");
#elif defined(__linux__) // __LP64__
// Only do a rough check, developer must pass OS cmsghdr in & expect same back.
_Static_assert(sizeof(struct cmsghdr) == 16,
"Unexpected size: struct msghdr, expected 16");
#else // 64 bit POSIX - macOS, FreeBSD

// Will use direct passthru to C, so check all fields.
_Static_assert(sizeof(struct cmsghdr) == 12,
"Unexpected size: struct cmsghdr, expected 12");

_Static_assert(sizeof(struct cmsghdr) == sizeof(struct scalanative_cmsghdr),
"sizeof mismatch: OS & SN cmsghdr");

_Static_assert(offsetof(struct cmsghdr, cmsg_len) ==
offsetof(struct scalanative_cmsghdr, cmsg_len),
"offset mismatch: OS & SN cmsg_len expected 0");

_Static_assert(offsetof(struct cmsghdr, cmsg_level) ==
offsetof(struct scalanative_cmsghdr, cmsg_level),
"offset mismatch: OS & SN cmsg_level expected 4");

_Static_assert(offsetof(struct cmsghdr, cmsg_type) ==
offsetof(struct scalanative_cmsghdr, cmsg_type),
"offset mismatch: OS & SN cmsg_type expected 8");
#endif // POSIX cmsghdr
#endif // structure size checking
#endif // !_WIN32

// Symbolic constants

int scalanative_scm_rights() {
#ifdef SCM_RIGHTS
Expand Down Expand Up @@ -153,3 +253,157 @@ int scalanative_af_inet6() { return AF_INET6; }
int scalanative_af_unix() { return AF_UNIX; }

int scalanative_af_unspec() { return AF_UNSPEC; }

int scalanative_shut_rd() {
#ifdef SHUT_RD
return SHUT_RD;
#else // _WIN32
return 0;
#endif
}

int scalanative_shut_rdwr() {
#ifdef SHUT_RDWR
return SHUT_RDWR;
#else // _WIN32
return 0;
#endif
}

int scalanative_shut_wr() {
#ifdef SHUT_WR
return SHUT_WR;
#else // _WIN32
return 0;
#endif
}

// Macros
#ifdef _WIN32
void *scalanative_cmsg_data(void *cmsg) { return NULL; }
#else
unsigned char *scalanative_cmsg_data(struct cmsghdr *cmsg) {
return CMSG_DATA(cmsg);
}
#endif

#ifdef _WIN32
void *scalanative_cmsg_nxthdr(void *mhdr, void *cmsg) { return NULL; }
#else
struct cmsghdr *scalanative_cmsg_nxthdr(struct msghdr *mhdr,
struct cmsghdr *cmsg) {
return CMSG_NXTHDR(mhdr, cmsg);
}
#endif

#ifdef _WIN32
void *scalanative_cmsg_firsthdr(void *mhdr) { return NULL; }
#else
struct cmsghdr *scalanative_cmsg_firsthdr(struct msghdr *mhdr) {
return CMSG_FIRSTHDR(mhdr);
}
#endif

// Functions
#ifdef _WIN32
long scalanative_recvmsg(int socket, void *msg, int flags) {
errno = ENOTSUP;
return -1;
}
#else // unix
long scalanative_recvmsg(int socket, struct msghdr *msg, int flags) {
#if !defined(__linux__) || !defined(__LP64__)
return recvmsg(socket, (struct msghdr *)msg, flags);
#else // Linux 64 bits
/* BEWARE: Embedded control messages are not converted!
* Caller must send non-POSIX linux64 ctlhdr structures
* and expect such to be returned by OS.
*/

int status = -1;

if (msg == NULL) {
errno = EINVAL;
} else {

struct msghdr cMsg = {.msg_name = msg->msg_name,
.msg_namelen = msg->msg_namelen,
.msg_iov = msg->msg_iov,
.msg_iovlen = msg->msg_iovlen,
.msg_control = msg->msg_control,
.msg_controllen = msg->msg_controllen,
.msg_flags = msg->msg_flags};

status = recvmsg(socket, &cMsg, flags);

// recvmsg can alter some of these fields, so copy everything back.
if (status > -1) {
msg->msg_name = cMsg.msg_name;
msg->msg_namelen = cMsg.msg_namelen;
msg->msg_iov = cMsg.msg_iov;
msg->msg_iovlen = cMsg.msg_iovlen;
msg->msg_control = cMsg.msg_control;
msg->msg_controllen = cMsg.msg_controllen;
msg->msg_flags = cMsg.msg_flags;
}
}

return status;
#endif
}
#endif // unix

#ifdef _WIN32
long scalanative_sendmsg(int socket, struct msghdr *msg, int flags) {
errno = ENOTSUP;
return -1;
}
#else // unix
long scalanative_sendmsg(int socket, struct msghdr *msg, int flags) {
#if !defined(__linux__) || !defined(__LP64__)
return sendmsg(socket, (struct msghdr *)msg, flags);
#else // Linux 64 bits
/* BEWARE: Embedded control messages are not converted!
* Caller must send non-POSIX linux64 ctlhdr structures
* and expect such to be returned by OS.
*/

int status = -1;

if (msg == NULL) {
errno = EINVAL;
} else {
struct msghdr cMsg = {.msg_name = msg->msg_name,
.msg_namelen = msg->msg_namelen,
.msg_iov = msg->msg_iov,
.msg_iovlen = msg->msg_iovlen,
.msg_control = msg->msg_control,
.msg_controllen = msg->msg_controllen,
.msg_flags = msg->msg_flags};

// cMsg is read-only, so no need to copy data back to Scala
status = sendmsg(socket, &cMsg, flags);
}

return status;
#endif
}
#endif // unix

int scalanative_sockatmark(int socket) {
#if defined(_WIN32)
errno = ENOTSUP;
return -1;
#else
return sockatmark(socket);
#endif
}

int scalanative_socketpair(int domain, int type, int protocol, int *sv) {
#if defined(_WIN32)
errno = ENOTSUP;
return -1;
#else
return socketpair(domain, type, protocol, sv);
#endif
}

0 comments on commit 7c947a5

Please sign in to comment.