ape_socket *ape_listen(unsigned int port, char *listen_ip, acetables *g_ape) { int sock; struct sockaddr_in addr; int reuse_addr = 1; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "ape_listen() - socket()"); 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) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "ape_listen() - bind()"); printf("Error: cannot bind to port %i; %s\n", port, strerror(errno)); ape_server_is_running = 0; return NULL; } if (listen(sock, 2048) == -1) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "ape_listen() - listen()"); return NULL; } setnonblocking(sock); prepare_ape_socket(sock, g_ape); g_ape->co[sock]->fd = sock; g_ape->co[sock]->state = STREAM_ONLINE; g_ape->co[sock]->stream_type = STREAM_SERVER; events_add(g_ape->events, sock, EVENT_READ); return g_ape->co[sock]; }
void ape_dns_init(acetables *g_ape) { int sock = dns_init(NULL, 1); prepare_ape_socket(sock, g_ape); g_ape->co[sock]->fd = sock; g_ape->co[sock]->stream_type = STREAM_DELEGATE; g_ape->co[sock]->callbacks.on_read = ape_dns_read; g_ape->co[sock]->callbacks.on_write = ape_dns_write; events_add(g_ape->events, sock, EVENT_READ|EVENT_WRITE); dns_timer_id = add_ticked(ape_dns_timeout, NULL)->identifier; }
ape_socket *ape_connect(char *ip, int port, acetables *g_ape) { int sock, ret; struct sockaddr_in addr; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "ape_connect() - socket() : %s", strerror(errno)); 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; } prepare_ape_socket(sock, g_ape); g_ape->co[sock]->buffer_in.data = xmalloc(sizeof(char) * (DEFAULT_BUFFER_SIZE + 1)); g_ape->co[sock]->buffer_in.size = DEFAULT_BUFFER_SIZE; g_ape->co[sock]->fd = sock; g_ape->co[sock]->state = STREAM_PROGRESS; g_ape->co[sock]->stream_type = STREAM_OUT; g_ape->bufout[sock].fd = sock; g_ape->bufout[sock].buf = NULL; g_ape->bufout[sock].buflen = 0; g_ape->bufout[sock].allocsize = 0; ret = events_add(g_ape->events, sock, EVENT_READ|EVENT_WRITE); return g_ape->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; 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; }