Esempio n. 1
0
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen)
{
    struct fdtab_entry *e = fdtab_get(sockfd);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        assert(!"NYI");
        return -1;
        break;

    case FDTAB_TYPE_LWIP_SOCKET:
        lwip_mutex_lock();
        ssize_t ret = lwip_recvfrom(e->fd, buf, len, flags, src_addr, addrlen);
        lwip_mutex_unlock();
        return ret;

    case FDTAB_TYPE_AVAILABLE:
        errno = EBADF;
        return -1;

    default:
        errno = ENOTSOCK;
        return -1;
    }
}
Esempio n. 2
0
int listen(int sockfd, int backlog)
{
    struct fdtab_entry *e = fdtab_get(sockfd);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        POSIXCOMPAT_DEBUG("listen(%d, %d)\n", sockfd, backlog);
        struct _unix_socket *us = e->handle;

        errval_t err =
            unixsock_export(us, unixsock_listening, unixsock_connected,
                            get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
        if(err_is_fail(err)) {
            DEBUG_ERR(err, "unixsock_export failed");
            return -1;
        }
        while(us->u.passive.listen_iref == NULL_IREF) {
            // XXX: Should wait only on monitor
            event_dispatch(get_default_waitset());
        }

        us->passive = true;
        us->u.passive.max_backlog = backlog;
        us->u.passive.backlog = calloc(backlog, sizeof(struct unixsock_binding *));

        char str[128];
        snprintf(str, 128, "%"PRIuIREF, us->u.passive.listen_iref);
        err = vfs_write(us->vfs_handle, str, strlen(str), NULL);
        if(err_is_fail(err)) {
            USER_PANIC_ERR(err, "vfs_write");
        }
        break;

    case FDTAB_TYPE_LWIP_SOCKET:
        lwip_mutex_lock();
        int ret = lwip_listen(e->fd, backlog);
        lwip_mutex_unlock();
        return ret;

    default:
        return -1;
    }

    return 0;
}
Esempio n. 3
0
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
    struct fdtab_entry *e = fdtab_get(sockfd);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        assert(addrlen >= sizeof(struct sockaddr_un));
        assert(addr->sa_family == AF_UNIX);
        struct _unix_socket *us = e->handle;
        memcpy(&us->sockaddr, addr, sizeof(struct sockaddr_un));

        POSIXCOMPAT_DEBUG("bind(%d, %p (%s), %u)\n", sockfd, addr,
                          us->sockaddr.sun_path, addrlen);

        // XXX: Should fail if file already exists

        // Create socket file
        errval_t err = vfs_create(us->sockaddr.sun_path, &us->vfs_handle);
        if(err_is_fail(err)) {
            DEBUG_ERR(err, "vfs_create");
            return -1;
        }
        break;

    case FDTAB_TYPE_LWIP_SOCKET:
        lwip_mutex_lock();
        int ret = lwip_bind(e->fd, addr, addrlen);
        lwip_mutex_unlock();
        return ret;

    default:
        return -1;
    }

    return 0;
}
Esempio n. 4
0
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
    struct fdtab_entry *e = fdtab_get(sockfd);
    POSIXCOMPAT_DEBUG("%s:%s:%d: accept(sockfd=%d , e->type=%d)\n",
           __FILE__, __FUNCTION__, __LINE__, sockfd, e->type);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        {
            struct _unix_socket *us = e->handle;
            int i;

            if(!us->passive) {
                return -1;
            }

            for(;;) {
                for(i = 0; i < us->u.passive.max_backlog; i++) {
                    if(us->u.passive.backlog[i] != NULL) {
                        break;
                    }
                }

                if(i != us->u.passive.max_backlog) {
                    // Found a pending connection
                    break;
                }

                if(us->nonblocking) {
                    errno = EAGAIN;
                    return -1;
                }

                // XXX: This should wait only on the monitor
                event_dispatch(get_default_waitset());
            }

            // XXX: Using socket() to create new socket. Probably dangerous.
            int newfd = socket(AF_UNIX, us->type, us->protocol);
            assert(newfd != -1);
            struct _unix_socket *newus = fdtab_get(newfd)->handle;
            newus->u.active.binding = us->u.passive.backlog[i];
            newus->u.active.mode = _UNIX_SOCKET_MODE_CONNECTED;
            memcpy(&newus->sockaddr, &us->sockaddr, sizeof(struct sockaddr_un));

            // Associate binding with new socket and remove from backlog
            assert(newus->u.active.binding->st == NULL);
            newus->u.active.binding->st = newus;
            us->u.passive.backlog[i] = NULL;

            if(addr != NULL) {
                assert(addrlen != NULL);

                // TODO: Should request address from peer (if peer is bound)

                if(*addrlen > sizeof(struct sockaddr_un)) {
                    *addrlen = sizeof(struct sockaddr_un);
                }

                memcpy(addr, &newus->peer, *addrlen);
            }

            return newfd;
        }

	case FDTAB_TYPE_LWIP_SOCKET:
            {
                lwip_mutex_lock();
                int newfd = lwip_accept(e->fd, addr, addrlen);
                lwip_mutex_unlock();

                if(newfd != -1) {
                    struct fdtab_entry newe;
                    newe.type = FDTAB_TYPE_LWIP_SOCKET;
                    newe.fd = newfd;
                    newe.inherited = false;
                    newe.epoll_fd = -1;

                    newfd = fdtab_alloc(&newe);
                    POSIXCOMPAT_DEBUG("accept(%d, _, _) as fd %d\n", sockfd, newfd);
                    if (newfd < 0) {
                        return -1;
                    }
                }

                return newfd;
            }

    default:
        return -1;
    }
}
Esempio n. 5
0
int socket(int domain, int type, int protocol)
{
    struct fdtab_entry e;

    switch(domain) {
    case AF_UNIX:
        if(type != SOCK_STREAM) {
            errno = EPROTOTYPE;
            return -1;
        }

        if(protocol != 0) {
            errno = EPROTONOSUPPORT;
            return -1;
        }

        struct _unix_socket *us = malloc(sizeof(struct _unix_socket));
        assert(us != NULL);

        memset(us, 0, sizeof(struct _unix_socket));
        us->type = type;
        us->protocol = protocol;
        us->recv_buf_size = _UNIX_SOCKET_RECV_BUF_SIZE;

        /*
         * XXX: Even though POSIX says the result of
         * get{sock,peer}name() shall be unspecified if not bound,
         * some programs still expect its type to be of AF_UNIX.
         */
        us->sockaddr.sun_len = us->peer.sun_len = sizeof(struct sockaddr_un);
        us->sockaddr.sun_family = us->peer.sun_family = AF_UNIX;

        e.type = FDTAB_TYPE_UNIX_SOCKET;
        e.handle = us;
        e.inherited = false;
        e.epoll_fd = -1;
        break;

    case AF_INET:
        {
            lwip_mutex_lock();
            int fd = lwip_socket(domain, type, protocol);
            lwip_mutex_unlock();

            if(fd == -1) {
                return fd;
            }

            e.type = FDTAB_TYPE_LWIP_SOCKET;
            e.fd = fd;
            e.inherited = false;
            e.epoll_fd = -1;
        }
        break;

    default:
        errno = EAFNOSUPPORT;
        return -1;
    }

    int fd = fdtab_alloc(&e);
    POSIXCOMPAT_DEBUG("socket(%d, %d, %d) as fd %d\n", domain, type, protocol, fd);
    if (fd < 0) {
        return -1;
    } else {
        return fd;
    }
}
Esempio n. 6
0
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
    struct fdtab_entry *e = fdtab_get(sockfd);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        {
            struct _unix_socket *us = e->handle;

            // XXX: Don't support flags
            assert(flags == 0);

            thread_mutex_lock(&us->mutex);

            if(us->passive
               || us->u.active.mode != _UNIX_SOCKET_MODE_CONNECTED) {
                errno = ENOTCONN;
                thread_mutex_unlock(&us->mutex);
                return -1;
            }

            if(us->recv_buf_valid == 0) {
                // No more data
                if(us->nonblocking) {
                    errno = EAGAIN;
                    thread_mutex_unlock(&us->mutex);
                    return -1;
                } else {
                    struct waitset ws;
                    errval_t err;

                    waitset_init(&ws);

                    err = us->u.active.binding->change_waitset
                        (us->u.active.binding, &ws);
                    if(err_is_fail(err)) {
                        USER_PANIC_ERR(err, "change_waitset");
                    }

                    while(us->recv_buf_valid == 0) {
                        err = event_dispatch(&ws);
                        if(err_is_fail(err)) {
                            USER_PANIC_ERR(err, "waitset_destroy");
                        }
                    }

                    // XXX: Assume it was on the default waitset
                    err = us->u.active.binding->change_waitset
                        (us->u.active.binding, get_default_waitset());
                    if(err_is_fail(err)) {
                        USER_PANIC_ERR(err, "change_waitset");
                    }

                    err = waitset_destroy(&ws);
                    if(err_is_fail(err)) {
                        USER_PANIC_ERR(err, "waitset_destroy");
                    }
                }
            }

            size_t recved = 0;
            while(recved < len && us->recv_list != NULL) {
                struct _unix_socket_recv *usr = us->recv_list;
                size_t consume = MIN(len - recved, usr->size - usr->consumed);

                memcpy(buf + recved, &usr->msg[usr->consumed], consume);
                usr->consumed += consume;
                us->recv_buf_valid -= consume;
                recved += consume;

                if(usr->consumed == usr->size) {
                    us->recv_list = usr->next;
                    if(us->recv_list == NULL) {
                        us->recv_list_end = NULL;
                    }
                    free(usr->msg);
                    free(usr);
                } else {
                    assert(recved == len);
                }
            }

            thread_mutex_unlock(&us->mutex);
            return recved;
        }

    case FDTAB_TYPE_LWIP_SOCKET:
        lwip_mutex_lock();
        ssize_t ret = lwip_recv(e->fd, buf, len, flags);
        lwip_mutex_unlock();
        return ret;

    case FDTAB_TYPE_AVAILABLE:
        errno = EBADF;
        return -1;

    default:
        errno = ENOTSOCK;
        return -1;
    }
}
Esempio n. 7
0
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
    struct fdtab_entry *e = fdtab_get(sockfd);

    switch(e->type) {
    case FDTAB_TYPE_UNIX_SOCKET:
        {
            struct _unix_socket *us = e->handle;

            // XXX: Don't support flags
            assert(flags == 0);

            thread_mutex_lock(&us->mutex);

            if(us->passive
               || us->u.active.mode != _UNIX_SOCKET_MODE_CONNECTED) {
                errno = ENOTCONN;
                thread_mutex_unlock(&us->mutex);
                return -1;
            }

            if(us->send_buf != NULL) {
                if(us->nonblocking) {
                    errno = EAGAIN;
                    thread_mutex_unlock(&us->mutex);
                    return -1;
                } else {
                    assert(!"NYI");
                }
            }

            // Bleh. Gotta copy here. I can't just wait until the
            // message is fully sent, as that might block
            // indefinitely.
            us->send_buf = malloc(len);
            memcpy(us->send_buf, buf, len);

            struct event_closure ec = {
                .handler = unixsock_sent,
                .arg = us,
            };
            errval_t err = us->u.active.binding->tx_vtbl.
                send(us->u.active.binding, ec, us->send_buf, len);
            if(err_is_fail(err)) {
                USER_PANIC_ERR(err, "unixsock->send");
                thread_mutex_unlock(&us->mutex);
                return -1;
            }

            // Wait until all data sent if blocking
            if(!us->nonblocking) {
                struct waitset ws;
                waitset_init(&ws);

                err = us->u.active.binding->change_waitset
                    (us->u.active.binding, &ws);
                if(err_is_fail(err)) {
                    USER_PANIC_ERR(err, "change_waitset");
                }

                while(us->send_buf != NULL) {
                    err = event_dispatch(&ws);
                    if(err_is_fail(err)) {
                        USER_PANIC_ERR(err, "waitset_destroy");
                    }
                }

                // XXX: Assume it was on the default waitset
                err = us->u.active.binding->change_waitset
                    (us->u.active.binding, get_default_waitset());
                if(err_is_fail(err)) {
                    USER_PANIC_ERR(err, "change_waitset");
                }

                err = waitset_destroy(&ws);
                if(err_is_fail(err)) {
                    USER_PANIC_ERR(err, "waitset_destroy");
                }
            }

            // XXX: We send all or nothing
            thread_mutex_unlock(&us->mutex);
            return len;
        }

    case FDTAB_TYPE_LWIP_SOCKET:
        lwip_mutex_lock();
        ssize_t ret = lwip_send(e->fd, buf, len, flags);
        lwip_mutex_unlock();
        return ret;

    case FDTAB_TYPE_AVAILABLE:
        errno = EBADF;
        return -1;

    default:
        errno = ENOTSOCK;
        return -1;
    }
}
Esempio n. 8
0
int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout)
{
    struct fdtab_entry *mye = fdtab_get(epfd);
    assert(mye->type == FDTAB_TYPE_EPOLL_INSTANCE);
    struct _epoll_fd *efd = mye->handle;
    struct monitor_binding *mb = get_monitor_binding();
    errval_t err;

    /* waitset_init(&efd->ws); */
    assert(maxevents >= 1);

    for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) {
        struct fdtab_entry *e = fdtab_get(i->fd);
        struct epoll_event *event = &i->event;

        switch (e->type) {
        case FDTAB_TYPE_LWIP_SOCKET:
        {
            int retval;

            lwip_mutex_lock();
            if(event->events & EPOLLIN) {
                retval = lwip_sock_waitset_register_read(e->fd, &efd->ws);
                assert(retval == 0);
            }
            if(event->events & EPOLLOUT) {
                retval = lwip_sock_waitset_register_write(e->fd, &efd->ws);
                assert(retval == 0);
            }
            lwip_mutex_unlock();
        }
        break;

        case FDTAB_TYPE_UNIX_SOCKET:
        {
            struct _unix_socket *us = e->handle;

            if(event->events & EPOLLIN) {
                if (us->passive) { /* passive side */
                    int j;

                    /* Check for pending connection requests. */
                    for (j = 0; j < us->u.passive.max_backlog; j++)
                    {
                        if (us->u.passive.backlog[j] != NULL) {
                            break;
                        }
                    }

                    /*
                     * If there are not pending connection request
                     * wait on monitor binding.
                     */
                    if (j == us->u.passive.max_backlog) {
                        /* wait on monitor */
                        err = mb->change_waitset(mb, &efd->ws);
                        if (err_is_fail(err)) {
                            USER_PANIC_ERR(err, "change_waitset");
                        }
                    }
                }
            }

            if(event->events & EPOLLOUT) {
                assert(!us->passive);

                if(us->u.active.mode == _UNIX_SOCKET_MODE_CONNECTING) {
                    /* wait on monitor */
                    err = mb->change_waitset(mb, &efd->ws);
                    if (err_is_fail(err)) {
                        USER_PANIC_ERR(err, "change_waitset");
                    }
                }
            }

            assert(event->events & (EPOLLIN | EPOLLOUT));

            // Change waitset
            err = us->u.active.binding->change_waitset
                  (us->u.active.binding, &efd->ws);
            if (err_is_fail(err)) {
                USER_PANIC_ERR(err, "change waitset");
            }

        }
        break;

        default:
        {
            fprintf(stderr, "change waitset on FD type %d NYI.\n",
                    e->type);
            assert(!"NYI");
            errno = EBADF;
            return -1;
        }
        }
    }

    // Timeout handling
    struct timeout_event toe = {
        .fired = false
    };
    struct deferred_event timeout_event;
    if (timeout > 0) {
        deferred_event_init(&timeout_event);
        err = deferred_event_register(&timeout_event, &efd->ws, timeout,
                                      MKCLOSURE(timeout_fired, &toe));
        if (err_is_fail(err)) {
            errno = EINVAL;
            return -1;
        }
    }

    int retevents = 0;
    while(!toe.fired && retevents == 0) {
        if(timeout == 0) {
            // Just poll once, don't block
            err = event_dispatch_non_block(&efd->ws);
            assert(err_is_ok(err) || err_no(err) == LIB_ERR_NO_EVENT);
            toe.fired = true;
        } else {
            err = event_dispatch(&efd->ws);
            if (err_is_fail(err)) {
                USER_PANIC_ERR(err, "Error in event_dispatch.");
            }
        }

        // Return ready file descriptors
        for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) {
            struct epoll_event *event = &i->event;
            struct fdtab_entry *e = fdtab_get(i->fd);

            assert(retevents < maxevents);
            events[retevents] = *event;
            events[retevents].events = 0;

            // Check errors (hangup)
            {
                switch (e->type) {
                case FDTAB_TYPE_LWIP_SOCKET:
                {
                    lwip_mutex_lock();
                    if (!lwip_sock_is_open(e->fd)) {
                        events[retevents].events |= EPOLLHUP;
                    }
                    lwip_mutex_unlock();
                }
                break;

                default:
                    // No-Op
                    break;
                }
            }

            // Check readable FDs
            if(event->events & EPOLLIN) {
                switch (e->type) {
                case FDTAB_TYPE_LWIP_SOCKET:
                {
                    lwip_mutex_lock();
                    if (lwip_sock_ready_read(e->fd)) {
                        events[retevents].events |= EPOLLIN;
                    }
                    lwip_mutex_unlock();
                }
                break;

                case FDTAB_TYPE_UNIX_SOCKET:
                {
                    struct _unix_socket *us = e->handle;

                    if (us->passive) { /* passive side */
                        /* Check for pending connection requests. */
                        for (int j = 0; j < us->u.passive.max_backlog; j++)
                        {
                            if (us->u.passive.backlog[j] != NULL) {
                                events[retevents].events |= EPOLLIN;
                                break;
                            }
                        }
                    } else { /* active side */
                        /* Check for incoming data. */
                        if (us->recv_buf_valid > 0) {
                            events[retevents].events |= EPOLLIN;
                        }
                    }
                }
                break;

                default:
                {
                    fprintf(stderr, "epoll_wait() on FD type %d NYI.\n",
                            e->type);
                    assert(!"NYI");
                    errno = EBADF;
                    return -1;
                }
                }
            }

            // Check writeable FDs
            if(event->events & EPOLLOUT) {
                switch (e->type) {
                case FDTAB_TYPE_LWIP_SOCKET:
                {
                    lwip_mutex_lock();
                    if (lwip_sock_ready_write(e->fd)) {
                        events[retevents].events |= EPOLLOUT;
                    }
                    lwip_mutex_unlock();
                }
                break;

                case FDTAB_TYPE_UNIX_SOCKET:
                {
                    struct _unix_socket *us = e->handle;
                    assert(!us->passive);

                    switch (us->u.active.mode) {
                    case _UNIX_SOCKET_MODE_CONNECTING:
                        break;

                    case _UNIX_SOCKET_MODE_CONNECTED:
                        if (us->send_buf == NULL) {
                            events[retevents].events |= EPOLLOUT;
                        }
                        break;
                    }
                }
                break;

                default:
                {
                    fprintf(stderr, "epoll_wait() on FD type %d NYI.\n",
                            e->type);
                    assert(!"NYI");
                    errno = EBADF;
                    return -1;
                }
                }
            }

            // If any events were returned, go to next entry in array
            if(events[retevents].events != 0) {
                retevents++;
            }
        }
    }

    // Remove timeout from waitset if it was set and not fired
    if(timeout > 0 && !toe.fired) {
        deferred_event_cancel(&timeout_event);
    }

    // Restore old waitsets
    for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) {
        struct fdtab_entry *e = fdtab_get(i->fd);
        struct epoll_event *event = &i->event;

        switch (e->type) {
        case FDTAB_TYPE_LWIP_SOCKET:
        {
            lwip_mutex_lock();
            if(event->events & EPOLLIN) {
                err = lwip_sock_waitset_deregister_read(e->fd);
                if (err_is_fail(err) &&
                        err_no(err) != LIB_ERR_CHAN_NOT_REGISTERED) {
                    USER_PANIC_ERR(err, "error deregister read channel for "
                                   "lwip socket");
                }
            }
            if(event->events & EPOLLOUT) {
                err = lwip_sock_waitset_deregister_write(e->fd);
                if (err_is_fail(err) &&
                        err_no(err) != LIB_ERR_CHAN_NOT_REGISTERED) {
                    USER_PANIC_ERR(err, "error deregister write channel for "
                                   "lwip socket");
                }
            }
            lwip_mutex_unlock();
        }
        break;

        case FDTAB_TYPE_UNIX_SOCKET:
        {
            // NYI
        }
        break;

        default:
        {
            fprintf(stderr, "change waitset on FD type %d NYI.\n",
                    e->type);
            assert(!"NYI");
            errno = EBADF;
            return -1;
        }
        }
    }

    return retevents;
}

int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout,
                const sigset_t *sigmask)
{
    assert(!"NYI");
}
Esempio n. 9
0
static void call_tcp_tmr(void)
{
    lwip_mutex_lock();
    tcp_tmr();
    lwip_mutex_unlock();
}