Example #1
0
/**
 * @short Marks the poller to stop ASAP
 * @memberof onion_poller_t
 * @ingroup poller
 */
void onion_poller_stop(onion_poller *p){
  ONION_DEBUG("Stopping poller");
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
  p->stop=1;
	pthread_mutex_unlock(&p->mutex);
#else
	p->stop=1;
#endif

  char data[8]={0,0,0,0, 0,0,0,1};
  int __attribute__((unused)) r=read(p->eventfd, data, 8); // Flush eventfd data, discard data

#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&p->mutex);
  int n=p->npollers;
	pthread_mutex_unlock(&p->mutex);

  if (n>0){
		int w=write(p->eventfd,data,8); // Tell another thread to exit
		if (w<0){
			ONION_ERROR("Error signaling poller to stop!");
		}
	}
	else
		ONION_DEBUG("Poller stopped");
#endif
}
Example #2
0
/**
 * @short Gets the sessionid cookie, if any, and sets it to req->session_id.
 * @memberof onion_request_t
 */
void onion_request_guess_session_id(onion_request *req){
	if (req->session_id) // already known.
		return;
	const char *v=onion_dict_get(req->headers, "Cookie");
	ONION_DEBUG("Session ID, maybe from %s",v);
	char *r=NULL;
	onion_dict *session;
	
	do{ // Check all possible sessions
		if (r)
			free(r);
		if (!v)
			return;
		v=strstr(v,"sessionid=");
		if (!v) // exit point, no session found.
			return;
		v+=10;
		r=strdup(v); // Maybe allocated more memory, not much anyway.
		char *p=r;
		while (*p!='\0' && *p!=';') p++;
		*p='\0';
		ONION_DEBUG0("Checking if %s exists in sessions", r);
		session=onion_sessions_get(req->server->sessions, r);
	}while(!session);
	
	req->session_id=r;
	req->session=session;
	ONION_DEBUG("Session ID, from cookie, is %s",req->session_id);
}
Example #3
0
/// Gets the output data
int oterm_out(process *o, onion_request *req, onion_response *res){
	pthread_mutex_lock(&o->mutex);
	if (onion_request_get_query(req, "initial")){
		if (o->buffer[BUFFER_SIZE-1]!=0){ // If 0 then never wrote on it. So if not, write from pos to end too, first.
			onion_response_write(res, &o->buffer[o->buffer_pos], BUFFER_SIZE-o->buffer_pos);
		}
		onion_response_write(res, o->buffer, o->buffer_pos);
		onion_response_printf(res, "\033]oterm;%d;", o->buffer_pos);
    onion_response_printf(res, "\033]url;https://localhost:8080/uuid/%s/;", o->uuid);
		pthread_mutex_unlock(&o->mutex);
		return OCS_PROCESSED;
	}
	
	int16_t p=atoi(onion_request_get_queryd(req, "pos", "0")); //o->buffer_pos;
	ONION_DEBUG("Wait for data at %d", p);
	while(p==o->buffer_pos) // We need it to be diferent, if not does not make sense to wake up
		pthread_cond_wait(&o->dataReady, &o->mutex);
	ONION_DEBUG("Data ready at %d (waiting from %d)", o->buffer_pos, p);
	if (o->buffer_pos<p){
		onion_response_write(res, &o->buffer[p], BUFFER_SIZE-p);
		p=0;
	}
	onion_response_write(res, &o->buffer[p], o->buffer_pos-p);
	onion_response_printf(res, "\033]oterm;%d;", o->buffer_pos);
	pthread_mutex_unlock(&o->mutex);
	return OCS_PROCESSED;
}
Example #4
0
/**
 * @short Removes the allocated data
 * @memberof onion_t
 */
void onion_free(onion *onion){
	ONION_DEBUG("Onion free");
	onion_listen_stop(onion);
	
	if (onion->poller)
		onion_poller_free(onion->poller);
	
	if (onion->username)
		free(onion->username);
	
	if (onion->listen_points){
		onion_listen_point **p=onion->listen_points;
		while(*p!=NULL){
			ONION_DEBUG("Free %p listen_point", *p);
			onion_listen_point_free(*p++);
		}
		free(onion->listen_points);
	}
	if (onion->root_handler)
		onion_handler_free(onion->root_handler);
	if (onion->internal_error_handler)
		onion_handler_free(onion->internal_error_handler);
	onion_mime_set(NULL);
	if (onion->sessions)
		onion_sessions_free(onion->sessions);
	
#ifdef HAVE_PTHREADS
	if (onion->threads)
		free(onion->threads);
#endif
	free(onion);
}
Example #5
0
onion_connection_status oterm_uuid(void *data, onion_request *req, onion_response *res){
  const char *path=onion_request_get_path(req);
  
  ONION_DEBUG("Ask path %s (%p)", path, data);
  // split id / function
  int l=strlen(path)+1;
  char *id=alloca(l);
  char *function=NULL;
  
  int i;
  memcpy(id,path,l);
  int func_pos=0;
  for (i=0;i<l;i++){
    if (id[i]=='/'){
      if (!function && id[i+1]!='\0')
        function=id+i+1;
      id[i]=0;
      func_pos=i;
      break;
    }
  }
  ONION_DEBUG("Id %s, function %s", id, function);
  process *term=oterm_get_process_by_uuid(data, id);
  if (!term)
    return OCS_INTERNAL_ERROR;
  
  if (!function)
    return onion_shortcut_internal_redirect("static/oterm.html", req, res);
  // do it
  onion_request_advance_path(req, func_pos);

  return oterm_process(data, term, function, req, res);
}
Example #6
0
onion_connection_status index_html_template(onion_dict *context){
	char *lang = (char*)malloc (3*sizeof(char));
	strcpy(lang,"en\0");  
	ONION_DEBUG("Add to dict");
  if (context) onion_dict_add(context, "LANG", lang, OD_FREE_VALUE);
	ONION_DEBUG("Free dict");
  if (context) onion_dict_free(context); // if you remove this line, it works correctly
  return OCS_PROCESSED;
}
Example #7
0
/**
 * @short Checks a specific set of major.minor.patch and returns if the current using onion is ABI compatible.
 *
 * Onion uses SEMVER (http://semver.org/), and with this simple function its
 * possible to check if your compiled code is compatible with the onion
 * version.
 *
 * It also allows to in the rare case that there is some really bad version of
 * onion to warn the users.
 *
 * Normally users need just to add a onion_version_is_compatible() check, and
 * if not compatible abort:
 *
 *   if (!onion_version_is_compatible()) abort();
 *
 */
bool onion_version_is_compatible3(int major, int minor, int patch){
  if (major != ONION_VERSION_MAJOR){
    ONION_DEBUG("Onion major version (%d) is not compatible with program's (%d). Should match.", ONION_VERSION_MAJOR, major);
    return false;
  }
  if (minor > ONION_VERSION_MINOR){
    ONION_DEBUG("Onion minor version (%d) is not compatible with program's (%d). Program's has to be equal or greater.", ONION_VERSION_MINOR, minor);
    return false;
  }
  return true;
}
Example #8
0
/**
 * @short Closes the https connection
 * @memberof onion_https_t
 * 
 * It frees local data and closes the socket.
 * 
 * @param req to close.
 */
static void onion_https_close(onion_request *req){
	ONION_DEBUG("Close HTTPS connection");
	gnutls_session_t session=(gnutls_session_t)req->connection.user_data;
	if (session){
		ONION_DEBUG("Free session %p", session);
		gnutls_bye (session, GNUTLS_SHUT_WR);
		gnutls_deinit(session);
	
	}
	onion_listen_point_request_close_socket(req);
}
Example #9
0
File: onion.c Project: Nov11/onion
/**
 * @short Removes the allocated data
 * @memberof onion_t
 */
void onion_free(onion *onion){
	ONION_DEBUG("Onion free");

	if (onion->flags&O_LISTENING)
		onion_listen_stop(onion);

	if (onion->poller)
		onion_poller_free(onion->poller);

	if (onion->username)
		onion_low_free(onion->username);

	if (onion->listen_points){
		onion_listen_point **p=onion->listen_points;
		while(*p!=NULL){
			ONION_DEBUG("Free %p listen_point", *p);
			onion_listen_point_free(*p++);
		}
		onion_low_free(onion->listen_points);
	}
	if (onion->root_handler)
		onion_handler_free(onion->root_handler);
	if (onion->internal_error_handler)
		onion_handler_free(onion->internal_error_handler);
	onion_mime_set(NULL);
	if (onion->sessions)
		onion_sessions_free(onion->sessions);

	{
#ifdef HAVE_PTHREADS
	  pthread_mutex_lock (&onion->mutex);
#endif
	  void* data = onion->client_data;
	  onion->client_data = NULL;
	  if (data && onion->client_data_free)
	     onion->client_data_free (data);
	  onion->client_data_free = NULL;
#ifdef HAVE_PTHREADS
	  pthread_mutex_unlock (&onion->mutex);
	  pthread_mutex_destroy (&onion->mutex);
#endif
	};
#ifdef HAVE_PTHREADS
	if (onion->threads)
		onion_low_free(onion->threads);
#endif
	if (!(onion->flags&O_NO_SIGTERM)){
		signal(SIGINT,SIG_DFL);
		signal(SIGTERM,SIG_DFL);
	}
	last_onion=NULL;
	onion_low_free(onion);
}
Example #10
0
/**
 * @short Default implementation that initializes the request from a socket
 * @memberof onion_listen_point_t
 * 
 * Accepts the connection and initializes it.
 * 
 * @param req Request to initialize
 * @returns <0 if error opening the connection
 */
int onion_listen_point_request_init_from_socket(onion_request *req){
	onion_listen_point *op=req->connection.listen_point;
	int listenfd=op->listenfd;
	if (listenfd<0){
		ONION_DEBUG("Listen point closed, no request allowed");
		return -1;
	}
	
	/// Follows default socket implementation. If your protocol is socket based, just use it.
	
	req->connection.cli_len = sizeof(req->connection.cli_addr);

	int set_cloexec=SOCK_CLOEXEC == 0;
	int clientfd=accept4(listenfd, (struct sockaddr *) &req->connection.cli_addr, 
				&req->connection.cli_len, SOCK_CLOEXEC);
	if (clientfd<0){
		ONION_DEBUG("Second try? errno %d, clientfd %d", errno, clientfd);
		if (errno==ENOSYS){
			clientfd=accept(listenfd, (struct sockaddr *) &req->connection.cli_addr, 
					&req->connection.cli_len);
		}
		ONION_DEBUG("How was it? errno %d, clientfd %d", errno, clientfd);
		if (clientfd<0){
			ONION_ERROR("Error accepting connection: %s",strerror(errno),errno);
			onion_listen_point_request_close_socket(req);
			return -1;
		}
	}
	req->connection.fd=clientfd;
	
	/// Thanks to Andrew Victor for pointing that without this client may block HTTPS connection. It could lead to DoS if occupies all connections.
	{
		struct timeval t;
		t.tv_sec = op->server->timeout / 1000;
		t.tv_usec = ( op->server->timeout % 1000 ) * 1000;

		setsockopt(clientfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
	}
	
	if(set_cloexec) { // Good compiler know how to cut this out
		int flags=fcntl(clientfd, F_GETFD);
		if (flags==-1){
			ONION_ERROR("Retrieving flags from connection");
		}
		flags|=FD_CLOEXEC;
		if (fcntl(clientfd, F_SETFD, flags)==-1){
			ONION_ERROR("Setting FD_CLOEXEC to connection");
		}
	}
	
	ONION_DEBUG0("New connection, socket %d",clientfd);
	return 0;
}
Example #11
0
void *t08_thread_write(onion_dict *d){
	int n=0;
	while (n!=N_READERS){
		int i;
		n=0;
		//ONION_DEBUG("Lock read");
		onion_dict_lock_read(d);
		//ONION_DEBUG("Got read lock");
		for (i=0;i<N_READERS;i++){
			char tmp[16];
			snprintf(tmp,16,"%d",i+1);
			const char *r=onion_dict_get(d,tmp);
			if (r)
				n++;
		}
		//ONION_DEBUG("Unlock");
		onion_dict_unlock(d);
		//ONION_DEBUG("Lock write");
		onion_dict_lock_write(d);
		//ONION_DEBUG("Got write lock");
		onion_dict_add(d, "test", "test", OD_DUP_ALL|OD_REPLACE);
		//ONION_DEBUG("Unlock");
		onion_dict_unlock(d);
		ONION_DEBUG("Found %d answers, should be %d.", n, N_READERS);
		usleep(200);
	}
	
	onion_dict_free(d);
	return (char*)1;
}
Example #12
0
void POST_a_lot(void) {
  sleep(1);

  onion_block *tosend = onion_block_new();
  onion_block_add_str(tosend,
                      "POST /configuration HTTP/1.1\nHost: example.com\nContent-Type: x-application/garbage\nContent-Length: 1000000\n\n");

  {
    int i;
    onion_block *bl = onion_block_new();
    for (i = 0; i < 1000; i++) {
      onion_block_add_char(bl, rand() & 255);
    }
    for (i = 0; i < 1000; i++) {
      onion_block_add_block(tosend, bl);
    }
    onion_block_free(bl);
  }

  onion_block *bl = connect_and_send("127.0.0.1", "8080", tosend, 1024 * 64);
  onion_block_free(tosend);

  ONION_DEBUG("%p", strstr(onion_block_data(bl), "\n1000000\n"));
  FAIL_IF_NOT(strstr(onion_block_data(bl), "\n1000000\n") != NULL);

  onion_block_free(bl);
}
Example #13
0
char *t08_thread_read(onion_dict *d){
	char done=0;
	char *ret=NULL;
	while (!done){
		//ONION_DEBUG("Lock read");
		onion_dict_lock_write(d);
		//ONION_DEBUG("Got read lock");
		const char *test=onion_dict_get(d,"test");
		if (test){
			//ONION_DEBUG("Unlock");
			
			//onion_dict_lock_write(d);
			//ONION_DEBUG("Got write lock");
			char tmp[16];
			snprintf(tmp,16,"%d",onion_dict_count(d));
			onion_dict_remove(d,"test");
			onion_dict_add(d,tmp,"test",OD_DUP_ALL);
			ONION_DEBUG("Write answer %d", onion_dict_count(d));
			done=1;
			//ONION_DEBUG("Unlock");
			onion_dict_unlock(d);
			ret=(char*)1;
			break;
		}
		//ONION_DEBUG("Unlock");
		onion_dict_unlock(d);
		usleep(200);
	}
	//ONION_DEBUG("dict free");
	onion_dict_free(d);
	return ret;
}
Example #14
0
void t05_post_content_json(){
	INIT_LOCAL();

	onion *server=onion_new(0);
	onion_listen_point *lp=onion_buffer_listen_point_new();
	json_response post_json = { 0 };
	
	onion_add_listen_point(server,NULL,NULL,lp);
	onion_set_root_handler(server, onion_handler_new((void*)&post_json_check,&post_json,NULL));
	
	onion_request *req=onion_request_new(lp);
#define POST_HEADER "POST / HTTP/1.1\nContent-Type: application/json\nContent-Length: %d\n\n"
	char tmp[1024];
	int json_length=sizeof(JSON_EXAMPLE);
	ONION_DEBUG("Post size is about %d",json_length);
	snprintf(tmp, sizeof(tmp), POST_HEADER, json_length);
// 	ONION_DEBUG("%s",tmp);
	onion_request_write(req,tmp,strlen(tmp));
	onion_request_write(req,JSON_EXAMPLE,json_length);
// 	ONION_DEBUG("%s",JSON_EXAMPLE);
	
	FAIL_IF_NOT_EQUAL_INT(post_json.processed, 2);
	
	onion_request_free(req);
	onion_free(server);
	
	END_LOCAL();
}
Example #15
0
/**
 * @short Sets the port to listen to.
 * @memberof onion_t
 * 
 * Default listen point is HTTP at localhost:8080.
 * 
 * @param server The onion server to act on.
 * @param port The number of port to listen to, or service name, as string always.
 */
int onion_add_listen_point(onion* server, const char* hostname, const char* port, onion_listen_point* protocol){
	if (protocol==NULL){
		ONION_ERROR("Trying to add an invalid entry point. Ignoring.");
		return -1;
	}
	
	protocol->server=server;
	if (hostname)
		protocol->hostname=strdup(hostname);
	if (port)
		protocol->port=strdup(port);
	
	if (server->listen_points){
		onion_listen_point **p=server->listen_points;
		int protcount=0;
		while (*p++) protcount++;
		server->listen_points=realloc(server->listen_points, (protcount+2)*sizeof(onion_listen_point));
		server->listen_points[protcount]=protocol;
		server->listen_points[protcount+1]=NULL;
	}
	else{
		server->listen_points=malloc(sizeof(onion_listen_point*)*2);
		server->listen_points[0]=protocol;
		server->listen_points[1]=NULL;
	}
	
	ONION_DEBUG("add %p listen_point (%p, %p, %p)", protocol, server->listen_points, *server->listen_points, *(server->listen_points+1));
	return 0;
}
Example #16
0
File: poller.c Project: Nov11/onion
/**
 * @short Returns a poller object that helps polling on sockets and files
 * @memberof onion_poller_t
 *
 * This poller is implemented through epoll, but other implementations are possible
 *
 */
onion_poller *onion_poller_new(int n){
	onion_poller *p=onion_low_malloc(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_slot *ev=onion_poller_slot_new(p->eventfd,onion_poller_stop_helper,p);
  onion_poller_add(p,ev);

	return p;
}
Example #17
0
/**
 * @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;
}
Example #18
0
/// @memberof onion_poller_t
void onion_poller_free(onion_poller *p){
	ONION_DEBUG("Free onion poller: %d waiting", p->n);
	p->stop=1;
	close(p->fd);
	// Wait until all pollers exit.

	if (pthread_mutex_trylock(&p->mutex)>0){
		ONION_WARNING("When cleaning the poller object, some poller is still active; not freeing memory");
	}
	else{
		onion_poller_slot *next=p->head;
		while (next){
			onion_poller_slot *tnext=next->next;
			if (next->shutdown)
				next->shutdown(next->shutdown_data);
			next=tnext;
		}
		pthread_mutex_unlock(&p->mutex);

		if (p->eventfd>=0)
			close(p->eventfd);
		if (p->timerfd>=0)
			close(p->timerfd);

		onion_poller_static_deinit();

		onion_low_free(p);
	}
	ONION_DEBUG0("Done");
}
Example #19
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;
}
Example #20
0
/**
 * @short Simple put on webdav is just move a file from tmp to the final destination (or copy if could not move).
 * 
 */
onion_connection_status onion_webdav_put(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){
	ONION_DEBUG("Webdav puts %s", filename);
	
	const char *tmpfile=onion_block_data(onion_request_get_data(req));
	
	int ok=onion_shortcut_rename(tmpfile, filename);
	
	if (ok==0){
		ONION_DEBUG("Created %s succesfully", filename);
		return onion_shortcut_response("201 Created", 201, req, res);
	}
	else{
		ONION_ERROR("Could not rename %s to %s (%s)", tmpfile, filename, strerror(errno));
		return onion_shortcut_response("Could not create resource", HTTP_FORBIDDEN, req, res);
	}
}
Example #21
0
/// Plexes the request depending on arguments.
int oterm_get_data(oterm_data *data, onion_request *req, onion_response *res){
  const char *username=onion_request_get_session(req,"username");
  if (!username){
    ONION_WARNING("Trying to enter authenticated area without username.");
    return OCS_FORBIDDEN;
  }
	oterm_session *o=(oterm_session*)onion_dict_get(data->sessions, onion_request_get_session(req,"username"));
	if (!o){
		o=oterm_session_new();
		onion_dict_lock_write(data->sessions);
		onion_dict_add(data->sessions,onion_request_get_session(req,"username"),o, 0);
		onion_dict_unlock(data->sessions);
	}
  const char *path=onion_request_get_path(req);

  ONION_DEBUG("Ask path %s (%p)", path, data);
  
  if (strcmp(path,"new")==0){
    if (onion_request_get_post(req, "command")){
      free(data->exec_command);
      data->exec_command=strdup(onion_request_get_post(req, "command"));
    }
    oterm_new(data, o, onion_request_get_session(req, "username"), onion_request_get_session(req, "nopam") ? 0 : 1 );
    return onion_shortcut_response("ok", 200, req, res);
  }
  if (strcmp(path,"status")==0)
    return oterm_status(o,req, res);

  return OCS_NOT_PROCESSED;
}
Example #22
0
/// Reads a string until a '\n|\r\n' is found. Returns an onion_token.
int token_read_LINE(onion_token *token, onion_buffer *data){
	if (data->pos>=data->size)
		return OCS_NEED_MORE_DATA;

	char c=data->data[data->pos++];
	int ignore_to_end=0;
	while (c!='\n'){
		if (!ignore_to_end && (token->pos>=(sizeof(token->str)-1))){
			ONION_WARNING("Token too long to parse it. Ignoring remaining. ");
#ifdef __DEBUG__
				char tmp[16];
				strncpy(tmp, token->str, 16);
				tmp[15]='\0';
				ONION_DEBUG("Long token starts with: %s...",tmp);
#endif
			ignore_to_end=1;
		}
		if (!ignore_to_end)
			token->str[token->pos++]=c;
		if (data->pos>=data->size)
			return OCS_NEED_MORE_DATA;

		c=data->data[data->pos++];
	}
	if (token->str[token->pos-1]=='\r')
		token->str[token->pos-1]='\0';
	else
		token->str[token->pos]='\0';
	//token->pos=0;

	//ONION_DEBUG0("Found LINE token %s",token->str);
	return LINE;
}
Example #23
0
void do_petition_set_threaded(float wait_s, float wait_c, int nrequests, char close, int nthreads){
  ONION_DEBUG("Using %d threads, %d petitions per thread",nthreads,nrequests);
  processed=0;

  params_t params;
  params.wait_s=wait_s;
  params.wait_t=wait_c;
  params.n_requests=nrequests;
  params.close_at_n=close;

  pthread_t *thread=malloc(sizeof(pthread_t*)*nthreads);
  pthread_t listen_thread;
  int i;
  pthread_create(&listen_thread, NULL, (void*)do_listen, NULL);
  for (i=0;i<nthreads;i++){
    pthread_create(&thread[i], NULL, (void*)do_requests, &params);
  }
  for (i=0;i<nthreads;i++){
    pthread_join(thread[i], NULL);
  }
  free(thread);
  if (close==2){
    usleep(wait_s*1000000);
    onion_listen_stop(o);
  }
  pthread_join(listen_thread, NULL);


  FAIL_IF_NOT_EQUAL_INT(params.n_requests * nthreads, processed);
}
Example #24
0
/**
 * @short Initializes a connection on a request
 * @memberof onion_https_t
 * 
 * Do the accept of the request, and the SSL handshake.
 * 
 * @param req The request
 * @returns <0 in case of error.
 */
static int onion_https_request_init(onion_request *req){
	onion_listen_point_request_init_from_socket(req);
	onion_https *https=(onion_https*)req->connection.listen_point->user_data;
	
	ONION_DEBUG("Accept new request, fd %d",req->connection.fd);
	
	gnutls_session_t session;

  gnutls_init (&session, GNUTLS_SERVER);
  gnutls_priority_set (session, https->priority_cache);
  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, https->x509_cred);
  /* Set maximum compatibility mode. This is only suggested on public webservers
   * that need to trade security for compatibility
   */
  gnutls_session_enable_compatibility_mode (session);

	gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t)(long) req->connection.fd);
	int ret;
	do{
			ret = gnutls_handshake (session);
	}while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
	if (ret<0){ // could not handshake. assume an error.
	  ONION_ERROR("Handshake has failed (%s)", gnutls_strerror (ret));
		gnutls_bye (session, GNUTLS_SHUT_WR);
		gnutls_deinit(session);
		onion_listen_point_request_close_socket(req);
		return -1;
	}
	
	req->connection.user_data=(void*)session;
	return 0;
}
Example #25
0
/**
 * @short Do the real authorization. Checks if access allowed
 */
int authorize(const char *pamname, const char *username, const char *password){
	int ok;
	pam_handle_t *pamh=NULL;
	
	const char *password_local=password; //strdup(password);
	struct pam_conv conv = {
    authPAM_passwd,
    (void*)password_local
	};
	
	ok=pam_start(pamname, username, &conv, &pamh);
	
	if (ok==PAM_SUCCESS)
		ok = pam_authenticate(pamh, 0);    /* is user really user? */
	if (ok==PAM_SUCCESS)
		ok = pam_acct_mgmt(pamh, 0);       /* permitted access? */
	
	if (pam_end(pamh, ok)!=PAM_SUCCESS){
		ONION_ERROR("Error releasing PAM structures");
	}
	if (ok==PAM_SUCCESS){
		ONION_DEBUG("Authenticated user %s OK", username);
		return 1;
	}
	ONION_WARNING("NOT authenticated user '%s', code %d", username, ok);
	return 0;
}
Example #26
0
/**
 * @short Internal function to accept one connection. 
 * 
 * It performs timeout setting, CLOEXEC as needed by accept4/accept, and get client info.
 * 
 * @param o onion object.
 * @param cli_info char pointer to where to store the client info.
 * @param info_len size available at cli_info.
 * 
 * @returns new connection socket file descriptor
 */
static int onion_accept(onion *o, struct sockaddr_storage *cli_addr, socklen_t *clilen){
  *clilen = sizeof(*cli_addr);

  int clientfd=accept4(o->listenfd, (struct sockaddr *) cli_addr, clilen, SOCK_CLOEXEC);
  if (clientfd<0){
    ONION_ERROR("Error accepting connection: %s",strerror(errno));
    return -1;
  }
  
  /// Thanks to Andrew Victor for pointing that without this client may block HTTPS connection. It could lead to DoS if occupies all connections.
  {
    struct timeval t;
    t.tv_sec = o->timeout / 1000;
    t.tv_usec = ( o->timeout % 1000 ) * 1000;

    setsockopt(clientfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
   }
  
  if(SOCK_CLOEXEC == 0) { // Good compiler know how to cut this out
    int flags=fcntl(clientfd, F_GETFD);
    if (flags==-1){
      ONION_ERROR("Retrieving flags from connection");
    }
    flags|=FD_CLOEXEC;
    if (fcntl(clientfd, F_SETFD, flags)==-1){
      ONION_ERROR("Setting FD_CLOEXEC to connection");
    }
  }
  
  ONION_DEBUG("Accepted connection");
  return clientfd;
}
Example #27
0
/**
 * @short Write some response data.
 * @memberof onion_response_t
 *
 * This is the main write data function. If the headers have not been sent yet, they are now.
 *
 * It's internally used also by the write0 and printf versions.
 *
 * Also it does some buffering, so data is not sent as written by code, but only in chunks.
 * These chunks are when the response is finished, or when the internal buffer is full. This
 * helps performance, and eases the programming on the user side.
 *
 * If length is 0, forces the write of pending data.
 *
 * @returns The bytes written, normally just length. On error returns OCS_CLOSE_CONNECTION.
 */
ssize_t onion_response_write(onion_response *res, const char *data, size_t length){
	if (res->flags&OR_SKIP_CONTENT){
		if (!(res->flags&OR_HEADER_SENT)){ // Automatic header write
			onion_response_write_headers(res);
		}
		ONION_DEBUG("Skipping content as we are in HEAD mode");
		return OCS_CLOSE_CONNECTION;
	}
	if (length==0){
		onion_response_flush(res);
		return 0;
	}
	//ONION_DEBUG0("Write %d bytes [%d total] (%p)", length, res->sent_bytes, res);

	int l=length;
	int w=0;
	while (res->buffer_pos+l>sizeof(res->buffer)){
		int wb=sizeof(res->buffer)-res->buffer_pos;
		memcpy(&res->buffer[res->buffer_pos], data, wb);

		res->buffer_pos=sizeof(res->buffer);
		if (onion_response_flush(res)<0)
			return w;

		l-=wb;
		data+=wb;
		w+=wb;
	}

	memcpy(&res->buffer[res->buffer_pos], data, l);
	res->buffer_pos+=l;
	w+=l;

	return w;
}
Example #28
0
void t05_server_timeout_threaded_ssl(){
  INIT_LOCAL();
  CURL *curl=prepare_curl("https://localhost:8081");

  ONION_DEBUG("%s",__FUNCTION__);
  o=onion_new(O_THREADED | O_DETACH_LISTEN);
  onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL));
  FAIL_IF_NOT_EQUAL_INT(onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, "mycert.pem", "mycert.pem"),0);
  onion_set_port(o,"8081");
  onion_set_timeout(o,3000);
  onion_listen(o);
  sleep(1);

  int fd=connect_to("localhost","8081");
  sleep(4);
  // Should have closed the connection
  int w=write(fd,"GET /\n\n",7);
  FAIL_IF_NOT_EQUAL_INT(w,7);
  char data[256];
  FAIL_IF(read(fd, data,sizeof(data))>0);
  close(fd);

  FAIL_IF_NOT(curl_get(curl, "https://localhost:8081"));

	onion_free(o);

	curl_easy_cleanup(curl);
  END_LOCAL();
}
Example #29
0
int onion_assets_file_free(onion_assets_file *f){
	fseek(f->file, 0, SEEK_SET);
	
	int i;
	for (i=0;i<f->lines_count;i++){
		ONION_DEBUG("Write: %s", f->lines[i]);
		ssize_t length=strlen(f->lines[i]);
		ssize_t wlength=fwrite(f->lines[i], 1, length, f->file);
		if (wlength!=length){
			ONION_ERROR("Could not write all data. Aborting");
			abort();
		}
		wlength=fwrite("\n",1, 1, f->file);
		if (wlength!=1){
			ONION_ERROR("Could not write all data. Aborting");
			abort();
		}
		free(f->lines[i]);
	}
	free(f->lines);
	
	if (f->has_endif)
		fprintf(f->file, "#endif\n");
	
	assert(fclose(f->file)==0);
	free(f);
	return 0;
}
Example #30
0
onion_connection_status upload_file(upload_file_data *data, onion_request *req, onion_response *res){
	if (onion_request_get_flags(req)&OR_POST){
		const char *name=onion_request_get_post(req,"file");
		const char *filename=onion_request_get_file(req,"file");
		
		if (name && filename){
			char finalname[1024];
			snprintf(finalname,sizeof(finalname),"%s/%s",data->abspath,name);
			ONION_DEBUG("Copying from %s to %s",filename,finalname);

			unlink(finalname); // Just try to unlink it, if fail, sure its because it does not exist.
			int src=open(filename,O_RDONLY);
			int dst=open(finalname, O_WRONLY|O_CREAT, 0666);
			if (!src || !dst){
				ONION_ERROR("Could not open src or dst file (%d %d)",src,dst);
				return OCS_INTERNAL_ERROR;
			}
			ssize_t r,w;
			char buffer[1024*4];
			while ( (r=read(src,buffer,sizeof(buffer))) > 0){
				w=write(dst,buffer,r);
				if (w!=r){
					ONION_ERROR("Error writing file");
					break;
				}
			}
			close(src);
			close(dst);
		}
	}
	return 0; // I just ignore the request, but process over the FILE data
}