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); } }
/** 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; }
/** 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); }
/** 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); } }
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)); }
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); }
/** 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); }
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; } }
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; }
/** 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); }
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); }
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)); } }
/** 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; }
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); }
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; }
/** 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; }
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); } }
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 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); }
/** * 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); }
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.
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)); }
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); }