Browse Source

Merge commit 'origin/andrei/send_flags'

* commit 'origin/andrei/send_flags':
  NEWS: update
  core: new close after send and reuse only script functions
  tcp: send_flags support
  sl: use the msg reply send_flags
  tm: support for send_flags
  core: send flags support
Andrei Pelinescu-Onciul 16 years ago
parent
commit
643491da0b
16 changed files with 199 additions and 36 deletions
  1. 17 0
      NEWS
  2. 17 0
      action.c
  3. 12 0
      cfg.lex
  4. 28 0
      cfg.y
  5. 10 5
      forward.c
  6. 9 0
      ip_addr.h
  7. 6 3
      modules/tm/t_fwd.c
  8. 1 0
      modules/tm/t_lookup.c
  9. 3 3
      modules/tm/uac.c
  10. 12 5
      modules/tm/ut.h
  11. 2 1
      modules_k/sl/sl_funcs.c
  12. 1 0
      modules_s/sl/sl_funcs.c
  13. 2 0
      parser/msg_parser.h
  14. 5 1
      route_struct.h
  15. 6 1
      tcp_conn.h
  16. 68 17
      tcp_main.c

+ 17 - 0
NEWS

@@ -62,13 +62,30 @@ config script changes:
   - support for kamailio style pvars
   - support for kamailio style pvars
   - C-like switch()/case (integer only)
   - C-like switch()/case (integer only)
   - while()
   - while()
+  - include file support: include_file "somefile"
+  - event route support: event_route[module_name:eventid]
+
 build system:
 build system:
   - multiple modules directories are now supported (defined in Makefile.dirs)
   - multiple modules directories are now supported (defined in Makefile.dirs)
 
 
 new config variables:
 new config variables:
   - max_while_loops - maximum iterations allowed for a while  (can be changed
   - max_while_loops - maximum iterations allowed for a while  (can be changed
        at runtime). Default 100.
        at runtime). Default 100.
+  - log_name - set the application name used when printing to syslog.
 
 
+new script commands:
+  add_local_rport() - adds the rport parameter to the added via header
+       (rfc3581).
+  set_forward_no_connect() - the message will be forwarded only if there is
+       already an existing connection to the destination (it applies only to
+       connection oriented protocols like tcp, tls and in the future sctp).
+  set_reply_no_connect() - like set_forward_no_connect(),  but works for
+       replies to the current message.
+  set_forward_close()  - try to close the connection after forwarding the
+       current message (it applies only when the underlying protocol is
+       connection oriented).
+  set_reply_close() - like set_forward_close(), but it works for replies to
+       the current message.
 
 
 
 
 
 

+ 17 - 0
action.c

@@ -50,6 +50,7 @@
  *  2008-12-03  use lvalues/rvalues for assignments (andrei)
  *  2008-12-03  use lvalues/rvalues for assignments (andrei)
  *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  *  2009-05-04  switched IF_T to rval_expr (andrei)
  *  2009-05-04  switched IF_T to rval_expr (andrei)
+ *  2009-09-15  added SET_{FWD,RPL}_NO_CONNECT, SET_{FWD,RPL}_CLOSE (andrei)
  */
  */
 
 
 
 
@@ -1214,6 +1215,22 @@ match_cleanup:
 			else
 			else
 				ret=v;
 				ret=v;
 			break;
 			break;
+		case SET_FWD_NO_CONNECT_T:
+			msg->fwd_send_flags|= SND_F_FORCE_CON_REUSE;
+			ret=1; /* continue processing */
+			break;
+		case SET_RPL_NO_CONNECT_T:
+			msg->rpl_send_flags|= SND_F_FORCE_CON_REUSE;
+			ret=1; /* continue processing */
+			break;
+		case SET_FWD_CLOSE_T:
+			msg->fwd_send_flags|= SND_F_CON_CLOSE;
+			ret=1; /* continue processing */
+			break;
+		case SET_RPL_CLOSE_T:
+			msg->rpl_send_flags|= SND_F_CON_CLOSE;
+			ret=1; /* continue processing */
+			break;
 /*
 /*
 		default:
 		default:
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);

+ 12 - 0
cfg.lex

@@ -215,6 +215,10 @@ ELSE			"else"
 SET_ADV_ADDRESS	"set_advertised_address"
 SET_ADV_ADDRESS	"set_advertised_address"
 SET_ADV_PORT	"set_advertised_port"
 SET_ADV_PORT	"set_advertised_port"
 FORCE_SEND_SOCKET	"force_send_socket"
 FORCE_SEND_SOCKET	"force_send_socket"
+SET_FWD_NO_CONNECT		"set_forward_no_connect"
+SET_RPL_NO_CONNECT	"set_reply_no_connect"
+SET_FWD_CLOSE	"set_forward_close"
+SET_RPL_CLOSE	"set_reply_close"
 SWITCH			"switch"
 SWITCH			"switch"
 CASE			"case"
 CASE			"case"
 DEFAULT			"default"
 DEFAULT			"default"
@@ -572,6 +576,14 @@ EAT_ABLE	[\ \t\b\r]
 										return SET_ADV_PORT; }
 										return SET_ADV_PORT; }
 <INITIAL>{FORCE_SEND_SOCKET}	{	count(); yylval.strval=yytext;
 <INITIAL>{FORCE_SEND_SOCKET}	{	count(); yylval.strval=yytext;
 									return FORCE_SEND_SOCKET; }
 									return FORCE_SEND_SOCKET; }
+<INITIAL>{SET_FWD_NO_CONNECT}	{ count(); yylval.strval=yytext;
+									return SET_FWD_NO_CONNECT; }
+<INITIAL>{SET_RPL_NO_CONNECT}	{ count(); yylval.strval=yytext;
+									return SET_RPL_NO_CONNECT; }
+<INITIAL>{SET_FWD_CLOSE}		{ count(); yylval.strval=yytext;
+									return SET_FWD_CLOSE; }
+<INITIAL>{SET_RPL_CLOSE}		{ count(); yylval.strval=yytext;
+									return SET_RPL_CLOSE; }
 <INITIAL>{SWITCH}	{ count(); yylval.strval=yytext; return SWITCH; }
 <INITIAL>{SWITCH}	{ count(); yylval.strval=yytext; return SWITCH; }
 <INITIAL>{CASE}	{ count(); yylval.strval=yytext; return CASE; }
 <INITIAL>{CASE}	{ count(); yylval.strval=yytext; return CASE; }
 <INITIAL>{DEFAULT}	{ count(); yylval.strval=yytext; return DEFAULT; }
 <INITIAL>{DEFAULT}	{ count(); yylval.strval=yytext; return DEFAULT; }

+ 28 - 0
cfg.y

@@ -319,6 +319,10 @@ extern char *finame;
 %token SET_ADV_ADDRESS
 %token SET_ADV_ADDRESS
 %token SET_ADV_PORT
 %token SET_ADV_PORT
 %token FORCE_SEND_SOCKET
 %token FORCE_SEND_SOCKET
+%token SET_FWD_NO_CONNECT
+%token SET_RPL_NO_CONNECT
+%token SET_FWD_CLOSE
+%token SET_RPL_CLOSE
 %token SWITCH
 %token SWITCH
 %token CASE
 %token CASE
 %token DEFAULT
 %token DEFAULT
@@ -2990,6 +2994,30 @@ cmd:
 		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
 		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
 	}
 	}
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
+	| SET_FWD_NO_CONNECT LPAREN RPAREN	{
+		$$=mk_action(SET_FWD_NO_CONNECT_T, 0); set_cfg_pos($$);
+	}
+	| SET_FWD_NO_CONNECT	{
+		$$=mk_action(SET_FWD_NO_CONNECT_T, 0); set_cfg_pos($$);
+	}
+	| SET_RPL_NO_CONNECT LPAREN RPAREN	{
+		$$=mk_action(SET_RPL_NO_CONNECT_T, 0); set_cfg_pos($$);
+	}
+	| SET_RPL_NO_CONNECT	{
+		$$=mk_action(SET_RPL_NO_CONNECT_T, 0); set_cfg_pos($$);
+	}
+	| SET_FWD_CLOSE LPAREN RPAREN	{
+		$$=mk_action(SET_FWD_CLOSE_T, 0); set_cfg_pos($$);
+	}
+	| SET_FWD_CLOSE	{
+		$$=mk_action(SET_FWD_CLOSE_T, 0); set_cfg_pos($$);
+	}
+	| SET_RPL_CLOSE LPAREN RPAREN	{
+		$$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
+	}
+	| SET_RPL_CLOSE	{
+		$$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
+	}
 	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
 	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
 			0); } LPAREN func_params RPAREN	{
 			0); } LPAREN func_params RPAREN	{
 		mod_func_action->val[0].u.data = 
 		mod_func_action->val[0].u.data = 

+ 10 - 5
forward.c

@@ -384,9 +384,12 @@ int check_self_port(unsigned short port, unsigned short proto)
  *               default port or non srv. lookup is desired, the port must
  *               default port or non srv. lookup is desired, the port must
  *               be !=0 
  *               be !=0 
  *   port      - used only if dst!=0 (else the port in send_info->to is used)
  *   port      - used only if dst!=0 (else the port in send_info->to is used)
- *   send_info - filled dest_info structure:
- *               if the send_socket member is null, a send_socket will be 
- *               chosen automatically
+ *   send_info - value/result partially filled dest_info structure:
+ *                 - send_info->proto and comp are used
+ *                 - send_info->to will be filled (dns)
+ *                 - send_info->send_flags is filled from the message
+ *                 - if the send_socket member is null, a send_socket will be 
+ *                   chosen automatically
  * WARNING: don't forget to zero-fill all the  unused members (a non-zero 
  * WARNING: don't forget to zero-fill all the  unused members (a non-zero 
  * random id along with proto==PROTO_TCP can have bad consequences, same for
  * random id along with proto==PROTO_TCP can have bad consequences, same for
  *   a bogus send_socket value)
  *   a bogus send_socket value)
@@ -438,13 +441,14 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 			goto error;
 			goto error;
 		}
 		}
 	}/* dst */
 	}/* dst */
+	send_info->send_flags=msg->fwd_send_flags;
 	/* calculate branch for outbound request;  if syn_branch is turned off,
 	/* calculate branch for outbound request;  if syn_branch is turned off,
 	   calculate is from transaction key, i.e., as an md5 of From/To/CallID/
 	   calculate is from transaction key, i.e., as an md5 of From/To/CallID/
 	   CSeq exactly the same way as TM does; good for reboot -- than messages
 	   CSeq exactly the same way as TM does; good for reboot -- than messages
 	   belonging to transaction lost due to reboot will still be forwarded
 	   belonging to transaction lost due to reboot will still be forwarded
 	   with the same branch parameter and will be match-able downstream
 	   with the same branch parameter and will be match-able downstream
-
-       if it is turned on, we don't care about reboot; we simply put a simple
+	
+	   if it is turned on, we don't care about reboot; we simply put a simple
 	   value in there; better for performance
 	   value in there; better for performance
 	*/
 	*/
 	if (syn_branch ) {
 	if (syn_branch ) {
@@ -694,6 +698,7 @@ int forward_reply(struct sip_msg* msg)
 	}
 	}
 
 
 	dst.proto=msg->via2->proto;
 	dst.proto=msg->via2->proto;
+	dst.send_flags=msg->fwd_send_flags | msg->rpl_send_flags;
 	if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
 	if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
 #ifdef USE_COMP
 #ifdef USE_COMP
 	dst.comp=msg->via2->comp_no;
 	dst.comp=msg->via2->comp_no;

+ 9 - 0
ip_addr.h

@@ -34,6 +34,7 @@
  *  2006-04-21  added init_dst_from_rcv (andrei)
  *  2006-04-21  added init_dst_from_rcv (andrei)
  *  2007-06-26  added ip_addr_mk_any() (andrei)
  *  2007-06-26  added ip_addr_mk_any() (andrei)
  *  2008-05-21  added su2a(), ip_addr2sbuf(), ip4tosbuf(), ip62sbuf() (andrei)
  *  2008-05-21  added su2a(), ip_addr2sbuf(), ip4tosbuf(), ip62sbuf() (andrei)
+ *  2009-09-14  added send flags support to dest_info (andrei)
  */
  */
 
 
 #ifndef ip_addr_h
 #ifndef ip_addr_h
@@ -136,11 +137,18 @@ struct receive_info{
 };
 };
 
 
 
 
+/* send flags */
+#define SND_F_FORCE_CON_REUSE	1 /* reuse an existing connection or fail */
+#define SND_F_CON_CLOSE			2 /* close the connection after sending */
+
+typedef unsigned char  snd_flags_t;
+
 struct dest_info{
 struct dest_info{
 	struct socket_info* send_sock;
 	struct socket_info* send_sock;
 	union sockaddr_union to;
 	union sockaddr_union to;
 	int id; /* tcp stores the connection id here */ 
 	int id; /* tcp stores the connection id here */ 
 	char proto;
 	char proto;
+	snd_flags_t send_flags;
 #ifdef USE_COMP
 #ifdef USE_COMP
 	short comp;
 	short comp;
 #endif
 #endif
@@ -748,6 +756,7 @@ inline static void init_dst_from_rcv(struct dest_info* dst,
 		dst->to=rcv->src_su;
 		dst->to=rcv->src_su;
 		dst->id=rcv->proto_reserved1;
 		dst->id=rcv->proto_reserved1;
 		dst->proto=rcv->proto;
 		dst->proto=rcv->proto;
+		dst->send_flags=0;
 #ifdef USE_COMP
 #ifdef USE_COMP
 		dst->comp=rcv->comp;
 		dst->comp=rcv->comp;
 #endif
 #endif

+ 6 - 3
modules/tm/t_fwd.c

@@ -413,6 +413,8 @@ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
 		t->uac[branch].request.dst.send_sock =
 		t->uac[branch].request.dst.send_sock =
 		get_send_socket( request, &t->uac[branch].request.dst.to,
 		get_send_socket( request, &t->uac[branch].request.dst.to,
 								t->uac[branch].request.dst.proto);
 								t->uac[branch].request.dst.proto);
+		t->uac[branch].request.dst.send_flags=request?
+												request->fwd_send_flags:0;
 	}else {
 	}else {
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 		if (uri2dst(&t->uac[branch].dns_h, &t->uac[branch].request.dst,
 		if (uri2dst(&t->uac[branch].dns_h, &t->uac[branch].request.dst,
@@ -1083,15 +1085,16 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	} else try_new=0;
 	} else try_new=0;
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri.s, &dst_uri.len, &si))) {
+	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri.s,
+										&dst_uri.len, &si))) {
 		try_new++;
 		try_new++;
 		p_msg->force_send_socket = si;
 		p_msg->force_send_socket = si;
 		getbflagsval(get_branch_iterator(), &bflags);
 		getbflagsval(get_branch_iterator(), &bflags);
 		setbflagsval(0, bflags);
 		setbflagsval(0, bflags);
 
 
 		branch_ret=add_uac( t, p_msg, &current_uri, 
 		branch_ret=add_uac( t, p_msg, &current_uri, 
-				    (dst_uri.len) ? (&dst_uri) : &current_uri, 
-				    proxy, proto);
+							(dst_uri.len) ? (&dst_uri) : &current_uri, 
+							proxy, proto);
 		/* pick some of the errors in case things go wrong;
 		/* pick some of the errors in case things go wrong;
 		   note that picking lowest error is just as good as
 		   note that picking lowest error is just as good as
 		   any other algorithm which picks any other negative
 		   any other algorithm which picks any other negative

+ 1 - 0
modules/tm/t_lookup.c

@@ -1218,6 +1218,7 @@ int init_rb( struct retr_buf *rb, struct sip_msg *msg)
 #ifdef USE_COMP
 #ifdef USE_COMP
 	rb->dst.comp=via->comp_no;
 	rb->dst.comp=via->comp_no;
 #endif
 #endif
+	rb->dst.send_flags=msg->rpl_send_flags;
 	/* turn off mhomed for generating replies -- they are ideally sent to where
 	/* turn off mhomed for generating replies -- they are ideally sent to where
 	   request came from to make life with NATs and other beasts easier
 	   request came from to make life with NATs and other beasts easier
 	*/
 	*/

+ 3 - 3
modules/tm/uac.c

@@ -238,7 +238,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 	if (cfg_get(core, core_cfg, use_dns_failover)){
 	if (cfg_get(core, core_cfg, use_dns_failover)){
 		dns_srv_handle_init(&dns_h);
 		dns_srv_handle_init(&dns_h);
-		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock,
+		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, 0,
 							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
 							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
 				|| (dst.send_sock==0)){
 				|| (dst.send_sock==0)){
 			dns_srv_handle_put(&dns_h);
 			dns_srv_handle_put(&dns_h);
@@ -249,7 +249,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 		}
 		}
 		dns_srv_handle_put(&dns_h); /* not needed anymore */
 		dns_srv_handle_put(&dns_h); /* not needed anymore */
 	}else{
 	}else{
-		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock,
+		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, 0,
 						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 				(dst.send_sock==0)){
 				(dst.send_sock==0)){
 			ser_error = E_NO_SOCKET;
 			ser_error = E_NO_SOCKET;
@@ -259,7 +259,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 		}
 		}
 	}
 	}
 #else /* USE_DNS_FAILOVER */
 #else /* USE_DNS_FAILOVER */
-	if ((uri2dst2(&dst, uac_r->dialog->send_sock,
+	if ((uri2dst2(&dst, uac_r->dialog->send_sock, 0,
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 			(dst.send_sock==0)){
 			(dst.send_sock==0)){
 		ser_error = E_NO_SOCKET;
 		ser_error = E_NO_SOCKET;

+ 12 - 5
modules/tm/ut.h

@@ -221,6 +221,7 @@ inline static int get_uri_send_info(str* uri, str* host, unsigned short* port,
  *         dst   - will be filled
  *         dst   - will be filled
  *         force_send_sock - if 0 dst->send_sock will be set to the default 
  *         force_send_sock - if 0 dst->send_sock will be set to the default 
  *                 (see get_send_socket2()) 
  *                 (see get_send_socket2()) 
+ *         sflags - send flags
  *         uri   - uri in str form
  *         uri   - uri in str form
  *         proto - if != PROTO_NONE, this protocol will be forced over the
  *         proto - if != PROTO_NONE, this protocol will be forced over the
  *                 uri_proto, otherwise the uri proto will be used if set or
  *                 uri_proto, otherwise the uri proto will be used if set or
@@ -231,10 +232,12 @@ inline static int get_uri_send_info(str* uri, str* host, unsigned short* port,
 inline static struct dest_info *uri2dst2(struct dns_srv_handle* dns_h,
 inline static struct dest_info *uri2dst2(struct dns_srv_handle* dns_h,
 										struct dest_info* dst,
 										struct dest_info* dst,
 										struct socket_info *force_send_socket,
 										struct socket_info *force_send_socket,
+										snd_flags_t sflags,
 										str *uri, int proto )
 										str *uri, int proto )
 #else
 #else
 inline static struct dest_info *uri2dst2(struct dest_info* dst,
 inline static struct dest_info *uri2dst2(struct dest_info* dst,
 										struct socket_info *force_send_socket,
 										struct socket_info *force_send_socket,
+										snd_flags_t sflags,
 										str *uri, int proto )
 										str *uri, int proto )
 #endif
 #endif
 {
 {
@@ -268,6 +271,7 @@ inline static struct dest_info *uri2dst2(struct dest_info* dst,
 #ifdef USE_COMP
 #ifdef USE_COMP
 	dst->comp=parsed_uri.comp;
 	dst->comp=parsed_uri.comp;
 #endif
 #endif
+	dst->send_flags=sflags;
 #ifdef HONOR_MADDR
 #ifdef HONOR_MADDR
 	if (parsed_uri.maddr_val.s && parsed_uri.maddr_val.len) {
 	if (parsed_uri.maddr_val.s && parsed_uri.maddr_val.len) {
 		host=&parsed_uri.maddr_val;
 		host=&parsed_uri.maddr_val;
@@ -336,9 +340,10 @@ inline static struct dest_info *uri2dst2(struct dest_info* dst,
  *                 null. If null or use_dns_failover==0 normal dns lookup will
  *                 null. If null or use_dns_failover==0 normal dns lookup will
  *                 be performed (no failover).
  *                 be performed (no failover).
  *         dst   - will be filled
  *         dst   - will be filled
- *         msg   -  sip message used to set dst->send_sock, if 0 dst->send_sock
- *                 will be set to the default w/o using msg->force_send_socket 
- *                 (see get_send_socket()) 
+ *         msg   -  sip message used to set dst->send_sock and dst->send_flags,
+ *                 if 0 dst->send_sock will be set to the default w/o using 
+ *                  msg->force_send_socket (see get_send_socket()) and the 
+ *                  send_flags will be set to 0.
  *         uri   - uri in str form
  *         uri   - uri in str form
  *         proto - if != PROTO_NONE, this protocol will be forced over the
  *         proto - if != PROTO_NONE, this protocol will be forced over the
  *                 uri_proto, otherwise the uri proto will be used if set or
  *                 uri_proto, otherwise the uri proto will be used if set or
@@ -351,14 +356,16 @@ inline static struct dest_info *uri2dst(struct dns_srv_handle* dns_h,
 										struct sip_msg *msg, str *uri, 
 										struct sip_msg *msg, str *uri, 
 											int proto )
 											int proto )
 {
 {
-	return uri2dst2(dns_h, dst, msg?msg->force_send_socket:0, uri, proto);
+	return uri2dst2(dns_h, dst, msg?msg->force_send_socket:0,
+						msg?msg->fwd_send_flags:0, uri, proto);
 }
 }
 #else
 #else
 inline static struct dest_info *uri2dst(struct dest_info* dst,
 inline static struct dest_info *uri2dst(struct dest_info* dst,
 										struct sip_msg *msg, str *uri, 
 										struct sip_msg *msg, str *uri, 
 											int proto )
 											int proto )
 {
 {
-	return uri2dst2(dst, msg?msg->force_send_socket:0, uri, proto);
+	return uri2dst2(dst, msg?msg->force_send_socket:0,
+						msg?msg->fwd_send_flags:0, uri, proto);
 }
 }
 #endif /* USE_DNS_FAILOVER */
 #endif /* USE_DNS_FAILOVER */
 
 

+ 2 - 1
modules_k/sl/sl_funcs.c

@@ -245,10 +245,11 @@ int sl_send_reply_helper(struct sip_msg *msg ,int code, str *text, str *tag)
 	/* use for sending the received interface -bogdan*/
 	/* use for sending the received interface -bogdan*/
 	dst.proto=msg->rcv.proto;
 	dst.proto=msg->rcv.proto;
 	dst.send_sock=msg->rcv.bind_address;
 	dst.send_sock=msg->rcv.bind_address;
-	dst.id=msg->rcv.proto_reserved1;	
+	dst.id=msg->rcv.proto_reserved1;
 #ifdef USE_COMP
 #ifdef USE_COMP
 	dst.comp=msg->via1->comp_no;
 	dst.comp=msg->via1->comp_no;
 #endif
 #endif
+	dst.send_flags=msg->rpl_send_flags;
 	ret = msg_send(&dst, buf.s, buf.len);
 	ret = msg_send(&dst, buf.s, buf.len);
 	mhomed=backup_mhomed;
 	mhomed=backup_mhomed;
 	pkg_free(buf.s);
 	pkg_free(buf.s);

+ 1 - 0
modules_s/sl/sl_funcs.c

@@ -168,6 +168,7 @@ int sl_send_reply(struct sip_msg *msg , int code, char* reason)
 #ifdef USE_COMP
 #ifdef USE_COMP
 	dst.comp=msg->via1->comp_no;
 	dst.comp=msg->via1->comp_no;
 #endif
 #endif
+	dst.send_flags=msg->rpl_send_flags;
 	ret = msg_send(&dst, buf, len);
 	ret = msg_send(&dst, buf, len);
 	mhomed=backup_mhomed;
 	mhomed=backup_mhomed;
 	pkg_free(buf);
 	pkg_free(buf);

+ 2 - 0
parser/msg_parser.h

@@ -246,6 +246,8 @@ typedef struct msg_body {
 
 
 typedef struct sip_msg {
 typedef struct sip_msg {
 	unsigned int id;               /* message id, unique/process*/
 	unsigned int id;               /* message id, unique/process*/
+	snd_flags_t fwd_send_flags;    /* send flags for forwarding */
+	snd_flags_t rpl_send_flags;    /* send flags for replies */
 	struct msg_start first_line;   /* Message first line */
 	struct msg_start first_line;   /* Message first line */
 	struct via_body* via1;         /* The first via */
 	struct via_body* via1;         /* The first via */
 	struct via_body* via2;         /* The second via */
 	struct via_body* via2;         /* The second via */

+ 5 - 1
route_struct.h

@@ -106,7 +106,11 @@ enum action_type{
 		FORCE_SEND_SOCKET_T,
 		FORCE_SEND_SOCKET_T,
 		ASSIGN_T,
 		ASSIGN_T,
 		ADD_T,
 		ADD_T,
-		UDP_MTU_TRY_PROTO_T
+		UDP_MTU_TRY_PROTO_T,
+		SET_FWD_NO_CONNECT_T,
+		SET_RPL_NO_CONNECT_T,
+		SET_FWD_CLOSE_T,
+		SET_RPL_CLOSE_T
 };
 };
 /* parameter types for actions or types for expression right operands
 /* parameter types for actions or types for expression right operands
    (WARNING right operands only, not working for left operands) */
    (WARNING right operands only, not working for left operands) */

+ 6 - 1
tcp_conn.h

@@ -170,7 +170,8 @@ struct tcp_connection{
 	struct tcp_req req; /* request data */
 	struct tcp_req req; /* request data */
 	atomic_t refcnt;
 	atomic_t refcnt;
 	enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
 	enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
-	int flags; /* connection related flags */
+	unsigned short flags; /* connection related flags */
+	unsigned short send_flags; /* special send flags */
 	enum tcp_conn_states state; /* connection state */
 	enum tcp_conn_states state; /* connection state */
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
 	struct timer_ln timer;
 	struct timer_ln timer;
@@ -190,6 +191,10 @@ struct tcp_connection{
 
 
 /* helper macros */
 /* helper macros */
 
 
+#define tcpconn_set_send_flags(c, snd_flags) ((c)->send_flags|=(snd_flags))
+
+#define tcpconn_close_after_send(c)	((c)->send_flags & SND_F_CON_CLOSE)
+
 #define TCP_RCV_INFO(c) (&(c)->rcv)
 #define TCP_RCV_INFO(c) (&(c)->rcv)
 
 
 #define TCP_RCV_LADDR(r) (&((r).dst_ip))
 #define TCP_RCV_LADDR(r) (&((r).dst_ip))

+ 68 - 17
tcp_main.c

@@ -100,7 +100,9 @@
  *  2009-02-26  direct blacklist support (andrei)
  *  2009-02-26  direct blacklist support (andrei)
  *  2009-03-20  s/wq_timeout/send_timeout ; send_timeout is now in ticks
  *  2009-03-20  s/wq_timeout/send_timeout ; send_timeout is now in ticks
  *              (andrei)
  *              (andrei)
- * 2009-04-09  tcp ev and tcp stats macros added (andrei)
+ *  2009-04-09  tcp ev and tcp stats macros added (andrei)
+ *  2009-09-15  support for force connection reuse and close after send
+ *               send flags (andrei)
  */
  */
 
 
 
 
@@ -1762,18 +1764,24 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 			if (likely(port)){
 			if (likely(port)){
 				/* try again w/o id */
 				/* try again w/o id */
 				c=tcpconn_get(0, &ip, port, from, con_lifetime);
 				c=tcpconn_get(0, &ip, port, from, con_lifetime);
-				goto no_id;
 			}else{
 			}else{
 				LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
 				LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
 						dst->id);
 						dst->id);
 				return -1;
 				return -1;
 			}
 			}
-		}else goto get_fd;
+		}
 	}
 	}
-no_id:
-		if (unlikely(c==0)){
+/* no_id: */
+		if (unlikely((c==0) || tcpconn_close_after_send(c))){
+			if (unlikely(c)){
+				/* can't use c if it's marked as close-after-send  =>
+				   release it and try opening new one */
+				tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
+				c=0;
+			}
 			/* check if connect() is disabled */
 			/* check if connect() is disabled */
-			if (cfg_get(tcp, tcp_cfg, no_connect))
+			if (unlikely((dst->send_flags & SND_F_FORCE_CON_REUSE) ||
+							cfg_get(tcp, tcp_cfg, no_connect)))
 				return -1;
 				return -1;
 			DBG("tcp_send: no open tcp connection found, opening new one\n");
 			DBG("tcp_send: no open tcp connection found, opening new one\n");
 			/* create tcp connection */
 			/* create tcp connection */
@@ -1814,6 +1822,7 @@ no_id:
 					return -1;
 					return -1;
 				}
 				}
 				c->flags|=F_CONN_PENDING|F_CONN_FD_CLOSED;
 				c->flags|=F_CONN_PENDING|F_CONN_FD_CLOSED;
+				tcpconn_set_send_flags(c, dst->send_flags);
 				atomic_set(&c->refcnt, 2); /* ref from here and from main hash
 				atomic_set(&c->refcnt, 2); /* ref from here and from main hash
 											 table */
 											 table */
 				/* add it to id hash and aliases */
 				/* add it to id hash and aliases */
@@ -1918,6 +1927,14 @@ no_id:
 				}
 				}
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
+				if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
+					/* if close-after-send requested, don't bother
+					   sending the fd back to tcp_main, try closing it
+					   immediately (no other tcp_send should use it,
+					   because it is marked as close-after-send before
+					   being added to the hash */
+					goto conn_wait_close;
+				}
 				c->state=S_CONN_OK;
 				c->state=S_CONN_OK;
 				/* send to tcp_main */
 				/* send to tcp_main */
 				response[0]=(long)c;
 				response[0]=(long)c;
@@ -1938,6 +1955,7 @@ no_id:
 								su2a(&dst->to, sizeof(dst->to)));
 								su2a(&dst->to, sizeof(dst->to)));
 				return -1;
 				return -1;
 			}
 			}
+			tcpconn_set_send_flags(c, dst->send_flags);
 			if (likely(c->state==S_CONN_OK))
 			if (likely(c->state==S_CONN_OK))
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
 			atomic_set(&c->refcnt, 2); /* ref. from here and it will also
 			atomic_set(&c->refcnt, 2); /* ref. from here and it will also
@@ -1962,7 +1980,7 @@ no_id:
 			}
 			}
 			goto send_it;
 			goto send_it;
 		}
 		}
-get_fd:
+/* get_fd: */
 #ifdef TCP_ASYNC
 #ifdef TCP_ASYNC
 		/* if data is already queued, we don't need the fd any more */
 		/* if data is already queued, we don't need the fd any more */
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
@@ -2048,6 +2066,8 @@ get_fd:
 send_it:
 send_it:
 	DBG("tcp_send: sending...\n");
 	DBG("tcp_send: sending...\n");
 	lock_get(&c->write_lock);
 	lock_get(&c->write_lock);
+	/* update connection send flags with the current ones */
+	tcpconn_set_send_flags(c, dst->send_flags);
 #ifdef TCP_ASYNC
 #ifdef TCP_ASYNC
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
 		if (_wbufq_non_empty(c)
 		if (_wbufq_non_empty(c)
@@ -2203,6 +2223,31 @@ error:
 			TCP_STATS_ESTABLISHED(c->state);
 			TCP_STATS_ESTABLISHED(c->state);
 			c->state=S_CONN_OK;
 			c->state=S_CONN_OK;
 	}
 	}
+	if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
+		/* close after write => send EOF request to tcp_main */
+		c->state=S_CONN_BAD;
+		c->timeout=get_ticks_raw();
+		/* tell "main" it should drop this*/
+		response[0]=(long)c;
+		response[1]=CONN_EOF;
+		if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
+			LOG(L_CRIT, "BUG: tcp_send: error return failed (write):%s (%d)\n",
+					strerror(errno), errno);
+			tcpconn_chld_put(c); /* deref. it manually */
+			n=-1;
+		}
+		/* CONN_EOF will auto-dec refcnt => we must not call tcpconn_put 
+		 * if it succeeds */
+#ifdef TCP_FD_CACHE
+		if (unlikely(fd_cache_e)){
+			tcp_fd_cache_rm(fd_cache_e);
+			fd_cache_e=0;
+			close(fd);
+		}else
+#endif /* TCP_FD_CACHE */
+		if (do_close_fd) close(fd);
+		goto end_no_conn;
+	}
 end:
 end:
 #ifdef TCP_FD_CACHE
 #ifdef TCP_FD_CACHE
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
@@ -2216,11 +2261,14 @@ end_no_conn:
 	return n;
 	return n;
 #ifdef TCP_CONNECT_WAIT
 #ifdef TCP_CONNECT_WAIT
 conn_wait_error:
 conn_wait_error:
-	/* connect or send failed on newly created connection which was not
-	 * yet sent to tcp_main (but was already hashed) => don't send to main,
-	 * unhash and destroy directly (if refcnt>2 it will be destroyed when the 
-	 * last sender releases the connection (tcpconn_chld_put(c))) or when
-	 * tcp_main receives a CONN_ERROR it*/
+	n=-1;
+conn_wait_close:
+	/* connect or send failed or immediate close-after-send was requested on
+	 * newly created connection which was not yet sent to tcp_main (but was
+	 * already hashed) => don't send to main, unhash and destroy directly
+	 * (if refcnt>2 it will be destroyed when the last sender releases the
+	 * connection (tcpconn_chld_put(c))) or when tcp_main receives a
+	 * CONN_ERROR it*/
 	c->state=S_CONN_BAD;
 	c->state=S_CONN_BAD;
 	TCPCONN_LOCK;
 	TCPCONN_LOCK;
 		if (c->flags & F_CONN_HASHED){
 		if (c->flags & F_CONN_HASHED){
@@ -2234,7 +2282,7 @@ conn_wait_error:
 			TCPCONN_UNLOCK;
 			TCPCONN_UNLOCK;
 	/* dec refcnt -> mark it for destruction */
 	/* dec refcnt -> mark it for destruction */
 	tcpconn_chld_put(c);
 	tcpconn_chld_put(c);
-	return -1;
+	return n;
 #endif /* TCP_CONNET_WAIT */
 #endif /* TCP_CONNET_WAIT */
 }
 }
 
 
@@ -3025,11 +3073,12 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 			LOG(L_ERR, "handle_ser_child: ERROR: received CON_ERROR for %p"
 			LOG(L_ERR, "handle_ser_child: ERROR: received CON_ERROR for %p"
 					" (id %d), refcnt %d\n", 
 					" (id %d), refcnt %d\n", 
 					tcpconn, tcpconn->id, atomic_get(&tcpconn->refcnt));
 					tcpconn, tcpconn->id, atomic_get(&tcpconn->refcnt));
+		case CONN_EOF: /* forced EOF after full send, due to send flags */
 #ifdef TCP_CONNECT_WAIT
 #ifdef TCP_CONNECT_WAIT
 			/* if the connection is pending => it might be on the way of
 			/* if the connection is pending => it might be on the way of
 			 * reaching tcp_main (e.g. CONN_NEW_COMPLETE or 
 			 * reaching tcp_main (e.g. CONN_NEW_COMPLETE or 
 			 *  CONN_NEW_PENDING_WRITE) =>  it cannot be destroyed here */
 			 *  CONN_NEW_PENDING_WRITE) =>  it cannot be destroyed here */
-			if ( !(tcpconn->flags & F_CONN_PENDING) && 
+			if ( !(tcpconn->flags & F_CONN_PENDING) &&
 					tcpconn_try_unhash(tcpconn) )
 					tcpconn_try_unhash(tcpconn) )
 				tcpconn_put(tcpconn);
 				tcpconn_put(tcpconn);
 #else /* ! TCP_CONNECT_WAIT */
 #else /* ! TCP_CONNECT_WAIT */
@@ -3155,7 +3204,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 					}
 					}
 				}
 				}
 			}else{
 			}else{
-				LOG(L_WARN, "tcp_main: hanlder_ser_child: connection %p"
+				LOG(L_WARN, "tcp_main: handler_ser_child: connection %p"
 							" already watched for write\n", tcpconn);
 							" already watched for write\n", tcpconn);
 			}
 			}
 			break;
 			break;
@@ -3466,8 +3515,10 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 	empty_q=0; /* warning fix */
 	empty_q=0; /* warning fix */
 	if (unlikely((ev & (POLLOUT|POLLERR|POLLHUP)) &&
 	if (unlikely((ev & (POLLOUT|POLLERR|POLLHUP)) &&
 					(tcpconn->flags & F_CONN_WRITE_W))){
 					(tcpconn->flags & F_CONN_WRITE_W))){
-		if (unlikely((ev & (POLLERR|POLLHUP)) || 
-					(wbufq_run(tcpconn->s, tcpconn, &empty_q)<0))){
+		if (unlikely((ev & (POLLERR|POLLHUP)) ||
+					(wbufq_run(tcpconn->s, tcpconn, &empty_q)<0) ||
+					(empty_q && tcpconn_close_after_send(tcpconn))
+			)){
 			if (unlikely(io_watch_del(&io_h, tcpconn->s, fd_i, 0)<0)){
 			if (unlikely(io_watch_del(&io_h, tcpconn->s, fd_i, 0)<0)){
 				LOG(L_ERR, "ERROR: handle_tcpconn_ev: io_watch_del(1) failed:"
 				LOG(L_ERR, "ERROR: handle_tcpconn_ev: io_watch_del(1) failed:"
 							" for %p, fd %d\n", tcpconn, tcpconn->s);
 							" for %p, fd %d\n", tcpconn, tcpconn->s);