Skip to content
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
9 changes: 9 additions & 0 deletions erts/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,15 @@ AC_CHECK_TYPES([struct ip_mreqn], [], [],
#include <netinet/in.h>
])

AC_CHECK_TYPES([struct scm_timestamping], [], [],
[
#define _GNU_SOURCE
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/errqueue.h>
#include <linux/net_tstamp.h>
])


dnl ----------------------------------------------------------------------
dnl Check the availability of systemd
Expand Down
266 changes: 264 additions & 2 deletions erts/emulator/nifs/common/prim_socket_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL)
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#endif
#ifdef SO_TIMESTAMPING
#include <linux/net_tstamp.h>
#endif

#define HAVE_UDP

Expand Down Expand Up @@ -1728,6 +1731,17 @@ static ERL_NIF_TERM esock_setopt_uint_opt(ErlNifEnv* env,
int level,
int opt,
ERL_NIF_TERM eVal);
#ifdef SO_TIMESTAMPING
static ERL_NIF_TERM esock_setopt_timestamping(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
int opt,
ERL_NIF_TERM eVal);
static ERL_NIF_TERM esock_getopt_timestamping(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
int opt);
#endif
#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \
&& defined(ESOCK_USE_RCVSNDTIMEO)
static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env,
Expand Down Expand Up @@ -2236,6 +2250,7 @@ static const struct in6_addr in6addr_loopback =
GLOBAL_ATOM_DECL(protocol); \
GLOBAL_ATOM_DECL(pup); \
GLOBAL_ATOM_DECL(raw); \
GLOBAL_ATOM_DECL(raw_hardware); \
GLOBAL_ATOM_DECL(rawip); \
GLOBAL_ATOM_DECL(rcvbuf); \
GLOBAL_ATOM_DECL(rcvbufforce); \
Expand Down Expand Up @@ -2275,6 +2290,8 @@ static const struct in6_addr in6addr_loopback =
GLOBAL_ATOM_DECL(rtoinfo); \
GLOBAL_ATOM_DECL(rtt); \
GLOBAL_ATOM_DECL(running); \
GLOBAL_ATOM_DECL(rx_hardware); \
GLOBAL_ATOM_DECL(rx_software); \
GLOBAL_ATOM_DECL(rxq_ovfl); \
GLOBAL_ATOM_DECL(scope_id); \
GLOBAL_ATOM_DECL(sctp); \
Expand Down Expand Up @@ -2310,6 +2327,7 @@ static const struct in6_addr in6addr_loopback =
GLOBAL_ATOM_DECL(sockaddr); \
GLOBAL_ATOM_DECL(socket); \
GLOBAL_ATOM_DECL(socktype); \
GLOBAL_ATOM_DECL(software); \
GLOBAL_ATOM_DECL(spec_dst); \
GLOBAL_ATOM_DECL(staticarp); \
GLOBAL_ATOM_DECL(state); \
Expand All @@ -2324,6 +2342,10 @@ static const struct in6_addr in6addr_loopback =
GLOBAL_ATOM_DECL(tcp); \
GLOBAL_ATOM_DECL(throughput); \
GLOBAL_ATOM_DECL(timestamp); \
GLOBAL_ATOM_DECL(timestampns); \
GLOBAL_ATOM_DECL(timestamping); \
GLOBAL_ATOM_DECL(tx_hardware); \
GLOBAL_ATOM_DECL(tx_software); \
GLOBAL_ATOM_DECL(tos); \
GLOBAL_ATOM_DECL(transparent); \
GLOBAL_ATOM_DECL(timeout); \
Expand All @@ -2347,6 +2369,7 @@ static const struct in6_addr in6addr_loopback =
GLOBAL_ATOM_DECL(update_accept_context); \
GLOBAL_ATOM_DECL(update_connect_context); \
GLOBAL_ATOM_DECL(usec); \
GLOBAL_ATOM_DECL(nsec); \
GLOBAL_ATOM_DECL(user); \
GLOBAL_ATOM_DECL(user_timeout); \
GLOBAL_ATOM_DECL(use_ext_recvinfo); \
Expand Down Expand Up @@ -3031,6 +3054,24 @@ static struct ESockOpt optLevelSocket[] =
#endif
&esock_atom_timestamp},

{
#ifdef SO_TIMESTAMPNS
SO_TIMESTAMPNS,
esock_setopt_bool_opt, esock_getopt_bool_opt,
#else
0, NULL, NULL,
#endif
&esock_atom_timestampns},

{
#ifdef SO_TIMESTAMPING
SO_TIMESTAMPING,
esock_setopt_timestamping, esock_getopt_timestamping,
#else
0, NULL, NULL,
#endif
&esock_atom_timestamping},

{
#ifdef SO_TYPE
SO_TYPE,
Expand Down Expand Up @@ -8343,6 +8384,122 @@ ERL_NIF_TERM esock_setopt_uint_opt(ErlNifEnv* env,



#ifdef SO_TIMESTAMPING
/* esock_setopt_timestamping - set SO_TIMESTAMPING option
* Accepts a list of atoms representing SOF_TIMESTAMPING flags
* and converts them to the bit-AND flag value.
*/
static
ERL_NIF_TERM esock_setopt_timestamping(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
int opt,
ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
unsigned int flags = 0;
ERL_NIF_TERM head, tail;
ERL_NIF_TERM list = eVal;

SSDBG( descP,
("SOCKET", "esock_setopt_timestamping -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );

if (! enif_is_list(env, eVal)) {
goto invalid;
}

while (enif_get_list_cell(env, list, &head, &tail)) {
unsigned int intFlag;
if (GET_UINT(env, head, &intFlag)) {
flags |= intFlag;
} else if (COMPARE(head, esock_atom_rx_hardware) == 0) {
flags |= SOF_TIMESTAMPING_RX_HARDWARE;
} else if (COMPARE(head, esock_atom_rx_software) == 0) {
flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
} else if (COMPARE(head, esock_atom_tx_hardware) == 0) {
flags |= SOF_TIMESTAMPING_TX_HARDWARE;
} else if (COMPARE(head, esock_atom_tx_software) == 0) {
flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
} else if (COMPARE(head, esock_atom_software) == 0) {
flags |= SOF_TIMESTAMPING_SOFTWARE;
} else if (COMPARE(head, esock_atom_raw_hardware) == 0) {
flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
} else {
/* Unknown atom - user can pass integer flags for other values */
goto invalid;
}
list = tail;
}

SSDBG( descP,
("SOCKET", "esock_setopt_timestamping -> flags: %u"
"\r\n", flags) );

result = esock_setopt_level_opt(env, descP, level, opt,
&flags, sizeof(flags));
return result;

invalid:
SSDBG( descP,
("SOCKET", "esock_setopt_timestamping -> invalid"
"\r\n") );
return esock_make_invalid(env, esock_atom_value);
}

/* esock_getopt_timestamping - get SO_TIMESTAMPING option
* Converts the integer flag value back to a list of atoms.
*/
static
ERL_NIF_TERM esock_getopt_timestamping(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
int opt)
{
unsigned int flags;
ERL_NIF_TERM result;
ERL_NIF_TERM list = enif_make_list(env, 0); /* Empty list */

SSDBG( descP,
("SOCKET", "esock_getopt_timestamping -> entry"
"\r\n") );

if (! esock_getopt_uint(descP->sock, level, opt, &flags)) {
return esock_make_error_errno(env, sock_errno());
}

SSDBG( descP,
("SOCKET", "esock_getopt_timestamping -> flags: %u"
"\r\n", flags) );

/* Build list of atoms from flags */
if (flags & SOF_TIMESTAMPING_RX_HARDWARE) {
list = enif_make_list_cell(env, esock_atom_rx_hardware, list);
}
if (flags & SOF_TIMESTAMPING_RX_SOFTWARE) {
list = enif_make_list_cell(env, esock_atom_rx_software, list);
}
if (flags & SOF_TIMESTAMPING_TX_HARDWARE) {
list = enif_make_list_cell(env, esock_atom_tx_hardware, list);
}
if (flags & SOF_TIMESTAMPING_TX_SOFTWARE) {
list = enif_make_list_cell(env, esock_atom_tx_software, list);
}
if (flags & SOF_TIMESTAMPING_SOFTWARE) {
list = enif_make_list_cell(env, esock_atom_software, list);
}
if (flags & SOF_TIMESTAMPING_RAW_HARDWARE) {
list = enif_make_list_cell(env, esock_atom_raw_hardware, list);
}

result = esock_make_ok2(env, list);
return result;
}
#endif /* SO_TIMESTAMPING */



/* esock_setopt_str_opt - set an option that has an string value
*/

Expand Down Expand Up @@ -10986,6 +11143,98 @@ static BOOLEAN_T esock_cmsg_decode_timeval(ErlNifEnv *env,
}
#endif

#ifdef SCM_TIMESTAMPNS
static
BOOLEAN_T esock_cmsg_encode_timespec(ErlNifEnv *env,
unsigned char *data,
size_t dataLen,
ERL_NIF_TERM *eResult) {
struct timespec* timeP = (struct timespec *) data;

if (dataLen < sizeof(*timeP))
return FALSE;

esock_encode_timespec(env, timeP, eResult);
return TRUE;
}

static BOOLEAN_T esock_cmsg_decode_timespec(ErlNifEnv *env,
ERL_NIF_TERM eValue,
struct cmsghdr *cmsgP,
size_t rem,
size_t *usedP)
{
struct timespec time, *timeP;

if (! esock_decode_timespec(env, eValue, &time))
return FALSE;

if ((timeP = esock_init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL)
return FALSE;

*timeP = time;
return TRUE;
}
#endif

#if defined(SCM_TIMESTAMPING) && defined(HAVE_STRUCT_SCM_TIMESTAMPING)
static
BOOLEAN_T esock_cmsg_encode_scm_timestamping(ErlNifEnv *env,
unsigned char *data,
size_t dataLen,
ERL_NIF_TERM *eResult) {
struct scm_timestamping* tsP = (struct scm_timestamping *) data;
ERL_NIF_TERM tsList[3];

if (dataLen < sizeof(*tsP))
return FALSE;

esock_encode_timespec(env, &tsP->ts[0], &tsList[0]);
esock_encode_timespec(env, &tsP->ts[1], &tsList[1]);
esock_encode_timespec(env, &tsP->ts[2], &tsList[2]);

*eResult = MKLA(env, tsList, 3);
return TRUE;
}

static BOOLEAN_T esock_cmsg_decode_scm_timestamping(ErlNifEnv *env,
ERL_NIF_TERM eValue,
struct cmsghdr *cmsgP,
size_t rem,
size_t *usedP)
{
struct scm_timestamping *tsP;
ERL_NIF_TERM eTs[3];
unsigned int listLen;

/* Expect a list of 3 timespec maps */
if (! enif_is_list(env, eValue))
return FALSE;

if (! enif_get_list_length(env, eValue, &listLen) || listLen != 3)
return FALSE;

if (! enif_get_list_cell(env, eValue, &eTs[0], &eValue))
return FALSE;
if (! enif_get_list_cell(env, eValue, &eTs[1], &eValue))
return FALSE;
if (! enif_get_list_cell(env, eValue, &eTs[2], NULL))
return FALSE;

if ((tsP = esock_init_cmsghdr(cmsgP, rem, sizeof(*tsP), usedP)) == NULL)
return FALSE;

if (! esock_decode_timespec(env, eTs[0], &tsP->ts[0]))
return FALSE;
if (! esock_decode_timespec(env, eTs[1], &tsP->ts[1]))
return FALSE;
if (! esock_decode_timespec(env, eTs[2], &tsP->ts[2]))
return FALSE;

return TRUE;
}
#endif


#if defined(IP_TOS) || defined(IP_RECVTOS)
static
Expand Down Expand Up @@ -11468,8 +11717,9 @@ static int cmpESockCmsgSpec(const void *vpa, const void *vpb) {
return COMPARE(*(a->nameP), *(b->nameP));
}


#if defined(SCM_CREDENTIALS) || defined(SCM_RIGHTS) || defined(SCM_TIMESTAMP)
#if defined(SCM_CREDENTIALS) || defined(SCM_RIGHTS) || \
defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || \
defined(SCM_TIMESTAMPING)
#define HAVE_ESOCK_CMSG_SOCKET
#endif

Expand All @@ -11495,6 +11745,18 @@ static ESockCmsgSpec cmsgLevelSocket[] =
&esock_cmsg_encode_timeval, esock_cmsg_decode_timeval,
&esock_atom_timestamp},
#endif

#if defined(SCM_TIMESTAMPNS)
{SCM_TIMESTAMPNS,
&esock_cmsg_encode_timespec, esock_cmsg_decode_timespec,
&esock_atom_timestampns},
#endif

#if defined(SCM_TIMESTAMPING) && defined(HAVE_STRUCT_SCM_TIMESTAMPING)
{SCM_TIMESTAMPING,
&esock_cmsg_encode_scm_timestamping, esock_cmsg_decode_scm_timestamping,
&esock_atom_timestamping},
#endif
};
#endif

Expand Down
Loading
Loading