Skip to content
Browse files

Added lot of documentation to listen points and https.

  • Loading branch information...
1 parent 2aff44d commit 76370c92616c2046dd586cca299aae897f431706 @davidmoreno committed Jul 24, 2012
View
2 examples/basic/basic.c
@@ -6,7 +6,7 @@
int main(int argc, char **argv){
onion *o=onion_new(O_THREADED);
- onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, "cert.pem", "cert.key");
+ onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, "cert.pem", "cert.key", O_SSL_NONE);
onion_set_root_handler(o, onion_handler_auth_pam("Onion Example", "login", onion_handler_export_local_new(".")));
onion_listen(o);
onion_free(o);
View
111 src/onion/https.c
@@ -34,6 +34,11 @@
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
+/**
+ * @short Stores some data about the connection
+ *
+ * It has the main data for the connection; the setup certificate and such.
+ */
struct onion_https_t{
gnutls_certificate_credentials_t x509_cred;
gnutls_dh_params_t dh_params;
@@ -44,14 +49,27 @@ typedef struct onion_https_t onion_https;
int onion_http_read_ready(onion_request *req);
-int onion_https_request_init(onion_request *req);
+static int onion_https_request_init(onion_request *req);
static ssize_t onion_https_read(onion_request *req, char *data, size_t len);
ssize_t onion_https_write(onion_request *req, const char *data, size_t len);
static void onion_https_close(onion_request *req);
static void onion_https_listen_stop(onion_listen_point *op);
static void onion_https_free_user_data(onion_listen_point *op);
-onion_listen_point *onion_https_new(onion_ssl_certificate_type type, const char *filename, ...){
+/**
+ * @short Creates a new listen point with HTTPS powers.
+ * @struct 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->user_data=calloc(1,sizeof(onion_https));
@@ -79,33 +97,32 @@ onion_listen_point *onion_https_new(onion_ssl_certificate_type type, const char
gnutls_certificate_set_dh_params (https->x509_cred, https->dh_params);
gnutls_priority_init (&https->priority_cache, "PERFORMANCE:%SAFE_RENEGOTIATION:-VERS-TLS1.0", NULL);
- int r=0;
- if (type!=O_SSL_NONE){
- va_list va;
- va_start(va, filename);
- r=onion_https_set_certificate_argv(op, type, filename, va);
- va_end(va);
- }
-
- if (r<0){
- ONION_ERROR("Error setting the certificate (%s)", gnutls_strerror (r));
- onion_listen_point_free(op);
- return NULL;
- }
-
-
ONION_DEBUG("HTTPS connection ready");
return op;
}
-
+/**
+ * @short Stop the listening.
+ * @struct onion_https_t
+ *
+ * Just closes the listen port.
+ *
+ * @param op The listen port.
+ */
static void onion_https_listen_stop(onion_listen_point *op){
ONION_DEBUG("Close HTTPS %s:%s", op->hostname, op->port);
shutdown(op->listenfd,SHUT_RDWR);
close(op->listenfd);
+ op->listenfd=-1;
}
+/**
+ * @short Frees the user data
+ * @struct onion_https_t
+ *
+ * @param op
+ */
static void onion_https_free_user_data(onion_listen_point *op){
ONION_DEBUG("Free HTTPS %s:%s", op->hostname, op->port);
onion_https *https=(onion_https*)op->user_data;
@@ -118,7 +135,16 @@ static void onion_https_free_user_data(onion_listen_point *op){
free(https);
}
-int onion_https_request_init(onion_request *req){
+/**
+ * @short Initializes a connection on a request
+ * @struct 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;
@@ -154,6 +180,15 @@ int onion_https_request_init(onion_request *req){
return 0;
}
+/**
+ * @short Method to read some HTTPS data.
+ * @struct onion_https_t
+ *
+ * @param req to get data from
+ * @param data where to store unencrypted data
+ * @param Lenght of desired data
+ * @returns Actual read data. 0 means EOF.
+ */
static ssize_t onion_https_read(onion_request *req, char *data, size_t len){
gnutls_session_t session=(gnutls_session_t)req->connection.user_data;
ssize_t ret=gnutls_record_recv(session, data, len);
@@ -164,12 +199,29 @@ static ssize_t onion_https_read(onion_request *req, char *data, size_t len){
return ret;
}
+/**
+ * @short Writes some data to the HTTPS client.
+ * @struct onion_https_t
+ *
+ * @param req to where write the data
+ * @param data to write
+ * @param len Ammount of data desired to write
+ * @returns Actual ammount of data written.
+ */
ssize_t onion_https_write(onion_request *req, const char *data, size_t len){
gnutls_session_t session=(gnutls_session_t)req->connection.user_data;
ONION_DEBUG("Write! (%p)", session);
return gnutls_record_send(session, data, len);
}
+/**
+ * @short Closes the https connection
+ * @struct 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;
@@ -182,7 +234,15 @@ static void onion_https_close(onion_request *req){
onion_listen_point_request_close_socket(req);
}
-
+/**
+ * @short Set new certificate elements
+ * @struct onion_https_t
+ *
+ * @param ol Listen point
+ * @param type Type of certificate to add
+ * @param filename File where this data is.
+ * @returns If the operation was sucesful
+ */
int onion_https_set_certificate(onion_listen_point *ol, onion_ssl_certificate_type type, const char *filename, ...){
va_list va;
va_start(va, filename);
@@ -192,6 +252,14 @@ int onion_https_set_certificate(onion_listen_point *ol, onion_ssl_certificate_ty
return r;
}
+/**
+ * @short Same as onion_https_set_certificate, but with a va_list
+ * @struct onion_https_t
+ *
+ * This allows to manage va_lists more easily.
+ *
+ * @see onion_https_set_certificate
+ */
int onion_https_set_certificate_argv(onion_listen_point *ol, onion_ssl_certificate_type type, const char *filename, va_list va){
onion_https *https=(onion_https*)ol->user_data;
@@ -203,6 +271,7 @@ int onion_https_set_certificate_argv(onion_listen_point *ol, onion_ssl_certifica
int r=0;
switch(type&0x0FF){
case O_SSL_CERTIFICATE_CRL:
+ ONION_DEBUG("Setting SSL Certificate CRL");
r=gnutls_certificate_set_x509_crl_file(https->x509_cred, filename, (type&O_SSL_DER) ? GNUTLS_X509_FMT_DER : GNUTLS_X509_FMT_PEM);
break;
case O_SSL_CERTIFICATE_KEY:
@@ -215,10 +284,12 @@ int onion_https_set_certificate_argv(onion_listen_point *ol, onion_ssl_certifica
}
break;
case O_SSL_CERTIFICATE_TRUST:
+ ONION_DEBUG("Setting SSL Certificate Trust");
r=gnutls_certificate_set_x509_trust_file(https->x509_cred, filename, (type&O_SSL_DER) ? GNUTLS_X509_FMT_DER : GNUTLS_X509_FMT_PEM);
break;
case O_SSL_CERTIFICATE_PKCS12:
{
+ ONION_DEBUG("Setting SSL Certificate PKCS12");
r=gnutls_certificate_set_x509_simple_pkcs12_file(https->x509_cred, filename,
(type&O_SSL_DER) ? GNUTLS_X509_FMT_DER : GNUTLS_X509_FMT_PEM,
va_arg(va, const char *));
View
2 src/onion/https.h
@@ -22,7 +22,7 @@
#include <stdarg.h>
#include "types.h"
-onion_listen_point *onion_https_new(onion_ssl_certificate_type type, const char *filename, ...);
+onion_listen_point *onion_https_new();
int onion_https_set_certificate(onion_listen_point *ol, onion_ssl_certificate_type type, const char *filename, ...);
int onion_https_set_certificate_argv(onion_listen_point *ol, onion_ssl_certificate_type type, const char *filename, va_list va);
View
63 src/onion/listen_point.c
@@ -44,11 +44,27 @@
static int onion_listen_point_read_ready(onion_request *req);
+/**
+ * @short Creates an empty listen point.
+ * @struct 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=calloc(1,sizeof(onion_listen_point));
return ret;
}
+/**
+ * @short Free and closes the listen point
+ * @struct onion_listen_point_t
+ *
+ * Calls the custom listen_stop mathod, and frees all common structures.
+ *
+ * @param op the listen point
+ */
void onion_listen_point_free(onion_listen_point *op){
ONION_DEBUG("Free listen point %d", op->listenfd);
onion_listen_point_listen_stop(op);
@@ -62,6 +78,14 @@ void onion_listen_point_free(onion_listen_point *op){
}
+/**
+ * @short Called when a new connection appears on the listenfd
+ *
+ * When the new conneciton appears, creates the request and adds it to the pollers.
+ *
+ * @param op The listen point from where the request must be built
+ * @returns 1 if ok, <0 if error; the request was invalid (for example HTTP asked for an HTTPS).
+ */
int onion_listen_point_accept(onion_listen_point *op){
onion_request *req=onion_request_new(op);
if (req){
@@ -76,6 +100,13 @@ int onion_listen_point_accept(onion_listen_point *op){
return -1;
}
+/**
+ * @short Stops listening the listen point
+ *
+ * Calls the op->listen_stop if any, and if not just closes the listenfd.
+ *
+ * @param op The listen point
+ */
void onion_listen_point_listen_stop(onion_listen_point *op){
if (op->listen_stop)
op->listen_stop(op);
@@ -88,7 +119,14 @@ void onion_listen_point_listen_stop(onion_listen_point *op){
}
}
-
+/**
+ * @short Starts the listening phase for this listen point for sockets.
+ *
+ * Default listen implementation that listens on sockets. Opens sockets and setup everything properly.
+ *
+ * @param op The listen point
+ * @returns 0 if ok, !=0 some error; it will be the errno value.
+ */
int onion_listen_point_listen(onion_listen_point *op){
if (op->listen){
op->listen(op);
@@ -169,6 +207,12 @@ int onion_listen_point_listen(onion_listen_point *op){
return 0;
}
+/**
+ * @short This listen point has data ready to read; calls the listen_point read_ready
+ *
+ * @param req The request with data ready
+ * @returns <0 in case of error and request connection should be closed.
+ */
static int onion_listen_point_read_ready(onion_request *req){
#ifdef __DEBUG__
if (!req->connection.listen_point->read_ready){
@@ -181,7 +225,15 @@ static int onion_listen_point_read_ready(onion_request *req){
}
-void onion_listen_point_request_init_from_socket(onion_request *req){
+/**
+ * @short Default implementation that initializes the request from a socket
+ *
+ * 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;
/// Follows default socket implementation. If your protocol is socket based, just use it.
@@ -192,6 +244,7 @@ void onion_listen_point_request_init_from_socket(onion_request *req){
if (clientfd<0){
ONION_ERROR("Error accepting connection: %s",strerror(errno));
onion_listen_point_request_close_socket(req);
+ return -1;
}
req->connection.fd=clientfd;
@@ -216,8 +269,14 @@ void onion_listen_point_request_init_from_socket(onion_request *req){
}
ONION_DEBUG0("New connection, socket %d",clientfd);
+ return 0;
}
+/**
+ * @short Default implementation that just closes the connection
+ *
+ * @param oc The request
+ */
void onion_listen_point_request_close_socket(onion_request *oc){
int fd=oc->connection.fd;
ONION_DEBUG0("Closing connection socket %d",fd);
View
6 src/onion/listen_point.h
@@ -16,8 +16,8 @@
License along with this library; if not see <http://www.gnu.org/licenses/>.
*/
-#ifndef __ONION_LISTEN_POINTL_H__
-#define __ONION_LISTEN_POINTL_H__
+#ifndef __ONION_LISTEN_POINT_H__
+#define __ONION_LISTEN_POINT_H__
#include "types.h"
@@ -26,7 +26,7 @@ int onion_listen_point_listen(onion_listen_point *);
void onion_listen_point_listen_stop(onion_listen_point *op);
void onion_listen_point_free(onion_listen_point *);
int onion_listen_point_accept(onion_listen_point *);
-void onion_listen_point_request_init_from_socket(onion_request *op);
+int onion_listen_point_request_init_from_socket(onion_request *op);
void onion_listen_point_request_close_socket(onion_request *oc);
#endif
View
16 src/onion/onion.c
@@ -39,7 +39,7 @@ void onion_set_port(onion *server, const char *port);
void onion_set_hostname(onion *server, const char *hostname);
/// Set a certificate for use in the connection
-int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const char *filename, ...);
+int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const char *filename);
*
@@ -304,6 +304,8 @@ int onion_listen(onion *o){
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;
@@ -377,7 +379,8 @@ void onion_listen_stop(onion* server){
ONION_DEBUG("Stop listening");
onion_poller_stop(server->poller);
#ifdef HAVE_PTHREADS
- pthread_join(server->listen_thread, NULL);
+ if (server->flags&O_DETACHED)
+ pthread_join(server->listen_thread, NULL);
#endif
}
@@ -599,9 +602,9 @@ void onion_set_hostname(onion *server, const char *hostname){
}
/// Set a certificate for use in the connection
-int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const char *filename, ...){
+int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const char *filename,...){
if (!onion->listen_points){
- onion_add_listen_point(onion,NULL,NULL,onion_https_new(O_SSL_NONE,NULL));
+ onion_add_listen_point(onion,NULL,NULL,onion_https_new());
}
else{
onion_listen_point *first_listen_point=onion->listen_points[0];
@@ -614,7 +617,7 @@ int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const c
char *port=first_listen_point->port ? strdup(first_listen_point->port) : NULL;
char *hostname=first_listen_point->hostname ? strdup(first_listen_point->hostname) : NULL;
onion_listen_point_free(first_listen_point);
- onion_listen_point *https=onion_https_new(O_SSL_NONE,NULL);
+ onion_listen_point *https=onion_https_new();
if (NULL==https){
ONION_ERROR("Could not promote from HTTP to HTTPS. Certificate not set.");
}
@@ -626,8 +629,9 @@ int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const c
}
va_list va;
va_start(va, filename);
- int r=onion_https_set_certificate_argv(onion->listen_points[0], type, filename, va);
+ int r=onion_https_set_certificate_argv(onion->listen_points[0], type, filename,va);
va_end(va);
+
return r;
}
View
48 src/onion/types_internal.h
@@ -140,18 +140,38 @@ typedef struct onion_url_data_t onion_url_data;
struct onion_listen_point_t{
- onion *server;
- char *hostname;
- char *port;
- int listenfd;
+ onion *server; ///< Onion server
+ char *hostname; ///< Stated hostname, as a string. If NULL tries to attach to any hostname, normally 0.0.0.0 (ipv4 and ipv6)
+ char *port; ///< Stated port, if none then 8080
+ int listenfd; ///< For socket listening listen points, the listen fd. For others may be -1 as not used, or an fd to watch and when changed calls the request_init with a new request.
- void *user_data;
- void (*free_user_data)(onion_listen_point *lp);
- /// Frees internal data and state of listen point, but not listen point itself. NULL means socket listen, and should be closed.
- void (*listen_stop)(onion_listen_point *lp);
+ /// Internal data used by the listen point, for example in HTTPS is the certificate loaded data.
+ void *user_data;
+ /// Method to call to free the user data
+ void (*free_user_data)(onion_listen_point *lp);
- /// How to start the listening phase. Normally NULL means socket listening. Must set at listenfd a file descriptor that will be polled.
+ /**
+ * @short How to start the listening phase.
+ *
+ * Normally NULL means socket listening.
+ *
+ * Must set at listenfd a file descriptor that will be polled, and when data arrives,
+ * it will call the request_init with a new request object.
+ */
void (*listen)(onion_listen_point *lp);
+ /**
+ * @short Frees internal data and state of listen point, but not listen point itself.
+ *
+ * If NULL means socket listen, and should be closed calling onion_listen_point_listen_stop.
+ * If a port is open must be closed. Its the exact oposite of listen.
+ *
+ * May be called in a loop: listen -> ... -> listen_stop -> ... -> listen.
+ *
+ * It also may be called two succesive times, and should do nothing on second.
+ */
+ void (*listen_stop)(onion_listen_point *lp);
+
+ /// @{ @name To be used by requests, but as these methods are shared by protocol, done here.
/**
* @short Initialize the request object. Data is already malloc'd but specific listen protocols may need custom data
*
@@ -161,12 +181,10 @@ struct onion_listen_point_t{
* @returns 0 if everything ok, <0 if request is invalid and should be closed.
*/
int (*request_init)(onion_request *req);
-
- /// @{ @name To be used by connections, but as these methods are shared by protocol, done here.
- int (*read_ready)(onion_request *con); ///< When poller detects data is ready to be read. Might be diferent in diferent parts of the processing.
- ssize_t (*write)(onion_request *con, const char *data, size_t len);
- ssize_t (*read)(onion_request *con, char *data, size_t len);
- void (*close)(onion_request *con); ///< Closes the connection and frees listen point user data. Request itself it left. It is called from onion_request_free ONLY.
+ int (*read_ready)(onion_request *req); ///< When poller detects data is ready to be read. Might be diferent in diferent parts of the processing.
+ ssize_t (*write)(onion_request *req, const char *data, size_t len); ///< Write data to the given request.
+ ssize_t (*read)(onion_request *req, char *data, size_t len); ///< Read data from the given request and write it in data.
+ void (*close)(onion_request *req); ///< Closes the connection and frees listen point user data. Request itself it left. It is called from onion_request_free ONLY.
/// @}
};
View
2 tests/01-internal/06-onion.c
@@ -255,7 +255,7 @@ void t02_server_epoll(){
void t03_server_https(){
INIT_LOCAL();
- o=onion_new(O_THREADED | O_DETACH_LISTEN);
+ o=onion_new(O_ONE_LOOP | 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);
FAIL_IF_NOT_EQUAL_INT(onion_listen(o),0);

0 comments on commit 76370c9

Please sign in to comment.
Something went wrong with that request. Please try again.