/* * 0001/0002 (client->server) Client Online * * Although the client will probably make more requests to learn about its * environment after this, reception of the Client Online message is when the * server will consider the client to be online, and, in the case of a BOS * connection, light them up on the buddy lists. */ static int toscar_snachandler_0001_0002(struct nafmodule *mod, struct nafconn *conn, struct toscar_snac *snac) { char *sn = NULL; struct gnrnode *node; if (!(conn->type & NAF_CONN_TYPE_CLIENT)) return HRET_ERROR; if ((naf_conn_tag_fetch(mod, conn->endpoint, "conn.screenname", NULL, (void **)&sn) == -1) || !sn) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] received Client Online on connection with no user info; killing\n", conn->cid); return HRET_ERROR; } { /* * Disconnect any old server connections for this user. AIM * used to do this automatically, but they fixed the glitch. */ toscar__detacholdconns(mod, sn); } node = gnr_node_online(mod, sn, OSCARSERVICE, GNR_NODE_FLAG_NONE, GNR_NODE_METRIC_LOCAL); if (!node) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] [%s] unable to create gnrnode; disconnecting\n", conn->cid, sn); return HRET_ERROR; } return HRET_FORWARD; }
static int toscar_flap_handlechan1__newconn(struct nafmodule *mod, struct nafconn *conn, naf_tlv_t **tlvh) { naf_tlv_t *cktlv; char *ip = NULL, *sn = NULL; naf_u16_t servtype = TOSCAR_SERVTYPE_UNKNOWN; int ret = HRET_DIGESTED; if (!(cktlv = naf_tlv_get(mod, *tlvh, 0x0006))) { /* no cookie = wtf are we doing here? */ if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] cookie FLAP missing cookie\n", conn->cid); return HRET_ERROR; } if (toscar_ckcache_rem(mod, cktlv->tlv_value, cktlv->tlv_length, &ip, &sn, &servtype) == -1) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] received unknown cookie\n", conn->cid); ret = HRET_ERROR; goto out; } if (timps_oscar__debug > 1) dvprintf(mod, "[cid %lu] matched cookie to sn '%s', ip '%s', servtype %d\n", conn->cid, sn, ip, servtype); if (naf_conn_startconnect(mod, conn, ip, TIMPS_OSCAR_DEFAULTPORT) == -1) { ret = HRET_ERROR; goto out; } conn->servtype = servtype; conn->endpoint->servtype = servtype; if (sn) { /* XXX store full userinfo here */ /* Note that the user information is attached to the server connection. */ if (naf_conn_tag_add(mod, conn->endpoint, "conn.screenname", 'S', sn) == -1) { ret = HRET_ERROR; goto out; } sn = NULL; } /* need to resend these when connection completes */ if (naf_conn_tag_add(mod, conn->endpoint, "conn.cookietlvs", 'V', (void *)*tlvh) == -1) { ret = HRET_ERROR; goto out; } *tlvh = NULL; /* will get freed with tag */ out: naf_free(mod, sn); naf_free(mod, ip); return ret; }
/*! @brief Sets the process's parameter buffer. Sets the process's parameter buffer to the given RAM dataspace. Only support a RAM dataspace which orginated from the process server's own dataspace implementation, does not support an external dataspace. */ refos_err_t proc_set_parambuffer_handler(void *rpc_userptr , seL4_CPtr rpc_dataspace , uint32_t rpc_size) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; assert(pcb->magic == REFOS_PCB_MAGIC); struct ram_dspace *dataspace; /* Special case zero size and NULL parameter buffer - means unset the parameter buffer. */ if (rpc_size == 0 && rpc_dataspace == 0) { proc_set_parambuffer(pcb, NULL); return ESUCCESS; } if (!check_dispatch_caps(m, 0x00000001, 1)) { return EINVALIDPARAM; } /* Check if the given badge is a RAM dataspace. */ if (!dispatcher_badge_dspace(rpc_dataspace)) { return EINVALIDPARAM; } /* Retrieve RAM dataspace structure. */ dataspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dataspace); if (!dataspace) { dvprintf("No such dataspace!.\n"); return EINVALID; } /* Set new parameter buffer. */ proc_set_parambuffer(pcb, dataspace); return ESUCCESS; }
/*! @brief Handles device server device map syscalls. */ refos_err_t proc_device_map_handler(void *rpc_userptr , seL4_CPtr rpc_window , uint32_t rpc_windowOffset , uint32_t rpc_paddr , uint32_t rpc_size , int rpc_cached) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; assert(pcb && pcb->magic == REFOS_PCB_MAGIC); if (!check_dispatch_caps(m, 0x00000001, 1)) { return EINVALIDPARAM; } if ((pcb->systemCapabilitiesMask & PROCESS_PERMISSION_DEVICE_MAP) == 0) { dvprintf("Process needs device map permissions to perform this.\n"); return EACCESSDENIED; } /* Retrieve and verify window. */ struct w_window *window = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE); if (!window) { ROS_ERROR("window does not exist!\n"); return EINVALIDWINDOW; } /* Get the client PCB that owns the given window. */ struct proc_pcb* clientPCB = pid_get_pcb(&procServ.PIDList, window->clientOwnerPID); if (!clientPCB) { ROS_ERROR("invalid window owner!\n"); return EINVALID; } assert(clientPCB->magic == REFOS_PCB_MAGIC); return vs_map_device(&clientPCB->vspace, window, rpc_windowOffset, rpc_paddr, rpc_size, rpc_cached ? true : false); }
static void freetag(struct nafmodule *mod, void *object, const char *tagname, char tagtype, void *tagdata) { dvprintf(mod, "freetag: unknown tagname '%s'\n", tagname); return; }
void dprintf(const char *debug_context, const char *fmt, ...) { va_list args; va_start(args, fmt); dvprintf(debug_context, fmt, args); va_end(args); }
struct gnrnode *gnr_node_online(struct nafmodule *owner, const char *name, const char *service, naf_u32_t flags, int metric) { struct gnrnode *gn; if (!owner || !name || !service) return NULL; if ((gn = gnr_node_findbyname(name, service))) return gn; if (!(gn = naf_malloc(gnr__module, sizeof(struct gnrnode)))) return NULL; memset(gn, 0, sizeof(struct gnrnode)); if (!(gn->name = naf_strdup(gnr__module, name))) { naf_free(gnr__module, gn); return NULL; } if (!(gn->service = naf_strdup(gnr__module, service))) { naf_free(gnr__module, gn->name); naf_free(gnr__module, gn); return NULL; } gn->flags = flags; gn->metric = metric; gn->ownermod = owner; gn->taglistv = NULL; gn->refcount = 0; /* caller should immediatly _ref if it wants it */ gn->createtime = gn->lastuse = time(NULL); gn->ttl = -1; if (gn->metric > GNR_NODE_METRIC_LOCAL) gn->ttl = GNR_NODE_TTL_DEFAULT; gnr_node__hash_add(gn); gnr__nodestats.total++; if (gn->metric == GNR_NODE_METRIC_LOCAL) gnr__nodestats.local++; else if (gn->metric == GNR_NODE_METRIC_MAX) gnr__nodestats.external++; else gnr__nodestats.peered++; #if 0 dvprintf(gnr__module, "user online: %s[%s][%s][%s%s%s]\n", gn->name, gn->service, gn->ownermod ? gn->ownermod->name : "unknown", (gn->metric == GNR_NODE_METRIC_LOCAL) ? "local" : "", GNR_NODE_METRIC_ISPEERED(gn->metric) ? "peer" : "", (gn->metric == GNR_NODE_METRIC_MAX) ? "remote" : ""); #endif gnr_event_throw_withnode(GNR_EVENT_NODEUP, gn, NULL); return gn; }
/*! \brief Call from external dataserver asking to be the content initialiser for this dataspace. */ refos_err_t data_have_data_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_faultNotifyEP , uint32_t* rpc_dataID) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; assert(pcb && pcb->magic == REFOS_PCB_MAGIC); if (!(check_dispatch_caps(m, 0x00000001, 2) || check_dispatch_caps(m, 0x00000001, 1))) { return EINVALIDPARAM; } if (rpc_dataID) { (*rpc_dataID) = 0; } /* Verify and find the RAM dataspace. */ if (!dispatcher_badge_dspace(rpc_dspace_fd)) { ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); return EINVALIDPARAM; } struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); if (!dspace) { ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); return EINVALIDPARAM; } /* Special case - no fault notify EP, means unset content-init mode. */ if (!rpc_faultNotifyEP) { cspacepath_t path; vka_cspace_make_path(&procServ.vka, 0, &path); return ram_dspace_content_init(dspace, path, PID_NULL); } /* Copyout the content-init fault notify EP. */ seL4_CPtr faultNotifyEP = dispatcher_copyout_cptr(rpc_faultNotifyEP); if (!faultNotifyEP) { dvprintf("could not copy out faultNotifyEP."); return EINVALIDPARAM; } cspacepath_t path; vka_cspace_make_path(&procServ.vka, faultNotifyEP, &path); /* Initialise the dataspace content with given dataserver EP. */ int error = ram_dspace_content_init(dspace, path, pcb->pid); if (error != ESUCCESS) { dispatcher_release_copyout_cptr(faultNotifyEP); return error; } if (rpc_dataID) { (*rpc_dataID) = dspace->ID; } return ESUCCESS; }
/* * 0001/000b (server->client) Server Pause * * This is the first step in migration, where the server moves the client to a * different server. * */ static int toscar_snachandler_0001_000b(struct nafmodule *mod, struct nafconn *conn, struct toscar_snac *snac) { char *sn = NULL; naf_conn_tag_fetch(mod, conn, "conn.screenname", NULL, (void **)&sn); dvprintf(mod, "[cid %lu] [%s] received server pause; disconnecting for safety\n", conn->cid, sn); return HRET_ERROR; }
/* * 0001/0003 (server->client) Host Online * * Received after we're somewhat authenticated with the host. * */ static int toscar_snachandler_0001_0003(struct nafmodule *mod, struct nafconn *conn, struct toscar_snac *snac) { conn->flags |= TOSCAR_FLAG_READY; if (timps_oscar__debug > 0) dvprintf(mod, "[%lu] received Host Online\n", conn->cid); return HRET_FORWARD; }
/*! @brief Handles memory window resize syscalls. */ refos_err_t proc_resize_mem_window_handler(void *rpc_userptr , seL4_CPtr rpc_window , uint32_t rpc_size) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; assert(pcb && pcb->magic == REFOS_PCB_MAGIC); if (!check_dispatch_caps(m, 0x00000001, 1)) { dvprintf("Warning: proc_resize_mem_window invalid window cap.\n"); return EINVALIDWINDOW; } if (!dispatcher_badge_window(rpc_window)) { dvprintf("Warning: proc_resize_mem_window invalid window badge.\n"); return EINVALIDWINDOW; } /* Perform the actual window resize operation. */ return vs_resize_window(&pcb->vspace, rpc_window - W_BADGE_BASE, rpc_size); }
static int toscar_flap_handlechan1(struct nafmodule *mod, struct nafconn *conn, naf_u8_t *buf, naf_u16_t buflen) { naf_sbuf_t sb; naf_u32_t flapver; naf_tlv_t *tlvh; int ret = HRET_FORWARD; naf_sbuf_init(mod, &sb, buf, buflen); naf_sbuf_advance(&sb, FLAPHDRLEN); flapver = naf_sbuf_get32(&sb); if (flapver != 0x00000001) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] %s sent invalid FLAP version\n", conn->cid, !(conn->type & NAF_CONN_TYPE_CLIENT) ? "server" : "client"); return HRET_ERROR; } tlvh = naf_tlv_parse(mod, &sb); if (FLAPHDR_LEN(buf) == 4) { /* version only */ if (conn->type & NAF_CONN_TYPE_SERVER) ret = toscar_flap_handlechan1__conncomplete(mod, conn); else ret = HRET_DIGESTED; /* wait to see what else they have for us */ } else if ((conn->type & NAF_CONN_TYPE_CLIENT) && naf_tlv_get(mod, tlvh, 0x0001 /* screen name */)) ret = toscar_flap_handlechan1__xorlogin(mod, conn, &tlvh); else if ((conn->type & NAF_CONN_TYPE_CLIENT) && naf_tlv_get(mod, tlvh, 0x0006 /* cookie */)) ret = toscar_flap_handlechan1__newconn(mod, conn, &tlvh); else { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] unable to determine purpose of channel 1 packet\n", conn->cid); ret = HRET_ERROR; } naf_tlv_free(mod, tlvh); return ret; }
/*! @brief Handles memory window creation syscalls. The window must not be overlapping with an existing window in the client's VSpace, or EINVALIDPARAM will be the returned. When mapping a dataspace to a non-page aligned window, the dataspace will actually be mapped to the page-aligned address of the window base due to technical restrictions. Thus, the first B - PAGE_ALIGN(B) bytes of the mapped dataspace is unaccessible. This can have unintended effects when two processes map the same dataspace for sharing purposes. In other words, when sharing dataspaces, it's easiest for the window bases for BOTH processes to be page-aligned. */ seL4_CPtr proc_create_mem_window_internal_handler(void *rpc_userptr , uint32_t rpc_vaddr , uint32_t rpc_size , uint32_t rpc_permissions, uint32_t flags, refos_err_t* rpc_errno) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; assert(pcb && pcb->magic == REFOS_PCB_MAGIC); /* Check that this window does not override protected kernel memory. */ if (rpc_vaddr >= PROCESS_KERNEL_RESERVED || PROCESS_KERNEL_RESERVED < (rpc_size + rpc_vaddr)) { dvprintf("memory window out of bounds, overlaps kernel reserved.\n"); SET_ERRNO_PTR(rpc_errno, EINVALIDPARAM); return 0; } /* Create the window. */ int windowID = W_INVALID_WINID; bool cached = (flags & W_FLAGS_UNCACHED) ? false : true; int error = vs_create_window(&pcb->vspace, rpc_vaddr, rpc_size, rpc_permissions, cached, &windowID); if (error != ESUCCESS || windowID == W_INVALID_WINID) { dvprintf("Could not create window.\n"); SET_ERRNO_PTR(rpc_errno, error); return 0; } /* Find the window and return the window capability. */ struct w_window* window = w_get_window(&procServ.windowList, windowID); if (!window) { assert(!"Successfully allocated window failed to be found. Process server bug."); /* Cannot recover from this situation cleanly. Shouldn't ever happen. */ SET_ERRNO_PTR(rpc_errno, EINVALID); return 0; } assert(window->magic == W_MAGIC); assert(window->capability.capPtr); SET_ERRNO_PTR(rpc_errno, ESUCCESS); return window->capability.capPtr; }
static int toscar_gnroutputfunc(struct nafmodule *mod, struct gnrmsg *gm, struct gnrmsg_handler_info *gmhi) { if (timps_oscar__debug > 1) { dvprintf(mod, "toscar_gnroutputfunc: type = %d, to = '%s'[%s](%d), from = '%s'[%s](%d), msg = (%s) '%s'\n", gm->type, gm->srcname, gm->srcnameservice, gmhi->srcnode ? gmhi->srcnode->metric : -1, gm->destname, gm->destnameservice, gmhi->destnode ? gmhi->destnode->metric : -1, gm->msgtexttype ? gm->msgtexttype : "type not specified", gm->msgtext); } if (gmhi->destnode->metric == GNR_NODE_METRIC_LOCAL) { struct nafconn *conn; if (!(conn = toscar__findconn(mod, gmhi->destnode->name))) { if (timps_oscar__debug > 0) dvprintf(mod, "gnroutputfunc(local): unable to find connection for local node '%s'[%s]\n", gmhi->destnode->name, gmhi->destnode->service); return -1; } toscar_icbm_sendincoming(mod, conn->endpoint, gm, gmhi); } else if (gmhi->srcnode->metric == GNR_NODE_METRIC_LOCAL) { struct nafconn *conn; if (!(conn = toscar__findconn(mod, gmhi->srcnode->name))) { if (timps_oscar__debug > 0) dvprintf(mod, "gnroutputfunc(forward): unable to find connection for local node '%s'[%s]\n", gmhi->srcnode->name, gmhi->srcnode->service); return -1; } toscar_icbm_sendoutgoing(mod, conn, gm, gmhi); } return 0; }
/*! @brief Main CPIO file server message loop. Simply loops through recieving and dispatching messages repeatedly. */ static void fileserv_mainloop(void) { struct fs_state *s = &fileServ; srv_msg_t msg; while (1) { dvprintf("Fileserver blocking for message...\n"); msg.message = seL4_Wait(fileServCommon->anonEP, &msg.badge); fileserv_handle_message(s, &msg); client_table_postaction(&fileServCommon->clientTable); } }
static int toscar__keepalive_matcher(struct nafmodule *mod, struct nafconn *conn, const void *ud) { const time_t now = (time_t)ud; if (!(conn->type & NAF_CONN_TYPE_FLAP) || !(conn->type & NAF_CONN_TYPE_SERVER)) return 0; if (!(conn->flags & TOSCAR_FLAG_READY)) return 0; if ((now - conn->lasttx_soft) > timps_oscar__keepalive_frequency) { if (timps_oscar__debug > 1) { dvprintf(mod, "[%lu] sending nop (%d seconds since last tx)\n", conn->cid, now - conn->lasttx_soft); } toscar_flap_sendnop(mod, conn); } /* * This closes connections that are 'stuck', at the TCP level. If a * host doesn't ack our data (to let us send our queue) for more than * thirty seconds (default), then consider the connection dead. This * can occur for a variety of reasons, most of them not good. * * The check above makes sure there's always pending data at least * this often. */ if ((now - conn->lasttx_hard) > timps_oscar__txtimeout) { dvprintf(mod, "[%lu] connection timed out, closing (%d seconds since last hard tx)\n", conn->cid, now - conn->lasttx_hard); naf_conn_schedulekill(conn); } return 0; }
static void freetag(struct nafmodule *mod, void *object, const char *tagname, char tagtype, void *tagdata) { if (strcmp(tagname, "module.gnrmsg_outputfunc") == 0) { /* pointer to non-dynamic object */ } else { dvprintf(mod, "freetag: unknown tag '%s'\n", tagname); } return; }
/*! @brief Main process server loop. The main loop that the process server goes into and keeps looping until the process server is to exit and the whole system is to by shut down (which is possibly never). It blocks on the process server endpoint and waits for an IPC message, and then handles the dispatching of the message when it recieves one, before looping around and waiting for the next IPC message. @return Does not return, runs endlessly. */ static int proc_server_loop(void) { struct procserv_state *s = &procServ; struct procserv_msg msg = { .state = s }; while (1) { dvprintf("procserv blocking for new message...\n"); msg.message = seL4_Recv(s->endpoint.cptr, &msg.badge); proc_server_handle_message(s, &msg); s->faketime++; } return 0; }
/* ** say something to server and check the response */ void chat(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(sfp, fmt, ap); va_end(ap); va_start(ap, fmt); dprintf("%s <-- ", mailhost); dvprintf(fmt, ap); va_end(ap); fflush(sfp); get_response(); }
static void freetag(struct nafmodule *mod, void *object, const char *tagname, char tagtype, void *tagdata) { if ((strcmp(tagname, "conn.logintlvs") == 0) || (strcmp(tagname, "conn.cookietlvs") == 0)) naf_tlv_free(mod, (naf_tlv_t *)tagdata); else if (strcmp(tagname, "conn.loginsnacid") == 0) ; /* an int */ else if (strcmp(tagname, "conn.screenname") == 0) { char *sn = (char *)tagdata; struct nafconn *conn = (struct nafconn *)object; struct gnrnode *node; if ((node = gnr_node_findbyname(sn, OSCARSERVICE)) && !toscar__userhasotherclient(mod, sn, conn)) gnr_node_offline(node, GNR_NODE_OFFLINE_REASON_DISCONNECTED); naf_free(mod, sn); } else if (strcmp(tagname, "gnrmsg.oscarmsgcookie") == 0) { naf_u8_t *msgck = (naf_u8_t *)tagdata; naf_free(mod, msgck); } else if (strcmp(tagname, "gnrmsg.snacid") == 0) { /* an int */ } else if (strcmp(tagname, "gnrmsg.oscarmsgtlv") == 0) { naf_tlv_t *msgtlv = (naf_tlv_t *)tagdata; naf_tlv_free(mod, msgtlv); } else if (strcmp(tagname, "gnrmsg.extraoscartlvs") == 0) { naf_tlv_t *tlvs = (naf_tlv_t *)tagdata; naf_tlv_free(mod, tlvs); } else if (strcmp(tagname, "gnrmsg.srcuserinfo") == 0) { struct touserinfo *toui = (struct touserinfo *)tagdata; touserinfo_free(mod, toui); } else dvprintf(mod, "freetag: unknown tagname '%s'\n", tagname); return; }
static void dumpbox(struct nafmodule *mod, const char *prefix, naf_conn_cid_t cid, unsigned char *buf, int len) { int z = 0, x, y; char tmpstr[256]; while (z<len) { x = snprintf(tmpstr, sizeof(tmpstr), "%sput, %d bytes to cid %ld: ", prefix, len, cid); for (y = 0; y < 8; y++) { if (z<len) { snprintf(tmpstr+x, sizeof(tmpstr)-strlen(tmpstr), "%02x ", buf[z]); z++; x += 3; } else break; } dvprintf(mod, "%s\n", tmpstr); } }
/*! @brief Handles server pager setup syscalls. A dataserver calls the process server with this call in order to set up to be the pager of one of its client processes for a particular window. The client process is identified by the passing of its liveliness cap. All faults for the client's process which happen at that window will then be delegated to the dataserver to be handled. */ refos_err_t proc_register_as_pager_handler(void *rpc_userptr , seL4_CPtr rpc_window , seL4_CPtr rpc_faultNotifyEP , seL4_Word* rpc_winID) { struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; assert(pcb && pcb->magic == REFOS_PCB_MAGIC); if (!check_dispatch_caps(m, 0x00000001, 2)) { return EINVALIDPARAM; } /* Retrieve and verify the window cap. */ if (!dispatcher_badge_window(rpc_window)) { ROS_WARNING("Invalid window badge."); return EINVALIDPARAM; } struct w_window *win = w_get_window(&procServ.windowList, rpc_window - W_BADGE_BASE); if (!win) { ROS_ERROR("invalid window ID."); return EINVALIDPARAM; } assert(win->magic == W_MAGIC); /* Copy out the fault endpoint. */ seL4_CPtr faultNotifyEP = dispatcher_copyout_cptr(rpc_faultNotifyEP); if (!faultNotifyEP) { dvprintf("could not copy out faultNotifyEP."); return EINVALIDPARAM; } /* Set the pager endpoint. If there was anything else mapped to this window, it will be unmapped. */ cspacepath_t faultNotifyEPPath; vka_cspace_make_path(&procServ.vka, faultNotifyEP, &faultNotifyEPPath); w_set_pager_endpoint(win, faultNotifyEPPath, pcb->pid); if (rpc_winID) { (*rpc_winID) = win->wID; } return ESUCCESS; }
static void freenode(struct gnrnode *gn, int reason) { { struct gnr_event_ei_nodechange ei; memset(&ei, 0, sizeof(struct gnr_event_ei_nodechange)); ei.reason = reason; gnr_event_throw_withnode(GNR_EVENT_NODEDOWN, gn, &ei); } #if 0 dvprintf(gnr__module, "user offline: %s[%s][%s][%s%s%s] -- %s%s%s\n", gn->name, gn->service, gn->ownermod ? gn->ownermod->name : "unknown", (gn->metric == GNR_NODE_METRIC_LOCAL) ? "local" : "", GNR_NODE_METRIC_ISPEERED(gn->metric) ? "peer" : "", (gn->metric == GNR_NODE_METRIC_MAX) ? "remote" : "", (reason == GNR_NODE_OFFLINE_REASON_TIMEOUT) ? "timed out" : "", (reason == GNR_NODE_OFFLINE_REASON_DISCONNECTED) ? "disconnected" : "", ((reason != GNR_NODE_OFFLINE_REASON_TIMEOUT) && (reason != GNR_NODE_OFFLINE_REASON_DISCONNECTED)) ? "unknown reason" : ""); #endif gnr__nodestats.total--; if (gn->metric == GNR_NODE_METRIC_LOCAL) gnr__nodestats.local--; else if (gn->metric == GNR_NODE_METRIC_MAX) gnr__nodestats.external--; else gnr__nodestats.peered--; naf_tag_freelist(&gn->taglistv, gn); naf_free(gnr__module, gn->name); naf_free(gnr__module, gn->service); naf_free(gnr__module, gn); return; }
int timer_write_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , uint32_t rpc_offset , rpc_buffer_t rpc_buf , uint32_t rpc_count) { struct srv_client *c = (struct srv_client *) rpc_userptr; assert(c && c->magic == TIMESERV_CLIENT_MAGIC); assert(rpc_dspace_fd == TIMESERV_DSPACE_BADGE_TIMER); if (rpc_buf.count < sizeof(uint64_t)) { return -EINVALIDPARAM; } /* Writing to the timer dataspace results in a sleep call. */ uint64_t timeWait = *( (uint64_t*) (rpc_buf.data) ); dvprintf("timer_write_handler client waiting for %llu nanoseconds.\n", timeWait); int error = device_timer_save_caller_as_waiter(&timeServ.devTimer, c, timeWait); if (error == ESUCCESS) { c->rpcClient.skip_reply = true; } return -error; }
/* Remetric'ing is a complicated thing. It's probably broken. */ int gnr_node_remetric(struct gnrnode *gn, int newmetric) { if (!gn) return -1; if (gn->metric < newmetric) dvprintf(gnr__module, "BUG: gnr_node_remetric asked to make node %s[%s] farther away (new = %d, old = %d)\n", gn->name, gn->service, newmetric, gn->metric); if (gn->metric == GNR_NODE_METRIC_LOCAL) gnr__nodestats.local--; else if (gn->metric == GNR_NODE_METRIC_MAX) gnr__nodestats.external--; else gnr__nodestats.peered--; gn->metric = newmetric; if (gn->metric == GNR_NODE_METRIC_LOCAL) gnr__nodestats.local++; else if (gn->metric == GNR_NODE_METRIC_MAX) gnr__nodestats.external++; else gnr__nodestats.peered++; if (gn->metric == GNR_NODE_METRIC_LOCAL) gn->ttl = -1; else gn->ttl = GNR_NODE_TTL_DEFAULT; gnr_node_usehit(gn); return 0; }
static int toscar__detacholdconns__matcher(struct nafmodule *mod, struct nafconn *conn, const void *udata) { const char *sn = (const char *)udata; char *cursn = NULL; if (!(conn->type & NAF_CONN_TYPE_SERVER)) return 0; if (conn->endpoint) return 0; if ((naf_conn_tag_fetch(mod, conn, "conn.screenname", NULL, (void **)&cursn) == -1) || !cursn) return 0; if (toscar_sncmp(sn, cursn) != 0) return 0; if (timps_oscar__debug) { dvprintf(mod, "disconnecting old server connection %lu for '%s'\n", conn->cid, cursn); } naf_conn_schedulekill(conn); return 0; /* keep going */ }
/*! @brief Handles client VM fault messages sent by the kernel. Handles the VM fault message by looking up the details of the window that it faulted in, and decides whether this fault should be delegated to an external dataspace server for paging or content initalisation, or be handled internally by the process server's own dataspace implementation for RAM, or is an invalid memory access. In the case of an invalid memory access, or if the process server runs out of RAM, then the fault is unable to be handled and the faulting process is blocked indefinitely. @param m The recieved IPC fault message from the kernel. @param f The VM fault message info struct. */ static void handle_vm_fault(struct procserv_msg *m, struct procserv_vmfault_msg *f) { assert(f && f->pcb); dvprintf("# Process server recieved PID %d VM fault\n", f->pcb->pid); dvprintf("# %s %s fault at 0x%x, Instruction Pointer 0x%x, Fault Status Register 0x%x\n", f->instruction ? "Instruction" : "Data", f->read ? "read" : "write", f->faultAddr, f->pc, f->fsr); /* Thread should never be fault blocked (or else how did this VM fault even happen?). */ if (f->pcb->faultReply.capPtr != 0) { ROS_ERROR("(how did this VM fault even happen? Check book-keeping.\n"); output_segmentation_fault("Process should already be fault-blocked.", f); return; } /* Check faulting vaddr in segment windows. */ struct w_associated_window *aw = w_associate_find(&f->pcb->vspace.windows, f->faultAddr); if (!aw) { output_segmentation_fault("invalid memory window segment", f); return; } /* Retrieve the associated window. */ struct w_window *window = w_get_window(&procServ.windowList, aw->winID); if (!window) { output_segmentation_fault("invalid memory window - procserv book-keeping error.", f); assert(!"Process server could not find window - book-keeping error."); return; } /* Check window permissions. */ if (f->read && !(window->permissions | W_PERMISSION_READ)) { output_segmentation_fault("no read access permission to window.", f); return; } if (!f->read && !(window->permissions | W_PERMISSION_WRITE)) { output_segmentation_fault("no write access permission to window.", f); return; } /* Check that there isn't a page entry already mapped. */ cspacepath_t pageEntry = vs_get_frame(&f->pcb->vspace, f->faultAddr); if (pageEntry.capPtr != 0) { output_segmentation_fault("entry already occupied; book-keeping error.", f); return; } /* Handle the dispatch request depending on window mode. */ int error = EINVALID; switch (window->mode) { case W_MODE_EMPTY: output_segmentation_fault("fault in empty window.", f); break; case W_MODE_ANONYMOUS: error = handle_vm_fault_dspace(m, f, aw, window); break; case W_MODE_PAGER: error = handle_vm_fault_pager(m, f, aw, window); break; default: assert(!"Invalid window mode. Process server bug."); break; } /* Reply to the faulting process to unblock it. */ if (error == ESUCCESS) { seL4_Reply(_dispatcherEmptyReply); } }
/*! @brief Handles faults on windows mapped to anonymous memory. This function is responsible for handling VM faults on windows which have been mapped to the process server's own anonymous dataspaces, including ones that have been content-initialised. If the dataspace has been set to content-initialised, then we will need to delegate and save the reply cap to reply to it once the content has been initialised. If it has not been initialised we simply map the dataspace page and reply. @param m The recieved IPC fault message from the kernel. @param f The VM fault message info struct. @param aw Found associated window of the faulting address & client. @param window The window structure of the faulting address & client. @return ESUCCESS on success, refos_err_t otherwise. */ static int handle_vm_fault_dspace(struct procserv_msg *m, struct procserv_vmfault_msg *f, struct w_associated_window *aw, struct w_window *window) { assert(f && f->pcb); assert(aw && window && window->mode == W_MODE_ANONYMOUS); vaddr_t dspaceOffset = (f->faultAddr + window->ramDataspaceOffset) - REFOS_PAGE_ALIGN(aw->offset); struct ram_dspace *dspace = window->ramDataspace; assert(dspace && dspace->magic == RAM_DATASPACE_MAGIC); dvprintf("# PID %d VM fault ―――――▶ anon RAM dspace %d\n", f->pcb->pid, dspace->ID); if (dspace->contentInitEnabled) { /* Data space is backed by external content. Content initialisation delegation. */ int contentInitState = ram_dspace_need_content_init(dspace, dspaceOffset); if (contentInitState < 0) { output_segmentation_fault("Failed to retrieve content-init state.", f); return EINVALID; } if (contentInitState == true) { /* Content has not yet been initialised so we delegate. */ if (f->faultAddr + window->ramDataspaceOffset >= aw->offset + aw->size) { output_segmentation_fault("Fault address out of range!", f); return EINVALID; } /* Find the pager's PCB. */ assert(dspace->contentInitPID != PID_NULL); struct proc_pcb* cinitPCB = pid_get_pcb(&procServ.PIDList, dspace->contentInitPID); if (!cinitPCB) { output_segmentation_fault("Invalid content initialiser PID.", f); return EINVALID; } if (!dspace->contentInitEP.capPtr) { output_segmentation_fault("Invalid content-init endpoint!", f); return EINVALID; } /* Save the reply endpoint. */ int error = ram_dspace_add_content_init_waiter_save_current_caller(dspace, dspaceOffset); if (error != ESUCCESS) { output_segmentation_fault("Failed to save reply cap as dspace waiter!", f); return EINVALID; } /* Set up and send the fault notification. */ struct proc_notification vmFaultNotification; vmFaultNotification.magic = PROCSERV_NOTIFICATION_MAGIC; vmFaultNotification.label = PROCSERV_NOTIFY_CONTENT_INIT; vmFaultNotification.arg[0] = dspace->ID; vmFaultNotification.arg[1] = REFOS_PAGE_ALIGN(dspaceOffset); fault_delegate_notification(f, cinitPCB, dspace->contentInitEP, vmFaultNotification, false); /* Return an error here to avoid resuming the client. */ return EDELEGATED; } /* Fallthrough to normal dspace mapping if content-init state is set to already provided. */ } /* Get the page at the dataspaceOffset into the dataspace. */ seL4_CPtr frame = ram_dspace_get_page(dspace, dspaceOffset); if (!frame) { output_segmentation_fault("Out of memory to allocate page or read off end of dspace.", f); return ENOMEM; } /* Map this frame into the client process's page directory. */ int error = vs_map(&f->pcb->vspace, f->faultAddr, &frame, 1); if (error != ESUCCESS) { output_segmentation_fault("Failed to map frame into client's vspace at faultAddr.", f); return error; } return ESUCCESS; }
int srv_dispatch_notification(srv_common_t *srv, srv_common_notify_handler_callbacks_t callbacks) { assert(srv && srv->magic == SRV_MAGIC); /* Allocate a notification structure. */ struct proc_notification *notification = malloc(sizeof(struct proc_notification)); if (!notification) { dprintf("Out of memory while creating notification struct.\n"); return DISPATCH_ERROR; } dvprintf("%s recieved fault notification!\n", srv->config.serverName); data_mapping_t *nb = &srv->notifyBuffer; uint32_t bytesRead = 0; int error = DISPATCH_PASS; while (1) { bytesRead = 0; error = refos_share_read ( (char*) notification, sizeof(struct proc_notification), nb->vaddr, nb->size, &srv->notifyBufferStart, &bytesRead ); if (!error && bytesRead == 0) { /* No more notifications to read. */ break; } if (error || bytesRead != sizeof(struct proc_notification)) { /* Error during reading notification. */ dprintf("Could not read information from notification buffer!\n"); dprintf(" error = %d\n, read = %d", error, bytesRead); free(notification); return DISPATCH_ERROR; } /* Paranoid sanity check here. */ assert(notification->magic == PROCSERV_NOTIFICATION_MAGIC); error = DISPATCH_ERROR; switch (notification->label) { case PROCSERV_NOTIFY_FAULT_DELEGATION: if (callbacks.handle_server_fault) { error = callbacks.handle_server_fault(notification); break; } case PROCSERV_NOTIFY_CONTENT_INIT: if (callbacks.handle_server_content_init) { error = callbacks.handle_server_content_init(notification); break; } case PROCSERV_NOTIFY_DEATH: if (callbacks.handle_server_death_notification) { error = callbacks.handle_server_death_notification(notification); break; } default: /* Should never get here. */ ROS_WARNING("Unknown notification.\n"); assert(!"Unknown notification."); break; } } if (error) { ROS_WARNING("Notification handling error on %s: %d\n", srv->config.serverName, error); } free(notification); return error; }
int toscar_flap_handleread(struct nafmodule *mod, struct nafconn *conn) { naf_u8_t *buf; int buflen; int hret = HRET_FORWARD; if (naf_conn_takeread(conn, &buf, &buflen) == -1) return -1; if (FLAPHDR_MAGIC(buf) != FLAP_MAGIC) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] FLAP packet did not start with correct magic\n", conn->cid); goto errout; } /* XXX check seqnums */ if (! ( (FLAPHDR_CHAN(buf) == 0x01) || (FLAPHDR_CHAN(buf) == 0x02) || (FLAPHDR_CHAN(buf) == 0x04) || (FLAPHDR_CHAN(buf) == 0x05) ) ) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] FLAP packet on invalid channel\n", conn->cid); goto errout; } if (FLAPHDR_LEN(buf) > MAXSNACLEN) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] FLAP packet contained invalid length\n", conn->cid); goto errout; } if (buflen != (FLAPHDR_LEN(buf) + FLAPHDRLEN)) { if (naf_conn_reqread(conn, buf, buflen + FLAPHDR_LEN(buf), buflen) == -1) { if (timps_oscar__debug > 0) dvprintf(mod, "[cid %lu] naf refused further read request\n", conn->cid); goto errout; } return 0; /* continue later */ } if (timps_oscar__debug > 1) dvprintf(mod, "[cid %lu] received full FLAP packet on channel 0x%02x, seqnum 0x%04lx, length 0x%04lx (%d bytes)\n", conn->cid, FLAPHDR_CHAN(buf), FLAPHDR_SEQNUM(buf), FLAPHDR_LEN(buf), FLAPHDR_LEN(buf)); if (FLAPHDR_CHAN(buf) == 0x01) hret = toscar_flap_handlechan1(mod, conn, buf, (naf_u16_t)buflen); else if (FLAPHDR_CHAN(buf) == 0x02) hret = toscar_flap_handlesnac(mod, conn, buf + FLAPHDRLEN, (naf_u16_t)(buflen - FLAPHDRLEN)); else if (FLAPHDR_CHAN(buf) == 0x04) hret = toscar_flap_handlechan4(mod, conn, buf, (naf_u16_t)buflen); else if (FLAPHDR_CHAN(buf) == 0x05) hret = toscar_flap_handlechan5(mod, conn, buf, (naf_u16_t)buflen); if (hret == HRET_ERROR) goto errout; else if ((hret == HRET_FORWARD) && conn->endpoint) { if (toscar_flap__sendraw(mod, conn->endpoint, buf, (naf_u16_t)buflen) == -1) goto errout; buf = NULL; /* consumed by sendraw */ } /* * HRET_DIGESTED means the packet was processed but should not be * forwarded -- it was not consumed, in the memory management sense, so * we can reuse it. */ /* go again... */ if (toscar_flap__reqflap(mod, conn, buf) == -1) goto errout; return 0; errout: naf_free(mod, buf); return -1; }