ape_socket *ape_connect(char *ip, int port, acetables *g_ape) { int sock, ret; struct sockaddr_in addr; ape_socket *co = g_ape->co; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("ERREUR: socket().. (%s line: %i)\n",__FILE__, __LINE__); return NULL; } addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); memset(&(addr.sin_zero), '\0', 8); setnonblocking(sock); if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == 0 || errno != EINPROGRESS) { return NULL; } ret = events_add(g_ape->events, sock, EVENT_READ|EVENT_WRITE); if (sock + 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; } co[sock].buffer_in.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); co[sock].buffer_in.size = DEFAULT_BUFFER_SIZE; co[sock].buffer_in.length = 0; co[sock].buffer_in.slot = NULL; co[sock].buffer_in.islot = 0; co[sock].attach = NULL; co[sock].idle = 0; co[sock].fd = sock; co[sock].stream_type = STREAM_OUT; co[sock].state = STREAM_PROGRESS; co[sock].callbacks.on_accept = NULL; co[sock].callbacks.on_connect = NULL; co[sock].callbacks.on_disconnect = NULL; co[sock].callbacks.on_read = NULL; co[sock].callbacks.on_read_lf = NULL; co[sock].callbacks.on_data_completly_sent = NULL; co[sock].callbacks.on_write = NULL; g_ape->bufout[sock].fd = sock; g_ape->bufout[sock].buf = NULL; g_ape->bufout[sock].buflen = 0; g_ape->bufout[sock].allocsize = 0; return &co[sock]; }
/* Create socket struct if not exists */ void prepare_ape_socket(int fd, acetables *g_ape) { while (fd >= g_ape->basemem) { /* Increase connection & events size */ growup(&g_ape->basemem, &g_ape->co, g_ape->events, &g_ape->bufout); } if (g_ape->co[fd] == NULL) { g_ape->co[fd] = xmalloc(sizeof(*g_ape->co[fd])); } memset(g_ape->co[fd], 0, sizeof(*g_ape->co[fd])); }
unsigned int sockroutine(int s_listen, acetables *g_ape) { int basemem = 512, epoll_fd; struct epoll_event ev, *events; int new_fd, nfds, sin_size = sizeof(struct sockaddr_in), i; struct timeval t_start, t_end; unsigned int ticks = 0; struct sockaddr_in their_addr; connection *co = xmalloc(sizeof(*co) * basemem); epoll_fd = epoll_create(1); /* the param is not used */ if (epoll_fd < 0) { printf("[ERR] Not enougth memory\n"); exit(0); } g_ape->epoll_fd = &epoll_fd; events = xmalloc(sizeof(*events) * basemem); g_ape->bufout = xmalloc(sizeof(struct _socks_bufout) * basemem); setnonblocking(s_listen); ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = s_listen; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s_listen, &ev); while (1) { /* Linux 2.6.25 provide a fd-driven timer system. It could be usefull to implement */ gettimeofday(&t_start, NULL); nfds = epoll_wait(epoll_fd, events, basemem, (1000/TICKS_RATE)-ticks); if (nfds < 0) { continue; } if (nfds > 0) { for (i = 0; i < nfds; i++) { if (events[i].data.fd == s_listen) { while (1) { struct epoll_event cev; http_state http = {0, HTTP_NULL, 0, -1, 0, 0, 0}; new_fd = accept(s_listen, (struct sockaddr *)&their_addr, (unsigned int *)&sin_size); if (new_fd == -1) { break; } if (new_fd + 4 == basemem) { /* Increase connection & events size */ growup(&basemem, &co, &events, &g_ape->bufout); } strncpy(co[new_fd].ip_client, inet_ntoa(their_addr.sin_addr), 16); co[new_fd].buffer.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); co[new_fd].buffer.size = DEFAULT_BUFFER_SIZE; co[new_fd].buffer.length = 0; co[new_fd].http = http; co[new_fd].attach = NULL; 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; setnonblocking(new_fd); cev.events = EPOLLIN | EPOLLET | EPOLLPRI | EPOLLOUT; cev.data.fd = new_fd; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &cev); } continue; } else { int readb = 0; if (events[i].events & EPOLLOUT) { if (co[events[i].data.fd].stream_type == STREAM_OUT && ((ape_proxy *)(co[events[i].data.fd].attach))->state == PROXY_IN_PROGRESS) { int serror = 0, ret; socklen_t serror_len = sizeof(serror); ret = getsockopt(events[i].data.fd, SOL_SOCKET, SO_ERROR, &serror, &serror_len); if (ret == 0 && serror == 0) { ((ape_proxy *)(co[events[i].data.fd].attach))->state = PROXY_CONNECTED; ((ape_proxy *)(co[events[i].data.fd].attach))->sock.fd = events[i].data.fd; proxy_onevent((ape_proxy *)(co[events[i].data.fd].attach), "CONNECT", g_ape); } else { /* This can be happen ? epoll seems set EPOLLIN as if the host is disconnecting */ ((ape_proxy *)(co[events[i].data.fd].attach))->state = PROXY_THROTTLED; //epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL); clear_buffer(&co[events[i].data.fd]); close(events[i].data.fd); } } else if (co[events[i].data.fd].stream_type == STREAM_IN && g_ape->bufout[events[i].data.fd].buf != NULL) { if (sendqueue(events[i].data.fd, g_ape) == 1) { if (co[events[i].data.fd].attach != NULL && ((subuser *)(co[events[i].data.fd].attach))->burn_after_writing) { do_died((subuser *)(co[events[i].data.fd].attach)); ((subuser *)(co[events[i].data.fd].attach))->burn_after_writing = 0; } } } } if (events[i].events & EPOLLIN) { do { /* TODO : Check if maximum data read can improve perf Huge data may attempt to increase third parameter */ readb = read(events[i].data.fd, co[events[i].data.fd].buffer.data + co[events[i].data.fd].buffer.length, co[events[i].data.fd].buffer.size - co[events[i].data.fd].buffer.length); if (readb == -1 && errno == EAGAIN) { /* Nothing to read again */ if (co[events[i].data.fd].stream_type == STREAM_OUT) { proxy_process_eol(&co[events[i].data.fd], g_ape); co[events[i].data.fd].buffer.length = 0; } else { co[events[i].data.fd].buffer.data[co[events[i].data.fd].buffer.length] = '\0'; } break; } else { if (readb < 1) { #if 0 TODO : if (events[i].events & EPOLLRDHUP) { /* Client hangup the connection (half-closed) */ } #endif if (co[events[i].data.fd].stream_type == STREAM_IN && co[events[i].data.fd].attach != NULL) { if (events[i].data.fd == ((subuser *)(co[events[i].data.fd].attach))->fd) { ((subuser *)(co[events[i].data.fd].attach))->headers_sent = 0; ((subuser *)(co[events[i].data.fd].attach))->state = ADIED; } if (((subuser *)(co[events[i].data.fd].attach))->wait_for_free == 1) { free(co[events[i].data.fd].attach); co[events[i].data.fd].attach = NULL; } } else if (co[events[i].data.fd].stream_type == STREAM_OUT) { if (((ape_proxy *)(co[events[i].data.fd].attach))->state == PROXY_TOFREE) { free(co[events[i].data.fd].attach); co[events[i].data.fd].attach = NULL; } else { ((ape_proxy *)(co[events[i].data.fd].attach))->state = PROXY_THROTTLED; proxy_onevent((ape_proxy *)(co[events[i].data.fd].attach), "DISCONNECT", g_ape); } } clear_buffer(&co[events[i].data.fd]); if (g_ape->bufout[events[i].data.fd].buf != NULL) { free(g_ape->bufout[events[i].data.fd].buf); g_ape->bufout[events[i].data.fd].buflen = 0; g_ape->bufout[events[i].data.fd].buf = NULL; g_ape->bufout[events[i].data.fd].allocsize = 0; } close(events[i].data.fd); break; } else if (co[events[i].data.fd].http.ready != -1) { co[events[i].data.fd].buffer.length += readb; if (co[events[i].data.fd].buffer.length == co[events[i].data.fd].buffer.size) { co[events[i].data.fd].buffer.size *= 2; co[events[i].data.fd].buffer.data = xrealloc(co[events[i].data.fd].buffer.data, sizeof(char) * (co[events[i].data.fd].buffer.size + 1)); } if (co[events[i].data.fd].stream_type == STREAM_IN) { process_http(&co[events[i].data.fd]); if (co[events[i].data.fd].http.ready == 1) { co[events[i].data.fd].attach = checkrecv(co[events[i].data.fd].buffer.data, events[i].data.fd, g_ape, co[events[i].data.fd].ip_client); co[events[i].data.fd].buffer.length = 0; co[events[i].data.fd].http.ready = -1; } else if (co[events[i].data.fd].http.error == 1) { shutdown(events[i].data.fd, 2); } } } } } while(readb >= 0); } } } } gettimeofday(&t_end, NULL); ticks += (1000*(t_end.tv_sec - t_start.tv_sec))+((t_end.tv_usec - t_start.tv_usec)/1000); /* Tic tac, tic tac :-) */ if (ticks >= 1000/TICKS_RATE) { ape_proxy *proxy = g_ape->proxy.list; int psock; ticks = 0; 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 == basemem) { growup(&basemem, &co, &events, &g_ape->bufout); } co[psock].ip_client[0] = '\0'; co[psock].buffer.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); co[psock].buffer.size = DEFAULT_BUFFER_SIZE; co[psock].buffer.length = 0; co[psock].http = http_s; co[psock].attach = proxy; co[psock].stream_type = STREAM_OUT; } proxy = proxy->next; } process_tick(g_ape); } } close(epoll_fd); return 0; }
//! Sets the buffer capacity to \p cap, and makes it non-resizable. void setFixedCapacity(int cap) { growup(cap); clear(); growable = false; }
ape_socket *ape_listen(unsigned int port, char *listen_ip, acetables *g_ape) { int sock; struct sockaddr_in addr; int reuse_addr = 1; ape_socket *co = g_ape->co; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("ERREUR: socket().. (%s line: %i)\n",__FILE__, __LINE__); return NULL; } addr.sin_family = AF_INET; addr.sin_port = htons(port); //addr.sin_addr.s_addr = inet_addr(CONFIG_VAL(Server, ip_listen, g_ape->srv)); addr.sin_addr.s_addr = inet_addr(listen_ip); memset(&(addr.sin_zero), '\0', 8); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { printf("ERREUR: bind(%i) (non-root ?).. (%s line: %i)\n", port, __FILE__, __LINE__); return NULL; } if (listen(sock, 2048) == -1) { printf("ERREUR: listen().. (%s line: %i)\n",__FILE__, __LINE__); return NULL; } setnonblocking(sock); if (sock + 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; } co[sock].buffer_in.data = NULL; co[sock].buffer_in.size = 0; co[sock].buffer_in.length = 0; co[sock].attach = NULL; co[sock].idle = 0; co[sock].fd = sock; co[sock].stream_type = STREAM_SERVER; co[sock].state = STREAM_ONLINE; co[sock].callbacks.on_accept = NULL; co[sock].callbacks.on_connect = NULL; co[sock].callbacks.on_disconnect = NULL; co[sock].callbacks.on_read = NULL; co[sock].callbacks.on_read_lf = NULL; co[sock].callbacks.on_data_completly_sent = NULL; co[sock].callbacks.on_write = NULL; events_add(g_ape->events, sock, EVENT_READ); return &co[sock]; }
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 (server_is_running) { // 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 */ nfds = events_poll(g_ape->events, 1); 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)) { 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); 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; } if (new_fd + 4 >= g_ape->basemem) { /* Increase connection & events size */ growup(&g_ape->basemem, &g_ape->co, g_ape->events, &g_ape->bufout); } 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].buffer_in.length = 0; g_ape->co[new_fd].buffer_in.slot = NULL; g_ape->co[new_fd].buffer_in.islot = 0; //g_ape->co[new_fd].http = http; g_ape->co[new_fd].attach = NULL; g_ape->co[new_fd].data = NULL; g_ape->co[new_fd].idle = time(NULL); g_ape->co[new_fd].burn_after_writing = 0; g_ape->co[new_fd].fd = new_fd; g_ape->co[new_fd].stream_type = STREAM_IN; g_ape->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; 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); } clear_buffer(&g_ape->co[active_fd], &tfd); close(active_fd); } } 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); } clear_buffer(&g_ape->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 { 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) { 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) { memmove(g_ape->co[active_fd].buffer_in.data, &g_ape->co[active_fd].buffer_in.data[g_ape->co[active_fd].buffer_in.length - len], len); g_ape->co[active_fd].buffer_in.length = 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; }