/* Process incoming commands */ void cmd_process_msg() { struct pm_msg_generic msg; INT32 task_id, retval; struct pm_task *tsk; struct pm_thread *thr; UINT16 destroy_task_id; struct pending_command *cmd = NULL, *ocmd = NULL; struct pm_msg_phymem_response pres; /* For some commands like FMAP, we should only process one command at the same time for each task. */ /* Add commands to the queue. */ while(get_msg_count(PMAN_COMMAND_PORT) > 0) { if(shutting_down) { cmd_shutdown_step(); } else if(get_msg(PMAN_COMMAND_PORT, &msg, &task_id) == SUCCESS) { switch(msg.pm_type) { case PM_LOADER_READY: { // destroy the SMO sent to the task for phdrs tsk = tsk_get(task_id); if(tsk != NULL) { loader_ready(tsk); } break; } case PM_PHYMEM: { /* if it's a service, it's entitled to know it's physical memory base address. */ tsk = tsk_get(task_id); if(tsk != NULL && (tsk->flags & (TSK_FLAG_SERVICE|TSK_LOW_MEM))==(TSK_FLAG_SERVICE|TSK_LOW_MEM)) { pres.pm_type = msg.pm_type; pres.req_id = msg.req_id; pres.physical = (UINT32)vmm_get_physical(task_id, (ADDR)((UINT32)((struct pm_msg_phymem*)&msg)->linear + SARTORIS_PROCBASE_LINEAR)); send_msg(task_id, msg.response_port, &pres); } break; } case PM_SHUTDOWN: { /* Begin shutdown */ cmd_shutdown_step(); break; } case PM_DBG_ATTACH: { cmd_begin_debug(task_id, (struct pm_msg_dbgattach*)&msg); break; } case PM_DBG_END: { cmd_end_debug(task_id, (struct pm_msg_dbgend*)&msg); break; } case PM_DBG_TRESUME: { cmd_resumethr_debug(task_id, (struct pm_msg_dbgtresume*)&msg); break; } case PM_LOAD_LIBRARY: { tsk = tsk_get(task_id); if(!tsk) break; cmd_load_library((struct pm_msg_loadlib *)&msg, task_id); break; } case PM_CREATE_TASK: { tsk = tsk_get(task_id); if(!tsk) break; cmd_create_task((struct pm_msg_create_task *)&msg, tsk); break; } case PM_CREATE_THREAD: { cmd_create_thread((struct pm_msg_create_thread*)&msg, task_id); break; } case PM_DESTROY_TASK: { destroy_task_id = ((struct pm_msg_destroy_task*)&msg)->task_id; // If sender is the task itself ignore it if(task_id == destroy_task_id) break; /* Trying to destroy PMAN? */ if(destroy_task_id == PMAN_TASK) { /* Suffer The concecuences!!!!!! */ fatal_exception(task_id, PMAN_RULEZ); break; } tsk = tsk_get(destroy_task_id); // if it's not the creator task, ignore it if(tsk->creator_task != task_id) { cmd_inform_result(&msg, task_id, PM_ERROR, 0, 0); break; } if(tsk && tsk->state != TSK_KILLING && tsk->state != TSK_KILLED) { // If task is executing a command, fail if(tsk->command_inf.executing != NULL) { cmd_inform_result(&msg, task_id, PM_TASK_RETRY_LATER, 0, 0); break; } // deactivate task threads thr = tsk->first_thread; while(thr) { sch_deactivate(thr); thr = thr->next_thread; } /* Remove all pending commands on the queue for this task */ cmd_queue_remove_bytask(tsk); tsk->command_inf.ret_value = ((struct pm_msg_destroy_task*)&msg)->ret_value; tsk->command_inf.command_sender_id = task_id; tsk->command_inf.command_req_id = msg.req_id; tsk->command_inf.command_ret_port = msg.response_port; tsk->state = TSK_KILLING; tsk->io_finished.callback = cmd_task_fileclosed_callback; io_begin_close( &tsk->io_event_src ); } else { cmd_inform_result(&msg, task_id, PM_TASK_ID_INVALID, 0, 0); } break; } case PM_DESTROY_THREAD: { tsk = NULL; thr = thr_get(((struct pm_msg_destroy_thread*)&msg)->thread_id); destroy_task_id = thr->task_id; thr = NULL; /* Trying to destroy PMAN threads? */ if(destroy_task_id == PMAN_TASK) { /* Suffer The concecuences!!!!!! */ fatal_exception(task_id, PMAN_RULEZ); break; } /* Is it a request from a different process? */ if(destroy_task_id != task_id) { cmd_inform_result(&msg, task_id, PM_ERROR, 0, 0); break; } tsk = tsk_get(destroy_task_id); struct dbg_message dbg_msg; if(tsk && tsk->state == TSK_NORMAL) { if(thr_destroy_thread(((struct pm_msg_destroy_thread*)&msg)->thread_id)) { if(tsk->flags & TSK_DEBUG) { dbg_msg.task = destroy_task_id; dbg_msg.thread = thr->id; dbg_msg.command = DEBUG_THR_DESTROYED; send_msg(tsk->dbg_task, tsk->dbg_port, &dbg_msg); } cmd_inform_result(&msg, task_id, PM_OK, 0, 0); } else cmd_inform_result(&msg, task_id, PM_ERROR, 0, 0); } else { if(!tsk) cmd_inform_result(&msg, task_id, PM_TASK_ID_INVALID, 0, 0); else cmd_inform_result(&msg, task_id, PM_ERROR, 0, 0); } break; } case PM_TASK_FINISHED: { tsk = tsk_get(task_id); if(tsk != NULL && tsk->state == TSK_NORMAL) { tsk->command_inf.ret_value = ((struct pm_msg_finished*)&msg)->ret_value; tsk->command_inf.command_sender_id = 0; tsk->command_inf.command_req_id = -1; tsk->command_inf.command_ret_port = -1; // deactivate task threads thr = tsk->first_thread; while(thr) { sch_deactivate(thr); thr = thr->next_thread; } cmd_queue_remove_bytask(tsk); tsk->state = TSK_KILLING; tsk->io_finished.callback = cmd_task_fileclosed_callback; io_begin_close( &tsk->io_event_src ); } else { if(!tsk) cmd_inform_result(&msg, task_id, PM_TASK_ID_INVALID, 0, 0); else cmd_inform_result(&msg, task_id, PM_ERROR, 0, 0); } break; } default: { tsk = tsk_get(task_id); if(tsk != NULL && tsk->state == TSK_NORMAL) { if(!cmd_queue_add(&msg, (UINT16)task_id)) { cmd_inform_result(&msg, task_id, PM_NOT_ENOUGH_MEM, 0, 0); } } else { cmd_inform_result(&msg, task_id, PM_TASK_ID_INVALID, 0, 0); } } } } } /* Attempt to process commands on the queue. */ cmd = command_queue.first; while(cmd != NULL) { pman_print_dbg("COMMAND.c: Got a queue COMMAND! task: %i cmd: %i\n", (cmd->sender_task & 0x0000FFFF), msg.pm_type); if(process_queue_msg(cmd)) { ocmd = cmd; cmd = cmd->next; cmd_queue_remove(ocmd); } else { cmd = cmd->next; } } }
static void mapidcom() //Communicates with clients through IPC { fd_set active_fd_set; // active file descriptor list fd_set read_fd_set; // temp file descriptor list for select() int fdmax; // maximum file descriptor number int yes = 1; // for setsockopt() SO_REUSEADDR, below struct sockaddr_un mapidaddr; struct sockaddr_un remoteaddr; struct mapiipcbuf qbuf; socklen_t addrlen; int nbytes, len, s; struct client *cl= NULL; flist_node_t *tmpnode; conf_category_entry_t *cat=NULL; char *local; struct group *mapi_group; conf_category_t *conf; mapidsocket=strdup(MAPIDSOCKGLOBAL); if ((conf = pc_load(mapid_conf)) != NULL) { cat = pc_get_category(conf, ""); local=pc_get_param(cat, "local"); if (local!=NULL && strcmp(local, "1")==0) { free(mapidsocket); mapidsocket=printf_string(MAPIDSOCKHOME, getenv("HOME") ); } pc_close(conf); } // create the listener socket if ((listenerfd = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { DEBUG_CMD(Debug_Message("ERROR: socket: %s", strerror(errno))); exit(EXIT_FAILURE); } // avoid "address already in use" error message if (setsockopt(listenerfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { DEBUG_CMD(Debug_Message("ERROR: setsockopt: %s", strerror(errno))); exit(EXIT_FAILURE); } // set up the address we will be binding to memset(&mapidaddr, 0, sizeof (mapidaddr)); mapidaddr.sun_family = AF_LOCAL; memcpy(mapidaddr.sun_path, mapidsocket, strlen(mapidsocket)+1); unlink(mapidsocket); len = sizeof mapidaddr.sun_family + strlen(mapidaddr.sun_path); if (bind(listenerfd, (struct sockaddr *) &mapidaddr, len)) { DEBUG_CMD(Debug_Message("ERROR: bind: %s", strerror(errno))); exit(EXIT_FAILURE); } // allow any member of our own group to connect chmod(mapidsocket, S_IRWXU | S_IRWXG); // if a mapi user group exists, set group permissions accordingly, // otherwise the group ID will be equal to the user ID of the user that // invoked mapid mapi_group = getgrnam(MAPI_GROUP_NAME); if (mapi_group != NULL) { chown(mapidsocket, -1, mapi_group->gr_gid); } if (listen(listenerfd, BACKLOG) == -1) { DEBUG_CMD(Debug_Message("ERROR: listen: %s", strerror(errno))); exit(EXIT_FAILURE); } FD_ZERO (&active_fd_set); // add the listener to the active set FD_SET (listenerfd, &active_fd_set) ; // keep track of the biggest file descriptor fdmax = listenerfd; // so far, it's just this one // wait for commands from the mapi stub, for ever... while (1) { read_fd_set = active_fd_set; // copy it if (select(fdmax + 1, &read_fd_set, NULL, NULL, NULL) == -1) { DEBUG_CMD(Debug_Message("ERROR: select: %s", strerror(errno))); break; } // run through the existing connections for (s = 0; s <= fdmax; s++) { if (FD_ISSET (s, &read_fd_set)) { // connection on the original listener socket if (s == listenerfd) { addrlen = sizeof (remoteaddr); if ((newfd = accept(listenerfd, (struct sockaddr *) &remoteaddr, &addrlen)) == -1) { DEBUG_CMD(Debug_Message("accept: %s", strerror(errno))); } else { FD_SET (newfd, &active_fd_set) ; // add to active set if (newfd > fdmax) { // keep track of the maximum fdmax = newfd; } } } // handle data from an existing client else { if ((nbytes = recv (s, &qbuf, MAX_SEND_SIZE, 0)) <= 0) { if (nbytes == 0) { // connection closed - find client's pid while(__sync_lock_test_and_set(&clientlist_lock,1)); tmpnode = (flist_node_t *) flist_head (clientlist); cl = NULL; while (tmpnode != NULL) { if (((struct client *) tmpnode->data)->sock == s) { cl = (struct client *) tmpnode->data; break; } tmpnode = flist_next (tmpnode); } clientlist_lock = 0; if (cl == NULL) {/* This is not interesting, as it will occur upon requests from clients without flows etc. WARNING_CMD (printf ("WARNING: Zero bytes from socket %d [%s:%d]\n", s, __FILE__, __LINE__)); */ /* shouldn't really exit here? * this will cause the program to exit on errors with an empty * client-list which isn't really an error (IMHO) */ //exit(EXIT_FAILURE); } else { while(__sync_lock_test_and_set(&clientlist_lock,1)); //clean up any remaining flows tmpnode = (flist_node_t *) flist_head (cl->flowlist); while (tmpnode != NULL) { cleanup_flow ((struct flow *) tmpnode->data); tmpnode = flist_next (tmpnode); } tmpnode = (flist_node_t *) flist_head (cl->devicelist); while (tmpnode != NULL) { mapidrv_delete_device = get_drv_funct (tmpnode->data, "mapidrv_delete_device"); mapidrv_delete_device (tmpnode->id); tmpnode = flist_next (tmpnode); } flist_destroy (cl->flowlist); flist_destroy (cl->devicelist); free(cl->devicelist); free (cl->flowlist); //remove this client from global client list free(flist_remove (clientlist, cl->pid)); clientlist_lock = 0; } } else { DEBUG_CMD(Debug_Message("WARNING: recv: %s at", strerror (errno))); } close (s); FD_CLR (s, &active_fd_set); // remove it from active set } else { // we got some data from a client: process request switch (qbuf.cmd) { case GET_LIBS: cmd_get_libs (qbuf.pid, s); break; case GET_LIBPATH: cmd_get_libpath (qbuf.pid, s); break; case CREATE_FLOW: cmd_create_flow ((char *)qbuf.data, qbuf.pid, qbuf.uid, s); break; case CLOSE_FLOW: cmd_close_flow (qbuf.fd, qbuf.pid, s, 1); break; case GET_FLOW_INFO: cmd_get_flow_info (qbuf.fd, qbuf.pid, s); break; case GET_FUNCTION_INFO: cmd_get_function_info (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case GET_NEXT_FUNCTION_INFO: cmd_get_next_function_info (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case GET_NEXT_FLOW_INFO: cmd_get_next_flow_info (qbuf.fd, qbuf.pid, s); break; case GET_NEXT_DEVICE_INFO: cmd_get_next_device_info (qbuf.fd, qbuf.pid, s); break; case GET_DEVICE_INFO: cmd_get_device_info (qbuf.fd, qbuf.pid, s); break; case MAPI_STATS: cmd_stats ((char *)qbuf.data, qbuf.pid, qbuf.uid, s); break; case APPLY_FUNCTION: cmd_apply_function (&qbuf, qbuf.pid, s); break; case READ_RESULT: cmd_read_results (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case CONNECT: cmd_connect (qbuf.fd, qbuf.pid, s); break; case CREATE_FLOW_ACK: case APPLY_FUNCTION_ACK: case READ_RESULT_ACK: case CONNECT_ACK: case CLOSE_FLOW_ACK: case SET_AUTHDATA_ACK: break; case READ_ERROR_ACK: break; case ERROR_ACK: break; case CREATE_OFFLINE_DEVICE: cmd_create_offline_device ((char *)qbuf.data, qbuf.fid, qbuf.pid, s); break; case CREATE_OFFLINE_DEVICE_ACK: break; case START_OFFLINE_DEVICE: cmd_start_offline_device ((char *)qbuf.data, qbuf.pid, s); break; case START_OFFLINE_DEVICE_ACK: break; case DELETE_OFFLINE_DEVICE: cmd_delete_offline_device ((char *)qbuf.data, qbuf.pid, s); break; case DELETE_OFFLINE_DEVICE_ACK: break; case CREATE_OFFLINE_FLOW_ACK: break; case LOAD_LIBRARY: cmd_load_library ((char *)qbuf.data, qbuf.pid, s); default: break; } } } } } // for } // while(1) }