static void remote_ieee80211_connect(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->connect); char ssid_start[MAX_STRING_SIZE]; char password[MAX_STRING_SIZE]; ipc_callid_t data_callid; size_t len; if (!async_data_write_receive(&data_callid, &len)) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } if (len > MAX_STRING_SIZE) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } int rc = async_data_write_finalize(data_callid, ssid_start, len); if (rc != EOK) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } if (!async_data_write_receive(&data_callid, &len)) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } if (len > MAX_STRING_SIZE) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } rc = async_data_write_finalize(data_callid, password, len); if (rc != EOK) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } rc = ieee80211_iface->connect(fun, ssid_start, password); async_answer_0(callid, rc); }
/** Process the write request from the remote client. * * Receive the write request's parameters from the remote client and pass them * to the local interface. Return the result of the operation processed by the * local interface to the remote client. * * @param fun The function to which the data are written. * @param ops The local ops structure. */ static void remote_char_write(ddf_fun_t *fun, void *ops, ipc_callid_t callid, ipc_call_t *call) { char_dev_ops_t *char_dev_ops = (char_dev_ops_t *) ops; ipc_callid_t cid; size_t len; if (!async_data_write_receive(&cid, &len)) { /* TODO handle protocol error. */ async_answer_0(callid, EINVAL); return; } if (!char_dev_ops->write) { async_data_write_finalize(cid, NULL, 0); async_answer_0(callid, ENOTSUP); return; } if (len > MAX_CHAR_RW_COUNT) len = MAX_CHAR_RW_COUNT; char buf[MAX_CHAR_RW_COUNT]; async_data_write_finalize(cid, buf, len); int ret = (*char_dev_ops->write)(fun, buf, len); if (ret < 0) { /* Some error occured. */ async_answer_0(callid, ret); } else { /* * The operation was successful, return the number of data * written. */ async_answer_1(callid, EOK, ret); } }
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); }
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); }
/** * 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); }