Пример #1
0
int n_dhcp4_s_connection_dispatch_io(NDhcp4SConnection *connection, NDhcp4Incoming **messagep) {
        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
        struct sockaddr_in dest = {};
        int r;

        r = n_dhcp4_s_socket_udp_recv(connection->fd_udp,
                                          connection->buf,
                                          sizeof(connection->buf),
                                          &message,
                                          &dest);
        if (r)
                return r;

        r = n_dhcp4_s_connection_verify_incoming(connection,
                                                 message,
                                                 dest.sin_addr.s_addr == INADDR_BROADCAST);
        if (r) {
                if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED) {
                        *messagep = NULL;
                        return 0;
                }

                return -ENOTRECOVERABLE;
        }

        *messagep = message;
        message = NULL;
        return 0;
}
Пример #2
0
/**
 * b1_handle_transfer() - transfer a handle from one peer to another
 * @src_handle:         source handle
 * @dst:                destination peer
 * @dst_handlep:        pointer to destination handle
 *
 * In order for peers to communicate, they must be reachable from one another.
 * This transfers a handle from one peer to another.
 *
 * Return: 0 on success, or a negative error code on failure.
 */
_c_public_ int b1_handle_transfer(B1Handle *src_handle, B1Peer *dst, B1Handle **dst_handlep) {
        _c_cleanup_(b1_handle_unrefp) B1Handle *dst_handle = NULL;
        uint64_t src_handle_id, dst_handle_id = BUS1_HANDLE_INVALID;
        int r;

        if (src_handle->id == BUS1_HANDLE_INVALID)
                src_handle_id = BUS1_NODE_FLAG_MANAGED | BUS1_NODE_FLAG_ALLOCATE;
        else
                src_handle_id = src_handle->id;

        r = bus1_peer_handle_transfer(src_handle->holder->peer, dst->peer, &src_handle_id, &dst_handle_id);
        if (r < 0)
                return r;

        if (src_handle->id == BUS1_HANDLE_INVALID) {
                r = b1_handle_link(src_handle, src_handle_id);
                if (r < 0)
                        return r;

                if (src_handle->node) {
                        r = b1_node_link(src_handle->node, src_handle_id);
                        if (r < 0)
                                return r;
                }
        }

        r = b1_handle_acquire(dst, &dst_handle, dst_handle_id);
        if (r < 0)
                return r;

        *dst_handlep = dst_handle;
        dst_handle = NULL;
        return 0;
}
Пример #3
0
static void test_handle(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *peer = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL;
        int r;

        r = b1_peer_new(&peer);
        assert(r >= 0);

        r = b1_node_new(peer, &node);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node), peer, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle == b1_node_get_handle(node));
}
Пример #4
0
static void test_message(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *peer = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        _c_cleanup_(b1_message_unrefp) B1Message *message = NULL;
        B1Handle *handle;
        int r, fd;

        r = b1_peer_new(&peer);
        assert(r >= 0);

        r = b1_node_new(peer, &node);
        assert(r >= 0);

        r = b1_message_new(peer, &message);
        assert(r >= 0);
        assert(message);

        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(!b1_message_get_destination_node(message));
        assert(!b1_message_get_destination_handle(message));
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);

        handle = b1_node_get_handle(node);

        r = b1_message_set_handles(message, &handle, 1);
        assert(r >= 0);

        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle == b1_node_get_handle(node));

        fd = b1_peer_get_fd(peer);

        r = b1_message_set_fds(message, &fd, 1);
        assert(r >= 0);

        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        assert(fd != b1_peer_get_fd(peer));
}
Пример #5
0
static void test_node(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *peer = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        B1Handle *handle;
        int r;

        r = b1_peer_new(&peer);
        assert(r >= 0);

        r = b1_node_new(peer, &node);
        assert(r >= 0);
        assert(node);

        assert(b1_node_get_peer(node) == peer);

        handle = b1_node_get_handle(node);
        assert(handle);

        handle = b1_handle_ref(handle);
        assert(handle);
        b1_handle_unref(handle);
}
Пример #6
0
/**
 * n_dhcp4_server_lease_new() - XXX
 */
int n_dhcp4_server_lease_new(NDhcp4ServerLease **leasep, NDhcp4Incoming *message) {
        _c_cleanup_(n_dhcp4_server_lease_unrefp) NDhcp4ServerLease *lease = NULL;

        c_assert(leasep);

        lease = malloc(sizeof(*lease));
        if (!lease)
                return -ENOMEM;

        *lease = (NDhcp4ServerLease)N_DHCP4_SERVER_LEASE_NULL(*lease);

        lease->request = message;

        *leasep = lease;
        lease = NULL;
        return 0;
}
Пример #7
0
/**
 * b1_node_new() - create a new node for a peer
 * @peer:               the owning peer, or null
 * @nodep:              pointer to the new node object
 * @userdata:           userdata to associate with the node
 *
 * A node is the recipient of messages, and. Nodes are allocated lazily in the
 * kernel, so it is not guaranteed to be a kernel equivalent to the userspace
 * object at all times. A node is associated with at most one peer, and for a
 * lazily created node it may not be associated with any peer until it is
 * actually created, at which point it is associated with the creating peer.
 *
 * Return: 0 on success, and a negative error code on failure.
 */
_c_public_ int b1_node_new(B1Peer *peer, B1Node **nodep, void *userdata) {
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        int r;

        r = b1_node_new_internal(peer, &node, userdata, BUS1_HANDLE_INVALID, NULL);
        if (r < 0)
                return r;

        r = b1_handle_new(peer, BUS1_HANDLE_INVALID, &node->handle);
        if (r < 0)
                return r;

        node->handle->node = node;

        *nodep = node;
        node = NULL;
        return 0;
}
Пример #8
0
int b1_handle_new(B1Peer *peer, uint64_t id, B1Handle **handlep) {
        _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL;

        assert(peer);
        assert(handlep);

        handle = calloc(1, sizeof(*handle));
        if (!handle)
                return -ENOMEM;

        handle->n_ref = 1;
        handle->holder = b1_peer_ref(peer);
        handle->id = id;
        handle->marked = false;
        c_rbnode_init(&handle->rb);

        *handlep = handle;
        handle = NULL;
        return 0;
}
Пример #9
0
static void test_peer(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *peer1 = NULL, *peer2 = NULL, *peer3 = NULL;
        int fd, r;

        /* create three peers: peer1 and peer2 are two instances of the same */
        r = b1_peer_new(&peer1);
        assert(r >= 0);
        assert(peer1);

        fd = b1_peer_get_fd(peer1);
        assert(fd >= 0);

        r = b1_peer_new_from_fd(&peer2, fd);
        assert(r >= 0);
        assert(peer2);

        r = b1_peer_new(&peer3);
        assert(r >= 0);
        assert(peer3);
}
Пример #10
0
static int b1_handle_new(B1Peer *peer, B1Handle **handlep) {
        _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL;

        assert(peer);
        assert(handlep);

        handle = calloc(1, sizeof(*handle));
        if (!handle)
                return -ENOMEM;

        handle->ref = (CRef)C_REF_INIT;
        handle->holder = b1_peer_ref(peer);
        handle->id = BUS1_HANDLE_INVALID;
        handle->marked = false;
        handle->live = false;
        c_rbnode_init(&handle->rb);

        *handlep = handle;
        handle = NULL;
        return 0;
}
Пример #11
0
/**
 * n_dhcp4_client_lease_new() - allocate new client lease object
 * @leasep:                     output argumnet for new client lease object
 * @message:                    incoming message representing the lease
 *
 * This creates a new client lease object. Client lease objects are simple
 * wrappers around an incoming message representing a lease.
 *
 * Return: 0 on success, negative error code on failure.
 */
int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message) {
        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
        int r;

        c_assert(leasep);

        lease = malloc(sizeof(*lease));
        if (!lease)
                return -ENOMEM;

        *lease = (NDhcp4ClientLease)N_DHCP4_CLIENT_LEASE_NULL(*lease);

        r = n_dhcp4_incoming_get_timeouts(message, &lease->t1, &lease->t2, &lease->lifetime);
        if (r)
                return r;

        lease->message = message;
        *leasep = lease;
        lease = NULL;
        return 0;
}
Пример #12
0
/**
 * b1_handle_subscribe() - subscribe to handle events
 * @handle:             handle to operate on
 * @slotp:              output argument for newly created slot
 * @fn:                 slot callback function
 * @userdata:           userdata to be passed to the callback function
 *
 * When a node is destroyed, all handle holders to that node receive a node
 * destruction notification. This function registers a new handler for such
 * notifications.
 *
 * The handler will stay linked to the handle as long as the returned slot is
 * valid. Once the slot is destroyed, the handler is unlinked as well.
 *
 * Return: 0 on success, negative error code on failure.
 */
_c_public_ int b1_handle_subscribe(B1Handle *handle, B1Subscription **subscriptionp, B1SubscriptionFn fn, void *userdata) {
        _c_cleanup_(b1_subscription_freep) B1Subscription *subscription = NULL;

        assert(subscriptionp);
        assert(fn);

        subscription = calloc(1, sizeof(*subscription));
        if (!subscription)
                return -ENOMEM;

        subscription->fn = fn;
        subscription->userdata = userdata;

        subscription->handle = handle;
        subscription->next = handle->subscriptions;

        handle->subscriptions = subscription;

        *subscriptionp = subscription;
        subscription = NULL;
        return 0;
}
Пример #13
0
/**
 * b1_node_new() - create a new node for a peer
 * @peer:               the owning peer
 * @nodep:              pointer to the new node object
 *
 * Return: 0 on success, and a negative error code on failure.
 */
_c_public_ int b1_node_new(B1Peer *peer, B1Node **nodep) {
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        int r;

        node = calloc(1, sizeof(*node));
        if (!node)
                return -ENOMEM;

        node->id = BUS1_HANDLE_INVALID;
        node->owner = b1_peer_ref(peer);
        c_rbnode_init(&node->rb_nodes);

        r = b1_handle_new(peer, &node->handle);
        if (r < 0)
                return r;

        node->handle->node = node;

        *nodep = node;
        node = NULL;
        return 0;
}
Пример #14
0
/**
 * b1_peer_new_from_fd() - create new peer object from existing fd
 * @peerp:              the new peer object
 * @fd:                 a file descriptor representing an existing peer
 *
 * This takes a pre-initialized bus1 filedescriptor and creates a b1_peer object
 * around it.
 *
 * Return: 0 on success, a negative error code on failure.
 */
_c_public_ int b1_peer_new_from_fd(B1Peer **peerp, int fd) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *peer = NULL;
        int r;

        peer = calloc(1, sizeof(*peer));
        if (!peer)
                return -ENOMEM;

        peer->ref = (CRef)C_REF_INIT;

        r = bus1_peer_new_from_fd(&peer->peer, fd);
        if (r < 0)
                return r;

        r = bus1_peer_mmap(peer->peer);
        if (r < 0)
                return r;

        *peerp = peer;
        peer = NULL;

        return 0;
}
Пример #15
0
int b1_node_new_internal(B1Peer *peer, B1Node **nodep, void *userdata, uint64_t id, const char *name) {
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        size_t n_name;

        assert(peer);
        assert(nodep);

        n_name = name ? strlen(name) + 1 : 0;
        node = calloc(1, sizeof(*node) + n_name);
        if (!node)
                return -ENOMEM;
        if (name)
                node->name = memcpy((void*)(node + 1), name, n_name);

        node->id = id;
        node->owner = b1_peer_ref(peer);
        node->userdata = userdata;
        node->live = false;

        *nodep = node;
        node = NULL;
        return 0;
}
Пример #16
0
static void test_transaction(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *src = NULL, *dst = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL;
        _c_cleanup_(b1_message_unrefp) B1Message *message = NULL;
        const char *payload = "WOOF";
        struct iovec vec = {
                .iov_base = (void*)payload,
                .iov_len = strlen(payload) + 1,
        };
        struct iovec *vec_out;
        size_t n_vec;
        int r, fd;

        r = b1_peer_new(&src);
        assert(r >= 0);

        r = b1_peer_new(&dst);
        assert(r >= 0);

        r = b1_node_new(dst, &node);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node), src, &handle);
        assert(r >= 0);

        r = b1_message_new(src, &message);
        assert(r >= 0);

        r = b1_message_set_payload(message, &vec, 1);
        assert(r >= 0);

        r = b1_message_set_handles(message, &handle, 1);
        assert(r >= 0);

        fd = eventfd(0, 0);
        assert(fd >= 0);

        r = b1_message_set_fds(message, &fd, 1);
        assert(r >= 0);

        assert(close(fd) >= 0);

        r = b1_message_send(message, &handle, 1);
        assert(r >= 0);

        message = b1_message_unref(message);
        assert(!message);
        handle = b1_handle_unref(handle);
        assert(!handle);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle == b1_node_get_handle(node));
        handle = NULL;
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node);
        assert(r >= 0);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message));
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(src, &message);
        assert(r == -EAGAIN);
}

static void test_multicast(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *src = NULL, *dst1 = NULL, *dst2 = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node1 = NULL, *node2 = NULL;
        _c_cleanup_(b1_message_unrefp) B1Message *message = NULL;
        const char *payload = "WOOF";
        struct iovec vec = {
                .iov_base = (void*)payload,
                .iov_len = strlen(payload) + 1,
        };
        struct iovec *vec_out;
        size_t n_vec;
        B1Handle *handles[2], *handle;
        int r, fd;

        r = b1_peer_new(&src);
        assert(r >= 0);

        r = b1_peer_new(&dst1);
        assert(r >= 0);

        r = b1_peer_new(&dst2);
        assert(r >= 0);

        r = b1_node_new(dst1, &node1);
        assert(r >= 0);

        r = b1_node_new(dst2, &node2);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node1), src, &handles[0]);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node2), src, &handles[1]);
        assert(r >= 0);

        r = b1_message_new(src, &message);
        assert(r >= 0);

        r = b1_message_set_payload(message, &vec, 1);
        assert(r >= 0);

        r = b1_message_set_handles(message, handles, 2);
        assert(r >= 0);

        fd = eventfd(0, 0);
        assert(fd >= 0);

        r = b1_message_set_fds(message, &fd, 1);
        assert(r >= 0);

        assert(close(fd) >= 0);

        r = b1_message_send(message, handles, 2);
        assert(r >= 0);

        message = b1_message_unref(message);
        assert(!message);
        handles[0] = b1_handle_unref(handles[0]);
        assert(!handles[0]);
        handles[1] = b1_handle_unref(handles[1]);
        assert(!handles[1]);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle == b1_node_get_handle(node1));
        r = b1_message_get_handle(message, 1, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle != b1_node_get_handle(node1));
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle != b1_node_get_handle(node2));
        r = b1_message_get_handle(message, 1, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle == b1_node_get_handle(node2));
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node1);
        assert(r >= 0);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node2);
        assert(r >= 0);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst1, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(dst2, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(src, &message);
        assert(r == -EAGAIN);
}

int main(int argc, char **argv) {
        if (access("/dev/bus1", F_OK) < 0 && errno == ENOENT)
                return 77;

        test_peer();
        test_node();
        test_handle();
        test_message();
        test_transaction();
        test_multicast();

        return 0;
}