Esempio n. 1
0
/** 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);
}
Esempio n. 2
0
static void ping_signal_done(void)
{
	fibril_mutex_lock(&done_lock);
	done = true;
	fibril_mutex_unlock(&done_lock);
	fibril_condvar_broadcast(&done_cv);
}
Esempio n. 3
0
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);
	}
}
Esempio n. 4
0
/** 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);
}
Esempio n. 5
0
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;
}
Esempio n. 6
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);
}
Esempio n. 7
0
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;
}
Esempio n. 8
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
/** 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);
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
/** 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;
}
Esempio n. 13
0
/** 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;
}
Esempio n. 14
0
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);
}
Esempio n. 15
0
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);

}