예제 #1
0
파일: onion.c 프로젝트: YggdrasiI/onion
/**
 * @short Creates the onion structure to fill with the server data, and later do the onion_listen()
 * @memberof onion_t
 * 
 * Creates an onion structure that can be used to set the server, port, SSL and similar parameters. It works over 
 * the onion structure, which is the main structure to control the listening of new connections throught TCP/IP.
 * 
 * A normal usage would be like this:
 * 
 * @code
 * 
 * onion *o=onion_new(O_THREADED);
 * onion_set_root_handler(o, onion_handler_directory("."));
 * onion_listen(o);
 * 
 * @endcode
 * 
 * @param flags Or'ed flags to use at the listening daemon. Normally one of O_ONE, O_ONE_LOOP or O_THREADED.
 * 
 * @returns The onion structure.
 * 
 * @see onion_mode_e onion_t
 */
onion *onion_new(int flags){
	ONION_DEBUG0("Some internal sizes: onion size: %d, request size %d, response size %d",sizeof(onion),sizeof(onion_request),sizeof(onion_response));
	if(SOCK_CLOEXEC == 0){
		ONION_WARNING("There is no support for SOCK_CLOEXEC compiled in libonion. This may be a SECURITY PROBLEM as connections may leak into executed programs.");
	}
	
	if (!(flags&O_NO_SIGPIPE)){
		ONION_DEBUG("Ignoring SIGPIPE");
		signal(SIGPIPE, SIG_IGN);
	}
	

	onion *o=onion_low_calloc(1,sizeof(onion));
	if (!o){
		return NULL;
	}
	o->flags=(flags&0x0FF)|O_SSL_AVAILABLE;
	o->timeout=5000; // 5 seconds of timeout, default.
	o->poller=onion_poller_new(15);
	if (!o->poller){
		onion_low_free(o);
		return NULL;
	}
	o->sessions=onion_sessions_new();
	o->internal_error_handler=onion_handler_new((onion_handler_handler)onion_default_error, NULL, NULL);
	o->max_post_size=1024*1024; // 1MB
	o->max_file_size=1024*1024*1024; // 1GB
#ifdef HAVE_PTHREADS
	o->flags|=O_THREADS_AVALIABLE;
	o->nthreads=8;
	if (o->flags&O_THREADED)
		o->flags|=O_THREADS_ENABLED;
#endif
	return o;
}
예제 #2
0
/** 
 * @short Creates an onion handler with that private datas.
 * @memberof onion_handler_t
 *
 */
onion_handler *onion_handler_new(onion_handler_handler handler, void *priv_data, onion_handler_private_data_free priv_data_free){
	onion_handler *phandler=onion_low_calloc(1, sizeof(onion_handler));
	phandler->handler=handler;
	phandler->priv_data=priv_data;
	phandler->priv_data_free=priv_data_free;
	return phandler;
}
예제 #3
0
/**
 *  @short Creates a request object
 * @memberof onion_request_t
 *
 * @param op Listen point this request is listening to, to be able to read and write data
 */
onion_request *onion_request_new(onion_listen_point *op) {
    onion_request *req;
    req=onion_low_calloc(1, sizeof(onion_request));

    req->connection.listen_point=op;
    req->connection.fd=-1;

    //req->connection=con;
    req->headers=onion_dict_new();
    onion_dict_set_flags(req->headers, OD_ICASE);
    ONION_DEBUG0("Create request %p", req);

    if (op) {
        if (op->request_init) {
            if (op->request_init(req)<0) {
                ONION_DEBUG("Invalid request, closing");
                onion_request_free(req);
                return NULL;
            }
        }
        else
            onion_listen_point_request_init_from_socket(req);
    }
    return req;
}
예제 #4
0
파일: poller.c 프로젝트: 1514louluo/onion
/**
 * @short Creates a new slot for the poller, for input data to be ready.
 * @memberof onion_poller_slot_t
 * @ingroup poller
  *
 * @param fd File descriptor to watch
 * @param f Function to call when data is ready. If function returns <0, the slot will be removed.
 * @param data Data to pass to the function.
 *
 * @returns A new poller slot, ready to be added (onion_poller_add) or modified (onion_poller_slot_set_shutdown, onion_poller_slot_set_timeout).
 */
onion_poller_slot *onion_poller_slot_new(int fd, int (*f)(void*), void *data){
	static onion_poller_slot empty_slot;
	static onion_poller_slot *slots;
	static rlim_t max_slots;
	if (!max_slots) {
		struct rlimit rlim;
		if (getrlimit(RLIMIT_NOFILE, &rlim)) {
			ONION_ERROR("getrlimit: %s", strerror(errno));
			return NULL;
		}
		max_slots = rlim.rlim_cur;
		if (max_slots > MAX_SLOTS)
			max_slots = MAX_SLOTS;
		slots = (onion_poller_slot *)onion_low_calloc(max_slots, sizeof(onion_poller_slot));
	}
	if (fd<0||fd>=max_slots){
		ONION_ERROR("Trying to add an invalid file descriptor to the poller. Please check.");
		return NULL;
	}
	onion_poller_slot *el=&slots[fd];
	*el=empty_slot;
	el->fd=fd;
	el->f=f;
	el->data=data;
	el->timeout=-1;
	el->timeout_limit=INT_MAX;
	el->type=EPOLLIN | EPOLLHUP | EPOLLONESHOT | EPOLLHUP;

	return el;
}
예제 #5
0
/// Create a new poller
onion_poller *onion_poller_new(int aprox_n){
	evthread_use_pthreads();

	onion_poller *ret=onion_low_calloc(1,sizeof(onion_poller));
	ret->base=event_base_new();
	sem_init(&ret->sem, 0, 1);
	return ret;
}
예제 #6
0
/// Create a new slot for the poller
onion_poller_slot *onion_poller_slot_new(int fd, int (*f)(void*), void *data){
	onion_poller_slot *ret=onion_low_calloc(1, sizeof(onion_poller_slot));
	ret->fd=fd;
	ret->f=f;
	ret->data=data;
	ret->type=EV_READ | EV_WRITE;

	return ret;
}
예제 #7
0
파일: dict.c 프로젝트: Sts0mrg0/onion
/**
 * @memberof onion_dict_t
 * Initializes the basic tree with all the structure in place, but empty.
 */
onion_dict *onion_dict_new(){
	onion_dict *dict=onion_low_calloc(1, sizeof(onion_dict));
#ifdef HAVE_PTHREADS
	pthread_rwlock_init(&dict->lock, NULL);
	pthread_mutex_init(&dict->refmutex, NULL);
#endif
	dict->refcount=1;
  dict->cmp=strcmp;
	ONION_DEBUG0("New %p, refcount %d",dict, dict->refcount);
	return dict;
}
예제 #8
0
파일: poller.c 프로젝트: Nov11/onion
/**
 * @short Creates a new slot for the poller, for input data to be ready.
 * @memberof onion_poller_slot_t
 *
 * @param fd File descriptor to watch
 * @param f Function to call when data is ready. If function returns <0, the slot will be removed.
 * @param data Data to pass to the function.
 *
 * @returns A new poller slot, ready to be added (onion_poller_add) or modified (onion_poller_slot_set_shutdown, onion_poller_slot_set_timeout).
 */
onion_poller_slot *onion_poller_slot_new(int fd, int (*f)(void*), void *data){
	if (fd<0){
		ONION_ERROR("Trying to add an invalid file descriptor to the poller. Please check.");
		return NULL;
	}
	onion_poller_slot *el=(onion_poller_slot*)onion_low_calloc(1, sizeof(onion_poller_slot));
	el->fd=fd;
	el->f=f;
	el->data=data;
	el->timeout=-1;
	el->timeout_limit=INT_MAX;
	el->type=EPOLLIN | EPOLLHUP | EPOLLONESHOT;

	return el;
}
예제 #9
0
파일: poller.c 프로젝트: LiKun-8/onion
/// Initializes static data. Init at onion_poller_new, deinit at _free.
static void onion_poller_static_init(){
	int16_t prevcount = __sync_fetch_and_add(&onion_poller_static.refcount, 1);
	if (prevcount!=0) // Only init first time
		return;

	memset(&onion_poller_static.empty_slot, 0, sizeof(onion_poller_static.empty_slot));

	struct rlimit rlim;
	if (getrlimit(RLIMIT_NOFILE, &rlim)) {
		ONION_ERROR("getrlimit: %s", strerror(errno));
		return;
	}
	onion_poller_static.max_slots = rlim.rlim_cur;
	if (onion_poller_static.max_slots > MAX_SLOTS)
		onion_poller_static.max_slots = MAX_SLOTS;
	onion_poller_static.slots = (onion_poller_slot *)onion_low_calloc(onion_poller_static.max_slots, sizeof(onion_poller_slot));
}
예제 #10
0
파일: poller.c 프로젝트: LiKun-8/onion
/**
 * @short Returns a poller object that helps polling on sockets and files
 * @memberof onion_poller_t
 * @ingroup poller
 *
 * This poller is implemented through epoll, but other implementations are possible
 *
 */
onion_poller *onion_poller_new(int n){
	onion_poller *p=onion_low_calloc(1, sizeof(onion_poller));
	p->fd=epoll_create1(EPOLL_CLOEXEC);
	if (p->fd < 0){
		ONION_ERROR("Error creating the poller. %s", strerror(errno));
		onion_low_free(p);
		return NULL;
	}
	p->eventfd=eventfd(0,EFD_CLOEXEC | EFD_NONBLOCK);
#if EFD_CLOEXEC == 0
  fcntl(p->eventfd,F_SETFD,FD_CLOEXEC);
#endif
	p->head=NULL;
	p->n=0;
  p->stop=0;

#ifdef HAVE_PTHREADS
  ONION_DEBUG("Init thread stuff for poll. Eventfd at %d", p->eventfd);
  p->npollers=0;
  pthread_mutexattr_t attr;
  pthread_mutexattr_init(&attr);
  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  pthread_mutex_init(&p->mutex, &attr);
  pthread_mutexattr_destroy(&attr);
#endif

	onion_poller_static_init();


  onion_poller_slot *ev=onion_poller_slot_new(p->eventfd,onion_poller_stop_helper,p);
  onion_poller_add(p,ev);

	p->timerfd=timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
	ev=onion_poller_slot_new(p->timerfd,&onion_poller_timer,p);
	onion_poller_add(p,ev);
	onion_poller_timer(p); // Force first timeout

	return p;
}
예제 #11
0
/**
 * @short Write some data into the request, and passes it line by line to onion_request_fill
 *
 * It features a state machine, from req->parse_state.
 *
 * Depending on the state input is redirected to a diferent parser, one for headers, POST url encoded data...
 *
 * @return Returns the number of bytes writen, or <=0 if connection should close, according to onion_connection_status
 * @see onion_connection_status
 */
onion_connection_status onion_request_write(onion_request *req, const char *data, size_t size){
	if (!req->parser_data){
		req->parser_data=onion_low_calloc(1, sizeof(onion_token));
		req->parser=parse_headers_GET;
	}

	onion_connection_status (*parse)(onion_request *req, onion_buffer *data);
	parse=req->parser;

	if (parse){
		onion_buffer odata={ data, size, 0};
		while (odata.size>odata.pos){
			int r=parse(req, &odata);
			if (r!=OCS_NEED_MORE_DATA){
				return r;
			}
			parse=req->parser;
		}
		return OCS_NEED_MORE_DATA;
	}

	return OCS_INTERNAL_ERROR;
}
예제 #12
0
/// Create a new poller
onion_poller *onion_poller_new(int aprox_n){
	onion_poller *ret=onion_low_calloc(1,sizeof(onion_poller));
	ret->loop=ev_default_loop(0);
	ret->sem=sem_open("/poller", O_CREAT, 0, 1);
	return ret;
}
예제 #13
0
/**
 * @short Creates an empty listen point.
 * @memberof onion_listen_point_t
 * 
 * Called by real listen points to ease the creation.
 * 
 * @returns An alloc'ed onion_listen_point pointer
 */
onion_listen_point *onion_listen_point_new(){
	onion_listen_point *ret=onion_low_calloc(1,sizeof(onion_listen_point));
	return ret;
}
예제 #14
0
파일: https.c 프로젝트: SEI-AMS/onion
/**
 * @short Creates a new listen point with HTTPS powers.
 * @memberof onion_https_t
 * 
 * Creates the HTTPS listen point.
 * 
 * Might be called with (O_SSL_NONE,NULL), and set up the certificate later with onion_https_set_certificate.
 * 
 * @param type Type of certificate to setup
 * @param filename File from where to get the data
 * @param ... More types and filenames until O_SSL_NONE.
 * @returns An onion_listen_point with the desired data, ready to start listening.
 */
onion_listen_point *onion_https_new(){
	onion_listen_point *op=onion_listen_point_new();
	op->request_init=onion_https_request_init;
	op->free_user_data=onion_https_free_user_data;
	op->listen_stop=onion_https_listen_stop;
	op->read=onion_https_read;
	op->write=onion_https_write;
	op->close=onion_https_close;
	op->read_ready=onion_http_read_ready;
	op->secure = true;
	
	op->user_data=onion_low_calloc(1,sizeof(onion_https));
	onion_https *https=(onion_https*)op->user_data;
	
#ifdef HAVE_PTHREADS
	gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
#endif
	//if (!(o->flags&O_USE_DEV_RANDOM)){
		gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
	//}
	
	gnutls_global_init ();
	gnutls_certificate_allocate_credentials (&https->x509_cred);
	
	// set cert here??
	//onion_https_set_certificate(op,O_SSL_CERTIFICATE_KEY, "mycert.pem","mycert.pem");
	int e;
	int bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW);
	e=gnutls_dh_params_init (&https->dh_params);
	if (e<0){
		ONION_ERROR("Error initializing HTTPS: %s", gnutls_strerror(e));
		gnutls_certificate_free_credentials (https->x509_cred);
		op->free_user_data=NULL;
		onion_listen_point_free(op);
		onion_low_free(https);
		return NULL;
	}
	e=gnutls_dh_params_generate2 (https->dh_params, bits);
	if (e<0){
		ONION_ERROR("Error initializing HTTPS: %s", gnutls_strerror(e));
		gnutls_certificate_free_credentials (https->x509_cred);
		op->free_user_data=NULL;
		onion_listen_point_free(op);
		onion_low_free(https);
		return NULL;
	}
	e=gnutls_priority_init (&https->priority_cache, "PERFORMANCE:%SAFE_RENEGOTIATION:-VERS-TLS1.0", NULL);
	if (e<0){
		ONION_ERROR("Error initializing HTTPS: %s", gnutls_strerror(e));
		gnutls_certificate_free_credentials (https->x509_cred);
		gnutls_dh_params_deinit(https->dh_params);
		op->free_user_data=NULL;
		onion_listen_point_free(op);
		onion_low_free(https);
		return NULL;
	}
	gnutls_certificate_set_dh_params (https->x509_cred, https->dh_params);
	gnutls_priority_init (&https->priority_cache, "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0:+VERS-SSL3.0:%COMPAT", NULL); // PERFORMANCE:%SAFE_RENEGOTIATION:-VERS-TLS1.0:%COMPAT"
	
	ONION_DEBUG("HTTPS connection ready");
	
	return op;
}