unsigned int sockroutine(acetables *g_ape) { struct _socks_list sl; int new_fd, nfds, sin_size = sizeof(struct sockaddr_in), i, tfd = 0; ape_socket *co = g_ape->co; struct timeval t_start, t_end; long int ticks = 0, uticks = 0, lticks = 0; struct sockaddr_in their_addr; sl.co = co; sl.tfd = &tfd; g_ape->bufout = xmalloc(sizeof(struct _socks_bufout) * g_ape->basemem); #if 0 add_periodical(5, 0, check_idle, &sl, g_ape); #endif while (1) { // int timeout_to_hang = MAX((1000/TICKS_RATE)-ticks, 1); /* Linux 2.6.25 provides a fd-driven timer system. It could be usefull to implement */ gettimeofday(&t_start, NULL); nfds = events_poll(g_ape->events, 1); if (nfds < 0) { continue; } if (nfds > 0) { for (i = 0; i < nfds; i++) { int active_fd = events_get_current_fd(g_ape->events, i); if (co[active_fd].stream_type == STREAM_SERVER) { while (1) { http_state http = {0, HTTP_NULL, 0, -1, 0, 0, 0}; new_fd = accept(active_fd, (struct sockaddr *)&their_addr, (unsigned int *)&sin_size); if (new_fd == -1) { break; } if (new_fd + 4 == g_ape->basemem) { /* Increase connection & events size */ growup(&g_ape->basemem, &g_ape->co, g_ape->events, &g_ape->bufout); co = g_ape->co; } strncpy(co[new_fd].ip_client, inet_ntoa(their_addr.sin_addr), 16); co[new_fd].buffer_in.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); co[new_fd].buffer_in.size = DEFAULT_BUFFER_SIZE; co[new_fd].buffer_in.length = 0; co[new_fd].buffer_in.slot = NULL; co[new_fd].buffer_in.islot = 0; co[new_fd].http = http; co[new_fd].attach = NULL; co[new_fd].data = NULL; co[new_fd].idle = time(NULL); co[new_fd].fd = new_fd; co[new_fd].stream_type = STREAM_IN; co[new_fd].state = STREAM_ONLINE; g_ape->bufout[new_fd].fd = new_fd; g_ape->bufout[new_fd].buf = NULL; g_ape->bufout[new_fd].buflen = 0; g_ape->bufout[new_fd].allocsize = 0; co[new_fd].callbacks.on_disconnect = co[active_fd].callbacks.on_disconnect; co[new_fd].callbacks.on_read = co[active_fd].callbacks.on_read; co[new_fd].callbacks.on_read_lf = co[active_fd].callbacks.on_read_lf; co[new_fd].callbacks.on_data_completly_sent = co[active_fd].callbacks.on_data_completly_sent; co[new_fd].callbacks.on_write = co[active_fd].callbacks.on_write; co[new_fd].attach = co[active_fd].attach; setnonblocking(new_fd); events_add(g_ape->events, new_fd, EVENT_READ|EVENT_WRITE); tfd++; if (co[active_fd].callbacks.on_accept != NULL) { co[active_fd].callbacks.on_accept(&co[new_fd], g_ape); } } continue; } else { int readb = 0; int bitev = events_revent(g_ape->events, i); if (bitev & EVENT_WRITE) { if (co[active_fd].stream_type == STREAM_OUT && co[active_fd].state == STREAM_PROGRESS) { int serror = 0, ret; socklen_t serror_len = sizeof(serror); ret = getsockopt(active_fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len); if (ret == 0 && serror == 0) { co[active_fd].state = STREAM_ONLINE; if (co[active_fd].callbacks.on_connect != NULL) { co[active_fd].callbacks.on_connect(&co[active_fd], g_ape); } } else { /* This can happen ? epoll seems set EPOLLIN as if the host is disconnecting */ if (co[active_fd].callbacks.on_disconnect != NULL) { co[active_fd].callbacks.on_disconnect(&co[active_fd], g_ape); } clear_buffer(&co[active_fd], &tfd); close(active_fd); } } #if 0 if (co[active_fd].stream_type == STREAM_OUT && ((ape_proxy *)(co[active_fd].attach))->state == PROXY_IN_PROGRESS) { int serror = 0, ret; socklen_t serror_len = sizeof(serror); ret = getsockopt(active_fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len); if (ret == 0 && serror == 0) { ((ape_proxy *)(co[active_fd].attach))->state = PROXY_CONNECTED; ((ape_proxy *)(co[active_fd].attach))->sock.fd = active_fd; proxy_onevent((ape_proxy *)(co[active_fd].attach), "CONNECT", g_ape); if (co[active_fd].callbacks.on_connect != NULL) { co[active_fd].callbacks.on_connect(&co[active_fd]); } } else { /* This can happen ? epoll seems set EPOLLIN as if the host is disconnecting */ if (co[active_fd].callbacks.on_disconnect != NULL) { co[active_fd].callbacks.on_disconnect(&co[active_fd]); } ((ape_proxy *)(co[active_fd].attach))->state = PROXY_THROTTLED; //epoll_ctl(event_fd, EPOLL_CTL_DEL, active_fd, NULL); clear_buffer(&co[active_fd], &tfd); close(active_fd); } } #endif else if (co[active_fd].stream_type == STREAM_IN && g_ape->bufout[active_fd].buf != NULL) { if (sendqueue(active_fd, g_ape) == 1) { if (co[active_fd].callbacks.on_data_completly_sent != NULL) { co[active_fd].callbacks.on_data_completly_sent(&co[active_fd], g_ape); } } } else if (co[active_fd].stream_type == STREAM_DELEGATE) { if (co[active_fd].callbacks.on_write != NULL) { co[active_fd].callbacks.on_write(&co[active_fd], g_ape); } } } if (bitev & EVENT_READ) { if (co[active_fd].stream_type == STREAM_DELEGATE) { if (co[active_fd].callbacks.on_read != NULL) { co[active_fd].callbacks.on_read(&co[active_fd], NULL, 0, g_ape); continue; } } do { /* TODO : Check if maximum data read can improve perf Huge data may attempt to increase third parameter */ readb = read(active_fd, co[active_fd].buffer_in.data + co[active_fd].buffer_in.length, co[active_fd].buffer_in.size - co[active_fd].buffer_in.length); if (readb == -1 && errno == EAGAIN) { /* Nothing to read again */ if (co[active_fd].stream_type == STREAM_OUT) { //proxy_process_eol(&co[active_fd], g_ape); //co[active_fd].buffer_in.length = 0; } else { // co[active_fd].buffer_in.data[co[active_fd].buffer_in.length] = '\0'; } break; } else { if (readb < 1) { if (co[active_fd].callbacks.on_disconnect != NULL) { co[active_fd].callbacks.on_disconnect(&co[active_fd], g_ape); } #if 0 if (co[active_fd].stream_type == STREAM_IN && co[active_fd].attach != NULL) { if (active_fd == ((subuser *)(co[active_fd].attach))->fd) { ((subuser *)(co[active_fd].attach))->headers_sent = 0; ((subuser *)(co[active_fd].attach))->state = ADIED; } if (((subuser *)(co[active_fd].attach))->wait_for_free == 1) { free(co[active_fd].attach); co[active_fd].attach = NULL; } } else if (co[active_fd].stream_type == STREAM_OUT) { if (((ape_proxy *)(co[active_fd].attach))->state == PROXY_TOFREE) { free(co[active_fd].attach); co[active_fd].attach = NULL; } else { ((ape_proxy *)(co[active_fd].attach))->state = PROXY_THROTTLED; proxy_onevent((ape_proxy *)(co[active_fd].attach), "DISCONNECT", g_ape); } } #endif clear_buffer(&co[active_fd], &tfd); if (g_ape->bufout[active_fd].buf != NULL) { free(g_ape->bufout[active_fd].buf); g_ape->bufout[active_fd].buflen = 0; g_ape->bufout[active_fd].buf = NULL; g_ape->bufout[active_fd].allocsize = 0; } close(active_fd); break; } else { co[active_fd].buffer_in.length += readb; /* realloc the buffer for the next read (x2) */ if (co[active_fd].buffer_in.length == co[active_fd].buffer_in.size) { co[active_fd].buffer_in.size *= 2; co[active_fd].buffer_in.data = xrealloc(co[active_fd].buffer_in.data, sizeof(char) * (co[active_fd].buffer_in.size + 1)); } if (co[active_fd].callbacks.on_read_lf != NULL) { int eol, len = co[active_fd].buffer_in.length; char *pBuf = co[active_fd].buffer_in.data; while ((eol = sneof(pBuf, len, 4096)) != -1) { pBuf[eol-1] = '\0'; co[active_fd].callbacks.on_read_lf(&co[active_fd], pBuf, g_ape); pBuf = &pBuf[eol]; len -= eol; } if (len > 4096 || !len) { co[active_fd].buffer_in.length = 0; } else if (len) { memmove(co[active_fd].buffer_in.data, &co[active_fd].buffer_in.data[co[active_fd].buffer_in.length - len], len); co[active_fd].buffer_in.length = len; } } /* on_read can't get along with on_read_lf */ if (co[active_fd].callbacks.on_read != NULL && co[active_fd].callbacks.on_read_lf == NULL) { co[active_fd].callbacks.on_read(&co[active_fd], &co[active_fd].buffer_in, co[active_fd].buffer_in.length - readb, g_ape); } } } } while(readb >= 0); } } } } gettimeofday(&t_end, NULL); ticks = 0; uticks = 1000000 * (t_end.tv_sec - t_start.tv_sec); uticks += (t_end.tv_usec - t_start.tv_usec); lticks += uticks; /* Tic tac, tic tac :-) */ { unsigned long int nticks; ape_proxy *proxy = g_ape->proxy.list; int psock; while (proxy != NULL) { if (proxy->state == PROXY_NOT_CONNECTED && ((psock = proxy_connect(proxy, g_ape)) != 0)) { http_state http_s = {0, HTTP_NULL, 0, -1, 0, 0, 0}; if (psock + 4 == g_ape->basemem) { growup(&g_ape->basemem, &g_ape->co, g_ape->events, &g_ape->bufout); co = g_ape->co; } co[psock].ip_client[0] = '\0'; co[psock].buffer_in.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); co[psock].buffer_in.size = DEFAULT_BUFFER_SIZE; co[psock].buffer_in.length = 0; co[psock].buffer_in.slot = NULL; co[psock].buffer_in.islot = 0; co[psock].idle = time(NULL); co[psock].http = http_s; co[psock].attach = proxy; co[psock].stream_type = STREAM_OUT; co[psock].fd = psock; tfd++; } proxy = proxy->next; } while (lticks > 1000) { ticks++; lticks -= 1000; } for (nticks = 0; nticks < ticks; nticks++) { process_tick(g_ape); } } } return 0; }
unsigned int sockroutine(acetables *g_ape) { struct _socks_list sl; int new_fd, nfds, sin_size = sizeof(struct sockaddr_in), i, tfd = 0; struct timeval t_start, t_end; long int ticks = 0, uticks = 0, lticks = 0; struct sockaddr_in their_addr; //sl.co = co; sl.tfd = &tfd; #if 0 add_periodical(5, 0, check_idle, &sl, g_ape); #endif gettimeofday(&t_start, NULL); while (ape_server_is_running) { /* Linux 2.6.25 provides a fd-driven timer system. It could be usefull to implement */ int timeout_to_hang = get_first_timer_ms(g_ape); nfds = events_poll(g_ape->events, timeout_to_hang); if (nfds < 0) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "events_poll() : %s", strerror(errno)); continue; } if (nfds > 0) { for (i = 0; i < nfds; i++) { int active_fd = events_get_current_fd(g_ape->events, i); if (g_ape->co[active_fd]->stream_type == STREAM_SERVER) { int bitev = events_revent(g_ape->events, i); if (!(bitev & EVENT_READ)) { /* Close server socket */ close_socket(active_fd, g_ape); continue; } while (1) { //http_state http = {NULL, 0, -1, 0, 0, HTTP_NULL, 0, 0}; new_fd = accept(active_fd, (struct sockaddr *)&their_addr, (unsigned int *)&sin_size); if (new_fd == -1) { break; } prepare_ape_socket(new_fd, g_ape); strncpy(g_ape->co[new_fd]->ip_client, inet_ntoa(their_addr.sin_addr), 16); g_ape->co[new_fd]->buffer_in.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); g_ape->co[new_fd]->buffer_in.size = DEFAULT_BUFFER_SIZE; g_ape->co[new_fd]->idle = time(NULL); g_ape->co[new_fd]->fd = new_fd; g_ape->co[new_fd]->state = STREAM_ONLINE; g_ape->co[new_fd]->stream_type = STREAM_IN; g_ape->bufout[new_fd].fd = new_fd; g_ape->bufout[new_fd].buf = NULL; g_ape->bufout[new_fd].buflen = 0; g_ape->bufout[new_fd].allocsize = 0; g_ape->co[new_fd]->callbacks.on_disconnect = g_ape->co[active_fd]->callbacks.on_disconnect; g_ape->co[new_fd]->callbacks.on_read = g_ape->co[active_fd]->callbacks.on_read; g_ape->co[new_fd]->callbacks.on_read_lf = g_ape->co[active_fd]->callbacks.on_read_lf; g_ape->co[new_fd]->callbacks.on_data_completly_sent = g_ape->co[active_fd]->callbacks.on_data_completly_sent; g_ape->co[new_fd]->callbacks.on_write = g_ape->co[active_fd]->callbacks.on_write; g_ape->co[new_fd]->attach = g_ape->co[active_fd]->attach; setnonblocking(new_fd); events_add(g_ape->events, new_fd, EVENT_READ|EVENT_WRITE); tfd++; if (g_ape->co[active_fd]->callbacks.on_accept != NULL) { g_ape->co[active_fd]->callbacks.on_accept(g_ape->co[new_fd], g_ape); } } continue; } else { int readb = 0; int bitev = events_revent(g_ape->events, i); if (bitev & EVENT_WRITE) { if (g_ape->co[active_fd]->stream_type == STREAM_OUT && g_ape->co[active_fd]->state == STREAM_PROGRESS) { int serror = 0, ret; socklen_t serror_len = sizeof(serror); ret = getsockopt(active_fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len); if (ret == 0 && serror == 0) { g_ape->co[active_fd]->state = STREAM_ONLINE; if (g_ape->co[active_fd]->callbacks.on_connect != NULL) { g_ape->co[active_fd]->callbacks.on_connect(g_ape->co[active_fd], g_ape); } } else { /* This can happen ? epoll seems set EPOLLIN as if the host is disconnecting */ if (g_ape->co[active_fd]->callbacks.on_disconnect != NULL) { g_ape->co[active_fd]->callbacks.on_disconnect(g_ape->co[active_fd], g_ape); } close_socket(active_fd, g_ape); tfd--; continue; } } else if (g_ape->bufout[active_fd].buf != NULL) { if (sendqueue(active_fd, g_ape) == 1) { if (g_ape->co[active_fd]->callbacks.on_data_completly_sent != NULL) { g_ape->co[active_fd]->callbacks.on_data_completly_sent(g_ape->co[active_fd], g_ape); } if (g_ape->co[active_fd]->burn_after_writing) { shutdown(active_fd, 2); g_ape->co[active_fd]->burn_after_writing = 0; } } } else if (g_ape->co[active_fd]->stream_type == STREAM_DELEGATE) { if (g_ape->co[active_fd]->callbacks.on_write != NULL) { g_ape->co[active_fd]->callbacks.on_write(g_ape->co[active_fd], g_ape); } } } if (bitev & EVENT_READ) { if (g_ape->co[active_fd]->stream_type == STREAM_DELEGATE) { if (g_ape->co[active_fd]->callbacks.on_read != NULL) { g_ape->co[active_fd]->callbacks.on_read(g_ape->co[active_fd], NULL, 0, g_ape); continue; } } do { /* TODO : Check if maximum data read can improve perf Huge data may attempt to increase third parameter */ readb = read(active_fd, g_ape->co[active_fd]->buffer_in.data + g_ape->co[active_fd]->buffer_in.length, g_ape->co[active_fd]->buffer_in.size - g_ape->co[active_fd]->buffer_in.length); if (readb == -1 && errno == EAGAIN) { if (g_ape->co[active_fd]->stream_type == STREAM_OUT) { //proxy_process_eol(&co[active_fd], g_ape); //co[active_fd].buffer_in.length = 0; } else { // co[active_fd].buffer_in.data[co[active_fd].buffer_in.length] = '\0'; } break; } else { if (readb < 1) { if (g_ape->co[active_fd]->callbacks.on_disconnect != NULL) { g_ape->co[active_fd]->callbacks.on_disconnect(g_ape->co[active_fd], g_ape); } close_socket(active_fd, g_ape); tfd--; break; } else { g_ape->co[active_fd]->buffer_in.length += readb; /* realloc the buffer for the next read (x2) */ if (g_ape->co[active_fd]->buffer_in.length == g_ape->co[active_fd]->buffer_in.size) { g_ape->co[active_fd]->buffer_in.size *= 2; g_ape->co[active_fd]->buffer_in.data = xrealloc(g_ape->co[active_fd]->buffer_in.data, sizeof(char) * (g_ape->co[active_fd]->buffer_in.size + 1)); } if (g_ape->co[active_fd]->callbacks.on_read_lf != NULL) { unsigned int eol, *len = &g_ape->co[active_fd]->buffer_in.length; char *pBuf = g_ape->co[active_fd]->buffer_in.data; while ((eol = sneof(pBuf, *len, 4096)) != -1) { pBuf[eol-1] = '\0'; g_ape->co[active_fd]->callbacks.on_read_lf(g_ape->co[active_fd], pBuf, g_ape); pBuf = &pBuf[eol]; *len -= eol; } if (*len > 4096 || !*len) { g_ape->co[active_fd]->buffer_in.length = 0; } else if (*len && pBuf != g_ape->co[active_fd]->buffer_in.data) { memmove(g_ape->co[active_fd]->buffer_in.data, pBuf, *len); } } /* on_read can't get along with on_read_lf */ if (g_ape->co[active_fd]->callbacks.on_read != NULL && g_ape->co[active_fd]->callbacks.on_read_lf == NULL) { g_ape->co[active_fd]->callbacks.on_read(g_ape->co[active_fd], &g_ape->co[active_fd]->buffer_in, g_ape->co[active_fd]->buffer_in.length - readb, g_ape); } } } } while(readb >= 0); } } } } gettimeofday(&t_end, NULL); ticks = 0; uticks = 1000000L * (t_end.tv_sec - t_start.tv_sec); uticks += (t_end.tv_usec - t_start.tv_usec); t_start = t_end; lticks += uticks; /* Tic tac, tic tac */ while (lticks >= 1000) { lticks -= 1000; process_tick(g_ape); } } return 0; }
void events_loop(ape_global *ape) { int nfd, fd, bitev; long int ticks = 0, uticks = 0, lticks = 0; void *attach; struct timeval t_start, t_end; gettimeofday(&t_start, NULL); while(ape->is_running && ape_running) { int i; if ((nfd = events_poll(&ape->events, 1)) == -1) { continue; } for (i = 0; i < nfd; i++) { if ((attach = events_get_current_fd(&ape->events, i)) == NULL) { continue; } bitev = events_revent(&ape->events, i); //if (attach == NULL) printf("Will failed\n"); fd = ((ape_fds *)attach)->fd; /* assuming that ape_fds is the first member */ //printf("Getting : %d on %d %d\n", i, fd, bitev); //if ((ape_fds *)attach)->state == () switch(((ape_fds *)attach)->type) { case APE_SOCKET: if (APE_SOCKET(attach)->states.type == APE_SOCKET_TP_SERVER) { if (bitev & EVENT_READ) { if (APE_SOCKET(attach)->states.proto == APE_SOCKET_PT_TCP || APE_SOCKET(attach)->states.proto == APE_SOCKET_PT_SSL) { ape_socket_accept(APE_SOCKET(attach)); } else { printf("read on UDP\n"); } } } else if (APE_SOCKET(attach)->states.type == APE_SOCKET_TP_CLIENT) { /* unset this before READ event because read can invoke writes */ if (bitev & EVENT_WRITE) { APE_SOCKET(attach)->states.flags &= ~APE_SOCKET_WOULD_BLOCK; } if (bitev & EVENT_READ && ape_socket_read(APE_SOCKET(attach)) == -1) { /* ape_socket is planned to be release after the for block */ continue; } if (bitev & EVENT_WRITE) { if (APE_SOCKET(attach)->states.state == APE_SOCKET_ST_ONLINE && !(APE_SOCKET(attach)->states.flags & APE_SOCKET_WOULD_BLOCK)) { ape_socket_do_jobs(APE_SOCKET(attach)); } else if (APE_SOCKET(attach)->states.state == APE_SOCKET_ST_PROGRESS) { int serror = 0, ret; socklen_t serror_len = sizeof(serror); if ((ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len)) == 0 && serror == 0) { APE_SOCKET(attach)->states.state = APE_SOCKET_ST_ONLINE; ape_socket_connected(APE_SOCKET(attach)); } else { printf("Failed to connect\n"); } } } } else if (APE_SOCKET(attach)->states.type == APE_SOCKET_TP_UNKNOWN) { } break; case APE_FILE: break; case APE_DELEGATE: ((struct _ape_fd_delegate *)attach)->on_io(fd, bitev, ape); /* punning */ break; } } gettimeofday(&t_end, NULL); ticks = 0; uticks = 1000000L * (t_end.tv_sec - t_start.tv_sec); uticks += (t_end.tv_usec - t_start.tv_usec); t_start = t_end; lticks += uticks; while (lticks >= 1000) { lticks -= 1000; process_tick(ape); } } }