Skip to content

Commit

Permalink
recvfrom/4: return socket address
Browse files Browse the repository at this point in the history
Add recvfrom/4 to return the socket address of the packet. recvfrom/4
takes 2 new args: flags and the size of the socket structure which is
allocated by the NIF. If the size is not large enough, the socket address
will be silently truncated.
  • Loading branch information
msantos committed Dec 17, 2010
1 parent 61cffda commit 3206498
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
33 changes: 27 additions & 6 deletions c_src/procket.c
Expand Up @@ -193,40 +193,61 @@ nif_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])




/* 0: socket, 1: length */ /* 0: socket, 1: length */
/* 0: socket, 1: length, 2: flags, 3: struct sockaddr length */
static ERL_NIF_TERM static ERL_NIF_TERM
nif_recvfrom(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) nif_recvfrom(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{ {
int sockfd = -1; int sockfd = -1;
int len = 0; int len = 0;
ssize_t bufsz = 0; int salen = 0;
int flags = 0;

ErlNifBinary buf; ErlNifBinary buf;
ErlNifBinary sa;
ssize_t bufsz = 0;
socklen_t sasz = 0;



if (!enif_get_int(env, argv[0], &sockfd)) if (!enif_get_int(env, argv[0], &sockfd))
return enif_make_badarg(env); return enif_make_badarg(env);
if (!enif_get_int(env, argv[1], &len)) if (!enif_get_int(env, argv[1], &len))
return enif_make_badarg(env); return enif_make_badarg(env);
if (!enif_get_int(env, argv[2], &flags))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[3], &salen))
return enif_make_badarg(env);


if (!enif_alloc_binary(len, &buf)) if (!enif_alloc_binary(len, &buf))
return error_tuple(env, ENOMEM); return error_tuple(env, ENOMEM);


if ( (bufsz = recvfrom(sockfd, buf.data, buf.size, 0, NULL, NULL)) == -1) { if (!enif_alloc_binary(salen, &sa))
return error_tuple(env, ENOMEM);

sasz = salen;
if ( (bufsz = recvfrom(sockfd, buf.data, buf.size, flags,
(sasz == 0 ? NULL : (struct sockaddr *)sa.data),
&sasz)) == -1) {
switch (errno) { switch (errno) {
case EAGAIN: case EAGAIN:
case EINTR: case EINTR:
enif_release_binary(&buf); enif_release_binary(&buf);
enif_release_binary(&sa);
return atom_eagain; return atom_eagain;
default: default:
enif_release_binary(&buf); enif_release_binary(&buf);
enif_release_binary(&sa);
return error_tuple(env, errno); return error_tuple(env, errno);
} }
} }


if (bufsz != buf.size) if (bufsz != buf.size)
enif_realloc_binary(&buf, bufsz); enif_realloc_binary(&buf, bufsz);


return enif_make_tuple(env, 2, if (salen != sasz)
atom_ok, enif_realloc_binary(&sa, sasz);
enif_make_binary(env, &buf));
return enif_make_tuple(env, 3, atom_ok, enif_make_binary(env, &buf),
enif_make_binary(env, &sa));
} }




Expand Down Expand Up @@ -383,9 +404,9 @@ static ErlNifFunc nif_funcs[] = {
{"bind", 2, nif_bind}, {"bind", 2, nif_bind},
{"connect", 2, nif_connect}, {"connect", 2, nif_connect},
{"listen", 2, nif_listen}, {"listen", 2, nif_listen},
{"recvfrom", 2, nif_recvfrom},
{"ioctl", 3, nif_ioctl}, {"ioctl", 3, nif_ioctl},
{"socket", 3, nif_socket}, {"socket", 3, nif_socket},
{"recvfrom", 4, nif_recvfrom},
{"sendto", 4, nif_sendto}, {"sendto", 4, nif_sendto},
{"setsockopt", 4, nif_setsockopt} {"setsockopt", 4, nif_setsockopt}
}; };
Expand Down
12 changes: 10 additions & 2 deletions src/procket.erl
Expand Up @@ -36,7 +36,8 @@
socket/3, listen/2,connect/2, socket/3, listen/2,connect/2,
accept/1,accept/2, accept/1,accept/2,
fdopen/1,fdrecv/1,close/1,close/2, fdopen/1,fdrecv/1,close/1,close/2,
recvfrom/2,sendto/4,bind/2, recv/2,recvfrom/2,recvfrom/4,
sendto/4,bind/2,
ioctl/3,setsockopt/4 ioctl/3,setsockopt/4
]). ]).
-export([make_args/2,progname/0]). -export([make_args/2,progname/0]).
Expand Down Expand Up @@ -74,7 +75,14 @@ connect(_,_) ->
listen(_,_) -> listen(_,_) ->
erlang:error(not_implemented). erlang:error(not_implemented).


recvfrom(_,_) -> recv(Socket,Size) ->
recvfrom(Socket,Size).
recvfrom(Socket,Size) ->
case recvfrom(Socket, Size, 0, 0) of
{ok, Buf, <<>>} -> {ok, Buf};
Error -> Error
end.
recvfrom(_,_,_,_) ->
erlang:error(not_implemented). erlang:error(not_implemented).


socket(_,_,_) -> socket(_,_,_) ->
Expand Down

0 comments on commit 3206498

Please sign in to comment.