aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-05-17 15:16:57 +0200
committerMicael Karlberg <[email protected]>2018-09-18 13:01:37 +0200
commit993f22cab851d704c40f04cda5d5c3730539a6f8 (patch)
tree323e34650d2491ece4e6335f55827e69518f323b /erts
parent24bcbd2040fad723648e25af87cd848da8aa27bc (diff)
downloadotp-993f22cab851d704c40f04cda5d5c3730539a6f8.tar.gz
otp-993f22cab851d704c40f04cda5d5c3730539a6f8.tar.bz2
otp-993f22cab851d704c40f04cda5d5c3730539a6f8.zip
[socket-nif] More getopt
Its now possible to specify some "base" type(s) when retreiving an "native" option (base type instead of value size).
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/nifs/common/socket_nif.c135
1 files changed, 105 insertions, 30 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index d87492dd54..c63eff40ec 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -295,6 +295,10 @@ typedef unsigned long long llu_t;
#define SOCKET_RECV_BUFFER_SIZE_DEFAULT 2048
+#define SOCKET_OPT_VALLUE_TYPE_UNSPEC 0
+#define SOCKET_OPT_VALLUE_TYPE_INT 1
+#define SOCKET_OPT_VALLUE_TYPE_BOOL 2
+
typedef union {
struct {
unsigned int open:1;
@@ -981,6 +985,11 @@ static ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
SocketDescriptor* descP,
int level,
int eOpt);
+static ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ SOCKOPTLEN_T valueSz);
static ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
SocketDescriptor* descP,
int level,
@@ -1204,6 +1213,7 @@ static BOOLEAN_T decode_bool(ErlNifEnv* env,
static BOOLEAN_T decode_native_get_opt(ErlNifEnv* env,
ERL_NIF_TERM eVal,
int* opt,
+ uint16_t* valueType,
int* valueSz);
static void encode_bool(BOOLEAN_T val, ERL_NIF_TERM* eVal);
static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val);
@@ -4429,6 +4439,7 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
{
ERL_NIF_TERM result = enif_make_badarg(env);
int opt;
+ uint16_t valueType;
SOCKOPTLEN_T valueSz;
/* <KOLLA>
@@ -4437,44 +4448,71 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
* </KOLLA>
*/
- if (decode_native_get_opt(env, eOpt, &opt, (int*) &valueSz)) {
- int res;
+ if (decode_native_get_opt(env, eOpt, &opt, &valueType, (int*) &valueSz)) {
+ switch (valueType) {
+ case SOCKET_OPT_VALLUE_TYPE_UNSPEC:
+ result = ngetopt_native_unspec(env, descP, level, opt, valueSz);
+ break;
+ case SOCKET_OPT_VALLUE_TYPE_INT:
+ result = ngetopt_int_opt(env, descP, level, opt);
+ break;
+ case SOCKET_OPT_VALLUE_TYPE_BOOL:
+ result = ngetopt_bool_opt(env, descP, level, opt);
+ break;
+ default:
+ result = make_error(env, atom_einval);
+ break;
+ }
+ } else {
+ result = make_error(env, atom_einval);
+ }
- if (valueSz == 0) {
- res = sock_getopt(descP->sock, level, opt, NULL, NULL);
- if (res != 0)
- result = make_error2(env, res);
- else
- result = atom_ok;
- } else {
- ErlNifBinary val;
+ return result;
+}
- if (ALLOC_BIN(valueSz, &val)) {
- res = sock_getopt(descP->sock, level, opt, val.data, &valueSz);
- if (res != 0) {
- result = make_error2(env, res);
- } else {
- if (valueSz < val.size) {
- if (REALLOC_BIN(&val, valueSz)) {
- result = make_ok2(env, MKBIN(env, &val));
- } else {
- result = enif_make_badarg(env);
- }
+
+static
+ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ SOCKOPTLEN_T valueSz)
+{
+ ERL_NIF_TERM result = enif_make_badarg(env);
+ int res;
+
+ if (valueSz == 0) {
+ res = sock_getopt(descP->sock, level, opt, NULL, NULL);
+ if (res != 0)
+ result = make_error2(env, res);
+ else
+ result = atom_ok;
+ } else {
+ ErlNifBinary val;
+
+ if (ALLOC_BIN(valueSz, &val)) {
+ res = sock_getopt(descP->sock, level, opt, val.data, &valueSz);
+ if (res != 0) {
+ result = make_error2(env, res);
+ } else {
+ if (valueSz < val.size) {
+ if (REALLOC_BIN(&val, valueSz)) {
+ result = make_ok2(env, MKBIN(env, &val));
+ } else {
+ result = enif_make_badarg(env);
}
}
- } else {
- result = enif_make_badarg(env);
}
+ } else {
+ result = enif_make_badarg(env);
}
-
- } else {
- result = make_error(env, atom_einval);
}
return result;
}
+
/* ngetopt_level - A "proper" level (option) has been specified
*/
static
@@ -6077,12 +6115,12 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
* {NativeOpt, ValueSize}
*
* NativeOpt :: integer()
- * ValueSize :: non_neg_integer()
+ * ValueSize :: int | bool | non_neg_integer()
*
*/
static
BOOLEAN_T decode_native_get_opt(ErlNifEnv* env, ERL_NIF_TERM eVal,
- int* opt, int* valueSz)
+ int* opt, uint16_t* valueType, int* valueSz)
{
const ERL_NIF_TERM* nativeOptT;
int nativeOptTSz;
@@ -6095,13 +6133,50 @@ BOOLEAN_T decode_native_get_opt(ErlNifEnv* env, ERL_NIF_TERM eVal,
if (nativeOptTSz != 2)
return FALSE;
- /* So far so good. Both elements should be integers */
+ /* So far so good.
+ * First element is an integer.
+ * Second element is an atom or an integer.
+ * The only "types" that we support at the moment are:
+ *
+ * bool - Which is actually a integer
+ * (but will be *returned* as a boolean())
+ * int - Just short for integer
+ */
if (!GET_INT(env, nativeOptT[0], opt))
return FALSE;
- if (!GET_INT(env, nativeOptT[1], valueSz))
+ if (IS_ATOM(env, nativeOptT[1])) {
+ unsigned int len;
+ char t[16]; // Just in case
+
+ if (!(GET_ATOM_LEN(env, nativeOptT[1], &len) &&
+ (len > 0) &&
+ (len <= (sizeof("bool")))))
+ return FALSE;
+
+ if (!GET_ATOM(env, nativeOptT[1], t, sizeof(t)))
+ return FALSE;
+
+ if (strncmp(t, "bool", len) == 0) {
+ *valueType = SOCKET_OPT_VALLUE_TYPE_BOOL;
+ *valueSz = sizeof(int); // Just to be sure
+ } else if (strncmp(t, "int", len) == 0) {
+ *valueType = SOCKET_OPT_VALLUE_TYPE_INT;
+ *valueSz = sizeof(int); // Just to be sure
+ } else {
+ return FALSE;
+ }
+
+ } else if (IS_NUM(env, nativeOptT[1])) {
+ if (GET_INT(env, nativeOptT[1], valueSz)) {
+ *valueType = SOCKET_OPT_VALLUE_TYPE_UNSPEC;
+ } else {
+ return FALSE;
+ }
+ } else {
return FALSE;
+ }
return TRUE;
}