コード例 #1
0
static void kbdev_callback_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	kbdev_t *kbdev;
	int retval;
	int type, key;

	/* Kbdev device structure */
	kbdev = arg;

	while (true) {
		ipc_call_t call;
		ipc_callid_t callid;

		callid = async_get_call(&call);
		if (!IPC_GET_IMETHOD(call)) {
			kbdev_destroy(kbdev);
			return;
		}

		switch (IPC_GET_IMETHOD(call)) {
		case KBDEV_EVENT:
			/* Got event from keyboard device */
			retval = 0;
			type = IPC_GET_ARG1(call);
			key = IPC_GET_ARG2(call);
			kbd_push_event(kbdev->kbd_dev, type, key);
			break;
		default:
			retval = ENOTSUP;
			break;
		}

		async_answer_0(callid, retval);
	}
}
コード例 #2
0
ファイル: udp.c プロジェクト: jvesely/helenos
/** Get information about the next received message from UDP service.
 *
 * @param udp  UDP client
 * @param rmsg Place to store message information
 *
 * @return EOK on success or negative error code
 */
static int udp_rmsg_info(udp_t *udp, udp_rmsg_t *rmsg)
{
	async_exch_t *exch;
	inet_ep_t ep;
	ipc_call_t answer;

	exch = async_exchange_begin(udp->sess);
	aid_t req = async_send_0(exch, UDP_RMSG_INFO, &answer);
	int rc = async_data_read_start(exch, &ep, sizeof(inet_ep_t));
	async_exchange_end(exch);

	if (rc != EOK) {
		async_forget(req);
		return rc;
	}

	sysarg_t retval;
	async_wait_for(req, &retval);
	if (retval != EOK)
		return retval;

	rmsg->udp = udp;
	rmsg->assoc_id = IPC_GET_ARG1(answer);
	rmsg->size = IPC_GET_ARG2(answer);
	rmsg->remote_ep = ep;
	return EOK;
}
コード例 #3
0
ファイル: clonable.c プロジェクト: fhector/helenOS-0.5-Hector
/** Register clonable service.
 *
 * @param service Service to be registered.
 * @param phone   Phone to be used for connections to the service.
 * @param call    Pointer to call structure.
 *
 */
void register_clonable(sysarg_t service, sysarg_t phone, ipc_call_t *call,
    ipc_callid_t callid)
{
	link_t *req_link;

	req_link = list_first(&cs_req);
	if (req_link == NULL) {
		/* There was no pending connection request. */
		printf("%s: Unexpected clonable server.\n", NAME);
		ipc_answer_0(callid, EBUSY);
		return;
	}
	
	cs_req_t *csr = list_get_instance(req_link, cs_req_t, link);
	list_remove(req_link);
	
	/* Currently we can only handle a single type of clonable service. */
	assert(csr->service == SERVICE_LOAD);
	
	ipc_answer_0(callid, EOK);
	
	ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call),
	    IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE);
	
	free(csr);
	ipc_hangup(phone);
}
コード例 #4
0
ファイル: i8042.c プロジェクト: pratikmankawde/HelenOS_Nano
/** Handle data requests.
 *
 * @param fun  ddf_fun_t function.
 * @param id   callid
 * @param call IPC request.
 *
 */
void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
{
    const sysarg_t method = IPC_GET_IMETHOD(*call);
    const size_t size = IPC_GET_ARG1(*call);

    switch (method) {
    case IPC_CHAR_READ:
        if (size <= 4 * sizeof(sysarg_t)) {
            sysarg_t message[4] = {};

            i8042_read(fun, (char *) message, size);
            async_answer_4(id, size, message[0], message[1],
                           message[2], message[3]);
        } else
            async_answer_0(id, ELIMIT);
        break;

    case IPC_CHAR_WRITE:
        if (size <= 3 * sizeof(sysarg_t)) {
            const sysarg_t message[3] = {
                IPC_GET_ARG2(*call),
                IPC_GET_ARG3(*call),
                IPC_GET_ARG4(*call)
            };

            i8042_write(fun, (char *) message, size);
            async_answer_0(id, size);
        } else
            async_answer_0(id, ELIMIT);

    default:
        async_answer_0(id, EINVAL);
    }
}
コード例 #5
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	tcp_sockdata_t *sock;
	int sock_id;
	int rc;
	ipc_call_t answer;

	log_msg(LVL_DEBUG, "tcp_sock_socket()");

	rc = tcp_sock_create(client, &sock);
	if (rc != EOK) {
		async_answer_0(callid, rc);
		return;
	}

	sock->laddr.ipv4 = TCP_IPV4_ANY;
	sock->lconn = NULL;
	sock->backlog = 0;

	sock_id = SOCKET_GET_SOCKET_ID(call);
	rc = tcp_sock_finish_setup(sock, &sock_id);
	if (rc != EOK) {
		tcp_sock_uncreate(sock);
		async_answer_0(callid, rc);
		return;
	}

	SOCKET_SET_SOCKET_ID(answer, sock_id);

	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
	SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
	
	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
}
コード例 #6
0
ファイル: remote_ieee80211.c プロジェクト: jvesely/helenos
static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface,
    ipc_callid_t callid, ipc_call_t *call)
{
	ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
	assert(ieee80211_iface->get_scan_results);
	
	ieee80211_scan_results_t scan_results;
	memset(&scan_results, 0, sizeof(ieee80211_scan_results_t));
	
	bool now = IPC_GET_ARG2(*call);
	
	int rc = ieee80211_iface->get_scan_results(fun, &scan_results, now);
	if (rc == EOK) {
		ipc_callid_t data_callid;
		size_t max_len;
		if (!async_data_read_receive(&data_callid, &max_len)) {
			async_answer_0(data_callid, EINVAL);
			async_answer_0(callid, EINVAL);
			return;
		}
		
		if (max_len < sizeof(ieee80211_scan_results_t)) {
			async_answer_0(data_callid, ELIMIT);
			async_answer_0(callid, ELIMIT);
			return;
		}
		
		async_data_read_finalize(data_callid, &scan_results,
		    sizeof(ieee80211_scan_results_t));
	}
	
	async_answer_0(callid, rc);
}
コード例 #7
0
ファイル: i8042.c プロジェクト: pratikmankawde/HelenOS_Nano
/** Interrupt handler routine.
 *
 * Write new data to the corresponding buffer.
 *
 * @param dev  Device that caued the interrupt.
 * @param iid  Call id.
 * @param call pointerr to call data.
 *
 */
static void i8042_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
                              ipc_call_t *call)
{
    i8042_t *controller = dev_i8042(dev);

    const uint8_t status = IPC_GET_ARG1(*call);
    const uint8_t data = IPC_GET_ARG2(*call);

    buffer_t *buffer = (status & i8042_AUX_DATA) ?
                       &controller->aux_buffer : &controller->kbd_buffer;

    buffer_write(buffer, data);
}
コード例 #8
0
static void notification_received(ipc_callid_t callid, ipc_call_t *call)
{
	switch (IPC_GET_IMETHOD(*call)) {
	case VFS_TASK_STATE_CHANGE:
		if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
			vfs_pass_handle(
			    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
			    IPC_GET_ARG5(*call)), call->in_task_id,
			    (int) IPC_GET_ARG2(*call));
		break;
	default:
		break;
	}
}
コード例 #9
0
ファイル: stchngath.c プロジェクト: jvesely/helenos
static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
{
	int rc = EOK;

	if (!IPC_GET_RETVAL(answer->data)) {
		/* The recipient authorized the change of state. */
		phone_t *recipient_phone;
		task_t *other_task_s;
		task_t *other_task_r;

		rc = phone_get(IPC_GET_ARG1(answer->data),
		    &recipient_phone);
		if (rc != EOK) {
			IPC_SET_RETVAL(answer->data, ENOENT);
			return ENOENT;
		}

		mutex_lock(&recipient_phone->lock);
		if (recipient_phone->state != IPC_PHONE_CONNECTED) {
			mutex_unlock(&recipient_phone->lock);
			IPC_SET_RETVAL(answer->data, EINVAL);
			return EINVAL;
		}

		other_task_r = recipient_phone->callee->task;
		other_task_s = (task_t *) IPC_GET_ARG5(*olddata);

		/*
		 * See if both the sender and the recipient meant the
		 * same third party task.
		 */
		if (other_task_r != other_task_s) {
			IPC_SET_RETVAL(answer->data, EINVAL);
			rc = EINVAL;
		} else {
			rc = event_task_notify_5(other_task_r,
			    EVENT_TASK_STATE_CHANGE, false,
			    IPC_GET_ARG1(*olddata),
			    IPC_GET_ARG2(*olddata),
			    IPC_GET_ARG3(*olddata),
			    LOWER32(olddata->task_id),
			    UPPER32(olddata->task_id));
			IPC_SET_RETVAL(answer->data, rc);
		}

		mutex_unlock(&recipient_phone->lock);
	}

	return rc;
}
コード例 #10
0
ファイル: sysipc.c プロジェクト: pratikmankawde/HelenOS_Nano
/** Forward a received call to another destination - slow version.
 *
 * This function is the slow verision of the sys_ipc_forward_fast interface.
 * It can copy all five new arguments and the new interface and method from
 * the userspace. It naturally extends the functionality of the fast version.
 * For system methods, it additionally stores the new value of arg3 to ARG4.
 * For non-system methods, it additionally stores the new value of arg3, arg4
 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
 *
 * @param callid  Hash of the call to forward.
 * @param phoneid Phone handle to use for forwarding.
 * @param data    Userspace address of the new IPC data.
 * @param mode    Flags that specify mode of the forward operation.
 *
 * @return 0 on succes, otherwise an error code.
 *
 */
sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
    ipc_data_t *data, unsigned int mode)
{
	ipc_data_t newdata;
	int rc = copy_from_uspace(&newdata.args, &data->args,
	    sizeof(newdata.args));
	if (rc != 0)
		return (sysarg_t) rc;
	
	return sys_ipc_forward_common(callid, phoneid,
	    IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
	    IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
	    IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
}
コード例 #11
0
ファイル: inet.c プロジェクト: fhector/helenOS-0.5-Hector
static void inet_ev_recv(ipc_callid_t callid, ipc_call_t *call)
{
	int rc;
	inet_dgram_t dgram;

	dgram.src.ipv4 = IPC_GET_ARG1(*call);
	dgram.dest.ipv4 = IPC_GET_ARG2(*call);
	dgram.tos = IPC_GET_ARG3(*call);

	rc = async_data_write_accept(&dgram.data, false, 0, 0, 0, &dgram.size);
	if (rc != EOK) {
		async_answer_0(callid, rc);
		return;
	}

	rc = inet_ev_ops->recv(&dgram);
	async_answer_0(callid, rc);
}
コード例 #12
0
static void iplink_send_srv(iplink_srv_t *srv, ipc_callid_t callid,
    ipc_call_t *call)
{
	iplink_srv_sdu_t sdu;
	int rc;

	sdu.lsrc.ipv4 = IPC_GET_ARG1(*call);
	sdu.ldest.ipv4 = IPC_GET_ARG2(*call);

	rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size);
	if (rc != EOK) {
		async_answer_0(callid, rc);
		return;
	}

	rc = srv->ops->send(srv, &sdu);
	free(sdu.data);
	async_answer_0(callid, rc);
}
コード例 #13
0
ファイル: taskmon.c プロジェクト: fhector/helenOS-0.5-Hector
static void fault_event(ipc_callid_t callid, ipc_call_t *call)
{
	const char *fname;
	char *s_taskid;
	int rc;

	task_id_t taskid;
	uintptr_t thread;

	taskid = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
	thread = IPC_GET_ARG3(*call);

	if (asprintf(&s_taskid, "%" PRIu64, taskid) < 0) {
		printf("Memory allocation failed.\n");
		return;
	}

	printf(NAME ": Task %" PRIu64 " fault in thread %p.\n", taskid,
	    (void *) thread);

	fname = "/app/taskdump";

#ifdef CONFIG_WRITE_CORE_FILES
	char *dump_fname;

	if (asprintf(&dump_fname, "/data/core%" PRIu64, taskid) < 0) {
		printf("Memory allocation failed.\n");
		return;
	}

	printf(NAME ": Executing %s -c %s -t %s\n", fname, dump_fname, s_taskid);
	rc = task_spawnl(NULL, fname, fname, "-c", dump_fname, "-t", s_taskid,
	    NULL);
#else
	printf(NAME ": Executing %s -t %s\n", fname, s_taskid);
	rc = task_spawnl(NULL, fname, fname, "-t", s_taskid, NULL);
#endif
	if (rc != EOK) {
		printf("%s: Error spawning %s (%s).\n", NAME, fname,
		    str_error(rc));
	}
}
コード例 #14
0
ファイル: loc.c プロジェクト: fhector/helenOS-0.5-Hector
/** Get object name.
 *
 * Provided ID of an object, return its name.
 *
 * @param method	IPC method
 * @param id		Object ID
 * @param name		Place to store pointer to new string. Caller should
 *			free it using free().
 * @return		EOK on success or negative error code
 */
static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
{
	async_exch_t *exch;
	char name_buf[LOC_NAME_MAXLEN + 1];
	ipc_call_t dreply;
	size_t act_size;
	sysarg_t dretval;
	
	*name = NULL;
	exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
	
	ipc_call_t answer;
	aid_t req = async_send_1(exch, method, id, &answer);
	aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
	    &dreply);
	async_wait_for(dreq, &dretval);
	
	loc_exchange_end(exch);
	
	if (dretval != EOK) {
		async_forget(req);
		return dretval;
	}
	
	sysarg_t retval;
	async_wait_for(req, &retval);
	
	if (retval != EOK)
		return retval;
	
	act_size = IPC_GET_ARG2(dreply);
	assert(act_size <= LOC_NAME_MAXLEN);
	name_buf[act_size] = '\0';

	*name = str_dup(name_buf);
	if (*name == NULL)
		return ENOMEM;
	
	return EOK;
}
コード例 #15
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int socket_id;
	int fragments;
	int index;
	struct sockaddr_in *addr;
	size_t addr_size;
	socket_core_t *sock_core;
	udp_sockdata_t *socket;
	udp_sock_t fsock, *fsockp;
	ipc_call_t answer;
	ipc_callid_t wcallid;
	size_t length;
	uint8_t buffer[UDP_FRAGMENT_SIZE];
	udp_error_t urc;
	int rc;

	log_msg(LVL_DEBUG, "udp_sock_send()");

	addr = NULL;

	if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
		rc = async_data_write_accept((void **) &addr, false,
		    0, 0, 0, &addr_size);
		if (rc != EOK) {
			async_answer_0(callid, rc);
			goto out;
		}

		if (addr_size != sizeof(struct sockaddr_in)) {
			async_answer_0(callid, EINVAL);
			goto out;
		}

		fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
		fsock.port = uint16_t_be2host(addr->sin_port);
		fsockp = &fsock;
	} else {
		fsockp = NULL;
	}

	socket_id = SOCKET_GET_SOCKET_ID(call);
	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
	SOCKET_GET_FLAGS(call);

	sock_core = socket_cores_find(&client->sockets, socket_id);
	if (sock_core == NULL) {
		async_answer_0(callid, ENOTSOCK);
		goto out;
	}

	if (sock_core->port == 0) {
		/* Implicitly bind socket to port */
		rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
		    addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
		    last_used_port);
		if (rc != EOK) {
			async_answer_0(callid, rc);
			goto out;
		}
	}

	socket = (udp_sockdata_t *)sock_core->specific_data;
	fibril_mutex_lock(&socket->lock);

	if (socket->assoc->ident.local.addr.ipv4 == UDP_IPV4_ANY) {
		/* Determine local IP address */
		inet_addr_t loc_addr, rem_addr;

		rem_addr.ipv4 = fsockp ? fsock.addr.ipv4 :
		    socket->assoc->ident.foreign.addr.ipv4;

		rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
			    "determine local address.");
			return;
		}

		socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
		log_msg(LVL_DEBUG, "Local IP address is %x",
		    socket->assoc->ident.local.addr.ipv4);
	}


	assert(socket->assoc != NULL);

	for (index = 0; index < fragments; index++) {
		if (!async_data_write_receive(&wcallid, &length)) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, EINVAL);
			goto out;
		}

		if (length > UDP_FRAGMENT_SIZE)
			length = UDP_FRAGMENT_SIZE;

		rc = async_data_write_finalize(wcallid, buffer, length);
		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			goto out;
		}

		urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);

		switch (urc) {
		case UDP_EOK:
			rc = EOK;
			break;
/*		case TCP_ENOTEXIST:
			rc = ENOTCONN;
			break;
		case TCP_ECLOSING:
			rc = ENOTCONN;
			break;
		case TCP_ERESET:
			rc = ECONNABORTED;
			break;*/
		default:
			assert(false);
		}

		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			goto out;
		}
	}
	
	IPC_SET_ARG1(answer, 0);
	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer));
	fibril_mutex_unlock(&socket->lock);
	
out:
	if (addr != NULL)
		free(addr);
}
コード例 #16
0
ファイル: ns.c プロジェクト: fhector/helenOS-0.5-Hector
int main(int argc, char **argv)
{
	printf("%s: HelenOS IPC Naming Service\n", NAME);
	
	int rc = service_init();
	if (rc != EOK)
		return rc;
	
	rc = clonable_init();
	if (rc != EOK)
		return rc;
	
	rc = task_init();
	if (rc != EOK)
		return rc;
	
	printf("%s: Accepting connections\n", NAME);
	
	while (true) {
		process_pending_conn();
		process_pending_wait();
		
		ipc_call_t call;
		ipc_callid_t callid = ipc_wait_for_call(&call);
		
		task_id_t id;
		sysarg_t retval;
		
		switch (IPC_GET_IMETHOD(call)) {
		case IPC_M_PHONE_HUNGUP:
			retval = ns_task_disconnect(&call);
			break;
		case IPC_M_CONNECT_TO_ME:
			/*
			 * Server requests service registration.
			 */
			if (service_clonable(IPC_GET_ARG1(call))) {
				register_clonable(IPC_GET_ARG1(call),
				    IPC_GET_ARG5(call), &call, callid);
				continue;
			} else {
				retval = register_service(IPC_GET_ARG1(call),
				    IPC_GET_ARG5(call), &call);
			}
			break;
		case IPC_M_CONNECT_ME_TO:
			/*
			 * Client requests to be connected to a service.
			 */
			if (service_clonable(IPC_GET_ARG1(call))) {
				connect_to_clonable(IPC_GET_ARG1(call),
				    &call, callid);
				continue;
			} else {
				connect_to_service(IPC_GET_ARG1(call), &call,
				    callid);
				continue;
			}
			break;
		case NS_PING:
			retval = EOK;
			break;
		case NS_TASK_WAIT:
			id = (task_id_t)
			    MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
			wait_for_task(id, &call, callid);
			continue;
		case NS_ID_INTRO:
			retval = ns_task_id_intro(&call);
			break;
		case NS_RETVAL:
			retval = ns_task_retval(&call);
			break;
		default:
			retval = ENOENT;
			break;
		}
		
		if (!(callid & IPC_CALLID_NOTIFICATION))
			ipc_answer_0(callid, retval);
	}
	
	/* Not reached */
	return 0;
}
コード例 #17
0
ファイル: vfs_lookup.c プロジェクト: jvesely/helenos
/** Perform a path lookup.
 *
 * @param path    Path to be resolved; it must be a NULL-terminated
 *                string.
 * @param lflag   Flags to be used during lookup.
 * @param result  Empty structure where the lookup result will be stored.
 *                Can be NULL.
 * @param altroot If non-empty, will be used instead of rootfs as the root
 *                of the whole VFS tree.
 *
 * @return EOK on success or an error code from errno.h.
 *
 */
int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
    vfs_pair_t *altroot, ...)
{
	vfs_pair_t *root;

	if (altroot)
		root = altroot;
	else
		root = &rootfs;

	if (!root->fs_handle)
		return ENOENT;
	
	size_t len;
	path = canonify(path, &len);
	if (!path)
		return EINVAL;
	
	fs_index_t index = 0;
	if (lflag & L_LINK) {
		va_list ap;

		va_start(ap, altroot);
		index = va_arg(ap, fs_index_t);
		va_end(ap);
	}
	
	fibril_mutex_lock(&plb_mutex);

	plb_entry_t entry;
	link_initialize(&entry.plb_link);
	entry.len = len;

	size_t first;	/* the first free index */
	size_t last;	/* the last free index */

	if (list_empty(&plb_entries)) {
		first = 0;
		last = PLB_SIZE - 1;
	} else {
		plb_entry_t *oldest = list_get_instance(
		    list_first(&plb_entries), plb_entry_t, plb_link);
		plb_entry_t *newest = list_get_instance(
		    list_last(&plb_entries), plb_entry_t, plb_link);

		first = (newest->index + newest->len) % PLB_SIZE;
		last = (oldest->index - 1) % PLB_SIZE;
	}

	if (first <= last) {
		if ((last - first) + 1 < len) {
			/*
			 * The buffer cannot absorb the path.
			 */
			fibril_mutex_unlock(&plb_mutex);
			return ELIMIT;
		}
	} else {
		if (PLB_SIZE - ((first - last) + 1) < len) {
			/*
			 * The buffer cannot absorb the path.
			 */
			fibril_mutex_unlock(&plb_mutex);
			return ELIMIT;
		}
	}

	/*
	 * We know the first free index in PLB and we also know that there is
	 * enough space in the buffer to hold our path.
	 */

	entry.index = first;
	entry.len = len;

	/*
	 * Claim PLB space by inserting the entry into the PLB entry ring
	 * buffer.
	 */
	list_append(&entry.plb_link, &plb_entries);
	
	fibril_mutex_unlock(&plb_mutex);

	/*
	 * Copy the path into PLB.
	 */
	size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
	size_t cnt2 = len - cnt1;
	
	memcpy(&plb[first], path, cnt1);
	memcpy(plb, &path[cnt1], cnt2);

	ipc_call_t answer;
	async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
	    (sysarg_t) (first + len - 1) % PLB_SIZE,
	    (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
	    &answer);
	
	sysarg_t rc;
	async_wait_for(req, &rc);
	vfs_exchange_release(exch);
	
	fibril_mutex_lock(&plb_mutex);
	list_remove(&entry.plb_link);
	/*
	 * Erasing the path from PLB will come handy for debugging purposes.
	 */
	memset(&plb[first], 0, cnt1);
	memset(plb, 0, cnt2);
	fibril_mutex_unlock(&plb_mutex);
	
	if ((int) rc < EOK)
		return (int) rc;

	if (!result)
		return EOK;
	
	result->triplet.fs_handle = (fs_handle_t) rc;
	result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
	result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
	result->size =
	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
	result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
	
	if (lflag & L_FILE)
		result->type = VFS_NODE_FILE;
	else if (lflag & L_DIRECTORY)
		result->type = VFS_NODE_DIRECTORY;
	else
		result->type = VFS_NODE_UNKNOWN;
	
	return EOK;
}
コード例 #18
0
ファイル: file_bd.c プロジェクト: fhector/helenOS-0.5-Hector
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	void *fs_va = NULL;
	ipc_callid_t callid;
	ipc_call_t call;
	sysarg_t method;
	size_t comm_size;
	unsigned int flags;
	int retval;
	uint64_t ba;
	size_t cnt;

	/* Answer the IPC_M_CONNECT_ME_TO call. */
	async_answer_0(iid, EOK);

	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
		async_answer_0(callid, EHANGUP);
		return;
	}

	(void) async_share_out_finalize(callid, &fs_va);
	if (fs_va == AS_MAP_FAILED) {
		async_answer_0(callid, EHANGUP);
		return;
	}

	while (true) {
		callid = async_get_call(&call);
		method = IPC_GET_IMETHOD(call);
		
		if (!method) {
			/* The other side has hung up. */
			async_answer_0(callid, EOK);
			return;
		}
		
		switch (method) {
		case BD_READ_BLOCKS:
			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
			    IPC_GET_ARG2(call));
			cnt = IPC_GET_ARG3(call);
			if (cnt * block_size > comm_size) {
				retval = ELIMIT;
				break;
			}
			retval = file_bd_read_blocks(ba, cnt, fs_va);
			break;
		case BD_WRITE_BLOCKS:
			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
			    IPC_GET_ARG2(call));
			cnt = IPC_GET_ARG3(call);
			if (cnt * block_size > comm_size) {
				retval = ELIMIT;
				break;
			}
			retval = file_bd_write_blocks(ba, cnt, fs_va);
			break;
		case BD_GET_BLOCK_SIZE:
			async_answer_1(callid, EOK, block_size);
			continue;
		case BD_GET_NUM_BLOCKS:
			async_answer_2(callid, EOK, LOWER32(num_blocks),
			    UPPER32(num_blocks));
			continue;
		default:
			retval = EINVAL;
			break;
		}
		async_answer_0(callid, retval);
	}
}
コード例 #19
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int socket_id;
	int fragments;
	int index;
	socket_core_t *sock_core;
	tcp_sockdata_t *socket;
	ipc_call_t answer;
	ipc_callid_t wcallid;
	size_t length;
	uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
	tcp_error_t trc;
	int rc;

	log_msg(LVL_DEBUG, "tcp_sock_send()");
	socket_id = SOCKET_GET_SOCKET_ID(call);
	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
	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;
	}

	for (index = 0; index < fragments; index++) {
		if (!async_data_write_receive(&wcallid, &length)) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, EINVAL);
			return;
		}

		if (length > TCP_SOCK_FRAGMENT_SIZE)
			length = TCP_SOCK_FRAGMENT_SIZE;

		rc = async_data_write_finalize(wcallid, buffer, length);
		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			return;
		}

		trc = tcp_uc_send(socket->conn, buffer, length, 0);

		switch (trc) {
		case TCP_EOK:
			rc = EOK;
			break;
		case TCP_ENOTEXIST:
			rc = ENOTCONN;
			break;
		case TCP_ECLOSING:
			rc = ENOTCONN;
			break;
		case TCP_ERESET:
			rc = ECONNABORTED;
			break;
		default:
			assert(false);
		}

		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			return;
		}
	}

	IPC_SET_ARG1(answer, 0);
	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer));
	fibril_mutex_unlock(&socket->lock);
}
コード例 #20
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	ipc_call_t answer;
	int socket_id;
	int asock_id;
	socket_core_t *sock_core;
	tcp_sockdata_t *socket;
	tcp_sockdata_t *asocket;
	tcp_error_t trc;
	tcp_sock_t lsocket;
	tcp_sock_t fsocket;
	tcp_conn_t *conn;
	tcp_conn_t *rconn;
	tcp_sock_lconn_t *lconn;
	int rc;

	log_msg(LVL_DEBUG, "tcp_sock_accept()");

	socket_id = SOCKET_GET_SOCKET_ID(call);
	asock_id = SOCKET_GET_NEW_SOCKET_ID(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);

	log_msg(LVL_DEBUG, " - verify socket->conn");
	if (socket->conn != NULL) {
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, EINVAL);
		return;
	}

	if (list_empty(&socket->ready)) {
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, ENOENT);
		return;
	}

	lconn = list_get_instance(list_first(&socket->ready),
	    tcp_sock_lconn_t, ready_list);
	list_remove(&lconn->ready_list);

	conn = lconn->conn;
	tcp_uc_set_cstate_cb(conn, NULL, NULL);

	/* Replenish listening connection */

	lsocket.addr.ipv4 = TCP_IPV4_ANY;
	lsocket.port = sock_core->port;
	fsocket.addr.ipv4 = TCP_IPV4_ANY;
	fsocket.port = TCP_PORT_ANY;

	trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
	    &rconn);
	if (rconn == NULL) {
		/* XXX Clean up */
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, ENOMEM);
		return;
	}

	tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);

	assert(trc == TCP_EOK);
	rconn->name = (char *)"S";

	lconn->conn = rconn;

	/* Allocate socket for accepted connection */

	rc = tcp_sock_create(client, &asocket);
	if (rc != EOK) {
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, rc);
		return;
	}

	asocket->conn = conn;
	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");

	rc = tcp_sock_finish_setup(asocket, &asock_id);
	if (rc != EOK) {
		tcp_sock_uncreate(asocket);
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, rc);
		return;
	}

	fibril_add_ready(asocket->recv_fibril);

	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");

	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
	SOCKET_SET_SOCKET_ID(answer, asock_id);
	SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
	
	async_answer_3(callid, asocket->sock_core->socket_id,
	    IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
	    IPC_GET_ARG3(answer));
	
	/* Push one fragment notification to client's queue */
	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
	fibril_mutex_unlock(&socket->lock);
}
コード例 #21
0
ファイル: protocol.c プロジェクト: jvesely/helenos
/**
 * Server side implementation of the hound protocol. IPC connection handler.
 * @param iid initial call id
 * @param icall pointer to initial call structure.
 * @param arg (unused)
 */
void hound_connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	/* Accept connection if there is a valid iface*/
	if (server_iface) {
		async_answer_0(iid, EOK);
	} else {
		async_answer_0(iid, ENOTSUP);
		return;
	}

	while (1) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		switch (IPC_GET_IMETHOD(call)) {
		case IPC_M_HOUND_CONTEXT_REGISTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->add_context) {
				async_answer_0(callid, ENOTSUP);
				break;
			}
			bool record = IPC_GET_ARG1(call);
			void *name;

			/* Get context name */
			int ret =
			    async_data_write_accept(&name, true, 0, 0, 0, 0);
			if (ret != EOK) {
				async_answer_0(callid, ret);
				break;
			}
			hound_context_id_t id = 0;
			ret = server_iface->add_context(server_iface->server,
			    &id, name, record);
			/** new context should create a copy */
			free(name);
			if (ret != EOK) {
				async_answer_0(callid, ret);
			} else {
				async_answer_1(callid, EOK, id);
			}
			break;
		}
		case IPC_M_HOUND_CONTEXT_UNREGISTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->rem_context) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			/* get id, 1st param */
			hound_context_id_t id = IPC_GET_ARG1(call);
			const int ret =
			    server_iface->rem_context(server_iface->server, id);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_GET_LIST: {
			/* check interface functions */
			if (!server_iface || !server_iface->get_list) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			const char **list = NULL;
			const int flags = IPC_GET_ARG1(call);
			size_t count = IPC_GET_ARG2(call);
			const bool conn = IPC_GET_ARG3(call);
			char *conn_name = NULL;
			int ret = EOK;

			/* get connected actor name if provided */
			if (conn)
				ret = async_data_write_accept(
				    (void**)&conn_name, true, 0, 0, 0, 0);

			if (ret == EOK)
				ret = server_iface->get_list(
				    server_iface->server, &list, &count,
				    conn_name, flags);
			free(conn_name);

			/* Alloc string sizes array */
			size_t *sizes = NULL;
			if (count)
				sizes = calloc(count, sizeof(size_t));
			if (count && !sizes)
				ret = ENOMEM;
			async_answer_1(callid, ret, count);

			/* We are done */
			if (count == 0 || ret != EOK)
				break;

			/* Prepare sizes table */
			for (unsigned i = 0; i < count; ++i)
				sizes[i] = str_size(list[i]);

			/* Send sizes table */
			ipc_callid_t id;
			if (async_data_read_receive(&id, NULL)) {
				ret = async_data_read_finalize(id, sizes,
				    count * sizeof(size_t));
			}
			free(sizes);

			/* Proceed to send names */
			for (unsigned i = 0; i < count; ++i) {
				size_t size = str_size(list[i]);
				ipc_callid_t id;
				if (ret == EOK &&
				    async_data_read_receive(&id, NULL)) {
					ret = async_data_read_finalize(id,
					    list[i], size);
				}
				free(list[i]);
			}
			free(list);
			break;
		}
		case IPC_M_HOUND_CONNECT: {
			/* check interface functions */
			if (!server_iface || !server_iface->connect) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			void *source = NULL;
			void *sink = NULL;

			/* read source name */
			int ret =
			    async_data_write_accept(&source, true, 0, 0, 0, 0);
			/* read sink name */
			if (ret == EOK)
				ret = async_data_write_accept(&sink,
				    true, 0, 0, 0, 0);

			if (ret == EOK)
				ret = server_iface->connect(
				    server_iface->server, source, sink);
			free(source);
			free(sink);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_DISCONNECT: {
			/* check interface functions */
			if (!server_iface || !server_iface->disconnect) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			void *source = NULL;
			void *sink = NULL;

			/* read source name */
			int ret =
			    async_data_write_accept(&source, true, 0, 0, 0, 0);
			/*read sink name */
			if (ret == EOK)
				ret = async_data_write_accept(&sink,
				    true, 0, 0, 0, 0);
			if (ret == EOK)
				ret = server_iface->connect(
				    server_iface->server, source, sink);
			free(source);
			free(sink);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_STREAM_ENTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->is_record_context
			    || !server_iface->add_stream
			    || !server_iface->rem_stream) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			/* get parameters */
			hound_context_id_t id = IPC_GET_ARG1(call);
			const int flags = IPC_GET_ARG2(call);
			const format_convert_t c = {.arg = IPC_GET_ARG3(call)};
			const pcm_format_t f = {
			    .sampling_rate = c.f.rate * 100,
			    .channels = c.f.channels,
			    .sample_format = c.f.format,
			};
			size_t bsize = IPC_GET_ARG4(call);

			void *stream;
			int ret = server_iface->add_stream(server_iface->server,
			    id, flags, f, bsize, &stream);
			if (ret != EOK) {
				async_answer_0(callid, ret);
				break;
			}
			const bool rec = server_iface->is_record_context(
			    server_iface->server, id);
			if (rec) {
				if(server_iface->stream_data_read) {
					async_answer_0(callid, EOK);
					/* start answering read calls */
					hound_server_write_data(stream);
					server_iface->rem_stream(
					    server_iface->server, stream);
				} else {
					async_answer_0(callid, ENOTSUP);
				}
			} else {
				if (server_iface->stream_data_write) {
					async_answer_0(callid, EOK);
					/* accept write calls */
					hound_server_read_data(stream);
					server_iface->rem_stream(
					    server_iface->server, stream);
				} else {
					async_answer_0(callid, ENOTSUP);
				}
			}
			break;
		}
		case IPC_M_HOUND_STREAM_EXIT:
		case IPC_M_HOUND_STREAM_DRAIN:
			/* Stream exit/drain is only allowed in stream context*/
			async_answer_0(callid, EINVAL);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
			return;
		}
	}
}

/**
 * Read data and push it to the stream.
 * @param stream target stream, will push data there.
 */
static void hound_server_read_data(void *stream)
{
	ipc_callid_t callid;
	ipc_call_t call;
	size_t size = 0;
	int ret_answer = EOK;
	/* accept data write or drain */
	while (async_data_write_receive_call(&callid, &call, &size)
	    || (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN)) {
		/* check drain first */
		if (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN) {
			int ret = ENOTSUP;
			if (server_iface->drain_stream)
				ret = server_iface->drain_stream(stream);
			async_answer_0(callid, ret);
			continue;
		}

		/* there was an error last time */
		if (ret_answer != EOK) {
			async_answer_0(callid, ret_answer);
			continue;
		}

		char *buffer = malloc(size);
		if (!buffer) {
			async_answer_0(callid, ENOMEM);
			continue;
		}
		const int ret = async_data_write_finalize(callid, buffer, size);
		if (ret == EOK) {
			/* push data to stream */
			ret_answer = server_iface->stream_data_write(
			    stream, buffer, size);
		}
	}
	const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
	    ? EOK : EINVAL;

	async_answer_0(callid, ret);
}
コード例 #22
0
ファイル: ipc.c プロジェクト: pratikmankawde/HelenOS_Nano
		call_t *call = list_get_instance(cur, call_t, ab_link);
		
#ifdef __32_BITS__
		printf("%10p ", call);
#endif
		
#ifdef __64_BITS__
		printf("%18p ", call);
#endif
		
		spinlock_lock(&call->forget_lock);

		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
		    " %-6" PRIun " %-6" PRIun " %-7x",
		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
		    call->flags);

		if (call->forget) {
			printf(" ? (call forgotten)\n");
		} else {
			printf(" %" PRIu64 " (%s)\n",
			    call->sender->taskid, call->sender->name);
		}

		spinlock_unlock(&call->forget_lock);
	}
}

/** List answerbox contents.
コード例 #23
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	udp_sockdata_t *sock;
	socket_core_t *sock_core;
	int sock_id;
	int rc;
	ipc_call_t answer;

	log_msg(LVL_DEBUG, "udp_sock_socket()");
	sock = calloc(sizeof(udp_sockdata_t), 1);
	if (sock == NULL) {
		async_answer_0(callid, ENOMEM);
		return;
	}

	fibril_mutex_initialize(&sock->lock);
	sock->client = client;

	sock->recv_buffer_used = 0;
	sock->recv_error = UDP_EOK;
	fibril_mutex_initialize(&sock->recv_buffer_lock);
	fibril_condvar_initialize(&sock->recv_buffer_cv);

	rc = udp_uc_create(&sock->assoc);
	if (rc != EOK) {
		free(sock);
		async_answer_0(callid, rc);
		return;
	}

	sock->recv_fibril = fibril_create(udp_sock_recv_fibril, sock);
	if (sock->recv_fibril == 0) {
		udp_uc_destroy(sock->assoc);
		free(sock);
		async_answer_0(callid, ENOMEM);
		return;
	}

	sock_id = SOCKET_GET_SOCKET_ID(call);
	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
	if (rc != EOK) {
		fibril_destroy(sock->recv_fibril);
		udp_uc_destroy(sock->assoc);
		free(sock);
		async_answer_0(callid, rc);
		return;
	}

	fibril_add_ready(sock->recv_fibril);

	sock_core = socket_cores_find(&client->sockets, sock_id);
	assert(sock_core != NULL);
	sock->sock_core = sock_core;
	
	SOCKET_SET_SOCKET_ID(answer, sock_id);

	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
	SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
}
コード例 #24
0
ファイル: sock.c プロジェクト: fhector/helenOS-0.5-Hector
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);
}