void delsubuser(subuser **current) { subuser *del = *current; ((*current)->user->nsub)--; *current = (*current)->next; clear_subuser_raws(del); if (del->state == ALIVE) { del->wait_for_free = 1; do_died(del); } else { do_died(del); free(del); } }
void transport_data_completly_sent(subuser *sub, transport_t transport, acetables *g_ape) { switch(transport) { case TRANSPORT_LONGPOLLING: case TRANSPORT_JSONP: default: do_died(sub, g_ape); break; case TRANSPORT_PERSISTANT: case TRANSPORT_XHRSTREAMING: case TRANSPORT_SSE_LONGPOLLING: case TRANSPORT_WEBSOCKET: case TRANSPORT_WEBSOCKET_IETF: break; } }
void check_timeout(acetables *g_ape) { USERS *list, *wait; long int ctime = time(NULL); list = g_ape->uHead; while (list != NULL) { wait = list->next; if ((ctime - list->idle) >= TIMEOUT_SEC && list->type == HUMAN) { deluser(list, g_ape); } else if (list->type == HUMAN) { subuser **n = &(list->subuser); while (*n != NULL) { if ((ctime - (*n)->idle) >= TIMEOUT_SEC) { delsubuser(n); continue; } if ((*n)->state == ALIVE && (*n)->nraw && !(*n)->need_update) { /* Data completetly sent => closed */ if (send_raws(*n, g_ape)) { do_died(*n); } else { (*n)->burn_after_writing = 1; } } else { FIRE_EVENT_NONSTOP(tickuser, *n, g_ape); } n = &(*n)->next; } } list = wait; } }
void delsubuser(subuser **current, acetables *g_ape) { subuser *del = *current; FIRE_EVENT_NONSTOP(delsubuser, del, g_ape); ((*current)->user->nsub)--; *current = (*current)->next; destroy_raw_pool(del->raw_pools.low.rawhead); destroy_raw_pool(del->raw_pools.high.rawhead); clear_properties(&del->properties); if (del->state == ALIVE) { del->wait_for_free = 1; do_died(del); } else { free(del); } }
void delsubuser(subuser **current, acetables *g_ape) { subuser *del = *current; USERS *user = (*current)->user; FIRE_EVENT_NULL(delsubuser, del, g_ape); ((*current)->user->nsub)--; *current = (*current)->next; destroy_raw_pool(del->raw_pools.low.rawhead); destroy_raw_pool(del->raw_pools.high.rawhead); del->raw_pools.low.rawhead = del->raw_pools.low.rawfoot = NULL; del->raw_pools.high.rawhead = del->raw_pools.high.rawfoot = NULL; del->raw_pools.nraw = 0; del->client->attach = NULL; clear_properties(&del->properties); if (del->state == ALIVE) { del->wait_for_free = 1; do_died(del); } else { free(del); } /* * If this is the last subuser, del the user */ if (user->nsub <= 0) { user->idle = time(NULL) - (TIMEOUT_SEC - USRLEFT_SEC); } HOOK_EVENT(delsubuser, del, g_ape); }
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; }