Exemplo n.º 1
0
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];	
}
Exemplo n.º 2
0
/* 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]));
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
 //! Sets the buffer capacity to \p cap, and makes it non-resizable.
 void setFixedCapacity(int cap) {
   growup(cap);
   clear();
   growable = false;
 }
Exemplo n.º 5
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];
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
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;
}