diff --git a/c_src/procket.c b/c_src/procket.c index dd4a456..6c25178 100644 --- a/c_src/procket.c +++ b/c_src/procket.c @@ -1058,6 +1058,45 @@ nif_socket_optname(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return atom_undefined; } + static ERL_NIF_TERM +nif_socket_protocols(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + const struct procket_define *p = NULL; + ERL_NIF_TERM list = {0}; + + list = enif_make_list(env, 0); + + for (p = procket_socket_protocol; p->key != NULL; p++) { + list = enif_make_list_cell( + env, + enif_make_tuple2( + env, + enif_make_atom(env, p->key), + enif_make_uint(env, p->val) + ), + list); + } + + return list; +} + + static ERL_NIF_TERM +nif_socket_protocol(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + char buf[256] = {0}; + const struct procket_define *p = NULL; + + if (!enif_get_atom(env, argv[0], buf, sizeof(buf), ERL_NIF_LATIN1)) + return enif_make_badarg(env); + + for (p = procket_socket_protocol; p->key != NULL; p++) { + if (!strcmp(buf, p->key)) + return enif_make_int(env, p->val); + } + + return atom_undefined; +} + /* 0: errno */ static ERL_NIF_TERM nif_errno_id(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) @@ -1124,8 +1163,10 @@ static ErlNifFunc nif_funcs[] = { {"socket_level", 0, nif_socket_levels}, {"socket_optname", 0, nif_socket_optnames}, + {"socket_protocol", 0, nif_socket_protocols}, {"socket_level", 1, nif_socket_level}, {"socket_optname", 1, nif_socket_optname}, + {"socket_protocol", 1, nif_socket_protocol}, {"errno_id", 1, nif_errno_id} }; diff --git a/c_src/procket_constants.h b/c_src/procket_constants.h index 4a9267f..bf787be 100644 --- a/c_src/procket_constants.h +++ b/c_src/procket_constants.h @@ -3,7 +3,7 @@ struct procket_define { int val; }; -const struct procket_define procket_socket_level[] = { +const struct procket_define procket_socket_protocol[] = { #ifdef IPPROTO_AH {"IPPROTO_AH", IPPROTO_AH}, #endif @@ -259,6 +259,10 @@ const struct procket_define procket_socket_level[] = { #ifdef IPPROTO_XTP {"IPPROTO_XTP", IPPROTO_XTP}, #endif + {NULL, -1} +}; + +const struct procket_define procket_socket_level[] = { #ifdef SOL_AAL {"SOL_AAL", SOL_AAL}, #endif diff --git a/src/procket.erl b/src/procket.erl index fbde99b..cb537b4 100644 --- a/src/procket.erl +++ b/src/procket.erl @@ -61,6 +61,7 @@ socket_level/0, socket_level/1, socket_optname/0, socket_optname/1, + socket_protocol/0, socket_protocol/1, errno_id/1 ]). @@ -187,7 +188,8 @@ sendmsg(_,_,_,_,_) -> erlang:nif_error(not_implemented). setsockopt(Socket,Level,Optname,Optval) when is_atom(Level) -> - case socket_level(Level) of + case socket_constant_foreach(Level, + [fun socket_level/1, fun socket_protocol/1]) of undefined -> {error,unsupported}; N -> @@ -204,7 +206,8 @@ setsockopt(Socket,Level,Optname,Optval) -> setsockopt_nif(Socket, Level, Optname, Optval). getsockopt(Socket,Level,Optname,Optval) when is_atom(Level) -> - case socket_level(Level) of + case socket_constant_foreach(Level, + [fun socket_level/1, fun socket_protocol/1]) of undefined -> {error,unsupported}; N -> @@ -238,9 +241,23 @@ socket_optname() -> socket_optname(_) -> erlang:nif_error(not_implemented). +socket_protocol() -> + erlang:nif_error(not_implemented). +socket_protocol(_) -> + erlang:nif_error(not_implemented). + errno_id(_) -> erlang:nif_error(not_implemented). +socket_constant_foreach(_Constant, []) -> + undefined; +socket_constant_foreach(Constant, [Fun|Funs]) -> + case Fun(Constant) of + undefined -> + socket_constant_foreach(Constant, Funs); + N when is_integer(N) -> + N + end. %%-------------------------------------------------------------------- %%% Setuid helper