rbn *os_select(rbn *x, int i) { int r; r = x->left->size + 1; if (i == r) return os_select(x->left, i); else return os_select(x->right, i - r); }
int exa_select_out(exa_select_handle_t *h, fd_set *set) { #if WIN32 int nb_sock; EXA_ASSERT_VERBOSE(h->magic == EXA_SELECT_MAGIC, "Corrupted handle detected %d", h->magic); nb_sock = os_select(0 /* ignored */, NULL, set, NULL, &select_timeout); if (nb_sock == 0) /* timeout is reached */ { /* reset set because there was actually no event on sockets */ FD_ZERO(set); return -EFAULT; } return nb_sock > 0 ? 0 : nb_sock; #else if (ioctl(h->fd, EXA_SELECT_OUT, set) == -1) return -errno; return 0; #endif }
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; }
int main(int argc, char *argv[]) { int listenfd; int connfd; int on = 1; struct sockaddr_in serv_addr, cli_addr; socklen_t cli_len; int client_fd[FD_SETSIZE];/* each for every client */ fd_set allset; /* save interested descriptors */ fd_set rdset; /* select on this set */ int maxfd; int max_indx; /* max index in client_fd[] array */ int i, n; int nready; char buf[MAXLINE]; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket error: %s\n", strerror(errno)); exit(1); } os_setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(SERV_PORT); if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr, "bind error: %s\n", strerror(errno)); exit(1); } if (listen(listenfd, LISTEN_QUEUE) < 0) { fprintf(stderr, "listern error: %s\n", strerror(errno)); exit(1); } for (i=0; i < FD_SETSIZE; i++) client_fd[i] = -1; FD_ZERO(&allset); FD_SET(listenfd, &allset); maxfd = listenfd; max_indx = 0; for (; ;) { rdset = allset; nready = os_select(maxfd + 1, &rdset, NULL, NULL, NULL); /* select will modify rdset once return */ /* task 1: listen... accept new connection */ if(FD_ISSET(listenfd, &rdset)) { cli_len = sizeof(cli_addr); connfd = os_accept(listenfd, (struct sockaddr *)&cli_addr, &cli_len); for (i=0; i < FD_SETSIZE; i++) { /* a new client coming, select a useable fd */ if (client_fd[i] == -1) { client_fd[i] = connfd; maxfd = (connfd > maxfd) ? connfd : maxfd; break; } } FD_SET(connfd, &allset); if (i > max_indx) max_indx = i; if (--nready <= 0) continue; /* no more readable descriptors */ } /* task 2: deal with all clients' data */ for (i=0; i < maxfd; i++) { if (client_fd[i] == -1) continue; if (FD_ISSET(client_fd[i], &rdset)) { if ((n = os_read(client_fd[i], buf, MAXLINE)) == 0) { close(client_fd[i]); FD_CLR(client_fd[i], &allset); client_fd[i] = -1; } else { #ifdef DEBUG os_write(fileno(stdout), buf, n); #endif os_write(client_fd[i], buf, n); } } if (--nready <= 0) break; /* no more readable descriptors */ } #if 0 cli_len = sizeof(cli_addr); if ((connfd = accept(listenfd, (struct sockaddr *)&cli_addr, &cli_len)) < 0) { if (errno == EINTR) continue; else os_err_sys("accept error"); } if ((childpid = fork()) == 0) { close(listenfd); echo_string(connfd); exit(1); } close(connfd); #endif } return 0; }