Beispiel #1
0
/** Receive a call setting arguments of the program to execute.
 *
 * @param rid
 * @param request
 */
static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
{
	char *buf;
	size_t buf_size;
	int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
	
	if (rc == EOK) {
		/*
		 * Count number of arguments
		 */
		char *cur = buf;
		int count = 0;
		
		while (cur < buf + buf_size) {
			size_t arg_size = str_size(cur);
			cur += arg_size + 1;
			count++;
		}
		
		/*
		 * Allocate new argv
		 */
		char **_argv = (char **) malloc((count + 1) * sizeof(char *));
		if (_argv == NULL) {
			free(buf);
			async_answer_0(rid, ENOMEM);
			return;
		}
		
		/*
		 * Fill the new argv with argument pointers
		 */
		cur = buf;
		count = 0;
		while (cur < buf + buf_size) {
			_argv[count] = cur;
			
			size_t arg_size = str_size(cur);
			cur += arg_size + 1;
			count++;
		}
		_argv[count] = NULL;
		
		/*
		 * Copy temporary data to global variables
		 */
		if (arg_buf != NULL)
			free(arg_buf);
		
		if (argv != NULL)
			free(argv);
		
		argc = count;
		arg_buf = buf;
		argv = _argv;
	}
	
	async_answer_0(rid, rc);
}
Beispiel #2
0
/** Receive a call setting pathname of the program to execute.
 *
 * @param rid
 * @param request
 */
static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
{
	char *buf;
	int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
	
	if (rc == EOK) {
		if (pathname != NULL)
			free(pathname);
		
		pathname = buf;
	}
	
	async_answer_0(rid, rc);
}
Beispiel #3
0
/** Handle VHC request for control write to the device.
 *
 * @param dev Target virtual device.
 * @param iid Caller id.
 * @param icall The call with the request.
 */
static void ipc_control_write(usbvirt_device_t *dev,
    ipc_callid_t iid, ipc_call_t *icall)
{
	size_t data_buffer_len = IPC_GET_ARG1(*icall);
	int rc;

	void *setup_packet = NULL;
	void *data_buffer = NULL;
	size_t setup_packet_len = 0;

	rc = async_data_write_accept(&setup_packet, false,
	    1, 0, 0, &setup_packet_len);
	if (rc != EOK) {
		async_answer_0(iid, rc);
		return;
	}

	if (data_buffer_len > 0) {
		rc = async_data_write_accept(&data_buffer, false,
		    1, 0, 0, &data_buffer_len);
		if (rc != EOK) {
			async_answer_0(iid, rc);
			free(setup_packet);
			return;
		}
	}

	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
	    data_buffer, data_buffer_len);

	async_answer_0(iid, rc);

	free(setup_packet);
	if (data_buffer != NULL) {
		free(data_buffer);
	}
}
Beispiel #4
0
/** Handle VHC request for control read from the device.
 *
 * @param dev Target virtual device.
 * @param iid Caller id.
 * @param icall The call with the request.
 */
static void ipc_control_read(usbvirt_device_t *dev,
    ipc_callid_t iid, ipc_call_t *icall)
{
	int rc;

	void *setup_packet = NULL;
	size_t setup_packet_len = 0;
	size_t data_len = 0;

	rc = async_data_write_accept(&setup_packet, false,
	    1, 1024, 0, &setup_packet_len);
	if (rc != EOK) {
		async_answer_0(iid, rc);
		return;
	}

	ipc_callid_t data_callid;
	if (!async_data_read_receive(&data_callid, &data_len)) {
		async_answer_0(iid, EPARTY);
		free(setup_packet);
		return;
	}

	void *buffer = malloc(data_len);
	if (buffer == NULL) {
		async_answer_0(iid, ENOMEM);
		free(setup_packet);
		return;
	}

	size_t actual_len;
	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
	    buffer, data_len, &actual_len);

	if (rc != EOK) {
		async_answer_0(data_callid, rc);
		async_answer_0(iid, rc);
		free(setup_packet);
		free(buffer);
		return;
	}

	async_data_read_finalize(data_callid, buffer, actual_len);
	async_answer_0(iid, EOK);

	free(setup_packet);
	free(buffer);
}
Beispiel #5
0
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);
}
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);
}
Beispiel #7
0
/** Handle VHC request for data write to the device (out transfer).
 *
 * @param dev Target virtual device.
 * @param iid Caller id.
 * @param icall The call with the request.
 */
static void ipc_data_out(usbvirt_device_t *dev,
    usb_transfer_type_t transfer_type,
    ipc_callid_t iid, ipc_call_t *icall)
{
	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);

	void *data_buffer = NULL;
	size_t data_buffer_size = 0;

	int rc = async_data_write_accept(&data_buffer, false,
	    1, 0, 0, &data_buffer_size);
	if (rc != EOK) {
		async_answer_0(iid, rc);
		return;
	}

	rc = usbvirt_data_out(dev, transfer_type, endpoint,
	    data_buffer, data_buffer_size);

	async_answer_0(iid, rc);

	free(data_buffer);
}
Beispiel #8
0
static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int rc;
	struct sockaddr *addr;
	size_t addr_len;
	socket_core_t *sock_core;
	tcp_sockdata_t *socket;

	log_msg(LVL_DEBUG, "tcp_sock_bind()");
	log_msg(LVL_DEBUG, " - async_data_write_accept");
	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
	if (rc != EOK) {
		async_answer_0(callid, rc);
		return;
	}

	log_msg(LVL_DEBUG, " - call socket_bind");
	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
	    addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
	    last_used_port);
	if (rc != EOK) {
		async_answer_0(callid, rc);
		return;
	}

	log_msg(LVL_DEBUG, " - call socket_cores_find");
	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
	if (sock_core != NULL) {
		socket = (tcp_sockdata_t *)sock_core->specific_data;
		/* XXX Anything to do? */
		(void) socket;
	}

	log_msg(LVL_DEBUG, " - success");
	async_answer_0(callid, EOK);
}
Beispiel #9
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);
}
Beispiel #10
0
static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int rc;
	struct sockaddr_in *addr;
	int socket_id;
	size_t addr_len;
	socket_core_t *sock_core;
	tcp_sockdata_t *socket;
	tcp_error_t trc;
	tcp_sock_t lsocket;
	tcp_sock_t fsocket;

	log_msg(LVL_DEBUG, "tcp_sock_connect()");

	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
	if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
		async_answer_0(callid, rc);
		return;
	}

	socket_id = SOCKET_GET_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;
	if (sock_core->port <= 0) {
		rc = socket_bind_free_port(&gsock, sock_core,
		    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
		    last_used_port);
		if (rc != EOK) {
			async_answer_0(callid, rc);
			return;
		}

		last_used_port = sock_core->port;
	}

	fibril_mutex_lock(&socket->lock);

	if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
		/* Determine local IP address */
		inet_addr_t loc_addr, rem_addr;

		rem_addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
		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, "tcp_sock_connect: Failed to "
			    "determine local address.");
			return;
		}

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

	lsocket.addr.ipv4 = socket->laddr.ipv4;
	lsocket.port = sock_core->port;
	fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
	fsocket.port = uint16_t_be2host(addr->sin_port);

	trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0, &socket->conn);

	if (socket->conn != NULL)
		socket->conn->name = (char *)"C";

	fibril_mutex_unlock(&socket->lock);

	switch (trc) {
	case TCP_EOK:
		rc = EOK;
		break;
	case TCP_ERESET:
		rc = ECONNREFUSED;
		break;
	default:
		assert(false);
	}

	if (rc == EOK)
		fibril_add_ready(socket->recv_fibril);

	async_answer_0(callid, rc);
}
Beispiel #11
0
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);
}
Beispiel #12
0
static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int rc;
	struct sockaddr_in *addr;
	size_t addr_size;
	socket_core_t *sock_core;
	udp_sockdata_t *socket;
	udp_sock_t fsock;
	udp_error_t urc;

	log_msg(LVL_DEBUG, "udp_sock_bind()");
	log_msg(LVL_DEBUG, " - async_data_write_accept");

	addr = NULL;

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

	log_msg(LVL_DEBUG, " - call socket_bind");
	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;
	}

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

	log_msg(LVL_DEBUG, " - call socket_cores_find");
	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
	if (sock_core == NULL) {
		async_answer_0(callid, ENOENT);
		goto out;
	}

	socket = (udp_sockdata_t *)sock_core->specific_data;

	fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
	fsock.port = sock_core->port;
	urc = udp_uc_set_local(socket->assoc, &fsock);

	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);
	}

	log_msg(LVL_DEBUG, " - success");
	async_answer_0(callid, rc);
out:
	if (addr != NULL)
		free(addr);
}
Beispiel #13
0
/**
 * 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);
}