예제 #1
0
파일: onion.c 프로젝트: arunsirrpi/onion
/**
 * @short Advises the listener to stop.
 * 
 * The listener is advised to stop listening. After this call no listening is still open, and listen could be
 * called again, or the onion server freed.
 * 
 * If there is any pending connection, it can finish if onion not freed before.
 */
void onion_listen_stop(onion* server){
	ONION_DEBUG("Stop listening");
	int fd=server->listenfd;
	server->listenfd=-1;
	if (server->poller && fd>0){
		onion_poller_remove(server->poller, fd);
	}
	if (fd>0){
    shutdown(fd,SHUT_RDWR); // If no shutdown, listen blocks. 
		close(fd);
  }
}
예제 #2
0
파일: onion.c 프로젝트: KokaKiwi/onion
/**
 * @short Performs the listening with the given mode
 * @memberof onion_t
 *
 * This is the main loop for the onion server.
 * 
 * It initiates the listening on all the selected ports and addresses.
 *
 * @returns !=0 if there is any error. It returns actualy errno from the network operations. See socket for more information.
 */
int onion_listen(onion *o){
#ifdef HAVE_PTHREADS
	if (!(o->flags&O_DETACHED) && (o->flags&O_DETACH_LISTEN)){ // Must detach and return
		o->flags|=O_DETACHED;
		pthread_create(&o->listen_thread,NULL, (void*)onion_listen, o);
		return 0;
	}
#endif
	
	if (!o->listen_points){
		onion_add_listen_point(o,NULL,NULL,onion_http_new());
		ONION_DEBUG("Created default HTTP listen port");
	}

	/// Start listening
	size_t successful_listened_points=0;
	onion_listen_point **lp=o->listen_points;
	while (*lp){
		int listen_result=onion_listen_point_listen(*lp);
		if (!listen_result) {
			successful_listened_points++;
		}
		lp++;
	}
	if (!successful_listened_points){
		ONION_ERROR("There are no available listen points");
		return 1;
	}

	
	if (o->flags&O_ONE){
		onion_listen_point **listen_points=o->listen_points;
		if (listen_points[1]!=NULL){
			ONION_WARNING("Trying to use non-poll and non-thread mode with several listen points. Only the first will be listened");
		}
		onion_listen_point *op=listen_points[0];
		do{
			onion_request *req=onion_request_new(op);
			if (!req)
				continue;
			ONION_DEBUG("Accepted request %p", req);
			onion_request_set_no_keep_alive(req);
			int ret;
			do{
				ret=req->connection.listen_point->read_ready(req);
			}while(ret>=0);
			ONION_DEBUG("End of request %p", req);
			onion_request_free(req);
			//req->connection.listen_point->close(req);
		}while(((o->flags&O_ONE_LOOP) == O_ONE_LOOP) && op->listenfd>0);
	}
	else{
		onion_listen_point **listen_points=o->listen_points;
		while (*listen_points){
			onion_listen_point *p=*listen_points;
			ONION_DEBUG("Adding listen point fd %d to poller", p->listenfd);
			onion_poller_slot *slot=onion_poller_slot_new(p->listenfd, (void*)onion_listen_point_accept, p);
			onion_poller_slot_set_type(slot, O_POLL_ALL);
			onion_poller_add(o->poller, slot);
			listen_points++;
		}

#ifdef HAVE_PTHREADS
		ONION_DEBUG("Start polling / listening %p, %p, %p", o->listen_points, *o->listen_points, *(o->listen_points+1));
		if (o->flags&O_THREADED){
			o->threads=malloc(sizeof(pthread_t)*(o->nthreads-1));
			int i;
			for (i=0;i<o->nthreads-1;i++){
				pthread_create(&o->threads[i],NULL,(void*)onion_poller_poll, o->poller);
			}
			
			// Here is where it waits.. but eventually it will exit at onion_listen_stop
			onion_poller_poll(o->poller);
			ONION_DEBUG("Closing onion_listen");
			
			for (i=0;i<o->nthreads-1;i++){
				pthread_join(o->threads[i],NULL);
			}
		}
		else
#endif
			onion_poller_poll(o->poller);

		listen_points=o->listen_points;
		while (*listen_points){
			onion_listen_point *p=*listen_points;
			if (p->listenfd>0){
				ONION_DEBUG("Removing %d from poller", p->listenfd);
				onion_poller_remove(o->poller, p->listenfd);
			}
			listen_points++;
		}
	}
	return 0;
}
예제 #3
0
파일: poller.c 프로젝트: Nov11/onion
/**
 * @short Do the event polling.
 * @memberof onion_poller_t
 *
 * It loops over polling. To exit polling call onion_poller_stop().
 *
 * If no fd to poll, returns.
 */
void onion_poller_poll(onion_poller *p){
	struct epoll_event event[MAX_EVENTS];
	ONION_DEBUG("Start polling");
	p->stop=0;
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
	p->npollers++;
	ONION_DEBUG0("Npollers %d. %d listenings %p", p->npollers, p->n, p->head);
	pthread_mutex_unlock(&p->mutex);
#endif
	int maxtime;
	time_t ctime;
	int timeout;
	while (!p->stop && p->head){
		ctime=time(NULL);
		pthread_mutex_lock(&p->mutex);
		maxtime=onion_poller_get_next_timeout(p);
		pthread_mutex_unlock(&p->mutex);

		timeout=maxtime-ctime;
		if (timeout>3600)
			timeout=3600000;
		else
			timeout*=1000;
		ONION_DEBUG0("Wait for %d ms", timeout);
		int nfds = epoll_wait(p->fd, event, MAX_EVENTS, timeout);
		int ctime_end=time(NULL);
		ONION_DEBUG0("Current time is %d, limit is %d, timeout is %d. Waited for %d seconds", ctime, maxtime, timeout, ctime_end-ctime);
    ctime=ctime_end;

		pthread_mutex_lock(&p->mutex);
		{ // Somebody timedout?
			onion_poller_slot *next=p->head;
			while (next){
				onion_poller_slot *cur=next;
				next=next->next;
				if (cur->timeout_limit <= ctime){
					ONION_DEBUG0("Timeout on %d, was %d (ctime %d)", cur->fd, cur->timeout_limit, ctime);
          int i;
          for (i=0;i<nfds;i++){
            onion_poller_slot *el=(onion_poller_slot*)event[i].data.ptr;
            if (cur==el){ // If removed just one with event, make it ignore the event later.
              ONION_DEBUG0("Ignoring event as it timeouted: %d", cur->fd);
              event[i].data.ptr=NULL;
            }
          }
          onion_poller_remove(p, cur->fd);
				}
			}
		}
		pthread_mutex_unlock(&p->mutex);

		if (nfds<0){ // This is normally closed p->fd
			//ONION_DEBUG("Some error happened"); // Also spurious wakeups... gdb is to blame sometimes or any other.
			if(p->fd<0 || !p->head){
				ONION_DEBUG("Finishing the epoll as finished: %s", strerror(errno));
#ifdef HAVE_PTHREADS
				pthread_mutex_lock(&p->mutex);
				p->npollers--;
				pthread_mutex_unlock(&p->mutex);
#endif
				return;
			}
		}
		int i;
		for (i=0;i<nfds;i++){
			onion_poller_slot *el=(onion_poller_slot*)event[i].data.ptr;
      if (!el)
        continue;
			// Call the callback
			//ONION_DEBUG("Calling callback for fd %d (%X %X)", el->fd, event[i].events);
			int n=-1;
			if (event[i].events&EPOLLRDHUP){
				n=-1;
			}
			else{ // I also take care of the timeout, no timeout when on the handler, it should handle it itself.
				el->timeout_limit=INT_MAX;

#ifdef __DEBUG0__
        char **bs=backtrace_symbols((void * const *)&el->f, 1);
        ONION_DEBUG0("Calling handler: %s (%d)",bs[0], el->fd);
        onion_low_free(bs); /* This cannot be onion_low_free since from
		     backtrace_symbols. */
#endif
	/* Sometimes, el->f happens to be null. We want to remove this
	   polling in that weird case. */
				if (el->f)
				  n= el->f(el->data);
				else
				  n= -1;

				ctime=time(NULL);
				if (el->timeout>0)
					el->timeout_limit=ctime+el->timeout;
			}
			if (n<0){
				onion_poller_remove(p, el->fd);
			}
			else{
				ONION_DEBUG0("Re setting poller %d", el->fd);
				event[i].events=el->type;
				if (p->fd>=0){
					int e=epoll_ctl(p->fd, EPOLL_CTL_MOD, el->fd, &event[i]);
					if (e<0){
						ONION_ERROR("Error resetting poller, %s", strerror(errno));
					}
				}
			}
		}
	}
	ONION_DEBUG("Finished polling fds");
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
	p->npollers--;
	ONION_DEBUG0("Npollers %d", p->npollers);
	pthread_mutex_unlock(&p->mutex);
#endif
}
예제 #4
0
파일: poller.c 프로젝트: LiKun-8/onion
/**
 * @short Do the event polling.
 * @memberof onion_poller_t
 * @ingroup poller
 *
 * It loops over polling. To exit polling call onion_poller_stop().
 *
 * If no fd to poll, returns.
 */
void onion_poller_poll(onion_poller *p){
	struct epoll_event event[onion_poller_max_events];
	ONION_DEBUG("Start polling");
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
	p->npollers++;
	p->stop=0;
	ONION_DEBUG0("Npollers %d. %d listenings %p", p->npollers, p->n, p->head);
	pthread_mutex_unlock(&p->mutex);
#else
	p->stop=0;
#endif
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
	char stop = !p->stop && p->head;
	pthread_mutex_unlock(&p->mutex);
#else
	char stop = !p->stop && p->head;
#endif
	while (stop){
		int nfds = epoll_wait(p->fd, event, onion_poller_max_events, -1);

		if (nfds<0){ // This is normally closed p->fd
			//ONION_DEBUG("Some error happened"); // Also spurious wakeups... gdb is to blame sometimes or any other.
			if(p->fd<0 || !p->head){
				ONION_DEBUG("Finishing the epoll as finished: %s", strerror(errno));
#ifdef HAVE_PTHREADS
				pthread_mutex_lock(&p->mutex);
				p->npollers--;
				pthread_mutex_unlock(&p->mutex);
#endif
				return;
			}
		}
		int i;
		for (i=0;i<nfds;i++){
			onion_poller_slot *el=(onion_poller_slot*)event[i].data.ptr;
      if (!el)
        continue;
			// Call the callback
			//ONION_DEBUG("Calling callback for fd %d (%X %X)", el->fd, event[i].events);
			int n=-1;
			if (event[i].events&(EPOLLRDHUP | EPOLLHUP)){
				n=-1;
			}
			else{ // I also take care of the timeout, no timeout when on the handler, it should handle it itself.
				el->timeout_limit=INT_MAX;

#ifdef __DEBUG0__
        char **bs=backtrace_symbols((void * const *)&el->f, 1);
        ONION_DEBUG0("Calling handler: %s (%d)",bs[0], el->fd);
        onion_low_free(bs); /* This cannot be onion_low_free since from
		     backtrace_symbols. */
#endif
				n = el->f(el->data);

				if (el->timeout>0){
					el->timeout_limit=onion_time()+el->timeout;
					onion_poller_timer_check(p, el->timeout_limit);
				}
			}
			if (n<0){
				onion_poller_remove(p, el->fd);
			}
			else{
				ONION_DEBUG0("Re setting poller %d", el->fd);
				event[i].events=el->type;
				if (p->fd>=0){
					int e=epoll_ctl(p->fd, EPOLL_CTL_MOD, el->fd, &event[i]);
					if (e<0){
						ONION_ERROR("Error resetting poller, %s", strerror(errno));
					}
				}
			}
		}
#ifdef HAVE_PTHREADS
		pthread_mutex_lock(&p->mutex);
		stop = !p->stop && p->head;
		pthread_mutex_unlock(&p->mutex);
#else
		stop = !p->stop && p->head;
#endif
	}
	ONION_DEBUG("Finished polling fds");
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
	p->npollers--;
	ONION_DEBUG0("Npollers %d", p->npollers);
	pthread_mutex_unlock(&p->mutex);
#endif
}