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

    ErlNifBinary buf = {0};
    ErlNifBinary sa = {0};
    ssize_t bufsz = 0;


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

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

    if (!enif_alloc_binary(salen, &sa))
        return error_tuple(env, ENOMEM);

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

    PROCKET_REALLOC(buf, bufsz);
    PROCKET_REALLOC(sa, salen);

    return enif_make_tuple3(env, atom_ok, enif_make_binary(env, &buf),
             enif_make_binary(env, &sa));
}
Ejemplo n.º 2
0
// int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    static ERL_NIF_TERM
nif_getsockname(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    int s = -1;
    ErlNifBinary addr = {0};
    socklen_t addrlen = 0;


    if (!enif_get_int(env, argv[0], &s))
        return enif_make_badarg(env);

    if (!enif_inspect_binary(env, argv[1], &addr))
        return enif_make_badarg(env);

    /* Make the binary mutable */
    if (!enif_realloc_binary(&addr, addr.size))
        return error_tuple(env, ENOMEM);

    addrlen = addr.size;

    if (getsockname(s, (struct sockaddr *)addr.data, (socklen_t *)&addrlen) < 0)
        return error_tuple(env, errno);

    PROCKET_REALLOC(addr, addrlen);

    return enif_make_tuple2(env,
            atom_ok,
            enif_make_binary(env, &addr));
}
Ejemplo n.º 3
0
/* 0: socket, 1: length */
    static ERL_NIF_TERM
nif_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    int fd = -1;
    unsigned long len = 0;

    ErlNifBinary buf = {0};
    ssize_t bufsz = 0;


    if (!enif_get_int(env, argv[0], &fd))
        return enif_make_badarg(env);
    if (!enif_get_ulong(env, argv[1], &len))
        return enif_make_badarg(env);

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

    if ( (bufsz = read(fd, buf.data, buf.size)) == -1) {
        int err = errno;
        enif_release_binary(&buf);
        switch (err) {
            case EAGAIN:
            case EINTR:
                return enif_make_tuple2(env, atom_error, atom_eagain);
            default:
                return error_tuple(env, err);
        }
    }

    PROCKET_REALLOC(buf, bufsz);

    return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &buf));
}
Ejemplo n.º 4
0
    static ERL_NIF_TERM
nif_setns(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef HAVE_SETNS
    int fd;
    ErlNifBinary buf = {0};
    int nstype = 0;
    int errnum = 0;

    if (!enif_inspect_iolist_as_binary(env, argv[0], &buf))
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[1], &nstype))
        return enif_make_badarg(env);

    PROCKET_REALLOC(buf, buf.size+1);
    buf.data[buf.size-1] = '\0';

    fd = open((const char*)buf.data, O_RDONLY);  /* Get descriptor for namespace */
    if (fd < 0)
        return error_tuple(env, errno);

    if (setns(fd, nstype) == -1) {
        errnum = errno;
        (void)close(fd);
        return error_tuple(env, errnum);
    }

    (void)close(fd);

    return atom_ok;
#else
    return error_tuple(env, ENOTSUP);
#endif
}
Ejemplo n.º 5
0
/* 0: socket, 1: struct sockaddr length */
    static ERL_NIF_TERM
nif_accept(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    int l = -1;
    int s = -1;
    unsigned long salen = 0;
    ErlNifBinary sa = {0};
    int flags = 0;


    if (!enif_get_int(env, argv[0], &l))
        return enif_make_badarg(env);

    if (!enif_get_ulong(env, argv[1], &salen))
        return enif_make_badarg(env);

    if (!enif_alloc_binary(salen, &sa))
        return error_tuple(env, ENOMEM);

    s = accept(l, (sa.size == 0 ? NULL : (struct sockaddr *)sa.data), (socklen_t *)&salen);
    if (s < 0)
        return error_tuple(env, errno);

    flags = fcntl(s, F_GETFL, 0);

    if (flags < 0)
        return error_tuple(env, errno);

    if (fcntl(s, F_SETFL, flags|O_NONBLOCK) < 0)
        return error_tuple(env, errno);

    PROCKET_REALLOC(sa, salen);

    return enif_make_tuple3(env,
            atom_ok,
            enif_make_int(env, s),
            enif_make_binary(env, &sa));
}
Ejemplo n.º 6
0
/* 0: int socket descriptor, 1: int level,
 * 2: int optname, 3: void *optval
 */
    static ERL_NIF_TERM
nif_getsockopt(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    int s = -1;
    int level = 0;
    int optname = 0;
    ErlNifBinary optval = {0};
    socklen_t optlen = 0;


    if (!enif_get_int(env, argv[0], &s))
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[1], &level))
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[2], &optname))
        return enif_make_badarg(env);

    if (!enif_inspect_binary(env, argv[3], &optval))
        return enif_make_badarg(env);

    /* Make the binary mutable */
    if (!enif_realloc_binary(&optval, optval.size))
        return error_tuple(env, ENOMEM);

    optlen = optval.size;

    if (getsockopt(s, level, optname,
                (optval.size == 0 ? NULL : optval.data), &optlen) < 0)
        return error_tuple(env, errno);

    PROCKET_REALLOC(optval, optlen);

    return enif_make_tuple2(env,
            atom_ok,
            enif_make_binary(env, &optval));
}
Ejemplo n.º 7
0
    static ERL_NIF_TERM
nif_recvmsg(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    int s = -1;
    ErlNifBinary buf = {0};
    ErlNifBinary src_addr = {0};
    char *ctrldata = NULL;
    ERL_NIF_TERM ctrldatalist;
    int flags = 0;
    unsigned long bufsize = 0;
    unsigned long ctrlsize = 0;
    unsigned long sasize = 0;

    struct iovec iov[1];
    struct msghdr message;
    struct cmsghdr *cmsg;

    ssize_t n = 0;

    if (!enif_get_int(env, argv[0], &s))
        return enif_make_badarg(env);

    if (!enif_get_ulong(env, argv[1], &bufsize))
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[2], &flags))
        return enif_make_badarg(env);

    if (!enif_get_ulong(env, argv[3], &ctrlsize))
        return enif_make_badarg(env);

    if (!enif_get_ulong(env, argv[4], &sasize))
        return enif_make_badarg(env);

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

    if (ctrlsize > 0 && !(ctrldata = malloc(ctrlsize))) {
        enif_release_binary(&buf);
        return error_tuple(env, ENOMEM);
    }

    if (!enif_alloc_binary(sasize, &src_addr)) {
        enif_release_binary(&buf);
        free(ctrldata);
        return error_tuple(env, ENOMEM);
    }

    iov[0].iov_base = (buf.size == 0 ? NULL : buf.data);
    iov[0].iov_len=buf.size;

    message.msg_name = (src_addr.size == 0 ? NULL : src_addr.data);
    message.msg_namelen=src_addr.size;
    message.msg_iov=iov;
    message.msg_iovlen=1;
    message.msg_control=ctrldata;
    message.msg_controllen=ctrlsize;

    n = recvmsg(s, &message, flags);

    if (n < 0) {
        int err = errno;
        enif_release_binary(&buf);
        enif_release_binary(&src_addr);
        free(ctrldata);
        return error_tuple(env, err);
    }

    /* resize the binary to the actual size of the received packet
     *
     * XXX On error, the macro will return ENOMEM here, leaking buf,
     * XXX src_addr and ctrldata. Since the VM has OOM'ed, it will probably
     * XXX crash anyway.
     */
    PROCKET_REALLOC(buf, n);
    PROCKET_REALLOC(src_addr, message.msg_namelen);

    ctrldatalist = enif_make_list(env, 0);

    for (cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL;
            cmsg = CMSG_NXTHDR(&message, cmsg)) {
        size_t len = cmsg->cmsg_len - CMSG_LEN(0);
        ErlNifBinary cdata = {0};

        if (!enif_alloc_binary(len, &cdata)) {
            enif_release_binary(&buf);
            enif_release_binary(&src_addr);
            free(ctrldata);
            return error_tuple(env, ENOMEM);
        }

        memcpy(cdata.data, CMSG_DATA(cmsg), len);

        ctrldatalist = enif_make_list_cell(env,
                enif_make_tuple3(env,
                    enif_make_int(env, cmsg->cmsg_level),
                    enif_make_int(env, cmsg->cmsg_type),
                    enif_make_binary(env, &cdata)), ctrldatalist);
    }

    free(ctrldata);

    return enif_make_tuple5(env,
            atom_ok,
            enif_make_binary(env, &buf), /* Data packet */
            enif_make_int(env, message.msg_flags), /* the message flags, eg. MSG_EOR, MSG_OOB, etc. */
            ctrldatalist, /* array of 3-tuples of {cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_data} */
            enif_make_binary(env, &src_addr) /* source address, as a sockaddr_storage */
            );
}