aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/nifs/common/socket_nif.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/nifs/common/socket_nif.c')
-rw-r--r--erts/emulator/nifs/common/socket_nif.c326
1 files changed, 208 insertions, 118 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index f7e59678bb..68a9730d0c 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -848,9 +848,6 @@ typedef struct {
-static ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_info(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
@@ -1973,7 +1970,18 @@ extern char* encode_msghdr_flags(ErlNifEnv* env,
SocketDescriptor* descP,
int msgFlags,
ERL_NIF_TERM* flags);
-
+static char* decode_cmsghdr_data(ErlNifEnv* env,
+ void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ ERL_NIF_TERM eData);
+static char* decode_cmsghdr_final(void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ char* data,
+ int sz);
static BOOLEAN_T decode_sock_linger(ErlNifEnv* env,
ERL_NIF_TERM eVal,
struct linger* valP);
@@ -2380,7 +2388,6 @@ static SocketData data;
*
* Utility and admin functions:
* ----------------------------
- * nif_is_loaded/0
* nif_info/0
* (nif_debug/1)
*
@@ -2417,27 +2424,6 @@ static SocketData data;
/* ----------------------------------------------------------------------
- * nif_is_loaded
- *
- * Description:
- * This functions only purpose is to return the atom 'true'.
- * This will happen *if* the (socket) nif library is loaded.
- * If its not, the erlang (nif_is_loaded) will instead return
- * 'false'.
- */
-static
-ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[])
-{
- if (argc != 0)
- return enif_make_badarg(env);
-
- return atom_true;
-}
-
-
-/* ----------------------------------------------------------------------
* nif_info
*
* Description:
@@ -11046,7 +11032,7 @@ char* encode_msghdr(ErlNifEnv* env,
*
* The cmsgHdrP arguments points to the start of the control data buffer,
* an actual binary. Its the only way to create sub-binaries. So, what we
- * need to continue processing this is to tern that into an binary erlang
+ * need to continue processing this is to turn that into an binary erlang
* term (which can then in turn be turned into sub-binaries).
*
* We need the cmsgBufP (even though cmsgHdrP points to it) to be able
@@ -11171,7 +11157,7 @@ char* encode_cmsghdrs(ErlNifEnv* env,
*
* Decode a list of cmsghdr(). There can be 0 or more cmsghdr "blocks".
*
- * Each element can either be a (erlang) map that needds to be decoded,
+ * Each element can either be a (erlang) map that needs to be decoded,
* or a (erlang) binary that just needs to be appended to the control
* buffer.
*
@@ -11267,46 +11253,121 @@ char* decode_cmsghdr(ErlNifEnv* env,
/* And finally data
* If its a binary, we are done. Otherwise, we need to check
* level and type to know what kind of data to expect.
- *
- * <KOLLA>
- *
- * At the moment, the only data we support is a binary...
- *
- * </KOLLA>
*/
+
+ return decode_cmsghdr_data(env, bufP, rem, level, type, eData);
+
+ } else {
+ return ESOCK_STR_EINVAL;
+ }
+
+ return NULL;
+}
+
+
+/* *** decode_cmsghdr_data ***
+ *
+ * For all combinations of level and type we accept a binary as data,
+ * so we begin by testing for that. If its not a binary, then we check
+ * level (ip) and type (tos or ttl), in which case the data *must* be
+ * an integer (we have already taken care of the binary).
+ */
+static
+char* decode_cmsghdr_data(ErlNifEnv* env,
+ void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ ERL_NIF_TERM eData)
+{
+ char* xres = ESOCK_STR_EINVAL;
+
+ if (IS_BIN(env, eData)) {
+ ErlNifBinary bin;
- if (IS_BIN(env, eData)) {
- ErlNifBinary bin;
- size_t currentRem = *rem;
+ if (GET_BIN(env, eData, &bin)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) bin.data, bin.size);
+ }
+ } else {
- if (!GET_BIN(env, eData, &bin)) {
- return ESOCK_STR_EINVAL;
- } else {
- int len = CMSG_LEN(bin.size); // The cmsghdr
- int space = CMSG_SPACE(bin.size); // With padding
- /* Make sure it fits before we copy */
- if (currentRem >= space) {
- struct cmsghdr* cmsgP = (struct cmsghdr*) bufP;
-
- /* The header */
- cmsgP->cmsg_len = len;
- cmsgP->cmsg_level = level;
- cmsgP->cmsg_type = type;
-
- /* And the data */
- sys_memcpy(CMSG_DATA(cmsgP), bin.data, bin.size);
- *bufP += space;
- *rem -= space;
- } else {
- return ESOCK_STR_EINVAL;
+ /* Its *not* a binary so we need to look at what level and type
+ * we have and treat them individually.
+ */
+
+ switch (level) {
+#if defined(SOL_IP)
+ case SOL_IP:
+#else
+ case IPPROTO_IP:
+#endif
+ switch (type) {
+#if defined(IP_TOS)
+ case IP_TOS:
+ {
+ int data;
+ if (decode_ip_tos(env, eData, &data)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) &data,
+ sizeof(data));
+ }
+ }
+ break;
+#endif
+
+#if defined(IP_TTL)
+ case IP_TTL:
+ {
+ int data;
+ if (GET_INT(env, eData, &data)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) &data,
+ sizeof(data));
+ }
}
+ break;
+#endif
+
}
- } else {
+ break;
+
+ default:
+ break;
+ }
- /* Here is where we should have the proper data decode */
+ }
- return ESOCK_STR_EINVAL;
- }
+ return xres;
+}
+
+
+/* *** decode_cmsghdr_final ***
+ *
+ * This does the final create of the cmsghdr (including the data copy).
+ */
+static
+char* decode_cmsghdr_final(void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ char* data,
+ int sz)
+{
+ int currentRem = *rem;
+ int len = CMSG_LEN(sz);
+ int space = CMSG_SPACE(sz);
+
+ if (currentRem >= space) {
+ struct cmsghdr* cmsgP = (struct cmsghdr*) bufP;
+
+ /* The header */
+ cmsgP->cmsg_len = len;
+ cmsgP->cmsg_level = level;
+ cmsgP->cmsg_type = type;
+
+ sys_memcpy(CMSG_DATA(cmsgP), &data, sz);
+ *bufP += space;
+ *rem -= space;
} else {
return ESOCK_STR_EINVAL;
}
@@ -11334,8 +11395,30 @@ char* encode_cmsghdr_level(ErlNifEnv* env,
xres = NULL;
break;
+#if defined(SOL_IP)
+ case SOL_IP:
+#else
+ case IPPROTO_IP:
+#endif
+ *eLevel = esock_atom_ip;
+ xres = NULL;
+ break;
+
+#if defined(SOL_IPV6)
+ case SOL_IPV6:
+ *eLevel = esock_atom_ip;
+ xres = NULL;
+ break;
+#endif
+
+ case IPPROTO_UDP:
+ *eLevel = esock_atom_udp;
+ xres = NULL;
+ break;
+
default:
- xres = esock_encode_protocol(env, level, eLevel);
+ *eLevel = MKI(env, level);
+ xres = NULL;
break;
}
@@ -11358,17 +11441,35 @@ char* decode_cmsghdr_level(ErlNifEnv* env,
char* xres = NULL;
if (IS_ATOM(env, eLevel)) {
+
if (COMPARE(eLevel, esock_atom_socket) == 0) {
*level = SOL_SOCKET;
xres = NULL;
+ } else if (COMPARE(eLevel, esock_atom_ip) == 0) {
+#if defined(SOL_IP)
+ *level = SOL_IP;
+#else
+ *level = IPPROTO_IP;
+#endif
+ xres = NULL;
+#if defined(SOL_IPV6)
+ } else if (COMPARE(eLevel, esock_atom_ipv6) == 0) {
+ *level = SOL_IPV6;
+ xres = NULL;
+#endif
+ } else if (COMPARE(eLevel, esock_atom_udp) == 0) {
+ *level = IPPROTO_UDP;
+ xres = NULL;
} else {
- xres = esock_decode_protocol(env, eLevel, level);
+ *level = -1;
+ xres = ESOCK_STR_EINVAL;
}
} else if (IS_NUM(env, eLevel)) {
if (!GET_INT(env, eLevel, level))
xres = ESOCK_STR_EINVAL;
} else {
- xres = ESOCK_STR_EINVAL;
+ *level = -1;
+ xres = ESOCK_STR_EINVAL;
}
return xres;
@@ -11521,25 +11622,13 @@ char* decode_cmsghdr_type(ErlNifEnv* env,
switch (level) {
case SOL_SOCKET:
- if (COMPARE(eType, esock_atom_timestamp) == 0) {
-#if defined(SO_TIMESTAMP)
- *type = SO_TIMESTAMP;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_rights) == 0) {
-#if defined(SCM_RIGHTS)
- *type = SCM_RIGHTS;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_credentials) == 0) {
-#if defined(SCM_CREDENTIALS)
- *type = SCM_CREDENTIALS;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
} else {
+ *type = -1;
xres = ESOCK_STR_EINVAL;
}
break;
@@ -11550,60 +11639,62 @@ char* decode_cmsghdr_type(ErlNifEnv* env,
#else
case IPPROTO_IP:
#endif
- if (COMPARE(eType, esock_atom_tos) == 0) {
+ if (IS_ATOM(env, eType)) {
+ if (COMPARE(eType, esock_atom_tos) == 0) {
#if defined(IP_TOS)
- *type = IP_TOS;
+ *type = IP_TOS;
#else
- xres = ESOCK_STR_EINVAL;
+ xres = ESOCK_STR_EINVAL;
#endif
- } else if (COMPARE(eType, esock_atom_ttl) == 0) {
+ } else if (COMPARE(eType, esock_atom_ttl) == 0) {
#if defined(IP_TTL)
- *type = IP_TTL;
+ *type = IP_TTL;
#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_pktinfo) == 0) {
-#if defined(IP_PKTINFO)
- *type = IP_PKTINFO;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_origdstaddr) == 0) {
-#if defined(IP_ORIGDSTADDR)
- *type = IP_ORIGDSTADDR;
-#else
- xres = ESOCK_STR_EINVAL;
+ xres = ESOCK_STR_EINVAL;
#endif
+ } else {
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
} else {
- xres = ESOCK_STR_EINVAL;
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
}
break;
#if defined(SOL_IPV6)
case SOL_IPV6:
- xres = ESOCK_STR_EINVAL;
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
break;
#endif
- case IPPROTO_TCP:
- xres = ESOCK_STR_EINVAL;
- break;
- break;
-
case IPPROTO_UDP:
- xres = ESOCK_STR_EINVAL;
- break;
- break;
-
-#if defined(HAVE_SCTP)
- case IPPROTO_SCTP:
- xres = ESOCK_STR_EINVAL;
- break;
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
break;
-#endif
default:
- xres = ESOCK_STR_EINVAL;
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
break;
}
@@ -13481,7 +13572,6 @@ static
ErlNifFunc socket_funcs[] =
{
// Some utility functions
- {"nif_is_loaded", 0, nif_is_loaded, 0},
{"nif_info", 0, nif_info, 0},
// {"nif_debug", 1, nif_debug_, 0},