[asterisk-commits] bbryant: branch bbryant/ssl-tcp-tls r69951 - in /team/bbryant/ssl-tcp-tls: ch...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jun 19 11:00:42 CDT 2007


Author: bbryant
Date: Tue Jun 19 11:00:42 2007
New Revision: 69951

URL: http://svn.digium.com/view/asterisk?view=rev&rev=69951
Log:
Adding the new server.c/.h files and my modifications to chan_sip

Added:
    team/bbryant/ssl-tcp-tls/include/asterisk/server.h   (with props)
    team/bbryant/ssl-tcp-tls/main/server.c   (with props)
Modified:
    team/bbryant/ssl-tcp-tls/channels/chan_sip.c

Modified: team/bbryant/ssl-tcp-tls/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/bbryant/ssl-tcp-tls/channels/chan_sip.c?view=diff&rev=69951&r1=69950&r2=69951
==============================================================================
--- team/bbryant/ssl-tcp-tls/channels/chan_sip.c (original)
+++ team/bbryant/ssl-tcp-tls/channels/chan_sip.c Tue Jun 19 11:00:42 2007
@@ -490,8 +490,9 @@
 /*! \brief SIP Extensions we support */
 #define SUPPORTED_EXTENSIONS "replaces" 
 
-/*! \brief Standard SIP port from RFC 3261. DO NOT CHANGE THIS */
+/*! \brief Standard SIP and TLS port from RFC 3261. DO NOT CHANGE THIS */
 #define STANDARD_SIP_PORT	5060
+#define STANDARD_TLS_PORT	5061
 /* Note: in many SIP headers, absence of a port number implies port 5060,
  * and this is why we cannot change the above constant.
  * There is a limited number of places in asterisk where we could,
@@ -925,7 +926,8 @@
 	char refer_contact[AST_MAX_EXTENSION];		/*!< Place to store Contact info from a REFER extension */
 	char replaces_callid[BUFSIZ];			/*!< Replace info: callid */
 	char replaces_callid_totag[BUFSIZ/2];		/*!< Replace info: to-tag */
-	char replaces_callid_fromtag[BUFSIZ/2];		/*!< Replace info: from-tag */
+	char replaces_callid_fromtag[BUFSIZ/2];		/*!< Rep
+lace info: from-tag */
 	struct sip_pvt *refer_call;			/*!< Call we are referring */
 	int attendedtransfer;				/*!< Attended or blind transfer? */
 	int localtransfer;				/*!< Transfer to local domain? */
@@ -1081,7 +1083,7 @@
 struct sip_pkt {
 	struct sip_pkt *next;			/*!< Next packet in linked list */
 	int retrans;				/*!< Retransmission number */
-	int method;				/*!< SIP method for this packet */
+	int method;				/*!< SIP me`:thod for this packet */
 	int seqno;				/*!< Sequence number */
 	unsigned int flags;			/*!< non-zero if this is a response packet (e.g. 200 OK) */
 	struct sip_pvt *owner;			/*!< Owner AST call */
@@ -1649,7 +1651,30 @@
 	.send_digit_end = sip_senddigit_end,
 	.bridge = ast_rtp_bridge,
 	.send_text = sip_sendtext,
-	.func_channel_read = acf_channel_read,
+};
+
+static void *sip_tcp_helper_thread(void *);
+
+static struct tls_config sip_tls_cfg;
+
+static struct server_args sip_tcp_desc = {
+	.accept_fd = -1,
+	.master = AST_PTHREADT_NULL,
+	.tls_cfg = NULL,
+	.poll_timeout = -1,
+	.name = "sip tcp server",
+	.accept_fn = server_root,
+	.worker_fn = sip_tcp_helper_thread,
+};
+
+static struct server_args sip_tls_desc = {
+	.accept_fd = -1,
+	.master = AST_PTHREADT_NULL,
+	.tls_cfg = &sip_tls_cfg,
+	.poll_timeout = -1,
+	.name = "sip tls server",
+	.accept_fn = server_root,
+	.worker_fn = sip_tcp_helper_thread,
 };
 
 /**--- some list management macros. **/
@@ -1670,6 +1695,19 @@
 	set_rtp_peer: sip_set_rtp_peer,
 	get_codec: sip_get_codec,
 };
+
+/*! \brieft SIP TCP helper function */
+static void *sip_tcp_helper_thread(void *data) {
+	char buf[4096];
+
+	struct server_instance *ser = data;
+
+	while (fgets(buf, sizeof(buf), ser->f)) {
+		ast_log(LOG_WARNING, buf);
+	}
+
+	return NULL;
+}
 
 /*! \brief Helper function to lock, hiding the underlying locking mechanism.  */
 static void sip_pvt_lock(struct sip_pvt *pvt)
@@ -3031,7 +3069,7 @@
 		ast_rtp_set_rtpkeepalive(dialog->trtp, peer->rtpkeepalive);
 	}
 
-	ast_string_field_set(dialog, peername, peer->name);
+	ast_string_field_set(dialog, peername, peer->username);
 	ast_string_field_set(dialog, authname, peer->username);
 	ast_string_field_set(dialog, username, peer->username);
 	ast_string_field_set(dialog, peersecret, peer->secret);
@@ -10096,14 +10134,14 @@
 /*! \brief  CLI Command to show calls within limits set by call_limit */
 static int sip_show_inuse(int fd, int argc, char *argv[])
 {
-#define FORMAT  "%-25.25s %-15.15s %-15.15s \n"
+#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
 #define FORMAT2 "%-25.25s %-15.15s %-15.15s \n"
 	char ilimits[40];
 	char iused[40];
 	int showall = FALSE;
 
 	if (argc < 3) 
-		return RESULT_SHOWUSAGE;
+		return RESULT_SHOWUSAGE; 
 
 	if (argc == 4 && !strcmp(argv[3],"all")) 
 			showall = TRUE;
@@ -10139,6 +10177,7 @@
 #undef FORMAT
 #undef FORMAT2
 }
+
 
 /*! \brief Convert transfer mode to text string */
 static char *transfermode2str(enum transfermodes mode)
@@ -13673,7 +13712,7 @@
 			ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV);
 		if (target->chan1)
 			ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV);
-		return -2;
+		return -1;
 	}
 	return 0;
 }
@@ -14585,16 +14624,13 @@
 	sip_pvt_unlock(targetcall_pvt);
 	if (res) {
 		/* Failed transfer */
-		transmit_notify_with_sipfrag(transferer, seqno, "486 Busy Here", TRUE);
+		/* Could find better message, but they will get the point */
+		transmit_notify_with_sipfrag(transferer, seqno, "486 Busy", TRUE);
 		append_history(transferer, "Xfer", "Refer failed");
-		transferer->refer->status = REFER_FAILED;
 		if (targetcall_pvt->owner)
 			ast_channel_unlock(targetcall_pvt->owner);
 		/* Right now, we have to hangup, sorry. Bridge is destroyed */
-		if (res != -2)
-			ast_hangup(transferer->owner);
-		else
-			ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
+		ast_hangup(transferer->owner);
 	} else {
 		/* Transfer succeeded! */
 
@@ -14884,6 +14920,7 @@
 	   be accessible after the transfer! */
 	*nounlock = 1;
 	ast_channel_unlock(current.chan1);
+	ast_channel_unlock(current.chan2);
 
 	/* Connect the call */
 
@@ -14996,14 +15033,11 @@
 	if (ast_strlen_zero(args.param) || strcasecmp(args.param, "rtpqos"))
 		return -1;
 
-	/* Default arguments of audio,all */
-	if (ast_strlen_zero(args.type))
-		args.type = "audio";
-	if (ast_strlen_zero(args.field))
-		args.field = "all";
-
 	memset(buf, 0, buflen);
 	memset(&qos, 0, sizeof(qos));
+
+	if (ast_strlen_zero(args.type))
+		return -1;
 
 	if (strcasecmp(args.type, "AUDIO") == 0) {
 		all = ast_rtp_get_quality(p->rtp, &qos);
@@ -15012,6 +15046,9 @@
 	} else if (strcasecmp(args.type, "TEXT") == 0) {
 		all = ast_rtp_get_quality(p->trtp, &qos);
 	}
+
+	if (ast_strlen_zero(args.field))
+		return -1;
 
 	if (strcasecmp(args.field, "local_ssrc") == 0)
 		snprintf(buf, buflen, "%u", qos.local_ssrc);
@@ -15852,10 +15889,6 @@
 		return;
 	/* If the call is not in UP state or redirected outside Asterisk, no need to check timers */
 	if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr)
-		return;
-
-	/* If the call is involved in a T38 fax session do not check RTP timeout */
-	if (dialog->t38.state == T38_ENABLED)
 		return;
 
 	/* If we have no timers set, return now */
@@ -17080,6 +17113,13 @@
 		ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
 		return -1;
 	}
+
+	/* Initialize tcp sockets */
+	bzero(&sip_tcp_desc.sin, sizeof(sip_tcp_desc.sin));
+	bzero(&sip_tls_desc.sin, sizeof(sip_tls_desc.sin));
+	
+	sip_tcp_desc.sin.sin_port = htons(STANDARD_SIP_PORT);
+	sip_tls_desc.sin.sin_port = htons(STANDARD_TLS_PORT);
 	
 	/* Initialize copy of current global_regcontext for later use in removing stale contexts */
 	ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
@@ -17176,10 +17216,6 @@
 
 	global_matchexterniplocally = FALSE;
 
-	/* Set some default TCP/TLS settings */
-	global_tcpenable = TRUE;
-	// sip_tls_cfg.enabled = FALSE;
-
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
@@ -17217,9 +17253,23 @@
 		} else if (!strcasecmp(v->name, "t1min")) {
 			global_t1min = atoi(v->value);
 		} else if (!strcasecmp(v->name, "tcpenable")) {
-			global_tcpenable = ast_true(v->value);
+			sip_tcp_desc.sin.sin_family = ast_false(v->value) ? 0 : AF_INET;
+		} else if (!strcasecmp(v->name, "tcpbindport")) {
+			if (sscanf(v->value, "%d", &ourport) == 1) {
+				sip_tcp_desc.sin.sin_port = htons(ourport);
+			} else {
+				ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
+			}
 		} else if (!strcasecmp(v->name, "tlsenable")) {
-			global_tcpenable = ast_true(v->value);
+			sip_tls_desc.tls_cfg->enabled = ast_true(v->value) ? AF_INET : 0;
+		} else if (!strcasecmp(v->name, "tlscertfile")) {
+			sip_tls_desc.tls_cfg->certfile = ast_strdup(v->value);
+		} else if (!strcasecmp(v->name,"tlsbindport")) {
+			if (sscanf(v->value, "%d", &ourport) == 1) {
+				sip_tls_desc.sin.sin_port = htons(ourport);
+			} else {
+				ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
+			}
 		} else if (!strcasecmp(v->name, "rtautoclear")) {
 			int i = atoi(v->value);
 			if (i > 0)
@@ -17627,6 +17677,11 @@
 		ast_config_destroy(notify_types);
 	notify_types = ast_config_load(notify_config);
 
+	server_start(&sip_tcp_desc);
+
+	if(ssl_setup(sip_tls_desc.tls_cfg))
+		server_start(&sip_tls_desc);
+
 	/* Done, tell the manager */
 	manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\nUser_Count: %d\r\n\r\n", channelreloadreason2txt(reason), registry_count, peer_count, user_count);
 
@@ -17881,16 +17936,14 @@
 		memset(&p->tredirip, 0, sizeof(p->tredirip));
 		changed = 1;
 	}
-	if (codecs) {
-		if ((p->redircodecs != codecs)) {
-			p->redircodecs = codecs;
-			changed = 1;
-		}
-		if ((p->capability & codecs) != p->capability) {
-			p->jointcapability &= codecs;
-			p->capability &= codecs;
-			changed = 1;
-		}
+	if (codecs && (p->redircodecs != codecs)) {
+		p->redircodecs = codecs;
+		changed = 1;
+	}
+	if ((p->capability & codecs) != p->capability) {
+		p->jointcapability &= codecs;
+		p->capability &= codecs;
+		changed = 1;
 	}
 	if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
 		if (chan->_state != AST_STATE_UP) {	/* We are in early state */

Added: team/bbryant/ssl-tcp-tls/include/asterisk/server.h
URL: http://svn.digium.com/view/asterisk/team/bbryant/ssl-tcp-tls/include/asterisk/server.h?view=auto&rev=69951
==============================================================================
--- team/bbryant/ssl-tcp-tls/include/asterisk/server.h (added)
+++ team/bbryant/ssl-tcp-tls/include/asterisk/server.h Tue Jun 19 11:00:42 2007
@@ -1,0 +1,135 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file server.h
+ *
+ * \brief Generic support for tcp/tls servers in Asterisk.
+ * \note In order to have TLS/SSL support, we need the openssl libraries.
+ * Still we can decide whether or not to use them by commenting
+ * in or out the DO_SSL macro.
+ * TLS/SSL support is basically implemented by reading from a config file
+ * (currently http.conf) the names of the certificate and cipher to use,
+ * and then run ssl_setup() to create an appropriate SSL_CTX (ssl_ctx)
+ * If we support multiple domains, presumably we need to read multiple
+ * certificates.
+ * When we are requested to open a TLS socket, we run make_file_from_fd()
+ * on the socket, to do the necessary setup. At the moment the context's name
+ * is hardwired in the function, but we can certainly make it into an extra
+ * parameter to the function.
+ * We declare most of ssl support variables unconditionally,
+ * because their number is small and this simplifies the code.
+ *
+ * \note: the ssl-support variables (ssl_ctx, do_ssl, certfile, cipher)
+ * and their setup should be moved to a more central place, e.g. asterisk.conf
+ * and the source files that processes it. Similarly, ssl_setup() should
+ * be run earlier in the startup process so modules have it available.
+ *
+ */
+
+
+#ifndef _ASTERISK_SERVER_H
+#define _ASTERISK_SERVER_H
+
+#if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
+#define DO_SSL  /* comment in/out if you want to support ssl */
+#endif
+
+#ifdef DO_SSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#else
+/* declare dummy types so we can define a pointer to them */
+typedef struct {} SSL;
+typedef struct {} SSL_CTX;
+#endif /*DO_SSL */
+
+/*! SSL support */
+#define AST_CERTFILE "asterisk.pem"
+
+struct tls_config {
+	int enabled;
+	char *certfile;
+	char *cipher;
+	SSL_CTX *ssl_ctx;
+};
+
+/*!
+ * The following code implements a generic mechanism for starting
+ * services on a TCP or TLS socket.
+ * The service is configured in the struct server_args, and
+ * then started by calling server_start(desc) on the descriptor.
+ * server_start() first verifies if an instance of the service is active,
+ * and in case shuts it down. Then, if the service must be started, creates
+ * a socket and a thread in charge of doing the accept().
+ *
+ * The body of the thread is desc->accept_fn(desc), which the user can define
+ * freely. We supply a sample implementation, server_root(), structured as an
+ * infinite loop. At the beginning of each iteration it runs periodic_fn()
+ * if defined (e.g. to perform some cleanup etc.) then issues a poll()
+ * or equivalent with a timeout of 'poll_timeout' milliseconds, and if the
+ * following accept() is successful it creates a thread in charge of
+ * running the session, whose body is desc->worker_fn(). The argument of
+ * worker_fn() is a struct server_instance, which contains the address
+ * of the other party, a pointer to desc, the file descriptors (fd) on which
+ * we can do a select/poll (but NOT IO/, and a FILE *on which we can do I/O.
+ * We have both because we want to support plain and SSL sockets, and
+ * going through a FILE *lets us provide the encryption/decryption
+ * on the stream without using an auxiliary thread.
+ *
+ * NOTE: in order to let other parts of asterisk use these services,
+ * we need to do the following:
+ * + move struct server_instance and struct server_args to
+ * a common header file, together with prototypes for
+ * server_start() and server_root().
+ */
+
+/*!
+ * describes a server instance
+ */
+struct server_instance {
+	FILE *f;    /* fopen/funopen result */
+	int fd;     /* the socket returned by accept() */
+	SSL *ssl;   /* ssl state */
+	struct sockaddr_in requestor;
+	struct server_args *parent;
+};
+
+/*!
+ * arguments for the accepting thread
+ */
+struct server_args {
+	struct sockaddr_in sin;
+	struct sockaddr_in oldsin;
+	struct tls_config *tls_cfg; /* points to the SSL configuration if any */
+	int accept_fd;
+	int poll_timeout;
+	pthread_t master;
+	void *(*accept_fn)(void *); /* the function in charge of doing the accept */
+	void (*periodic_fn)(void *);/* something we may want to run before after select on the accept socket */
+	void *(*worker_fn)(void *); /* the function in charge of doing the actual work */
+	const char *name;
+};
+
+void *server_root(void *);
+void server_start(struct server_args *desc);
+int ssl_setup(struct tls_config *cfg);
+
+void *ast_make_file_from_fd(void *data);
+
+#endif /* _ASTERISK_SERVER_H */

Propchange: team/bbryant/ssl-tcp-tls/include/asterisk/server.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/bbryant/ssl-tcp-tls/include/asterisk/server.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/bbryant/ssl-tcp-tls/include/asterisk/server.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/bbryant/ssl-tcp-tls/main/server.c
URL: http://svn.digium.com/view/asterisk/team/bbryant/ssl-tcp-tls/main/server.c?view=auto&rev=69951
==============================================================================
--- team/bbryant/ssl-tcp-tls/main/server.c (added)
+++ team/bbryant/ssl-tcp-tls/main/server.c Tue Jun 19 11:00:42 2007
@@ -1,0 +1,271 @@
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "asterisk/cli.h"
+#include "asterisk/server.h"
+#include "asterisk/http.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/options.h"
+#include "asterisk/config.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/version.h"
+#include "asterisk/manager.h"
+
+#ifdef DO_SSL
+#if defined(HAVE_FUNOPEN)
+#define HOOK_T int
+#define LEN_T int
+#else
+#define HOOK_T ssize_t
+#define LEN_T size_t
+#endif
+/*!
+ * replacement read/write functions for SSL support.
+ * We use wrappers rather than SSL_read/SSL_write directly so
+ * we can put in some debugging.
+ */
+
+static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
+{
+	int i = SSL_read(cookie, buf, len-1);
+#if 0
+	if (i >= 0)
+		buf[i] = '\0';
+	ast_verbose("ssl read size %d returns %d <%s>\n", (int)len, i, buf);
+#endif
+	return i;
+}
+
+static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
+{
+#if 0
+	char *s = alloca(len+1);
+	strncpy(s, buf, len);
+	s[len] = '\0';
+	ast_verbose("ssl write size %d <%s>\n", (int)len, s);
+#endif
+	return SSL_write(cookie, buf, len);
+}
+
+static int ssl_close(void *cookie)
+{
+	close(SSL_get_fd(cookie));
+	SSL_shutdown(cookie);
+	SSL_free(cookie);
+	return 0;
+}
+#endif	/* DO_SSL */
+
+void *server_root(void *data)
+{
+	struct server_args *desc = data;
+	int fd;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+	struct server_instance *ser;
+	pthread_t launched;
+	
+	for (;;) {
+		int i, flags;
+
+		if (desc->periodic_fn)
+			desc->periodic_fn(desc);
+		i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
+		if (i <= 0)
+			continue;
+		sinlen = sizeof(sin);
+		fd = accept(desc->accept_fd, (struct sockaddr *)&sin, &sinlen);
+		if (fd < 0) {
+			if ((errno != EAGAIN) && (errno != EINTR))
+				ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
+			continue;
+		}
+		ser = ast_calloc(1, sizeof(*ser));
+		if (!ser) {
+			ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
+			close(fd);
+			continue;
+		}
+		flags = fcntl(fd, F_GETFL);
+		fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+		ser->fd = fd;
+		ser->parent = desc;
+		memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
+			
+		if (ast_pthread_create_detached_background(&launched, NULL, ast_make_file_from_fd, ser)) {
+			ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+			close(ser->fd);
+			ast_free(ser);
+		}
+
+	}
+	return NULL;
+}
+
+int ssl_setup(struct tls_config *cfg)
+{
+#ifndef DO_SSL
+	cfg->enabled = 0;
+	return 0;
+#else
+	if (!cfg->enabled)
+		return 0;
+	SSL_load_error_strings();
+	SSLeay_add_ssl_algorithms();
+	cfg->ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
+	if (!ast_strlen_zero(cfg->certfile)) {
+		if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
+		    SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
+		    SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 ) {
+			ast_verbose("ssl cert error <%s>", cfg->certfile);
+			sleep(2);
+			cfg->enabled = 0;
+			return 0;
+		}
+	}
+	if (!ast_strlen_zero(cfg->cipher)) {
+		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
+			ast_verbose("ssl cipher error <%s>", cfg->cipher);
+			sleep(2);
+			cfg->enabled = 0;
+			return 0;
+		}
+	}
+	ast_verbose("ssl cert ok\n");
+	return 1;
+#endif
+}
+
+/*!
+ * This is a generic (re)start routine for a TCP server,
+ * which does the socket/bind/listen and starts a thread for handling
+ * accept().
+ */
+void server_start(struct server_args *desc)
+{
+	int flags;
+	int x = 1;
+	
+	/* Do nothing if nothing has changed */
+	if (!memcmp(&desc->oldsin, &desc->sin, sizeof(desc->oldsin))) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Nothing changed in %s\n", desc->name);
+		return;
+	}
+	
+	desc->oldsin = desc->sin;
+	
+	/* Shutdown a running server if there is one */
+	if (desc->master != AST_PTHREADT_NULL) {
+		pthread_cancel(desc->master);
+		pthread_kill(desc->master, SIGURG);
+		pthread_join(desc->master, NULL);
+	}
+	
+	if (desc->accept_fd != -1)
+		close(desc->accept_fd);
+
+	/* If there's no new server, stop here */
+	if (desc->sin.sin_family == 0)
+		return;
+
+	desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (desc->accept_fd < 0) {
+		ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
+			desc->name, strerror(errno));
+		return;
+	}
+	
+	setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
+	if (bind(desc->accept_fd, (struct sockaddr *)&desc->sin, sizeof(desc->sin))) {
+		ast_log(LOG_NOTICE, "Unable to bind %s to %s:%d: %s\n",
+			desc->name,
+			ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
+			strerror(errno));
+		goto error;
+	}
+	if (listen(desc->accept_fd, 10)) {
+		ast_log(LOG_NOTICE, "Unable to listen for %s!\n", desc->name);
+		goto error;
+	}
+	flags = fcntl(desc->accept_fd, F_GETFL);
+	fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
+	if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
+		ast_log(LOG_NOTICE, "Unable to launch %s on %s:%d: %s\n",
+			desc->name,
+			ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
+			strerror(errno));
+		goto error;
+	}
+	return;
+
+error:
+	close(desc->accept_fd);
+	desc->accept_fd = -1;
+}
+
+/*!
+* creates a FILE * from the fd passed by the accept thread.
+* This operation is potentially expensive (certificate verification),
+* so we do it in the child thread context.
+*/
+void *ast_make_file_from_fd(void *data)
+{
+   struct server_instance *ser = data;
+
+   /*
+	* open a FILE * as appropriate.
+	*/
+   if (!ser->parent->tls_cfg)
+	   ser->f = fdopen(ser->fd, "w+");
+#ifdef DO_SSL
+   else if ( (ser->ssl = SSL_new(ser->parent->tls_cfg->ssl_ctx)) ) {
+	   SSL_set_fd(ser->ssl, ser->fd);
+	   if (SSL_accept(ser->ssl) == 0)
+		   ast_verbose(" error setting up ssl connection");
+	   else {
+#if defined(HAVE_FUNOPEN)	/* the BSD interface */
+		   ser->f = funopen(ser->ssl, ssl_read, ssl_write, NULL, ssl_close);
+
+#elif defined(HAVE_FOPENCOOKIE)	/* the glibc/linux interface */
+		   static const cookie_io_functions_t cookie_funcs = {
+			   ssl_read, ssl_write, NULL, ssl_close
+		   };
+		   ser->f = fopencookie(ser->ssl, "w+", cookie_funcs);
+#else
+		   /* could add other methods here */
+			ast_log(LOG_WARNING, "no ser->f methods attempted!");
+#endif
+	   }
+	   if (!ser->f)	/* no success opening descriptor stacking */
+		   SSL_free(ser->ssl);
+   }
+#endif /* DO_SSL */
+
+   if (!ser->f) {
+	   close(ser->fd);
+	   ast_log(LOG_WARNING, "FILE * open failed!\n");
+	   ast_log(LOG_WARNING, "strerror: %s\n", strerror(errno));
+	   ast_free(ser);
+	   return NULL;
+   }
+   return ser->parent->worker_fn(ser);
+}

Propchange: team/bbryant/ssl-tcp-tls/main/server.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/bbryant/ssl-tcp-tls/main/server.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/bbryant/ssl-tcp-tls/main/server.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list