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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jun 21 00:11:29 CDT 2007


Author: bbryant
Date: Thu Jun 21 00:11:29 2007
New Revision: 70650

URL: http://svn.digium.com/view/asterisk?view=rev&rev=70650
Log:
Save progress to sip/tcp code.

Modified:
    team/bbryant/ssl-tcp-tls/channels/chan_sip.c
    team/bbryant/ssl-tcp-tls/main/server.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=70650&r1=70649&r2=70650
==============================================================================
--- team/bbryant/ssl-tcp-tls/channels/chan_sip.c (original)
+++ team/bbryant/ssl-tcp-tls/channels/chan_sip.c Thu Jun 21 00:11:29 2007
@@ -590,7 +590,6 @@
 static int global_t1min;		/*!< T1 roundtrip time minimum */
 static int global_regextenonqualify;  /*!< Whether to add/remove regexten when qualifying peers */
 static int global_autoframing;          /*!< Turn autoframing on or off. */
-static int global_tcpenable;	/*!< Turn TCP on/off */
 static enum transfermodes global_allowtransfer;	/*!< SIP Refer restriction scheme */
 static struct sip_proxy global_outboundproxy;	/*!< Outbound proxy */
 
@@ -868,6 +867,11 @@
 #define sipdebug_console	ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
 #define sipdebug_text		ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT)
 
+/*!< Define some SIP transports */
+#define SIP_TRANSPORT_UDP (1 << 0)
+#define SIP_TRANSPORT_TCP (1 << 1)
+#define SIP_TRANSPORT_TLS (1 << 2)
+
 /*! \brief T38 States for a call */
 enum t38state {
 	T38_DISABLED = 0,                /*!< Not enabled */
@@ -980,8 +984,9 @@
 		AST_STRING_FIELD(rpid);		/*!< Our RPID header */
 		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
 		AST_STRING_FIELD(url);		/*!< URL to be sent with next message to peer */
-		AST_STRING_FIELD(transport); /*!< Transport type (i.e. UDP, TCP, TLS ... etc) */
 	);
+	int transport;
+	struct server_instance *ser;
 	unsigned int ocseq;			/*!< Current outgoing seqno */
 	unsigned int icseq;			/*!< Current incoming seqno */
 	ast_group_t callgroup;			/*!< Call group */
@@ -1083,7 +1088,7 @@
 struct sip_pkt {
 	struct sip_pkt *next;			/*!< Next packet in linked list */
 	int retrans;				/*!< Retransmission number */
-	int method;				/*!< SIP me`:thod for this packet */
+	int method;				/*!< SIP method 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 */
@@ -1288,6 +1293,9 @@
 static int sip_senddigit_begin(struct ast_channel *ast, char digit);
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 
+static char *get_transport(struct sip_pvt *p);
+static int handle_request_do(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *nounlock);
+
 /*--- Transmitting responses and requests */
 static int sipsock_read(int *id, int fd, short events, void *ignore);
 static int __sip_xmit(struct sip_pvt *p, char *data, int len);
@@ -1468,6 +1476,11 @@
 static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to LOG_DEBUG at end of dialog, before destroying data */
 static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
 static inline int sip_debug_test_pvt(struct sip_pvt *p);
+
+
+/*! \brief Append to SIP dialog history 
+	\return Always returns 0 */
+#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
 static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
 static void sip_dump_history(struct sip_pvt *dialog);
 
@@ -1696,14 +1709,72 @@
 	get_codec: sip_get_codec,
 };
 
-/*! \brieft SIP TCP helper function */
+static void sip_pvt_unlock(struct sip_pvt *);
+
+/*! \brief SIP TCP helper function */
 static void *sip_tcp_helper_thread(void *data) {
-	char buf[4096];
-
+	struct sip_pvt *p;
 	struct server_instance *ser = data;
-
-	while (fgets(buf, sizeof(buf), ser->f)) {
-		ast_log(LOG_WARNING, buf);
+	int req_len, lockretry, nounlock;
+	char buf[1024];
+	struct sip_request req = { 0, };
+
+	for (;;) {
+		bzero(req.data, sizeof(req.data));
+		fgets(req.data, sizeof(req.data), ser->f);
+		req_len  = strlen(req.data);
+
+		while (req_len < 4 || strncmp((char *)&req.data + req_len - 4, "\r\n\r\n", 4)) {
+			if(!fgets(buf, sizeof(buf), ser->f))
+				return NULL;
+
+			strncat(req.data, buf, sizeof(req.data) - req_len - 1);
+			req_len = strlen(req.data);
+		}
+
+		for (lockretry = 100; lockretry > 0; lockretry--) {
+			ast_mutex_lock(&netlock);
+
+			/* Find the active SIP dialog or create a new one */
+			p = find_call(&req, &ser->parent->sin, req.method);	/* returns p locked */
+
+			if (p == NULL) {
+				ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req.len);
+				ast_mutex_unlock(&netlock);
+				return NULL;
+			}
+
+			p->transport = (ser->parent->tls_cfg) ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP;
+			/* Go ahead and lock the owner if it has one -- we may need it */
+			/* becaues this is deadlock-prone, we need to try and unlock if failed */
+			if (!p->owner || !ast_channel_trylock(p->owner))
+				break;	/* locking succeeded */
+			ast_debug(1, "Failed to grab owner channel lock, trying again. (SIP call %s)\n", p->callid);
+			sip_pvt_unlock(p);
+			ast_mutex_unlock(&netlock);
+			/* Sleep for a very short amount of time */
+			usleep(1);
+		}
+
+		p->recv = ser->parent->sin;
+
+		if (!lockretry) {
+			if (p->owner)
+				ast_log(LOG_ERROR, "We could NOT get the channel lock for %s! \n", S_OR(p->owner->name, "- no channel name ??? - "));
+			ast_log(LOG_ERROR, "SIP transaction failed: %s \n", p->callid);
+			if (req.method != SIP_ACK)
+				transmit_response(p, "503 Server error", &req);	/* We must respond according to RFC 3261 sec 12.2 */
+			/* XXX We could add retry-after to make sure they come back */
+			append_history(p, "LockFail", "Owner lock failed, transaction failed.");
+			return NULL;
+		}
+
+		handle_request_do(p, &req, &ser->parent->sin, &nounlock);
+
+		if (p->owner && !nounlock)
+			ast_channel_unlock(p->owner);
+		sip_pvt_unlock(p);
+		ast_mutex_unlock(&netlock);
 	}
 
 	return NULL;
@@ -1755,10 +1826,6 @@
 	get_udptl_info: sip_get_udptl_peer,
 	set_udptl_peer: sip_set_udptl_peer,
 };
-
-/*! \brief Append to SIP dialog history 
-	\return Always returns 0 */
-#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
 
 static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
@@ -1965,8 +2032,12 @@
 static int __sip_xmit(struct sip_pvt *p, char *data, int len)
 {
 	int res;
+	int fd;
 	const struct sockaddr_in *dst = sip_real_dst(p);
-	res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+
+	fd = (p->transport & SIP_TRANSPORT_UDP) ? sipsock : p->ser->parent->accept_fd;
+
+	res = sendto(fd, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
 
 	if (res == -1) {
 		switch (errno) {
@@ -1990,8 +2061,9 @@
 	const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
 
 	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
-			 ast_inet_ntoa(p->ourip), ourport, p->branch, rport);
+	ast_string_field_build(p, via, "%s/2.0/%s %s:%d;branch=z9hG4bK%08x%s",
+			((p->transport & SIP_TRANSPORT_TLS) ? "SIPS" : "SIP"),
+			get_transport(p), ast_inet_ntoa(p->ourip), ourport, p->branch, rport);
 }
 
 /*! \brief NAT fix - decide which IP address to use for ASterisk server?
@@ -2514,6 +2586,9 @@
 			ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
 		}
 	}
+	/* TODO Fix this to something cleaner  */
+	if (!strncmp(tmp, "sips:", 5))
+		sprintf(tmp, "sip%s", tmp+4);
 	return tmp;
 }
 
@@ -4869,6 +4944,7 @@
 			/* Found the call */
 			sip_pvt_lock(p);
 			dialoglist_unlock();
+			p->transport = SIP_TRANSPORT_UDP;
 			return p;
 		}
 	}
@@ -4901,6 +4977,8 @@
 				ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
 			}
 		}
+		p->transport = SIP_TRANSPORT_UDP;
+
 		return p;
 	} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
 		/* A method we do not support, let's take it on the volley */
@@ -4915,6 +4993,8 @@
 	   the session quickly */
 	if (intended_method == SIP_RESPONSE)
 		ast_debug(2, "That's odd...  Got a response on a call we dont know about. Callid %s\n", callid ? callid : "<unknown>");
+
+	p->transport = SIP_TRANSPORT_UDP;
 
 	return p;
 }
@@ -9580,7 +9660,7 @@
 	if (c) {
 		*c = '\0';
 		c = ast_skip_blanks(c+1);
-		if (strcasecmp(via, "SIP/2.0/UDP")) {
+		if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIPS/2.0/TCP")) {
 			ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
 			return;
 		}
@@ -15730,14 +15810,11 @@
 	struct sip_request req;
 	struct sockaddr_in sin = { 0, };
 	struct sip_pvt *p;
-	int res;
+	int res, lockretry, nounlock;
 	socklen_t len = sizeof(sin);
-	int nounlock;
-	int recount = 0;
-	int lockretry;
 
 	memset(&req, 0, sizeof(req));
-	res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
+	res = recvfrom(fd, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
 	if (res < 0) {
 #if !defined(__FreeBSD__)
 		if (errno == EAGAIN)
@@ -15759,7 +15836,9 @@
 	if (pedanticsipchecking)
 		req.len = lws2sws(req.data, req.len);	/* Fix multiline headers */
 	if (ast_test_flag(&req, SIP_PKT_DEBUG))
-		ast_verbose("\n<--- SIP read from %s:%d --->\n%s\n<------------->\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), req.data);
+		ast_verbose("\n<--- SIP read from %s://%s:%d %s--->\n%s\n<------------->\n", 
+					get_transport(p), ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 
+					((p->transport & SIP_TRANSPORT_TLS) ? "(Secure) " : ""), req.data);
 
 	parse_request(&req);
 	req.method = find_sip_method(req.rlPart1);
@@ -15793,9 +15872,6 @@
 	}
 	p->recv = sin;
 
-	if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) /* This is a request or response, note what it was for */
-		append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
-
 	if (!lockretry) {
 		if (p->owner)
 			ast_log(LOG_ERROR, "We could NOT get the channel lock for %s! \n", S_OR(p->owner->name, "- no channel name ??? - "));
@@ -15806,16 +15882,34 @@
 		append_history(p, "LockFail", "Owner lock failed, transaction failed.");
 		return 1;
 	}
-	nounlock = 0;
-	if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
-		/* Request failed */
-		ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
-	}
-		
+
+	handle_request_do(p, &req, &sin, &nounlock);
+
 	if (p->owner && !nounlock)
 		ast_channel_unlock(p->owner);
 	sip_pvt_unlock(p);
 	ast_mutex_unlock(&netlock);
+
+	return 1;
+}
+
+static char *get_transport(struct sip_pvt *p) {
+	char *str = (p->transport & SIP_TRANSPORT_UDP) ? "UDP" : "TCP";
+	return ast_strdup(str);
+}
+
+static int handle_request_do(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *nounlock) {
+	int recount = 0;
+
+	if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) /* This is a request or response, note what it was for */
+		append_history(p, "Rx", "%s / %s / %s", req->data, get_header(req, "CSeq"), req->rlPart2);
+
+	nounlock = 0;
+	if (handle_request(p, req, sin, &recount, nounlock) == -1) {
+		/* Request failed */
+		ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
+	}
+		
 	if (recount)
 		ast_update_use_count();
 
@@ -17120,9 +17214,19 @@
 	/* 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_family = AF_INET;
+
 	sip_tcp_desc.sin.sin_port = htons(STANDARD_SIP_PORT);
 	sip_tls_desc.sin.sin_port = htons(STANDARD_TLS_PORT);
+
+	if((hp = ast_gethostbyname("0.0.0.0", &ahp))) { // Default bind address for TCP / TLS
+		memcpy(&sip_tcp_desc.sin.sin_addr, hp->h_addr, sizeof(sip_tcp_desc.sin.sin_addr));
+		memcpy(&sip_tls_desc.sin.sin_addr, hp->h_addr, sizeof(sip_tls_desc.sin.sin_addr));
+	}
+	
+	sip_tls_desc.tls_cfg->certfile 	= ast_strdup(AST_CERTFILE); /*XXX Not sure if this is useful */
+	sip_tls_desc.tls_cfg->cipher 	= ast_strdup("");
 	
 	/* Initialize copy of current global_regcontext for later use in removing stale contexts */
 	ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
@@ -17257,6 +17361,12 @@
 			global_t1min = atoi(v->value);
 		} else if (!strcasecmp(v->name, "tcpenable")) {
 			sip_tcp_desc.sin.sin_family = ast_false(v->value) ? 0 : AF_INET;
+		} else if (!strcasecmp(v->name, "tcpbindaddr")) {
+			if((hp = ast_gethostbyname(v->value, &ahp))) {
+				memcpy(&sip_tcp_desc.sin.sin_addr, hp->h_addr, sizeof(sip_tcp_desc.sin.sin_addr));
+			} else {
+				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
+			}
 		} else if (!strcasecmp(v->name, "tcpbindport")) {
 			if (sscanf(v->value, "%d", &ourport) == 1) {
 				sip_tcp_desc.sin.sin_port = htons(ourport);
@@ -17267,6 +17377,14 @@
 			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, "tlscipher")) {
+			sip_tls_desc.tls_cfg->cipher = ast_strdup(v->value);
+		} else if (!strcasecmp(v->name, "tlsbindaddr")) {
+			if((hp = ast_gethostbyname(v->value, &ahp))) {
+				memcpy(&sip_tls_desc.sin.sin_addr, hp->h_addr, sizeof(sip_tls_desc.sin.sin_addr));
+			} else {
+				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
+			}
 		} else if (!strcasecmp(v->name,"tlsbindport")) {
 			if (sscanf(v->value, "%d", &ourport) == 1) {
 				sip_tls_desc.sin.sin_port = htons(ourport);

Modified: team/bbryant/ssl-tcp-tls/main/server.c
URL: http://svn.digium.com/view/asterisk/team/bbryant/ssl-tcp-tls/main/server.c?view=diff&rev=70650&r1=70649&r2=70650
==============================================================================
--- team/bbryant/ssl-tcp-tls/main/server.c (original)
+++ team/bbryant/ssl-tcp-tls/main/server.c Thu Jun 21 00:11:29 2007
@@ -115,7 +115,6 @@
 			close(ser->fd);
 			ast_free(ser);
 		}
-
 	}
 	return NULL;
 }
@@ -229,43 +228,45 @@
 */
 void *ast_make_file_from_fd(void *data)
 {
-   struct server_instance *ser = data;
+	struct server_instance *ser = data;
+	int ret;
+	char err[256];
 
    /*
 	* open a FILE * as appropriate.
 	*/
-   if (!ser->parent->tls_cfg)
-	   ser->f = fdopen(ser->fd, "w+");
+	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 {
+	else if ( (ser->ssl = SSL_new(ser->parent->tls_cfg->ssl_ctx)) ) {
+		SSL_set_fd(ser->ssl, ser->fd);
+		if ((ret = SSL_accept(ser->ssl)) <= 0) {
+			if(option_verbose > 1)
+				ast_verbose(VERBOSE_PREFIX_2 "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
+		} else {
 #if defined(HAVE_FUNOPEN)	/* the BSD interface */
-		   ser->f = funopen(ser->ssl, ssl_read, ssl_write, NULL, ssl_close);
+			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);
+			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 */
+			/* 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);
+		}
+		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;
+		close(ser->fd);
+		ast_log(LOG_WARNING, "FILE * open failed!\n");
+		ast_free(ser);
+		return NULL;
    }
    return ser->parent->worker_fn(ser);
 }




More information about the asterisk-commits mailing list