[asterisk-commits] russell: branch russell/dtls r207353 - /team/russell/dtls/main/dtls.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Jul 19 21:20:13 CDT 2009
Author: russell
Date: Sun Jul 19 21:20:11 2009
New Revision: 207353
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=207353
Log:
Update doxygen docs, make API compatible with not having OpenSSL (in theory)
Modified:
team/russell/dtls/main/dtls.c
Modified: team/russell/dtls/main/dtls.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/russell/dtls/main/dtls.c?view=diff&rev=207353&r1=207352&r2=207353
==============================================================================
--- team/russell/dtls/main/dtls.c (original)
+++ team/russell/dtls/main/dtls.c Sun Jul 19 21:20:11 2009
@@ -109,6 +109,7 @@
* \section DTLStodo TODO
*
* \todo Figure out how to handle timing out connections.
+ * \todo Add support for multiple address bindings
*
*
* \section DTLSlinks Useful Links
@@ -193,8 +194,35 @@
unsigned char stop;
};
+/*!
+ * \brief DTLS connection state.
+ *
+ * We must maintain some connection state so that we know if we can send out
+ * application level messages now, or if we must wait until some DTLS negotiation
+ * completes before continuing with application data.
+ */
enum dtls_connection_state {
+ /*!
+ * \brief Base state for a DTLS connection.
+ *
+ * In this state, frames are queued up to the DTLS handler thread for
+ * encryption and writing out to the network.
+ */
DTLS_CONN_STATE_CHILLIN,
+ /*!
+ * \brief State for waiting for data from the far end of the connection.
+ *
+ * If OpenSSL returns the WANT_READ error from SSL_read() or SSL_write(),
+ * this means that it expects to receive data from the far end of the
+ * connection and we must wait for that to occur before we can proceed
+ * with the operation that we just attempted.
+ *
+ * In this state, frames to be sent out on the network are put into a
+ * queue on the dtls_connection object. Any frames queued up here will
+ * be moved to the DTLS handler frame queue once the required data has
+ * been received from the far end and the state has gone back to the
+ * base state.
+ */
DTLS_CONN_STATE_WANT_READ,
};
@@ -225,6 +253,15 @@
#define dtls_connection_unref(c) ({ ao2_ref(c, -1); (NULL); })
+/*!
+ * \internal
+ * \brief Hash function for dtls_connection
+ *
+ * \param obj a dtls_connection
+ * \param flags unused
+ *
+ * \return an integer to be used as a hash value.
+ */
static int conn_hash(const void *obj, const int flags)
{
const struct dtls_connection *conn = obj;
@@ -232,6 +269,19 @@
return conn->sin_remote.sin_addr.s_addr ^ conn->sin_remote.sin_port;
}
+/*!
+ * \internal
+ * \brief Comparison function for dtls_connection
+ *
+ * \param obj a dtls_connection
+ * \param arg a dtls_connection
+ * \param flags unused
+ *
+ * Compare IP address and port number of 2 dtls_connection objects.
+ *
+ * \retval COMP_MATCH|CMP_STOP match
+ * \retval 0 not a match
+ */
static int conn_cmp(void *obj, void *arg, int flags)
{
const struct dtls_connection *conn1 = obj;
@@ -241,6 +291,14 @@
CMP_MATCH | CMP_STOP : 0;
}
+/*!
+ * \internal
+ * \brief Destructor for dtls_connection
+ *
+ * \param obj a dtls_connection
+ *
+ * \return nothing
+ */
static void conn_destructor(void *obj)
{
struct dtls_connection *conn = obj;
@@ -269,11 +327,27 @@
}
}
+/*!
+ * \brief Whether a packet is being sent or received.
+ */
enum direction {
SEND,
RECV
};
+/*!
+ * \internal
+ * \brief Find a dtls_connection for a given address and port number.
+ *
+ * \param handler the ast_dtls_handler
+ * \param sin the IP and port number associated with the lookup.
+ * \param dir whether a packet is being sent or received. This is used if
+ * the function allocates a connection, so that it knows whether to
+ * initialize a client side or server side connection.
+ *
+ * \retval non-NULL a dtls_connection
+ * \retval NULL if an error occurs.
+ */
static struct dtls_connection *dtls_find_connection(struct ast_dtls_handler *handler,
const struct sockaddr_in *sin, enum direction dir)
{
@@ -336,6 +410,16 @@
return NULL;
}
+/*!
+ * \internal
+ * \brief Write an alert to the ast_dtls_handler alert pipe.
+ *
+ * \param handler the ast_dlts_handler
+ * \param alert the dtls_alert to send
+ *
+ * \retval 0 success
+ * \retval -1 write error
+ */
static int dtls_handler_write_alert(struct ast_dtls_handler *handler,
enum dtls_alert alert)
{
@@ -348,6 +432,14 @@
return 0;
}
+/*!
+ * \internal
+ * \brief Destroy a dtls_frame
+ *
+ * \param dtls_fr the dtls_frame to destroy
+ *
+ * \return NULL for convenience to clear out an invalid pointer.
+ */
static struct dtls_frame *dtls_frame_destroy(struct dtls_frame *dtls_fr)
{
ast_free(dtls_fr);
@@ -358,9 +450,14 @@
/*!
* \internal
* \brief Queue a frame to a DTLS handler
+ *
+ * \param handler the ast_dtls_handler
+ * \param dtls_fr the dtls_frame to queue on to the handler
*
* \pre handler is locked
* \post handler is still locked
+ *
+ * \return nothing
*/
static void dtls_handler_queue_frame(struct ast_dtls_handler *handler,
struct dtls_frame *dtls_fr)
@@ -369,9 +466,12 @@
dtls_handler_write_alert(handler, DTLS_ALERT_FRAME);
}
+#endif /* HAVE_OPENSSL */
+
int ast_dtls_send(struct ast_dtls_handler *handler,
const void *buf, size_t len, struct sockaddr_in *sin_remote)
{
+#ifdef HAVE_OPENSSL
struct dtls_connection *conn;
struct dtls_frame *dtls_fr;
int res = 0;
@@ -409,18 +509,25 @@
conn = dtls_connection_unref(conn);
return res;
-}
-
+#else
+ return -1;
+#endif /* HAVE_OPENSSL */
+}
+
+#ifdef HAVE_OPENSSL
/*!
* \internal
* \brief Set connection state to CHILLIN
*
- * \param conn the DTLS connection
+ * \param handler the ast_dtls_handler
+ * \param conn the dtls_connection to set the state of
*
* \pre conn is locked
* \post conn is still locked
* \post Frames from the connection frame queue have now been queued up
* to the handler for transmission.
+ *
+ * \return nothing
*/
static void dtls_connection_set_chillin(struct ast_dtls_handler *handler,
struct dtls_connection *conn)
@@ -442,10 +549,13 @@
* \internal
* \brief Handle pending writes from OpenSSL
*
- * \param conn the associated connection
+ * \param handler the ast_dtls_handler
+ * \param conn the associated dtls_connection
*
* \pre conn is locked
* \post conn is still locked
+ *
+ * \return nothing
*/
static void dtls_handle_pending_writes(struct ast_dtls_handler *handler,
struct dtls_connection *conn)
@@ -536,8 +646,15 @@
* \internal
* \brief Handle frame from the network
*
+ * \param handler the ast_dtls_handler
+ * \param conn the dtls_connection the frame was received on
+ * \param enc_buf the received frame in encrypted form
+ * \param len the length of the encrypted frame
+ *
* \pre conn is locked
* \post conn is still locked
+ *
+ * \return nothing
*/
static void dtls_connection_incoming(struct ast_dtls_handler *handler,
struct dtls_connection *conn, unsigned char *enc_buf, size_t len)
@@ -604,6 +721,23 @@
dtls_handle_pending_writes(handler, conn);
}
+/*!
+ * \internal
+ * \brief Read a packet from a socket
+ *
+ * \param id I/O context ID
+ * \param fd socket descriptor
+ * \param events poll events that triggered this read
+ * \param data the associated ast_netsock
+ *
+ * This is an I/O context callback that gets called when poll() indicates
+ * that data is available for reading. The data read will be in encrypted
+ * form and must be passed through the associated DTLS connection before
+ * being passed up to the application (if it is an application packet).
+ *
+ * \return non-zero to indicate that the I/O context should continue to
+ * poll on this socket.
+ */
static int dtls_socket_read(int *id, int fd, short events, void *data)
{
struct ast_netsock *netsock = data;
@@ -648,6 +782,28 @@
return 1;
}
+/*!
+ * \internal
+ * \brief Remove and handle a frame from the handler frame queue.
+ *
+ * \param handler the ast_dtls_handler
+ *
+ * This function removes the frame on the head of the handler frame queue
+ * and then handles writing it out. The data in the frame has not yet been
+ * encrypted. This code attempts to pass it through the DTLS connection to
+ * encrypt it and then send it out on the network.
+ *
+ * OpenSSL may indicate that it has additional pending messages to send
+ * out to the network. In that case, we simply handle that synchronously and
+ * then try our write of this application message again.
+ *
+ * If OpenSSL indicates that it wants to receive some data from the far end
+ * before proceeding, this frame will go back on to the dtls_connection frame
+ * queue. The connection state will be set to WANT_READ. This will occur
+ * if DTLS negotiation is taking place, for example.
+ *
+ * \return nothing
+ */
static void dtls_handler_dequeue_frame(struct ast_dtls_handler *handler)
{
struct dtls_connection *conn;
@@ -715,6 +871,24 @@
conn = dtls_connection_unref(conn);
}
+/*!
+ * \internal
+ * \brief Read an alert from the ast_dtls_handler alert pipe.
+ *
+ * \param id the I/O context DI
+ * \param fd the read end of the alert pipe
+ * \param events the events that poll() reported
+ * \param data the ast_dtls_handler
+ *
+ * This function gets called by the I/O context when poll() indicates that
+ * there is data available for reading on the alert pipe. These alerts
+ * will indicate one of two possible things:
+ * - A request to stop the DTLS handling thread has been initiated.
+ * - A frame to be sent out has been queued up on the ast_dtls_handler.
+ *
+ * \return non-zero so that the I/O context knows that it should continue
+ * polling on this fd.
+ */
static int dtls_alert_pipe_read(int *id, int fd, short events, void *data)
{
struct ast_dtls_handler *handler = data;
@@ -740,6 +914,17 @@
return 1;
}
+/*!
+ * \internal
+ * \brief The ast_dtls_handler thread
+ *
+ * \param data the ast_dtls_handler
+ *
+ * This is the main function for the ast_dtls_handler thread. It just runs
+ * the I/O context waiting for input on either the socket or the alert pipe.
+ *
+ * \return NULL
+ */
static void *dtls_handler_thread(void *data)
{
struct ast_dtls_handler *handler = data;
@@ -751,6 +936,15 @@
return NULL;
}
+/*!
+ * \internal
+ * \brief Initialize the SSL_CTX for the server side
+ *
+ * \param config the ast_dtls_config
+ *
+ * \retval non-NULL an initialized server side SSL_CTX
+ * \retval NULL error
+ */
static SSL_CTX *dtls_server_ssl_ctx_init(struct ast_dtls_config *config)
{
SSL_CTX *server_ctx;
@@ -796,6 +990,15 @@
return NULL;
}
+/*!
+ * \internal
+ * \brief Initialize the SSL_CTX for the client side
+ *
+ * \param config the ast_dtls_config
+ *
+ * \retval non-NULL an initialized client side SSL_CTX
+ * \retval NULL error
+ */
static SSL_CTX *dtls_client_ssl_ctx_init(struct ast_dtls_config *config)
{
SSL_CTX *client_ctx;
@@ -824,6 +1027,17 @@
return NULL;
}
+/*!
+ * \internal
+ * \brief Destructor for ast_dtls_handler
+ *
+ * \param obj the ast_dtls_handler to destroy
+ *
+ * This destructor will stop the DTLS handler thread before proceeding to
+ * destroy the ast_dtls_handler object.
+ *
+ * \return nothing
+ */
static void handler_destructor(void *obj)
{
struct ast_dtls_handler *handler = obj;
@@ -874,9 +1088,12 @@
}
}
+#endif /* HAVE_OPENSSL */
+
struct ast_dtls_handler *ast_dtls_handler_alloc(struct ast_dtls_config *config,
ast_dtls_recv_cb recv_cb, void *recv_user_data)
{
+#ifdef HAVE_OPENSSL
struct ast_dtls_handler *handler;
if (!config->enabled) {
@@ -892,6 +1109,8 @@
handler->alert_pipe[1] = -1;
handler->config = ast_dtls_config_ref(config);
+
+ ao2_lock(handler->config);
if (!(handler->server_ctx = dtls_server_ssl_ctx_init(config))) {
goto return_unref;
@@ -947,14 +1166,31 @@
goto return_unref;
}
+ ao2_unlock(handler->config);
+
return handler;
return_unref:
+ ao2_unlock(handler->config);
+
handler = ast_dtls_handler_unref(handler);
return NULL;
-}
-
+#else
+ return NULL;
+#endif /* HAVE_OPENSSL */
+}
+
+#ifdef HAVE_OPENSSL
+
+/*!
+ * \internal
+ * \brief Destructor for ast_dtls_config
+ *
+ * \param obj the ast_dtls_config to destroy
+ *
+ * \return Nothing
+ */
static void config_destructor(void *obj)
{
struct ast_dtls_config *config = obj;
@@ -962,8 +1198,11 @@
ast_string_field_free_memory(config);
}
+#endif /* HAVE_OPENSSL */
+
struct ast_dtls_config *ast_dtls_config_alloc(void)
{
+#ifdef HAVE_OPENSSL
struct ast_dtls_config *config;
if (!(config = ao2_alloc(sizeof(struct ast_dtls_config), config_destructor))) {
@@ -976,17 +1215,27 @@
}
return config;
+#else
+ return NULL;
+#endif /* HAVE_OPENSSL */
}
unsigned int ast_dtls_config_get_enabled(const struct ast_dtls_config *config)
{
+#ifdef HAVE_OPENSSL
return config->enabled;
+#else
+ return 0;
+#endif /* HAVE_OPENSSL */
}
int ast_dtls_config_parse(struct ast_dtls_config *config,
const char *var, const char *val)
{
+#ifdef HAVE_OPENSSL
int res = 0;
+
+ ao2_lock(config);
CV_START(var, val);
@@ -1000,10 +1249,13 @@
CV_STRFIELD("dtlsdhfile", config, dh_params);
res = -1;
-
CV_END;
+ ao2_unlock(config);
+
return res;
-}
-
+#else
+ return -1;
#endif /* HAVE_OPENSSL */
+}
+
More information about the asterisk-commits
mailing list