static void run_task_test(void) { tasks_init(); events_init(); sleep(2); /* wait for both threads to run */ tasks_add(task_create(test, NULL)); events_add(event_create(2, config_parse_event, (void *)"config_test")); events_add(event_create(2, test, NULL)); sleep(5); events_add(event_create(3, test, NULL)); events_stop(); tasks_stop(); }
static void ares_socket_cb(void *data, int s, int read, int write) { ape_global *ape = data; unsigned i, f = 0u; int listenfor = read ? EVENT_READ : 0 | write ? EVENT_WRITE : 0; for (i = 0; i < ape->dns.sockets.size; i++) { if (!f && ape->dns.sockets.list[i].s.fd == 0) { f = i; } else if (ape->dns.sockets.list[i].s.fd == s) { /* Modify or delete the object (+ return) */ if (!listenfor) { ape->dns.sockets.list[i].s.fd = 0; events_del(s, ape); close(s); } else { events_mod((ape_event_descriptor *)&ape->dns.sockets.list[i], listenfor | EVENT_LEVEL, ape); } return; } } setnonblocking(s); ape->dns.sockets.list[f].s.fd = s; ape->dns.sockets.list[f].s.type = APE_EVENT_DELEGATE; ape->dns.sockets.list[f].on_io = ares_io; ape->dns.sockets.list[f].data = NULL; events_add((ape_event_descriptor *)&ape->dns.sockets.list[f], listenfor | EVENT_LEVEL, ape); }
int proxy_connect(ape_proxy *proxy, acetables *g_ape) { int sock; struct sockaddr_in addr; if (proxy == NULL || proxy->state != PROXY_NOT_CONNECTED || !strlen(proxy->sock.host->ip)) { return 0; } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("ERREUR: socket().. (%s line: %i)\n",__FILE__, __LINE__); return 0; } addr.sin_family = AF_INET; addr.sin_port = htons(proxy->sock.port); addr.sin_addr.s_addr = inet_addr(proxy->sock.host->ip); memset(&(addr.sin_zero), '\0', 8); setnonblocking(sock); if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == 0 || errno != EINPROGRESS) { return 0; } proxy->state = PROXY_IN_PROGRESS; events_add(g_ape->events, sock, EVENT_READ|EVENT_WRITE); return sock; }
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]; }
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]; }
static int ape_module_inotify_init(ape_global *ape) { if ((insocket.s.fd = inotify_init1(0x00 | IN_NONBLOCK)) == -1) { return -1; } insocket.s.type = APE_DELEGATE; insocket.on_io = inotify_io; events_add(insocket.s.fd, &insocket, EVENT_READ, ape); inotify_add_watch(insocket.s.fd, "/home/para/dev/", IN_ACCESS|IN_OPEN); return 0; }
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]; }
int main(int argc, char **argv) { apeconfig *srv; int random, im_r00t = 0, pidfd = 0, serverfd; unsigned int getrandom = 0, ct_id; const char *pidfile = NULL; char *confs_path = NULL; struct _fdevent fdev; char cfgfile[513] = APE_CONFIG_FILE; acetables *g_ape; if (argc > 1 && strcmp(argv[1], "--version") == 0) { printf("\n AJAX Push Engine Server %s - (C) Anthony Catel <*****@*****.**>\n http://www.ape-project.org/\n\n", _VERSION); return 0; } if (argc > 1 && strcmp(argv[1], "--help") == 0) { printf("\n AJAX Push Engine Server %s - (C) Anthony Catel <*****@*****.**>\n http://www.ape-project.org/\n", _VERSION); printf("\n usage: aped [options]\n\n"); printf(" Options:\n --help : Display this help\n --version : Show version number\n --cfg <config path>: Load a specific config file (default is %s)\n\n", cfgfile); return 0; } else if (argc > 2 && strcmp(argv[1], "--cfg") == 0) { memset(cfgfile, 0, 513); strncpy(cfgfile, argv[2], 512); confs_path = get_path(cfgfile); } else if (argc > 1) { printf("\n AJAX Push Engine Server %s - (C) Anthony Catel <*****@*****.**>\n http://www.ape-project.org/\n\n", _VERSION); printf(" Unknown parameters - check \"aped --help\"\n\n"); return 0; } if (NULL == (srv = ape_config_load(cfgfile))) { printf("\nExited...\n\n"); exit(1); } if (getuid() == 0) { im_r00t = 1; } signal(SIGINT, &signal_handler); signal(SIGTERM, &signal_handler); if (VTICKS_RATE < 1) { printf("[ERR] TICKS_RATE cant be less than 1\n"); return 0; } random = open("/dev/urandom", O_RDONLY); if (!random) { printf("Cannot open /dev/urandom... exiting\n"); return 0; } read(random, &getrandom, 3); srand(getrandom); close(random); g_ape = xmalloc(sizeof(*g_ape)); g_ape->basemem = 1; // set 1 for testing if growup works g_ape->srv = srv; g_ape->confs_path = confs_path; g_ape->is_daemon = 0; ape_log_init(g_ape); fdev.handler = EVENT_UNKNOWN; #ifdef USE_EPOLL_HANDLER fdev.handler = EVENT_EPOLL; #endif #ifdef USE_KQUEUE_HANDLER fdev.handler = EVENT_KQUEUE; #endif g_ape->co = xmalloc(sizeof(*g_ape->co) * g_ape->basemem); memset(g_ape->co, 0, sizeof(*g_ape->co) * g_ape->basemem); g_ape->bad_cmd_callbacks = NULL; g_ape->bufout = xmalloc(sizeof(struct _socks_bufout) * g_ape->basemem); g_ape->timers.timers = NULL; g_ape->timers.ntimers = 0; g_ape->events = &fdev; if (events_init(g_ape, &g_ape->basemem) == -1) { printf("Fatal error: APE compiled without an event handler... exiting\n"); return 0; }; serverfd = servers_init(g_ape); ape_log(APE_INFO, __FILE__, __LINE__, g_ape, "APE starting up - pid : %i", getpid()); if (strcmp(CONFIG_VAL(Server, daemon, srv), "yes") == 0 && (pidfile = CONFIG_VAL(Server, pid_file, srv)) != NULL) { if ((pidfd = open(pidfile, O_TRUNC | O_WRONLY | O_CREAT, 0655)) == -1) { ape_log(APE_WARN, __FILE__, __LINE__, g_ape, "Cant open pid file : %s", CONFIG_VAL(Server, pid_file, srv)); } } if (im_r00t) { struct group *grp = NULL; struct passwd *pwd = NULL; if (inc_rlimit(atoi(CONFIG_VAL(Server, rlimit_nofile, srv))) == -1) { ape_log(APE_WARN, __FILE__, __LINE__, g_ape, "Cannot set the max filedescriptos limit (setrlimit) %s", strerror(errno)); } /* Set uid when uid section exists */ if (ape_config_get_section(srv, "uid")) { /* Get the user information (uid section) */ if ((pwd = getpwnam(CONFIG_VAL(uid, user, srv))) == NULL) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "Can\'t find username %s", CONFIG_VAL(uid, user, srv)); return -1; } if (pwd->pw_uid == 0) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "%s uid can\'t be 0", CONFIG_VAL(uid, user, srv)); return -1; } /* Get the group information (uid section) */ if ((grp = getgrnam(CONFIG_VAL(uid, group, srv))) == NULL) { printf("[ERR] Can\'t find group %s\n", CONFIG_VAL(uid, group, srv)); ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "Can\'t find group %s", CONFIG_VAL(uid, group, srv)); return -1; } if (grp->gr_gid == 0) { ape_log(APE_ERR, __FILE__, __LINE__, g_ape, "%s gid can\'t be 0", CONFIG_VAL(uid, group, srv)); return -1; } setgid(grp->gr_gid); setgroups(0, NULL); initgroups(CONFIG_VAL(uid, user, srv), grp->gr_gid); setuid(pwd->pw_uid); } } else { printf("[WARN] You have to run \'aped\' as root to increase r_limit\n"); ape_log(APE_WARN, __FILE__, __LINE__, g_ape, "You have to run \'aped\' as root to increase r_limit"); } if (strcmp(CONFIG_VAL(Server, daemon, srv), "yes") == 0) { ape_log(APE_INFO, __FILE__, __LINE__, g_ape, "Starting daemon"); ape_daemon(pidfd, g_ape); events_reload(g_ape->events); events_add(g_ape->events, serverfd, EVENT_READ); } if (!g_ape->is_daemon) { printf(" _ ___ ___ \n"); printf(" /_\\ | _ \\ __|\n"); printf(" / _ \\| _/ _| \n"); printf("/_/ \\_\\_| |___|\nAJAX Push Engine\n\n"); printf("Bind on port %i\n\n", atoi(CONFIG_VAL(Server, port, srv))); printf("Version : %s\n", _VERSION); printf("Build : %s %s\n", __DATE__, __TIME__); printf("Author : Weelya ([email protected])\n\n"); } signal(SIGPIPE, SIG_IGN); ape_dns_init(g_ape); g_ape->cmd_hook.head = NULL; g_ape->cmd_hook.foot = NULL; g_ape->hSessid = hashtbl_init(); g_ape->hChannel = hashtbl_init(); g_ape->hPubid = hashtbl_init(); g_ape->proxy.list = NULL; g_ape->proxy.hosts = NULL; g_ape->hCallback = hashtbl_init(); g_ape->uHead = NULL; g_ape->cHead = NULL; g_ape->nConnected = 0; g_ape->plugins = NULL; g_ape->properties = NULL; ct_id = add_ticked(check_timeout, g_ape)->identifier; do_register(g_ape); transport_start(g_ape); findandloadplugin(g_ape); server_is_running = 1; server_is_shutdowning = 0; /* Starting Up */ sockroutine(g_ape); /* loop */ /* Shutdown */ if (pidfile != NULL) { unlink(pidfile); } free(confs_path); ape_dns_free(g_ape); del_timer_identifier(ct_id, g_ape); events_free(g_ape); transport_free(g_ape); hashtbl_free(g_ape->hSessid, 0); hashtbl_free(g_ape->hChannel, 0); hashtbl_free(g_ape->hPubid, 0); do_unregister(g_ape); hashtbl_free(g_ape->hCallback, 1); ape_config_free(srv); int i; for (i = 0; i < g_ape->basemem; i++) { if (g_ape->co[i] != NULL) { close_socket(i, g_ape); free(g_ape->co[i]); } } free(g_ape->co); free(g_ape->bufout); free_all_hook_cmd(g_ape); free_all_plugins(g_ape); free(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; }
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; }