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; }
static void parser_ready_http(ape_parser *http_parser, acetables *g_ape) { ape_socket *co = http_parser->socket; co->attach = checkrecv(co, g_ape); }