Sophie

Sophie

distrib > * > 2008.0 > x86_64 > by-pkgid > 7e0c65d5932e657171adf4a3de9f5f58 > files > 13

asterisk-1.4.11-2mdv2008.0.src.rpm

--- ../clean/asterisk-1.4.8/channels/chan_sip.c	2007-07-26 12:19:11.000000000 +0200
+++ channels/chan_sip.c	2007-08-08 13:05:18.000000000 +0200
@@ -25,11 +25,10 @@
  * See Also:
  * \arg \ref AstCREDITS
  *
- * Implementation of RFC 3261 - without S/MIME, TCP and TLS support
+ * Implementation of RFC 3261 - without S/MIME and TLS support
  * Configuration file \link Config_sip sip.conf \endlink
  *
  *
- * \todo SIP over TCP
  * \todo SIP over TLS
  * \todo Better support of forking
  * \todo VIA branch tag transaction checking
@@ -597,6 +596,7 @@
 static struct sched_context *sched;     /*!< The scheduling context */
 static struct io_context *io;           /*!< The IO context */
 static int *sipsock_read_id;            /*!< ID of IO entry for sipsock FD */
+static int *siptcpsock_read_id;         /*!< ID of IO entry for sipsock FD */
 
 #define DEC_CALL_LIMIT	0
 #define INC_CALL_LIMIT	1
@@ -786,10 +786,12 @@
 #define SIP_PAGE2_RFC2833_COMPENSATE    (1 << 25)	/*!< 25: ???? */
 #define SIP_PAGE2_BUGGY_MWI		(1 << 26)	/*!< 26: Buggy CISCO MWI fix */
 #define SIP_PAGE2_OUTGOING_CALL         (1 << 27)       /*!< 27: Is this an outgoing call? */
+#define SIP_PAGE2_TCP                   (1 << 28)       /*!< 28: Should we use  TCP with this peer*/
+#define SIP_PAGE2_TCP_CONNECTED         (1 << 29)       /*!< 28: Is this TCP peer connected */
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
 	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \
-	SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI)
+	SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI )
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
@@ -1006,6 +1008,7 @@
 	struct sip_pvt *next;			/*!< Next dialog in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
 	int autoframing;
+	int sockfd;				/*!< This is the socket FD for tcp connections */
 } *iflist = NULL;
 
 #define FLAG_RESPONSE (1 << 0)
@@ -1118,6 +1121,7 @@
 	struct sip_pvt *mwipvt;		/*!<  Subscription for MWI */
 	int lastmsg;
 	int autoframing;
+	int sockfd;			/*!< Socket used by this peer for tcp connections*/
 };
 
 
@@ -1183,7 +1187,8 @@
 
 
 /* --- Sockets and networking --------------*/
-static int sipsock  = -1;			/*!< Main socket for SIP network communication */
+static int sipsock  = -1;			/*!< Main socket for SIP network communication UDP*/
+static int siptcpsock  = -1;			/*!< Main socket for SIP network communication TCP*/
 static struct sockaddr_in bindaddr = { 0, };	/*!< The address we bind to */
 static struct sockaddr_in externip;		/*!< External IP address if we are behind NAT */
 static char externhost[MAXHOSTNAMELEN];		/*!< External host name (possibly with dynamic DNS and DHCP */
@@ -1755,7 +1760,20 @@
 {
 	int res;
 	const struct sockaddr_in *dst = sip_real_dst(p);
-	res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+	/* This is a  TCP connection*/
+	if (ast_test_flag(&p->flags[1], SIP_PAGE2_TCP)) {
+		if (!ast_test_flag(&p->flags[1], SIP_PAGE2_TCP_CONNECTED)) {
+			if (connect(p->sockfd, (const struct sockaddr *)dst, sizeof(struct sockaddr_in)) == 0) {
+				ast_set_flag(&p->flags[1], SIP_PAGE2_TCP_CONNECTED);
+			} else if (errno == EISCONN) {
+				ast_set_flag(&p->flags[1], SIP_PAGE2_TCP_CONNECTED);
+			} else {
+				ast_log(LOG_ERROR, "Connect Failed Sock: %i %s:%d %s\n",p->sockfd,ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), strerror(errno));
+			}
+		}
+		res = write(p->sockfd, data, len);
+	} else
+		res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
 
 	if (res == -1) {
 		switch (errno) {
@@ -1779,8 +1797,8 @@
 	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, "SIP/2.0/%s %s:%d;branch=z9hG4bK%08x%s",
+			 ast_test_flag(&p->flags[1], SIP_PAGE2_TCP) ? "TCP" : "UDP", ast_inet_ntoa(p->ourip), ourport, p->branch, rport);
 }
 
 /*! \brief NAT fix - decide which IP address to use for ASterisk server?
@@ -2650,6 +2668,8 @@
 
 	ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_TCP | SIP_PAGE2_TCP_CONNECTED);
+	dialog->sockfd = peer->sockfd;
 	dialog->capability = peer->capability;
 	if ((!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) || !(dialog->capability & AST_FORMAT_VIDEO_MASK)) && dialog->vrtp) {
 		ast_rtp_destroy(dialog->vrtp);
@@ -4272,6 +4292,7 @@
 	p->autokillid = -1;
 	p->subscribed = NONE;
 	p->stateid = -1;
+	p->sockfd=-1;	
 	p->prefs = default_prefs;		/* Set default codecs for this call */
 
 	if (intended_method != SIP_OPTIONS)	/* Peerpoke has it's own system */
@@ -7645,6 +7666,10 @@
 		return 0;
 
 	memset(&peer->addr, 0, sizeof(peer->addr));
+	if (peer->sockfd > 0) {
+		close(peer->sockfd);
+		ast_clear_flag(&peer->flags[1], SIP_PAGE2_TCP_CONNECTED);
+	}
 
 	destroy_association(peer);	/* remove registration data from storage */
 	
@@ -7722,7 +7747,7 @@
 	peer->addr.sin_family = AF_INET;
 	peer->addr.sin_addr = in;
 	peer->addr.sin_port = htons(port);
-	if (sipsock < 0) {
+	if ((sipsock < 0) || (siptcpsock < 0)){
 		/* SIP isn't up yet, so schedule a poke only, pretty soon */
 		if (peer->pokeexpire > -1)
 			ast_sched_del(sched, peer->pokeexpire);
@@ -7964,6 +7989,13 @@
 		if (option_verbose > 3)
 			ast_verbose(VERBOSE_PREFIX_3 "Saved useragent \"%s\" for peer %s\n", peer->useragent, peer->name);  
 	}
+
+	/* Allocate A TCP Soccket of incoming connection*/
+	if (((!ast_test_flag(&peer->flags[1], SIP_PAGE2_TCP)) || (peer->sockfd != pvt->sockfd)) && (ast_test_flag(&pvt->flags[1], SIP_PAGE2_TCP))) {
+		ast_set_flag(&peer->flags[1], SIP_PAGE2_TCP);
+		peer->sockfd=pvt->sockfd;
+		ast_set_flag(&peer->flags[1], SIP_PAGE2_TCP_CONNECTED);
+	}
 	return PARSE_REGISTER_UPDATE;
 }
 
@@ -8929,7 +8961,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"))) {
 			ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
 			return;
 		}
@@ -10148,6 +10180,7 @@
 		ast_cli(fd, "  ToHost       : %s\n", peer->tohost);
 		ast_cli(fd, "  Addr->IP     : %s Port %d\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
 		ast_cli(fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+		ast_cli(fd, "  Transport    : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_TCP) ? "TCP" : "UDP");
 		if (!ast_strlen_zero(global_regcontext))
 			ast_cli(fd, "  Reg. exten   : %s\n", peer->regexten);
 		ast_cli(fd, "  Def. Username: %s\n", peer->username);
@@ -15003,7 +15036,18 @@
 	int lockretry;
 
 	memset(&req, 0, sizeof(req));
-	res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
+	if (fd == sipsock)
+		res = recvfrom(fd, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
+	else {
+		if (getpeername(fd, (struct sockaddr *)&sin, &len) < 0) {
+			close(fd);
+			return 1;
+		}
+		if ((res = read(fd, req.data, sizeof(req.data) - 1)) == 0) {
+			close(fd);
+			return 1;
+		}
+	}
 	if (res < 0) {
 #if !defined(__FreeBSD__)
 		if (errno == EAGAIN)
@@ -15025,7 +15069,8 @@
 	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:%d:%s --->\n%s\n<------------->\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 
+			fd == sipsock ? "UDP" : "TCP",req.data);
 
 	parse_request(&req);
 	req.method = find_sip_method(req.rlPart1);
@@ -15075,6 +15120,13 @@
 		return 1;
 	}
 	nounlock = 0;
+	/* Is this a TCP connection ?? if so set the socket accordingly*/
+	if (fd != sipsock) {
+		p->sockfd=fd;
+		ast_set_flag(&p->flags[1], SIP_PAGE2_TCP);
+	} else {
+		p->sockfd=-1;
+	}
 	if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
 		/* Request failed */
 		if (option_debug)
@@ -15091,6 +15143,18 @@
 	return 1;
 }
 
+/*! \brief Accept incoming TCP connections*/
+static int siptcpsock_accept(int *id, int fd, short events, void *ignore)
+{
+	struct sockaddr_in sa;
+	socklen_t sa_len=sizeof(sa);
+	int newfd;
+
+	if ((newfd=accept(siptcpsock, (struct sockaddr *)&sa, &sa_len)) >= 0)
+		ast_io_add(io, newfd, sipsock_read, AST_IO_IN, NULL);
+	return 1;
+}
+
 /*! \brief Send message waiting indication to alert peer that they've got voicemail */
 static int sip_send_mwi_to_peer(struct sip_peer *peer)
 {
@@ -15177,6 +15241,8 @@
 	/* Add an I/O event to our SIP UDP socket */
 	if (sipsock > -1) 
 		sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
+	if (siptcpsock > -1) 
+		siptcpsock_read_id = ast_io_add(io, siptcpsock, siptcpsock_accept, AST_IO_IN, NULL);
 	
 	/* From here on out, we die whenever asked */
 	for(;;) {
@@ -15197,6 +15263,13 @@
 				else
 					sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
 			}
+
+			if (siptcpsock > -1) {
+				if (siptcpsock_read_id)
+					siptcpsock_read_id = ast_io_change(io, siptcpsock_read_id, siptcpsock, NULL, 0, NULL);
+				else
+					siptcpsock_read_id = ast_io_add(io, siptcpsock, siptcpsock_accept, AST_IO_IN, NULL);
+			}
 		}
 		/* Check for interfaces needing to be killed */
 		ast_mutex_lock(&iflock);
@@ -15400,6 +15473,8 @@
 	p->recv = peer->addr;
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_TCP | SIP_PAGE2_TCP_CONNECTED);
+	p->sockfd = peer->sockfd;
 
 	/* Send OPTIONs to peer's fullcontact */
 	if (!ast_strlen_zero(peer->fullcontact))
@@ -16152,6 +16227,7 @@
 	/* If we have realm authentication information, remove them (reload) */
 	clear_realm_authentication(peer->auth);
 	peer->auth = NULL;
+	peer->sockfd = -1;
 
 	for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
 		if (handle_common_options(&peerflags[0], &mask[0], v))
@@ -16822,15 +16898,20 @@
 		bindaddr.sin_port = ntohs(STANDARD_SIP_PORT);
 	bindaddr.sin_family = AF_INET;
 	ast_mutex_lock(&netlock);
-	if ((sipsock > -1) && (memcmp(&old_bindaddr, &bindaddr, sizeof(struct sockaddr_in)))) {
-		close(sipsock);
-		sipsock = -1;
+	if (memcmp(&old_bindaddr, &bindaddr, sizeof(struct sockaddr_in))) {
+		if (sipsock > -1) {
+			close(sipsock);
+			sipsock = -1;
+		}
+		if (siptcpsock > -1) {
+			close(siptcpsock);
+			siptcpsock = -1;
+		}
 	}
 	if (sipsock < 0) {
 		sipsock = socket(AF_INET, SOCK_DGRAM, 0);
 		if (sipsock < 0) {
 			ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno));
-			return -1;
 		} else {
 			/* Allow SIP clients on the same host to access us: */
 			const int reuseFlag = 1;
@@ -16842,22 +16923,60 @@
 			ast_enable_packet_fragmentation(sipsock);
 
 			if (bind(sipsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
-				ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
+				ast_log(LOG_WARNING, "Failed to bind to UDP %s:%d: %s\n",
 				ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
 				strerror(errno));
 				close(sipsock);
 				sipsock = -1;
 			} else {
 				if (option_verbose > 1) { 
-					ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n", 
+					ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on UDP %s:%d\n", 
 					ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
-					ast_verbose(VERBOSE_PREFIX_2 "Using SIP TOS: %s\n", ast_tos2str(global_tos_sip));
+					ast_verbose(VERBOSE_PREFIX_2 "Using SIP UDP TOS: %s\n", ast_tos2str(global_tos_sip));
 				}
 				if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) 
-					ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
+					ast_log(LOG_WARNING, "Unable to set SIP UDP TOS to %s\n", ast_tos2str(global_tos_sip));
 			}
 		}
 	}
+	if (siptcpsock < 0) {
+		siptcpsock = socket(AF_INET, SOCK_STREAM, 0);
+		if (siptcpsock < 0) {
+			ast_log(LOG_WARNING, "Unable to create SIP TCP socket: %s\n", strerror(errno));
+		} else {
+			/* Allow SIP clients on the same host to access us: */
+			const int reuseFlag = 1;
+
+			setsockopt(siptcpsock, SOL_SOCKET, SO_REUSEADDR,
+				   (const char*)&reuseFlag,
+				   sizeof reuseFlag);
+
+			ast_enable_packet_fragmentation(sipsock);
+
+			if (bind(siptcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
+				ast_log(LOG_WARNING, "Failed to bind to TCP %s:%d: %s\n",
+				ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
+				strerror(errno));
+				close(siptcpsock);
+				siptcpsock = -1;
+			} else {
+				if (listen(siptcpsock, 30) < 0) {
+					ast_log(LOG_WARNING, "Failed to listen on SIP TCP\n");
+				} else {
+					if (option_verbose > 1) { 
+						ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on TCP %s:%d\n", 
+						ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
+						ast_verbose(VERBOSE_PREFIX_2 "Using SIP TCP TOS: %s\n", ast_tos2str(global_tos_sip));
+					}
+					if (setsockopt(siptcpsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) 
+						ast_log(LOG_WARNING, "Unable to set SIP TCP TOS to %s\n", ast_tos2str(global_tos_sip));
+				}
+			}
+		}
+	}
+	if ((sipsock < 0) && (siptcpsock <0)) {
+		return -1;
+	}
 	ast_mutex_unlock(&netlock);
 
 	/* Add default domains - host name, IP address and IP:port */
@@ -17698,6 +17817,7 @@
 	clear_realm_authentication(authl);
 	clear_sip_domains();
 	close(sipsock);
+	close(siptcpsock);
 	sched_context_destroy(sched);
 		
 	return 0;