/** Reset connection. * * @param conn Connection */ void tcp_conn_reset(tcp_conn_t *conn) { log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_reset()", conn->name); conn->reset = true; tcp_conn_state_set(conn, st_closed); tcp_conn_tw_timer_clear(conn); tcp_tqueue_clear(&conn->retransmit); fibril_condvar_broadcast(&conn->rcv_buf_cv); fibril_condvar_broadcast(&conn->snd_buf_cv); }
static void ping_signal_done(void) { fibril_mutex_lock(&done_lock); done = true; fibril_mutex_unlock(&done_lock); fibril_condvar_broadcast(&done_cv); }
static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate) { tcp_cstate_t old_state; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set(%p)", conn); old_state = conn->cstate; conn->cstate = nstate; fibril_condvar_broadcast(&conn->cstate_cv); /* Run user callback function */ if (conn->cb != NULL && conn->cb->cstate_change != NULL) { log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - run user CB"); conn->cb->cstate_change(conn, conn->cb_arg, old_state); } else { log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - no user CB"); } assert(old_state != st_closed); if (nstate == st_closed) { tcp_conn_remove(conn); /* Drop one reference for now being in closed state */ tcp_conn_delref(conn); } }
/** Destroy timer. * * @param timer Timer, must not be active or accessed by other threads. */ void fibril_timer_destroy(fibril_timer_t *timer) { fibril_mutex_lock(&timer->lock); assert(timer->state != fts_active); timer->state = fts_cleanup; fibril_condvar_broadcast(&timer->cv); fibril_mutex_unlock(&timer->lock); }
static int tcp_sock_recv_fibril(void *arg) { tcp_sockdata_t *sock = (tcp_sockdata_t *)arg; size_t data_len; xflags_t xflags; tcp_error_t trc; log_msg(LVL_DEBUG, "tcp_sock_recv_fibril()"); fibril_mutex_lock(&sock->recv_buffer_lock); while (true) { log_msg(LVL_DEBUG, "call tcp_uc_receive()"); while (sock->recv_buffer_used != 0 && sock->sock_core != NULL) fibril_condvar_wait(&sock->recv_buffer_cv, &sock->recv_buffer_lock); trc = tcp_uc_receive(sock->conn, sock->recv_buffer, TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags); if (trc != TCP_EOK) { sock->recv_error = trc; fibril_condvar_broadcast(&sock->recv_buffer_cv); if (sock->sock_core != NULL) tcp_sock_notify_data(sock->sock_core); break; } log_msg(LVL_DEBUG, "got data - broadcast recv_buffer_cv"); sock->recv_buffer_used = data_len; fibril_condvar_broadcast(&sock->recv_buffer_cv); if (sock->sock_core != NULL) tcp_sock_notify_data(sock->sock_core); } fibril_mutex_unlock(&sock->recv_buffer_lock); tcp_uc_delete(sock->conn); return 0; }
/** Set timer. * * Set timer to execute a callback function after the specified * interval. * * @param timer Timer * @param delay Delay in microseconds * @param fun Callback function * @param arg Argument for @a fun */ void fibril_timer_set(fibril_timer_t *timer, suseconds_t delay, fibril_timer_fun_t fun, void *arg) { fibril_mutex_lock(&timer->lock); timer->state = fts_active; timer->delay = delay; timer->fun = fun; timer->arg = arg; fibril_condvar_broadcast(&timer->cv); fibril_mutex_unlock(&timer->lock); }
static int udp_sock_recv_fibril(void *arg) { udp_sockdata_t *sock = (udp_sockdata_t *)arg; udp_error_t urc; xflags_t xflags; size_t rcvd; log_msg(LVL_DEBUG, "udp_sock_recv_fibril()"); while (true) { log_msg(LVL_DEBUG, "[] wait for rcv buffer empty()"); fibril_mutex_lock(&sock->recv_buffer_lock); while (sock->recv_buffer_used != 0) { fibril_condvar_wait(&sock->recv_buffer_cv, &sock->recv_buffer_lock); } log_msg(LVL_DEBUG, "[] call udp_uc_receive()"); urc = udp_uc_receive(sock->assoc, sock->recv_buffer, UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock); sock->recv_error = urc; udp_sock_notify_data(sock->sock_core); if (urc != UDP_EOK) { fibril_condvar_broadcast(&sock->recv_buffer_cv); fibril_mutex_unlock(&sock->recv_buffer_lock); break; } log_msg(LVL_DEBUG, "[] got data - broadcast recv_buffer_cv"); sock->recv_buffer_used = rcvd; fibril_mutex_unlock(&sock->recv_buffer_lock); fibril_condvar_broadcast(&sock->recv_buffer_cv); } udp_uc_destroy(sock->assoc); return 0; }
/** Clear timer. * * Clears (cancels) timer and returns last state of the timer. * This can be one of: * - fts_not_set If the timer has not been set or has been cleared * - fts_active Timer was set but did not fire * - fts_fired Timer fired * * @param timer Timer * @return Last timer state */ fibril_timer_state_t fibril_timer_clear(fibril_timer_t *timer) { fibril_timer_state_t old_state; fibril_mutex_lock(&timer->lock); old_state = timer->state; timer->state = fts_not_set; timer->delay = 0; timer->fun = NULL; timer->arg = NULL; fibril_condvar_broadcast(&timer->cv); fibril_mutex_unlock(&timer->lock); return old_state; }
static int udp_assoc_queue_msg(udp_assoc_t *assoc, udp_sockpair_t *sp, udp_msg_t *msg) { udp_rcv_queue_entry_t *rqe; log_msg(LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)", assoc, sp, msg); rqe = calloc(1, sizeof(udp_rcv_queue_entry_t)); if (rqe == NULL) return ENOMEM; link_initialize(&rqe->link); rqe->sp = *sp; rqe->msg = msg; fibril_mutex_lock(&assoc->lock); list_append(&rqe->link, &assoc->rcv_queue); fibril_mutex_unlock(&assoc->lock); fibril_condvar_broadcast(&assoc->rcv_queue_cv); return EOK; }
/** VFS_REGISTER protocol function. * * @param rid Hash of the call with the request. * @param request Call structure with the request. * */ void vfs_register(ipc_callid_t rid, ipc_call_t *request) { dprintf("Processing VFS_REGISTER request received from %p.\n", request->in_phone_hash); vfs_info_t *vfs_info; int rc = async_data_write_accept((void **) &vfs_info, false, sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL); if (rc != EOK) { dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n", rc); async_answer_0(rid, rc); return; } /* * Allocate and initialize a buffer for the fs_info structure. */ fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t)); if (!fs_info) { dprintf("Could not allocate memory for FS info.\n"); async_answer_0(rid, ENOMEM); return; } link_initialize(&fs_info->fs_link); fs_info->vfs_info = *vfs_info; free(vfs_info); dprintf("VFS info delivered.\n"); if (!vfs_info_sane(&fs_info->vfs_info)) { free(fs_info); async_answer_0(rid, EINVAL); return; } fibril_mutex_lock(&fs_list_lock); /* * Check for duplicit registrations. */ if (fs_name_to_handle(fs_info->vfs_info.instance, fs_info->vfs_info.name, false)) { /* * We already register a fs like this. */ dprintf("FS is already registered.\n"); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EEXISTS); return; } /* * Add fs_info to the list of registered FS's. */ dprintf("Inserting FS into the list of registered file systems.\n"); list_append(&fs_info->fs_link, &fs_list); /* * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so * that a callback connection is created and we have a phone through * which to forward VFS requests to it. */ fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL); if (!fs_info->sess) { dprintf("Callback connection expected\n"); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EINVAL); return; } dprintf("Callback connection to FS created.\n"); /* * The client will want us to send him the address space area with PLB. */ size_t size; ipc_callid_t callid; if (!async_share_in_receive(&callid, &size)) { dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call)); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * We can only send the client address space area PLB_SIZE bytes long. */ if (size != PLB_SIZE) { dprintf("Client suggests wrong size of PFB, size = %d\n", size); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * Commit to read-only sharing the PLB with the client. */ (void) async_share_in_finalize(callid, plb, AS_AREA_READ | AS_AREA_CACHEABLE); dprintf("Sharing PLB.\n"); /* * That was it. The FS has been registered. * In reply to the VFS_REGISTER request, we assign the client file * system a global file system handle. */ fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next); async_answer_1(rid, EOK, (sysarg_t) fs_info->fs_handle); fibril_condvar_broadcast(&fs_list_cv); fibril_mutex_unlock(&fs_list_lock); dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle); }
static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call) { int socket_id; int flags; size_t addr_length, length; socket_core_t *sock_core; tcp_sockdata_t *socket; ipc_call_t answer; ipc_callid_t rcallid; size_t data_len; struct sockaddr_in addr; tcp_sock_t *rsock; int rc; log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client); socket_id = SOCKET_GET_SOCKET_ID(call); flags = SOCKET_GET_FLAGS(call); sock_core = socket_cores_find(&client->sockets, socket_id); if (sock_core == NULL) { async_answer_0(callid, ENOTSOCK); return; } socket = (tcp_sockdata_t *)sock_core->specific_data; fibril_mutex_lock(&socket->lock); if (socket->conn == NULL) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, ENOTCONN); return; } (void)flags; log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock"); fibril_mutex_lock(&socket->recv_buffer_lock); while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) { log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0"); fibril_condvar_wait(&socket->recv_buffer_cv, &socket->recv_buffer_lock); } log_msg(LVL_DEBUG, "Got data in sock recv_buffer"); data_len = socket->recv_buffer_used; rc = socket->recv_error; switch (socket->recv_error) { case TCP_EOK: rc = EOK; break; case TCP_ENOTEXIST: case TCP_ECLOSING: rc = ENOTCONN; break; case TCP_ERESET: rc = ECONNABORTED; break; default: assert(false); } log_msg(LVL_DEBUG, "**** recv result -> %d", rc); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, rc); return; } if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) { /* Fill addr */ rsock = &socket->conn->ident.foreign; addr.sin_family = AF_INET; addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4); addr.sin_port = host2uint16_t_be(rsock->port); log_msg(LVL_DEBUG, "addr read receive"); if (!async_data_read_receive(&rcallid, &addr_length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (addr_length > sizeof(addr)) addr_length = sizeof(addr); log_msg(LVL_DEBUG, "addr read finalize"); rc = async_data_read_finalize(rcallid, &addr, addr_length); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } } log_msg(LVL_DEBUG, "data read receive"); if (!async_data_read_receive(&rcallid, &length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (length > data_len) length = data_len; log_msg(LVL_DEBUG, "data read finalize"); rc = async_data_read_finalize(rcallid, socket->recv_buffer, length); socket->recv_buffer_used -= length; log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer", socket->recv_buffer_used); if (socket->recv_buffer_used > 0) { memmove(socket->recv_buffer, socket->recv_buffer + length, socket->recv_buffer_used); tcp_sock_notify_data(socket->sock_core); } fibril_condvar_broadcast(&socket->recv_buffer_cv); if (length < data_len && rc == EOK) rc = EOVERFLOW; SOCKET_SET_READ_DATA_LENGTH(answer, length); async_answer_1(callid, EOK, IPC_GET_ARG1(answer)); fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); }
/** Process segment text. * * @param conn Connection * @param seg Segment * @return cp_done if we are done with this segment, cp_continue * if not */ static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg) { size_t text_size; size_t xfer_size; log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)", conn->name, conn, seg); switch (conn->cstate) { case st_established: case st_fin_wait_1: case st_fin_wait_2: /* OK */ break; case st_close_wait: case st_closing: case st_last_ack: case st_time_wait: /* Invalid since FIN has been received. Ignore text. */ return cp_continue; case st_listen: case st_syn_sent: case st_syn_received: case st_closed: assert(false); } /* * Process segment text */ assert(seq_no_segment_ready(conn, seg)); /* Trim anything outside our receive window */ tcp_conn_trim_seg_to_wnd(conn, seg); /* Determine how many bytes to copy */ text_size = tcp_segment_text_size(seg); xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used); /* Copy data to receive buffer */ tcp_segment_text_copy(seg, conn->rcv_buf + conn->rcv_buf_used, xfer_size); conn->rcv_buf_used += xfer_size; /* Signal to the receive function that new data has arrived */ if (xfer_size > 0) { fibril_condvar_broadcast(&conn->rcv_buf_cv); if (conn->cb != NULL && conn->cb->recv_data != NULL) conn->cb->recv_data(conn, conn->cb_arg); } log_msg(LOG_DEFAULT, LVL_DEBUG, "Received %zu bytes of data.", xfer_size); /* Advance RCV.NXT */ conn->rcv_nxt += xfer_size; /* Update receive window. XXX Not an efficient strategy. */ conn->rcv_wnd -= xfer_size; /* Send ACK */ if (xfer_size > 0) tcp_tqueue_ctrl_seg(conn, CTL_ACK); if (xfer_size < seg->len) { /* Trim part of segment which we just received */ tcp_conn_trim_seg_to_wnd(conn, seg); } else { log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Nothing left in segment, dropping " "(xfer_size=%zu, SEG.LEN=%" PRIu32 ", seg->ctrl=%u)", conn->name, xfer_size, seg->len, (unsigned int) seg->ctrl); /* Nothing left in segment */ tcp_segment_delete(seg); return cp_done; } return cp_continue; }
/** Process segment FIN field. * * @param conn Connection * @param seg Segment * @return cp_done if we are done with this segment, cp_continue * if not */ static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg) { log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)", conn->name, conn, seg); log_msg(LOG_DEFAULT, LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len, (unsigned) seg->ctrl); /* Only process FIN if no text is left in segment. */ if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) { log_msg(LOG_DEFAULT, LVL_DEBUG, " - FIN found in segment."); /* Send ACK */ tcp_tqueue_ctrl_seg(conn, CTL_ACK); conn->rcv_nxt++; conn->rcv_wnd--; /* Change connection state */ switch (conn->cstate) { case st_listen: case st_syn_sent: case st_closed: /* Connection not synchronized */ assert(false); case st_syn_received: case st_established: log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Close-Wait", conn->name); tcp_conn_state_set(conn, st_close_wait); break; case st_fin_wait_1: log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Closing", conn->name); tcp_conn_state_set(conn, st_closing); break; case st_fin_wait_2: log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Time-Wait", conn->name); tcp_conn_state_set(conn, st_time_wait); /* Start the Time-Wait timer */ tcp_conn_tw_timer_set(conn); break; case st_close_wait: case st_closing: case st_last_ack: /* Do nothing */ break; case st_time_wait: /* Restart the Time-Wait timer */ tcp_conn_tw_timer_set(conn); break; } /* Add FIN to the receive buffer */ conn->rcv_buf_fin = true; fibril_condvar_broadcast(&conn->rcv_buf_cv); if (conn->cb != NULL && conn->cb->recv_data != NULL) conn->cb->recv_data(conn, conn->cb_arg); tcp_segment_delete(seg); return cp_done; } return cp_continue; }
static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call) { int socket_id; int flags; size_t addr_length, length; socket_core_t *sock_core; udp_sockdata_t *socket; ipc_call_t answer; ipc_callid_t rcallid; size_t data_len; udp_error_t urc; udp_sock_t rsock; struct sockaddr_in addr; int rc; log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client); socket_id = SOCKET_GET_SOCKET_ID(call); flags = SOCKET_GET_FLAGS(call); sock_core = socket_cores_find(&client->sockets, socket_id); if (sock_core == NULL) { async_answer_0(callid, ENOTSOCK); return; } socket = (udp_sockdata_t *)sock_core->specific_data; fibril_mutex_lock(&socket->lock); if (socket->assoc == NULL) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, ENOTCONN); return; } (void)flags; log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock"); fibril_mutex_lock(&socket->recv_buffer_lock); while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) { log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv"); fibril_condvar_wait(&socket->recv_buffer_cv, &socket->recv_buffer_lock); } log_msg(LVL_DEBUG, "Got data in sock recv_buffer"); rsock = socket->recv_fsock; data_len = socket->recv_buffer_used; urc = socket->recv_error; log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len); switch (urc) { case UDP_EOK: rc = EOK; break; /* case TCP_ENOTEXIST: case TCP_ECLOSING: rc = ENOTCONN; break; case TCP_ERESET: rc = ECONNABORTED; break;*/ default: assert(false); } log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, rc); return; } if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) { /* Fill addr */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = host2uint32_t_be(rsock.addr.ipv4); addr.sin_port = host2uint16_t_be(rsock.port); log_msg(LVL_DEBUG, "addr read receive"); if (!async_data_read_receive(&rcallid, &addr_length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (addr_length > sizeof(addr)) addr_length = sizeof(addr); log_msg(LVL_DEBUG, "addr read finalize"); rc = async_data_read_finalize(rcallid, &addr, addr_length); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } } log_msg(LVL_DEBUG, "data read receive"); if (!async_data_read_receive(&rcallid, &length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (length > data_len) length = data_len; log_msg(LVL_DEBUG, "data read finalize"); rc = async_data_read_finalize(rcallid, socket->recv_buffer, length); if (length < data_len && rc == EOK) rc = EOVERFLOW; log_msg(LVL_DEBUG, "read_data_length <- %zu", length); IPC_SET_ARG2(answer, 0); SOCKET_SET_READ_DATA_LENGTH(answer, length); SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(addr)); async_answer_3(callid, EOK, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer), IPC_GET_ARG3(answer)); socket->recv_buffer_used = 0; fibril_condvar_broadcast(&socket->recv_buffer_cv); fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); }
void vfs_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd) { vfs_client_data_t *donor_data = NULL; vfs_client_data_t *acceptor_data = NULL; vfs_file_t *donor_file = NULL; vfs_file_t *acceptor_file = NULL; vfs_boxed_handle_t *bh; int acceptor_fd; acceptor_data = async_get_client_data_by_id(acceptor_id); if (!acceptor_data) return; bh = malloc(sizeof(vfs_boxed_handle_t)); assert(bh); link_initialize(&bh->link); bh->handle = -1; donor_data = async_get_client_data_by_id(donor_id); if (!donor_data) goto out; donor_file = _vfs_file_get(donor_data, donor_fd); if (!donor_file) goto out; acceptor_fd = _vfs_fd_alloc(acceptor_data, false); if (acceptor_fd < 0) goto out; bh->handle = acceptor_fd; /* * Add a new reference to the underlying VFS node. */ vfs_node_addref(donor_file->node); (void) vfs_open_node_remote(donor_file->node); acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd); assert(acceptor_file); /* * Inherit attributes from the donor. */ acceptor_file->node = donor_file->node; acceptor_file->append = donor_file->append; acceptor_file->pos = donor_file->pos; out: fibril_mutex_lock(&acceptor_data->lock); list_append(&bh->link, &acceptor_data->passed_handles); fibril_condvar_broadcast(&acceptor_data->cv); fibril_mutex_unlock(&acceptor_data->lock); if (donor_data) async_put_client_data_by_id(donor_id); if (acceptor_data) async_put_client_data_by_id(acceptor_id); if (donor_file) _vfs_file_put(donor_data, donor_file); if (acceptor_file) _vfs_file_put(acceptor_data, acceptor_file); }