aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/nifs/common/socket_nif.c1378
1 files changed, 804 insertions, 574 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index eee96ee844..18375caf60 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -810,17 +810,169 @@ static ERL_NIF_TERM nsetopt(ErlNifEnv* env,
BOOLEAN_T isEncoded,
BOOLEAN_T isOTP,
int level,
- int opt,
- SocketOptValue* valP);
+ int eOpt,
+ ERL_NIF_TERM eVal);
static ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
SocketDescriptor* descP,
- int opt,
- SocketOptValue* valP);
-static ERL_NIF_TERM nsetopt_gen(ErlNifEnv* env,
- SocketDescriptor* descP,
- int level,
- int opt,
- SocketOptValue* valP);
+ int eOpt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_otp_debug(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_otp_iow(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(SO_BROADCAST)
+static ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_DONTROUTE)
+static ERL_NIF_TERM nsetopt_lvl_sock_dontroute(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_KEEPALIVE)
+static ERL_NIF_TERM nsetopt_lvl_sock_keepalive(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_LINGER)
+static ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_PRIORITY)
+static ERL_NIF_TERM nsetopt_lvl_sock_priority(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_RCVBUF)
+static ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_REUSEADDR)
+static ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SO_SNDBUF)
+static ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+static ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(IP_RECVTOS)
+static ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(IP_ROUTER_ALERT)
+static ERL_NIF_TERM nsetopt_lvl_ip_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(IP_TOS)
+static ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(IP_TTL)
+static ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SOL_IPV6)
+static ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(IPV6_HOPLIMIT)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#endif // defined(SOL_IPV6)
+static ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(TCP_CONGESTION)
+static ERL_NIF_TERM nsetopt_lvl_tcp_congestion(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(TCP_MAXSEG)
+static ERL_NIF_TERM nsetopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(TCP_NODELAY)
+static ERL_NIF_TERM nsetopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+static ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(UDP_CORK)
+static ERL_NIF_TERM nsetopt_lvl_udp_cork(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(HAVE_SCTP)
+static ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+#if defined(SCTP_AUTOCLOSE)
+static ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(SCTP_NODELAY)
+static ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#endif // defined(HAVE_SCTP)
+
+static ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ int max,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
+
static ERL_NIF_TERM nlink_if2idx(ErlNifEnv* env,
char* ifn);
static ERL_NIF_TERM nlink_idx2if(ErlNifEnv* env,
@@ -940,58 +1092,6 @@ static BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
int eLevel,
BOOLEAN_T* isOTP,
int* level);
-static BOOLEAN_T eoptval2optval(ErlNifEnv* env,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* val);
-static BOOLEAN_T eoptval2optval_otp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-static BOOLEAN_T eoptval2optval_plain(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-static BOOLEAN_T eoptval2optval_socket(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-static BOOLEAN_T eoptval2optval_ip(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-#if defined(SOL_IPV6)
-static BOOLEAN_T eoptval2optval_ipv6(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-#endif
-static BOOLEAN_T eoptval2optval_tcp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-static BOOLEAN_T eoptval2optval_udp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-#ifdef HAVE_SCTP
-static BOOLEAN_T eoptval2optval_sctp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP);
-#endif
#ifdef HAVE_SETNS
static BOOLEAN_T emap2netns(ErlNifEnv* env, ERL_NIF_TERM map, char** netns);
static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err);
@@ -3041,31 +3141,28 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
const ERL_NIF_TERM argv[])
{
SocketDescriptor* descP;
- unsigned int eIsEncoded;
- BOOLEAN_T isEncoded, isOTP;
int eLevel, level = -1;
- int eOpt, opt = -1;
+ int eOpt;
+ ERL_NIF_TERM eIsEncoded;
ERL_NIF_TERM eVal;
- SocketOptValue val;
+ BOOLEAN_T isEncoded, isOTP;
if ((argc != 5) ||
!enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
- !GET_UINT(env, argv[1], &eIsEncoded) ||
!GET_INT(env, argv[2], &eLevel) ||
!GET_INT(env, argv[3], &eOpt)) {
return enif_make_badarg(env);
}
- eVal = argv[4];
-
- isEncoded = ((eIsEncoded == 0) ? FALSE : TRUE);
+ eIsEncoded = argv[1];
+ eVal = argv[4];
- if (!elevel2level(isEncoded, eLevel, &isOTP, &level))
+ if (!decode_bool(env, eIsEncoded, &isEncoded))
return make_error(env, atom_einval);
- if (!eoptval2optval(env, isEncoded, isOTP, level, eOpt, eVal, &opt, &val))
+ if (!elevel2level(isEncoded, eLevel, &isOTP, &level))
return make_error(env, atom_einval);
- return nsetopt(env, descP, isEncoded, isOTP, level, opt, &val);
+ return nsetopt(env, descP, isEncoded, isOTP, level, eOpt, eVal);
}
@@ -3075,60 +3172,44 @@ ERL_NIF_TERM nsetopt(ErlNifEnv* env,
BOOLEAN_T isEncoded,
BOOLEAN_T isOTP,
int level,
- int opt,
- SocketOptValue* valP)
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
- int res;
- if (!isEncoded) {
- res = socket_setopt(descP->sock, level, opt,
- valP->u.binVal.data, valP->u.binVal.size);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
+ if (isOTP) {
+ /* These are not actual socket options,
+ * but options for our implementation.
+ */
+ result = nsetopt_otp(env, descP, eOpt, eVal);
+ } else if (!isEncoded) {
+ result = nsetopt_native(env, descP, level, eOpt, eVal);
} else {
- if (isOTP) {
- /* These are not actual socket options,
- * but options for our implementation.
- */
- result = nsetopt_otp(env, descP, opt, valP);
- } else {
- /* Basically, call setsockopt(...)
- * <KOLLA>
- * How do we know what type each option have? tag in value type?
- * </KOLLA>
- */
- result = nsetopt_gen(env, descP, level, opt, valP);
- }
+ result = nsetopt_level(env, descP, level, eOpt, eVal);
}
return result;
}
+
+/* nsetopt_otp - Handle OTP (level) options
+ */
static
ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
SocketDescriptor* descP,
- int opt,
- SocketOptValue* valP)
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
- /* Make an idiot check just to be on the safe side... */
- if (valP->tag == SOCKET_OPT_VALUE_UNDEF)
- return make_error(env, atom_einval);
-
- switch (opt) {
+ switch (eOpt) {
case SOCKET_OPT_OTP_DEBUG:
- descP->dbg = valP->u.boolVal;
- result = atom_ok;
+ result = nsetopt_otp_debug(env, descP, eVal);
break;
case SOCKET_OPT_OTP_IOW:
- descP->iow = valP->u.boolVal;
- result = atom_ok;
+ result = nsetopt_otp_iow(env, descP, eVal);
break;
default:
@@ -3140,67 +3221,18 @@ ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
}
+/* nsetopt_otp_debug - Handle the OTP (level) debug options
+ */
static
-ERL_NIF_TERM nsetopt_gen(ErlNifEnv* env,
- SocketDescriptor* descP,
- int level,
- int opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_otp_debug(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- socklen_t optLen;
- int res;
ERL_NIF_TERM result;
- switch (valP->tag) {
- case SOCKET_OPT_VALUE_INT:
- {
- optLen = sizeof(valP->u.intVal);
- res = socket_setopt(descP->sock, level, opt,
- (void*) &valP->u.intVal, optLen);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
- }
- break;
-
- case SOCKET_OPT_VALUE_BIN:
- {
- optLen = valP->u.binVal.size;
- res = socket_setopt(descP->sock, level, opt,
- &valP->u.binVal.data, optLen);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
- }
- break;
-
- case SOCKET_OPT_VALUE_LINGER:
- {
- optLen = sizeof(valP->u.lingerVal);
- res = socket_setopt(descP->sock, level, opt,
- &valP->u.lingerVal, optLen);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
- }
- break;
-
- case SOCKET_OPT_VALUE_STR:
- {
- optLen = valP->u.strVal.len;
- res = socket_setopt(descP->sock, level, opt,
- valP->u.strVal.str, optLen);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
- }
- break;
-
- default:
+ if (decode_bool(env, eVal, &descP->dbg)) {
+ result = atom_ok;
+ } else {
result = make_error(env, atom_einval);
}
@@ -3208,611 +3240,809 @@ ERL_NIF_TERM nsetopt_gen(ErlNifEnv* env,
}
-
+/* nsetopt_otp_iow - Handle the OTP (level) iow options
+ */
static
-BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
- int eLevel,
- BOOLEAN_T* isOTP,
- int* level)
+ERL_NIF_TERM nsetopt_otp_iow(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- BOOLEAN_T result;
-
- if (isEncoded) {
- switch (eLevel) {
- case SOCKET_OPT_LEVEL_OTP:
- *isOTP = TRUE;
- *level = -1;
- result = TRUE;
- break;
-
- case SOCKET_OPT_LEVEL_SOCKET:
- *isOTP = FALSE;
- *level = SOL_SOCKET;
- result = TRUE;
- break;
+ ERL_NIF_TERM result;
- case SOCKET_OPT_LEVEL_IP:
- *isOTP = FALSE;
-#if defined(SOL_IP)
- *level = SOL_IP;
-#else
- *level = IPROTO_IP;
-#endif
- result = TRUE;
- break;
+ if (decode_bool(env, eVal, &descP->iow)) {
+ result = atom_ok;
+ } else {
+ result = make_error(env, atom_einval);
+ }
-#if defined(SOL_IPV6)
- case SOCKET_OPT_LEVEL_IPV6:
- *isOTP = FALSE;
- *level = SOL_IPV6;
- result = TRUE;
- break;
-#endif
+ return result;
+}
- case SOCKET_OPT_LEVEL_TCP:
- *isOTP = FALSE;
- *level = IPPROTO_TCP;
- result = TRUE;
- break;
- case SOCKET_OPT_LEVEL_UDP:
- *isOTP = FALSE;
- *level = IPPROTO_UDP;
- result = TRUE;
- break;
-#ifdef HAVE_SCTP
- case SOCKET_OPT_LEVEL_SCTP:
- *isOTP = FALSE;
- *level = IPPROTO_SCTP;
- result = TRUE;
- break;
-#endif
+/* The option has *not* been encoded. Instead it has been provided
+ * in "native mode" (option is provided as is and value as a binary).
+ */
+static
+ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
+{
+ ErlNifBinary val;
+ ERL_NIF_TERM result;
- default:
- *isOTP = FALSE;
- *level = -1;
- result = FALSE;
- break;
- }
+ if (GET_BIN(env, eVal, &val)) {
+ int res = socket_setopt(descP->sock, level, opt,
+ val.data, val.size);
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
} else {
- *isOTP = FALSE;
- *level = eLevel;
- result = TRUE;
+ result = make_error(env, atom_einval);
}
return result;
}
+
+/* nsetopt_level - A "proper" level (option) has been specified
+ */
static
-BOOLEAN_T eoptval2optval(ErlNifEnv* env,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
- if (isOTP) {
- return eoptval2optval_otp(env, eOpt, eVal, opt, valP);
- } else if (!isEncoded) {
- return eoptval2optval_plain(env, eOpt, eVal, opt, valP);
- } else {
- switch (level) {
- case SOL_SOCKET:
- return eoptval2optval_socket(env, eOpt, eVal, opt, valP);
- break;
+ ERL_NIF_TERM result;
+
+ switch (level) {
+ case SOL_SOCKET:
+ result = nsetopt_lvl_socket(env, descP, eOpt, eVal);
+ break;
#if defined(SOL_IP)
- case SOL_IP:
+ case SOL_IP:
#else
- case IPPROTO_IP:
+ case IPPROTO_IP:
#endif
- return eoptval2optval_ip(env, eOpt, eVal, opt, valP);
- break;
+ result = nsetopt_lvl_ip(env, descP, eOpt, eVal);
+ break;
#if defined(SOL_IPV6)
- case SOL_IPV6:
- return eoptval2optval_ipv6(env, eOpt, eVal, opt, valP);
- break;
+ case SOL_IPV6:
+ result = nsetopt_lvl_ipv6(env, descP, eOpt, eVal);
+ break;
#endif
- case IPPROTO_TCP:
- return eoptval2optval_tcp(env, eOpt, eVal, opt, valP);
- break;
+ case IPPROTO_TCP:
+ result = nsetopt_lvl_tcp(env, descP, eOpt, eVal);
+ break;
- case IPPROTO_UDP:
- return eoptval2optval_udp(env, eOpt, eVal, opt, valP);
- break;
+ case IPPROTO_UDP:
+ result = nsetopt_lvl_udp(env, descP, eOpt, eVal);
+ break;
-#ifdef HAVE_SCTP
- case IPPROTO_SCTP:
- return eoptval2optval_sctp(env, eOpt, eVal, opt, valP);
- break;
+#if defined(HAVE_SCTP)
+ case IPPROTO_SCTP:
+ result = nsetopt_lvl_sctp(env, descP, eOpt, eVal);
+ break;
#endif
- default:
- *opt = -1;
- return FALSE;
- }
- }
-}
-
-
-
-static
-BOOLEAN_T eoptval2optval_otp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
-{
- BOOLEAN_T result = FALSE;
-
- switch (eOpt) {
- case SOCKET_OPT_OTP_IOW:
- case SOCKET_OPT_OTP_DEBUG:
- {
- if (decode_bool(env, eVal, &valP->u.boolVal)) {
- valP->tag = SOCKET_OPT_VALUE_BOOL;
- *opt = eOpt;
- result = TRUE;
- } else {
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- *opt = -1;
- result = FALSE;
- }
- }
- break;
-
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
+ result = make_error(env, atom_einval);
+ break;
}
return result;
}
-static
-BOOLEAN_T eoptval2optval_plain(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
-{
- if (!GET_BIN(env, eVal, &valP->u.binVal))
- return FALSE;
- valP->tag = SOCKET_OPT_VALUE_BIN;
- *opt = eOpt;
-
- return TRUE;
-}
-
-
+/* nsetopt_lvl_socket - Level *SOCKET* option
+ */
static
-BOOLEAN_T eoptval2optval_socket(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
+ ERL_NIF_TERM result;
+
switch (eOpt) {
#if defined(SO_BROADCAST)
case SOCKET_OPT_SOCK_BROADCAST:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- *opt = SO_BROADCAST;
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_sock_broadcast(env, descP, eVal);
break;
#endif
#if defined(SO_DONTROUTE)
case SOCKET_OPT_SOCK_DONTROUTE:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- *opt = SO_DONTROUTE;
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_sock_dontroute(env, descP, eVal);
break;
#endif
#if defined(SO_KEEPALIVE)
case SOCKET_OPT_SOCK_KEEPALIVE:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- *opt = SO_KEEPALIVE;
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_sock_keepalive(env, descP, eVal);
break;
#endif
#if defined(SO_LINGER)
case SOCKET_OPT_SOCK_LINGER:
- {
- if (decode_sock_linger(env, eVal, &valP->u.lingerVal)) {
- *opt = SO_LINGER;
- valP->tag = SOCKET_OPT_VALUE_LINGER;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_sock_linger(env, descP, eVal);
break;
#endif
#if defined(SO_PRIORITY)
case SOCKET_OPT_SOCK_PRIORITY:
- if (GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = SO_PRIORITY;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
+ result = nsetopt_lvl_sock_priority(env, descP, eVal);
break;
#endif
#if defined(SO_RCVBUF)
case SOCKET_OPT_SOCK_RCVBUF:
- if (GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = SO_RCVBUF;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
+ result = nsetopt_lvl_sock_rcvbuf(env, descP, eVal);
break;
#endif
#if defined(SO_REUSEADDR)
case SOCKET_OPT_SOCK_REUSEADDR:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- *opt = SO_REUSEADDR;
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_sock_reuseaddr(env, descP, eVal);
break;
#endif
#if defined(SO_SNDBUF)
case SOCKET_OPT_SOCK_SNDBUF:
- if (GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = SO_SNDBUF;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
+ result = nsetopt_lvl_sock_sndbuf(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
+ result = make_error(env, atom_einval);
+ break;
}
+
+ return result;
}
+#if defined(SO_BROADCAST)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_BROADCAST, eVal);
+}
+#endif
+
+#if defined(SO_DONTROUTE)
static
-BOOLEAN_T eoptval2optval_ip(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_sock_dontroute(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
+ return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_DONTROUTE, eVal);
+}
+#endif
+
+
+#if defined(SO_KEEPALIVE)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_keepalive(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_KEEPALIVE, eVal);
+}
+#endif
+
+
+#if defined(SO_LINGER)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ struct linger val;
+
+ if (decode_sock_linger(env, eVal, &val)) {
+ int optLen = sizeof(val);
+ int res = socket_setopt(descP->sock, SOL_SOCKET, SO_LINGER,
+ (void*) &val, optLen);
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+ } else {
+ result = make_error(env, atom_einval);
+ }
+
+ return result;
+}
+#endif
+
+
+#if defined(SO_PRIORITY)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_priority(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_PRIORITY, eVal);
+}
+#endif
+
+
+#if defined(SO_RCVBUF)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_RCVBUF, eVal);
+}
+#endif
+
+
+#if defined(SO_REUSEADDR)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEADDR, eVal);
+}
+#endif
+
+
+#if defined(SO_SNDBUF)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_SNDBUF, eVal);
+}
+#endif
+
+
+
+/* nsetopt_lvl_ip - Level *IP* option(s)
+ */
+static
+ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+
switch (eOpt) {
#if defined(IP_RECVTOS)
case SOCKET_OPT_IP_RECVTOS:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- *opt = IP_RECVTOS;
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return TRUE;
- }
- }
+ result = nsetopt_lvl_ip_recvtos(env, descP, eVal);
break;
#endif
#if defined(IP_ROUTER_ALERT)
case SOCKET_OPT_IP_ROUTER_ALERT:
- if (GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = IP_ROUTER_ALERT;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
+ result = nsetopt_lvl_ip_router_alert(env, descP, eVal);
break;
#endif
#if defined(IP_TOS)
case SOCKET_OPT_IP_TOS:
- {
- if (decode_ip_tos(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = IP_TOS;
- return TRUE;
- } else {
- *opt = -1;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_ip_tos(env, descP, eVal);
break;
#endif
#if defined(IP_TTL)
case SOCKET_OPT_IP_TTL:
- /* <KOLLA>
- * Should we care about the value? That is, if it is valid?
- * And what is the valid range anyway for ttl? 0 - 255?
- * </KOLLA>
- */
- if (!GET_INT(env, eVal, &valP->u.intVal))
- return FALSE; // PLACEHOLDER - We should really be more informative
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = IP_TTL;
- return TRUE;
+ result = nsetopt_lvl_ip_ttl(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
+ result = make_error(env, atom_einval);
+ break;
}
+ return result;
}
+/* nsetopt_lvl_ip_recvtos - Level IP RECVTOS option
+ */
+#if defined(IP_RECVTOS)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+
+ return nsetopt_bool_opt(env, descP, level, IP_RECVTOS, eVal);
+}
+#endif
+
+/* nsetopt_lvl_ip_router_alert - Level IP ROUTER_ALERT option
+ */
+#if defined(IP_ROUTER_ALERT)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+
+ return nsetopt_int_opt(env, descP, level, IP_ROUTER_ALERT, eVal);
+}
+#endif
+
+
+/* nsetopt_lvl_ip_tos - Level IP TOS option
+ */
+#if defined(IP_TOS)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+ ERL_NIF_TERM result;
+ int val;
+
+ if (decode_ip_tos(env, eVal, &val)) {
+ int res = socket_setopt(descP->sock, level, IP_TOS, &val, sizeof(val));
+
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+
+ } else {
+ result = make_error(env, atom_einval);
+ }
+
+ return result;
+}
+#endif
+
+
+/* nsetopt_lvl_ip_ttl - Level IP TTL option
+ */
+#if defined(IP_TTL)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+
+ return nsetopt_int_opt(env, descP, level, IP_TTL, eVal);
+}
+#endif
+
+
+
+/* nsetopt_lvl_ipv6 - Level *IPv6* option(s)
+ */
#if defined(SOL_IPV6)
static
-BOOLEAN_T eoptval2optval_ipv6(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
- BOOLEAN_T result = FALSE;
+ ERL_NIF_TERM result;
switch (eOpt) {
#if defined(IPV6_HOPLIMIT)
case SOCKET_OPT_IPV6_HOPLIMIT:
- {
- BOOLEAN_T val;
-
- if (decode_bool(env, eVal, &val)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- valP->u.intVal = (val) ? 1 : 0;
- *opt = IPV6_HOPLIMIT;
- result = TRUE;
- } else {
- *opt = -1;
- result = FALSE;
- }
- }
+ result = nsetopt_lvl_ipv6_hoplimit(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- result = FALSE;
+ result = make_error(env, atom_einval);
break;
}
return result;
}
+
+
+#if defined(IPV6_HOPLIMIT)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, SOL_IPV6, IPV6_HOPLIMIT, eVal);
+}
#endif
+#endif // defined(SOL_IPV6)
+
+
+/* nsetopt_lvl_tcp - Level *TCP* option(s)
+ */
static
-BOOLEAN_T eoptval2optval_tcp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
+ ERL_NIF_TERM result;
+
switch (eOpt) {
#if defined(TCP_CONGESTION)
case SOCKET_OPT_TCP_CONGESTION:
- {
- valP->u.strVal.len = SOCKET_OPT_TCP_CONGESTION_NAME_MAX+1;
- valP->u.strVal.str = MALLOC(valP->u.strVal.len);
-
- if (GET_STR(env, eVal, valP->u.strVal.str, valP->u.strVal.len) > 0) {
- valP->tag = SOCKET_OPT_VALUE_STR;
- *opt = TCP_CONGESTION;
- return TRUE;
- } else {
- FREE(valP->u.strVal.str);
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
- }
+ result = nsetopt_lvl_tcp_congestion(env, descP, eVal);
break;
#endif
#if defined(TCP_MAXSEG)
case SOCKET_OPT_TCP_MAXSEG:
- if (!GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = TCP_MAXSEG;
- return TRUE;
- } else {
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
- }
+ result = nsetopt_lvl_tcp_maxseg(env, descP, eVal);
break;
#endif
#if defined(TCP_NODELAY)
case SOCKET_OPT_TCP_NODELAY:
- if (decode_bool(env, eVal, &valP->u.boolVal)) {
- valP->tag = SOCKET_OPT_VALUE_BOOL;
- *opt = TCP_NODELAY;
- return TRUE;
- } else {
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- *opt = -1;
- return FALSE;
- }
+ result = nsetopt_lvl_tcp_nodelay(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
+ result = make_error(env, atom_einval);
+ break;
}
+
+ return result;
}
+/* nsetopt_lvl_tcp_congestion - Level TCP CONGESTION option
+ */
+#if defined(TCP_CONGESTION)
+static
+ERL_NIF_TERM nsetopt_lvl_tcp_congestion(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ int max = SOCKET_OPT_TCP_CONGESTION_NAME_MAX+1;
+
+ return nsetopt_str_opt(env, descP, IPPROTO_TCP, TCP_CONGESTION, max, eVal);
+}
+#endif
-/* +++ decode UDP socket options +++
- * Currently there are only one option, cork, and that may only
- * work on linux...
+
+/* nsetopt_lvl_tcp_maxseg - Level TCP MAXSEG option
*/
+#if defined(TCP_MAXSEG)
static
-BOOLEAN_T eoptval2optval_udp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
+ return nsetopt_int_opt(env, descP, IPPROTO_TCP, TCP_MAXSEG, eVal);
+}
+#endif
+
+
+/* nsetopt_lvl_tcp_nodelay - Level TCP NODELAY option
+ */
+#if defined(TCP_NODELAY)
+static
+ERL_NIF_TERM nsetopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, IPPROTO_TCP, TCP_NODELAY, eVal);
+}
+#endif
+
+
+
+/* nsetopt_lvl_udp - Level *UDP* option(s)
+ */
+static
+ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+
switch (eOpt) {
#if defined(UDP_CORK)
case SOCKET_OPT_UDP_CORK:
- if (decode_bool(env, eVal, &valP->u.boolVal)) {
- valP->tag = SOCKET_OPT_VALUE_BOOL;
- *opt = UDP_CORK;
- return TRUE;
- } else {
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- *opt = -1;
- return FALSE;
- }
+ result = nsetopt_lvl_udp_cork(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
+ result = make_error(env, atom_einval);
+ break;
}
+
+ return result;
}
+/* nsetopt_lvl_udp_cork - Level UDP CORK option
+ */
+#if defined(UDP_CORK)
+static
+ERL_NIF_TERM nsetopt_lvl_udp_cork(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, IPPROTO_UDP, UDP_CORK, eVal);
+}
+#endif
-#ifdef HAVE_SCTP
+
+
+
+/* nsetopt_lvl_sctp - Level *SCTP* option(s)
+ */
+#if defined(HAVE_SCTP)
static
-BOOLEAN_T eoptval2optval_sctp(ErlNifEnv* env,
- int eOpt,
- ERL_NIF_TERM eVal,
- int* opt,
- SocketOptValue* valP)
+ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
+ ERL_NIF_TERM result;
+
switch (eOpt) {
#if defined(SCTP_AUTOCLOSE)
case SOCKET_OPT_SCTP_AUTOCLOSE:
- if (GET_INT(env, eVal, &valP->u.intVal)) {
- valP->tag = SOCKET_OPT_VALUE_INT;
- *opt = SCTP_AUTOCLOSE;
- return TRUE;
- } else {
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- *opt = -1;
- return FALSE; // PLACEHOLDER - We should really be more informative
- }
+ result = nsetopt_lvl_sctp_autoclose(env, descP, eVal);
break;
#endif
#if defined(SCTP_NODELAY)
case SOCKET_OPT_SCTP_NODELAY:
- if (decode_bool(env, eVal, &valP->u.boolVal)) {
- valP->tag = SOCKET_OPT_VALUE_BOOL;
- *opt = SCTP_NODELAY;
- return TRUE;
- } else {
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- *opt = -1;
- return FALSE;
- }
+ result = nsetopt_lvl_sctp_nodelay(env, descP, eVal);
break;
#endif
default:
- *opt = -1;
- valP->tag = SOCKET_OPT_VALUE_UNDEF;
- return FALSE;
+ result = make_error(env, atom_einval);
+ break;
}
+
+ return result;
+}
+
+
+/* nsetopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
+ */
+#if defined(SCTP_AUTOCLOSE)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_AUTOCLOSE, eVal);
}
#endif
+/* nsetopt_lvl_sctp_nodelay - Level SCTP NODELAY option
+ */
+#if defined(SCTP_NODELAY)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_NODELAY, eVal);
+}
+#endif
+
+
+
+#endif // defined(HAVE_SCTP)
+
+
+
+
+/* nsetopt_str_opt - set an option that has an string value
+ */
+static
+ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ int max,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ char* val = MALLOC(max);
+
+ if (GET_STR(env, eVal, val, max) > 0) {
+ int optLen = strlen(val);
+ int res = socket_setopt(descP->sock, level, opt, &val, optLen);
+
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+
+ } else {
+ result = make_error(env, atom_einval);
+ }
+
+ FREE(val);
+
+ return result;
+}
+
+
+/* nsetopt_bool_opt - set an option that has an (integer) bool value
+ */
+static
+ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ BOOLEAN_T val;
+
+ if (decode_bool(env, eVal, &val)) {
+ int ival = (val) ? 1 : 0;
+ int res = socket_setopt(descP->sock, level, opt, &ival, sizeof(ival));
+
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+
+ } else {
+ result = make_error(env, atom_einval);
+ }
+
+ return result;
+}
+
+
+/* nsetopt_int_opt - set an option that has an integer value
+ */
+static
+ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ int val;
+
+ if (GET_INT(env, eVal, &val)) {
+ int res = socket_setopt(descP->sock, level, opt, &val, sizeof(val));
+
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+
+ } else {
+ result = make_error(env, atom_einval);
+ }
+
+ return result;
+}
+
+
+static
+BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
+ int eLevel,
+ BOOLEAN_T* isOTP,
+ int* level)
+{
+ BOOLEAN_T result;
+
+ if (isEncoded) {
+ switch (eLevel) {
+ case SOCKET_OPT_LEVEL_OTP:
+ *isOTP = TRUE;
+ *level = -1;
+ result = TRUE;
+ break;
+
+ case SOCKET_OPT_LEVEL_SOCKET:
+ *isOTP = FALSE;
+ *level = SOL_SOCKET;
+ result = TRUE;
+ break;
+
+ case SOCKET_OPT_LEVEL_IP:
+ *isOTP = FALSE;
+#if defined(SOL_IP)
+ *level = SOL_IP;
+#else
+ *level = IPROTO_IP;
+#endif
+ result = TRUE;
+ break;
+
+#if defined(SOL_IPV6)
+ case SOCKET_OPT_LEVEL_IPV6:
+ *isOTP = FALSE;
+ *level = SOL_IPV6;
+ result = TRUE;
+ break;
+#endif
+
+ case SOCKET_OPT_LEVEL_TCP:
+ *isOTP = FALSE;
+ *level = IPPROTO_TCP;
+ result = TRUE;
+ break;
+
+ case SOCKET_OPT_LEVEL_UDP:
+ *isOTP = FALSE;
+ *level = IPPROTO_UDP;
+ result = TRUE;
+ break;
+
+#ifdef HAVE_SCTP
+ case SOCKET_OPT_LEVEL_SCTP:
+ *isOTP = FALSE;
+ *level = IPPROTO_SCTP;
+ result = TRUE;
+ break;
+#endif
+
+ default:
+ *isOTP = FALSE;
+ *level = -1;
+ result = FALSE;
+ break;
+ }
+ } else {
+ *isOTP = FALSE;
+ *level = eLevel;
+ result = TRUE;
+ }
+
+ return result;
+}
+
+
/* +++ socket_setopt +++
*