static struct ns_connection *accept_conn(struct ns_connection *ls) { struct ns_connection *c = NULL; union socket_address sa; socklen_t len = sizeof(sa); sock_t sock = INVALID_SOCKET; /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */ if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) { } else if ((c = ns_add_sock(ls->mgr, sock, ls->handler)) == NULL) { closesocket(sock); #ifdef NS_ENABLE_SSL } else if (ls->ssl_ctx != NULL && ((c->ssl = SSL_new(ls->ssl_ctx)) == NULL || SSL_set_fd(c->ssl, sock) != 1)) { DBG(("SSL error")); ns_close_conn(c); c = NULL; #endif } else { c->listener = ls; c->proto_data = ls->proto_data; c->proto_handler = ls->proto_handler; c->user_data = ls->user_data; ns_call(c, NS_ACCEPT, &sa); DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl)); } return c; }
time_t ns_mgr_poll(struct ns_mgr *mgr, int timeout_ms) { int epoll_fd = (intptr_t) mgr->mgr_data; struct epoll_event events[NS_EPOLL_MAX_EVENTS]; struct ns_connection *nc, *next; int num_ev, fd_flags; time_t now; num_ev = epoll_wait(epoll_fd, events, NS_EPOLL_MAX_EVENTS, timeout_ms); now = time(NULL); DBG(("epoll_wait @ %ld num_ev=%d", (long) now, num_ev)); while (num_ev-- > 0) { intptr_t epf; struct epoll_event *ev = events + num_ev; nc = (struct ns_connection *) ev->data.ptr; if (nc == NULL) { ns_mgr_handle_ctl_sock(mgr); continue; } fd_flags = ((ev->events & (EPOLLIN | EPOLLHUP)) ? _NSF_FD_CAN_READ : 0) | ((ev->events & (EPOLLOUT)) ? _NSF_FD_CAN_WRITE : 0) | ((ev->events & (EPOLLERR)) ? _NSF_FD_ERROR : 0); ns_mgr_handle_connection(nc, fd_flags, now); epf = (intptr_t) nc->mgr_data; epf ^= _NS_EPF_NO_POLL; nc->mgr_data = (void *) epf; } for (nc = mgr->active_connections; nc != NULL; nc = next) { next = nc->next; if (!(((intptr_t) nc->mgr_data) & _NS_EPF_NO_POLL)) { ns_mgr_handle_connection(nc, 0, now); } else { intptr_t epf = (intptr_t) nc->mgr_data; epf ^= _NS_EPF_NO_POLL; nc->mgr_data = (void *) epf; } if ((nc->flags & NSF_CLOSE_IMMEDIATELY) || (nc->send_mbuf.len == 0 && (nc->flags & NSF_SEND_AND_CLOSE))) { ns_close_conn(nc); } else { ns_ev_mgr_epoll_ctl(nc, EPOLL_CTL_MOD); } } return now; }
void ns_mgr_free(struct ns_mgr *s) { struct ns_connection *conn, *tmp_conn; DBG(("%p", s)); if (s == NULL) return; /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */ ns_mgr_poll(s, 0); if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]); if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]); s->ctl[0] = s->ctl[1] = INVALID_SOCKET; for (conn = s->active_connections; conn != NULL; conn = tmp_conn) { tmp_conn = conn->next; ns_close_conn(conn); } ns_ev_mgr_free(s); }
/* * This function performs the actual IO, and must be called in a loop * (an event loop). Returns the current timestamp. */ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) { struct ns_connection *nc, *tmp; struct timeval tv; fd_set read_set, write_set, err_set; sock_t max_fd = INVALID_SOCKET; time_t current_time = time(NULL); FD_ZERO(&read_set); FD_ZERO(&write_set); FD_ZERO(&err_set); ns_add_to_set(mgr->ctl[1], &read_set, &max_fd); for (nc = mgr->active_connections; nc != NULL; nc = tmp) { tmp = nc->next; if (!(nc->flags & (NSF_LISTENING | NSF_CONNECTING))) { ns_call(nc, NS_POLL, ¤t_time); } /* * NS_POLL handler could have signaled us to close the connection * by setting NSF_CLOSE_IMMEDIATELY flag. In this case, we don't want to * trigger any other events on that connection, but close it right away. */ if (nc->flags & NSF_CLOSE_IMMEDIATELY) { /* NOTE(lsm): this call removes nc from the mgr->active_connections */ ns_close_conn(nc); continue; } if (!(nc->flags & NSF_WANT_WRITE)) { /*DBG(("%p read_set", nc)); */ ns_add_to_set(nc->sock, &read_set, &max_fd); } if (((nc->flags & NSF_CONNECTING) && !(nc->flags & NSF_WANT_READ)) || (nc->send_iobuf.len > 0 && !(nc->flags & NSF_CONNECTING) && !(nc->flags & NSF_BUFFER_BUT_DONT_SEND))) { /*DBG(("%p write_set", nc)); */ ns_add_to_set(nc->sock, &write_set, &max_fd); ns_add_to_set(nc->sock, &err_set, &max_fd); } } tv.tv_sec = milli / 1000; tv.tv_usec = (milli % 1000) * 1000; if (select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv) > 0) { /* select() might have been waiting for a long time, reset current_time * now to prevent last_io_time being set to the past. */ current_time = time(NULL); /* Read wakeup messages */ if (mgr->ctl[1] != INVALID_SOCKET && FD_ISSET(mgr->ctl[1], &read_set)) { struct ctl_msg ctl_msg; int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0); send(mgr->ctl[1], ctl_msg.message, 1, 0); if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) { struct ns_connection *c; for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) { ctl_msg.callback(c, NS_POLL, ctl_msg.message); } } } for (nc = mgr->active_connections; nc != NULL; nc = tmp) { tmp = nc->next; /* Windows reports failed connect() requests in err_set */ if (FD_ISSET(nc->sock, &err_set) && (nc->flags & NSF_CONNECTING)) { nc->last_io_time = current_time; ns_read_from_socket(nc); } if (FD_ISSET(nc->sock, &read_set)) { nc->last_io_time = current_time; if (nc->flags & NSF_LISTENING) { if (nc->flags & NSF_UDP) { ns_handle_udp(nc); } else { /* We're not looping here, and accepting just one connection at * a time. The reason is that eCos does not respect non-blocking * flag on a listening socket and hangs in a loop. */ accept_conn(nc); } } else { ns_read_from_socket(nc); } } if (FD_ISSET(nc->sock, &write_set)) { nc->last_io_time = current_time; if (nc->flags & NSF_CONNECTING) { ns_read_from_socket(nc); } else if (!(nc->flags & NSF_BUFFER_BUT_DONT_SEND) && !(nc->flags & NSF_CLOSE_IMMEDIATELY)) { ns_write_to_socket(nc); } } } } for (nc = mgr->active_connections; nc != NULL; nc = tmp) { tmp = nc->next; if ((nc->flags & NSF_CLOSE_IMMEDIATELY) || (nc->send_iobuf.len == 0 && (nc->flags & NSF_FINISHED_SENDING_DATA))) { ns_close_conn(nc); } } return current_time; }
time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) { time_t now; struct ns_connection *nc, *tmp; struct timeval tv; fd_set read_set, write_set, err_set; sock_t max_fd = INVALID_SOCKET; int num_selected, fd_flags; FD_ZERO(&read_set); FD_ZERO(&write_set); FD_ZERO(&err_set); ns_add_to_set(mgr->ctl[1], &read_set, &max_fd); for (nc = mgr->active_connections; nc != NULL; nc = tmp) { tmp = nc->next; if (!(nc->flags & NSF_WANT_WRITE) && nc->recv_mbuf.len < nc->recv_mbuf_limit) { ns_add_to_set(nc->sock, &read_set, &max_fd); } if (((nc->flags & NSF_CONNECTING) && !(nc->flags & NSF_WANT_READ)) || (nc->send_mbuf.len > 0 && !(nc->flags & NSF_CONNECTING) && !(nc->flags & NSF_DONT_SEND))) { ns_add_to_set(nc->sock, &write_set, &max_fd); ns_add_to_set(nc->sock, &err_set, &max_fd); } } tv.tv_sec = milli / 1000; tv.tv_usec = (milli % 1000) * 1000; num_selected = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv); now = time(NULL); DBG(("select @ %ld num_ev=%d", (long) now, num_selected)); if (num_selected > 0 && mgr->ctl[1] != INVALID_SOCKET && FD_ISSET(mgr->ctl[1], &read_set)) { ns_mgr_handle_ctl_sock(mgr); } fd_flags = 0; for (nc = mgr->active_connections; nc != NULL; nc = tmp) { if (num_selected > 0) { fd_flags = (FD_ISSET(nc->sock, &read_set) ? _NSF_FD_CAN_READ : 0) | (FD_ISSET(nc->sock, &write_set) ? _NSF_FD_CAN_WRITE : 0) | (FD_ISSET(nc->sock, &err_set) ? _NSF_FD_ERROR : 0); } tmp = nc->next; ns_mgr_handle_connection(nc, fd_flags, now); } for (nc = mgr->active_connections; nc != NULL; nc = tmp) { tmp = nc->next; if ((nc->flags & NSF_CLOSE_IMMEDIATELY) || (nc->send_mbuf.len == 0 && (nc->flags & NSF_SEND_AND_CLOSE))) { ns_close_conn(nc); } } return now; }