ut_cleanup() { os_closesocket(server_sock); os_closesocket(client_sock); os_closesocket(accept_sock); os_net_cleanup(); }
/** select a free connection * * \param[in] sock_xml: socket on which it receives commands. */ static void handle_connection(int msg_sock) { int i; static cl_error_desc_t busy = { .code = -EXA_ERR_ADM_BUSY, .msg = "Too many connections."}; /* Search free slot in connection array */ for (i = 0; i < MAX_CONNECTION; i++) { if (connectlist[i].uid == CMD_UID_INVALID && connectlist[i].fd == -1) { exalog_debug("CONNECTION %d: Using sock %d", i, msg_sock); /* uid is set when the command is actually scheduled */ connectlist[i].fd = msg_sock; FD_SET(msg_sock, &setSocks); return; } } /* * No free connection found. We disconnect the caller now because we * are no room in our connectionlist */ exalog_error("All connections are busy sock=%d", msg_sock); cli_command_end_complete(msg_sock, &busy); os_closesocket(msg_sock); } /*-------------------------------------------------------------------------*/ /** \brief Connection thread: wait on xml message to pass the command * to the work thread. * * \param[in] sock_xml_proto: socket xml on which it receives commands. * \return the selected working thread or a negative error code * */ /*-------------------------------------------------------------------------*/ static void accept_new_client(void) { int fd = os_accept(listen_fd, NULL, NULL); exalog_debug("Got an incoming XML Request on socket: %d", fd); if (fd < 0) { exalog_error("Failed during admind xml connection accept: error=%s", exa_error_msg(-fd)); return; } handle_connection(fd); }
/*-------------------------------------------------------------------------*/ static void close_connection(int connection_id) { int cli_fd = connectlist[connection_id].fd; EXA_ASSERT_VERBOSE(cli_fd > 2 , "fd = %d", cli_fd); FD_CLR(cli_fd, &setSocks); os_closesocket(cli_fd); exalog_debug("CONNECTION: %d Socket %d closed state_work NOT_USED", connection_id, cli_fd); /* Do not reset uid and free field because there may be a command still * running on the worker thread. Those fields will be reset when it ends. */ connectlist[connection_id].fd = -1; }
static void __close_socket(int sock) { os_shutdown(sock, SHUT_RDWR); os_closesocket(sock); }
static void check_internal_msg(void) { struct timeval timeout = { .tv_sec = 0, .tv_usec = EXAMSG_TIMEOUT }; static Examsg msg; command_end_t *end; int i, ret; ret = examsgWaitTimeout(cli_mh, &timeout); if (ret < 0 && ret != -ETIME) { exalog_error("Message wait failed %s (%d)", exa_error_msg(ret), ret); return; } if (ret == -ETIME) return; ret = examsgRecv(cli_mh, NULL, &msg, sizeof(msg)); if (ret == 0) return; EXA_ASSERT_VERBOSE(ret > 0, "Message receive failed: %s (%d)", exa_error_msg(ret), ret); if (ret < 0) exalog_error("Message receive failed: %s (%d)", exa_error_msg(ret), ret); /* The CLI server can only receive EXAMSG_ADM_CLUSTER_CMD_END messages for now */ EXA_ASSERT(msg.any.type == EXAMSG_ADM_CLUSTER_CMD_END); end = (command_end_t *)msg.payload; for (i = 0; i < MAX_CONNECTION; i++) if (end->cuid == connectlist[i].uid) { cli_command_end_complete(connectlist[i].fd, &end->err_desc); connectlist[i].uid = CMD_UID_INVALID; break; } EXA_ASSERT(i < MAX_CONNECTION); } static void check_tcp_connection(void) { static struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; fd_set setSave = setSocks; int ret, conn_id; do ret = os_select(FD_SETSIZE, &setSave, NULL, NULL, &timeout); while (ret == -EINTR); if (ret < 0) { /* FIXME should assert ? */ exalog_debug("Select failed %m"); return; } /* Check working sockets */ for (conn_id = 0; conn_id < MAX_CONNECTION; ++conn_id) { int sock_fd = connectlist[conn_id].fd; if (sock_fd >= 0 && FD_ISSET(sock_fd, &setSave)) handle_inputdata(conn_id, sock_fd); } /* Must be done at the end to make sure messages for current * working threads are processed first */ if (FD_ISSET(listen_fd, &setSave)) accept_new_client(); } /*-------------------------------------------------------------------------*/ /** \brief Connection thread: wait on xml message and pass the command * to the work thread. * * \param[in] sock_xml: socket xml on which it receives commands. * */ /*-------------------------------------------------------------------------*/ static void cli_server(void *data) { int i; /* Initialize exalog */ exalog_as(EXAMSG_ADMIND_ID); exalog_debug("cli_server: started"); /* Initialization */ FD_ZERO(&setSocks); FD_SET(listen_fd, &setSocks); for (i = 0; i < MAX_CONNECTION; i++) { connectlist[i].fd = -1; /* A command cannot be CMD_UID_INVALID, so CMD_UID_INVALID means here * no command running */ connectlist[i].uid = CMD_UID_INVALID; } while (!stop) { check_tcp_connection(); check_internal_msg(); } os_closesocket(listen_fd); os_net_cleanup(); examsgDelMbox(cli_mh, EXAMSG_ADMIND_CLISERVER_ID); examsgExit(cli_mh); } int cli_server_start(void) { listen_fd = listen_socket_port(ADMIND_SOCKET_PORT); if (listen_fd < 0) return listen_fd; cli_mh = examsgInit(EXAMSG_ADMIND_CLISERVER_ID); if (!cli_mh) return -EINVAL; /* The mailbox needs to be able to receive command end messages from the * event manager; as there can be at most MAX_CONNECTION client connections * we can receive at the time at most 10 command end messages. */ examsgAddMbox(cli_mh, EXAMSG_ADMIND_CLISERVER_ID, MAX_CONNECTION, sizeof(command_end_t)); stop = false; if (!exathread_create_named(&thr_xml_proto, ADMIND_THREAD_STACK_SIZE+MIN_THREAD_STACK_SIZE, &cli_server, NULL, "exa_adm_xml")) return -EXA_ERR_DEFAULT; return EXA_SUCCESS; }