Forráskód Böngészése

SRL finished, slower than expected though

Jiri Kuthan 23 éve
szülő
commit
4cb961a865
5 módosított fájl, 262 hozzáadás és 56 törlés
  1. 1 1
      Makefile.defs
  2. 146 1
      modules/tm/t_funcs.c
  3. 18 11
      modules/tm/t_funcs.h
  4. 1 1
      modules/tm/t_fwd.c
  5. 96 42
      modules/tm/t_reply.c

+ 1 - 1
Makefile.defs

@@ -81,7 +81,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
 	 -DF_MALLOC  -DUSE_SYNONIM\
 	 -DWAIT -DNEW_HNAME -DNOISY_REPLIES -DSRL\
-	 -DNO_DEBUG \
+	 -DNO_DEBUG 
 	 #-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=0 \
 	 #-DNOSMP \
 	 #-DEXTRA_DEBUG 

+ 146 - 1
modules/tm/t_funcs.c

@@ -689,7 +689,7 @@ int t_cancel_branch(unsigned int branch)
 
 
 
-
+#ifdef _REALLY_TOO_OLD
 /* Builds an ACK request based on an INVITE request. ACK is send
   * to same address */
 int t_build_and_send_ACK(struct cell *Trans,unsigned int branch,
@@ -822,6 +822,8 @@ error:
 	return -1;
 }
 
+#endif /* _REALLY_TOO_OLD */
+
 
 
 
@@ -1236,3 +1238,146 @@ void delete_handler( void *attr)
 	delete_cell( p_cell );
     DBG("DEBUG: delete_handler : done\n");
 }
+
+#ifndef _REALLY_TOO_OLD
+
+/* Builds an ACK request based on an INVITE request. ACK is send
+  * to same address */
+struct retrans_buff *build_ack( struct sip_msg* rpl, struct cell *trans, int branch )
+{
+	struct sip_msg      *p_msg , *r_msg;
+	struct hdr_field    *hdr;
+	char                *ack_buf, *p, *via;
+	unsigned int         len, via_len;
+	int                  n;
+	struct retrans_buff *srb;
+
+	ack_buf = 0;
+	via =0;
+	p_msg = trans->inbound_request;
+	r_msg = rpl;
+
+	if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
+	{
+		LOG(L_ERR, "ERROR: t_build_and_send_ACK: "
+			"cannot generate a HBH ACK if key HFs in reply missing\n");
+		goto error;
+	}
+
+	len = 0;
+	/*first line's len */
+	len += 4/*reply code and one space*/+
+		p_msg->first_line.u.request.version.len+CRLF_LEN;
+	/*uri's len*/
+	if (p_msg->new_uri.s)
+		len += p_msg->new_uri.len +1;
+	else
+		len += p_msg->first_line.u.request.uri.len +1;
+	/*via*/
+	via = via_builder( p_msg , &via_len );
+	if (!via)
+	{
+		LOG(L_ERR, "ERROR: t_build_and_send_ACK: "
+			"no via header got from builder\n");
+		goto error;
+	}
+	len+= via_len;
+	/*headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+		if (hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_CSEQ)
+			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
+		else if ( hdr->type==HDR_TO )
+			len += ((r_msg->to->body.s+r_msg->to->body.len ) -
+				r_msg->to->name.s ) + CRLF_LEN ;
+	/* CSEQ method : from INVITE-> ACK */
+	len -= 3  ;
+	/* end of message */
+	len += CRLF_LEN; /*new line*/
+
+	srb=(struct retrans_buff*)sh_malloc(sizeof(struct retrans_buff)+len+1);
+	if (!srb)
+	{
+		LOG(L_ERR, "ERROR: t_build_and_send_ACK: cannot allocate memory\n");
+		goto error1;
+	}
+	ack_buf = (char *) srb + sizeof(struct retrans_buff);
+	p = ack_buf;
+
+	/* first line */
+	memcpy( p , "ACK " , 4);
+	p += 4;
+	/* uri */
+	if ( p_msg->new_uri.s )
+	{
+		memcpy(p,p_msg->orig+(p_msg->new_uri.s-p_msg->buf),p_msg->new_uri.len);
+		p +=p_msg->new_uri.len;
+	}else{
+		memcpy(p,p_msg->orig+(p_msg->first_line.u.request.uri.s-p_msg->buf),
+			p_msg->first_line.u.request.uri.len );
+		p += p_msg->first_line.u.request.uri.len;
+	}
+	/* SIP version */
+	*(p++) = ' ';
+	memcpy(p,p_msg->orig+(p_msg->first_line.u.request.version.s-p_msg->buf),
+		p_msg->first_line.u.request.version.len );
+	p += p_msg->first_line.u.request.version.len;
+	memcpy( p, CRLF, CRLF_LEN );
+	p+=CRLF_LEN;
+
+	/* insert our via */
+	memcpy( p , via , via_len );
+	p += via_len;
+
+	/*other headers*/
+	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
+	{
+		if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID  )
+		{
+			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
+				((hdr->body.s+hdr->body.len ) - hdr->name.s ) );
+			p += ((hdr->body.s+hdr->body.len ) - hdr->name.s );
+			memcpy( p, CRLF, CRLF_LEN );
+			p+=CRLF_LEN;
+		}
+		else if ( hdr->type==HDR_TO )
+		{
+			memcpy( p , r_msg->orig+(r_msg->to->name.s-r_msg->buf) ,
+				((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s));
+			p+=((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s);
+			memcpy( p, CRLF, CRLF_LEN );
+			p+=CRLF_LEN;
+		}
+		else if ( hdr->type==HDR_CSEQ )
+		{
+			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
+				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
+			p+=((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s);
+			memcpy( p , "ACK" CRLF, 3+CRLF_LEN );
+			p += 3+CRLF_LEN;
+		}
+	}
+
+	/* end of message */
+	memcpy( p , CRLF , CRLF_LEN );
+	p += CRLF_LEN;
+
+	/* fill in the structure */
+	srb->bufflen = p-ack_buf;
+	srb->tolen = sizeof( struct sockaddr_in );
+	srb->my_T = trans;
+	srb->retr_buffer = (char *) srb + sizeof( struct retrans_buff );
+	memcpy( &srb->to, & trans->outbound_request[ branch ]->to, sizeof (struct sockaddr_in));
+
+	pkg_free( via );
+	DBG("DEBUG: t_build_and_send_ACK: ACK sent\n");
+	return srb;
+
+error1:
+	pkg_free(via );
+error:
+	return 0;
+}
+
+#endif
+
+

+ 18 - 11
modules/tm/t_funcs.h

@@ -277,7 +277,22 @@ void final_response_handler( void *);
 void wait_handler( void *);
 void delete_handler( void *);
 
-inline int static send_ack( struct cell *t, int branch, 
+inline int static attach_ack(  struct cell *t, int branch,
+    struct retrans_buff *srb )
+{
+	LOCK_ACK( t );
+	if (t->outbound_ack[branch]) {
+		UNLOCK_ACK(t);
+		shm_free( srb );
+		LOG(L_WARN, "attach_ack: Warning: ACK already sent out\n");
+		return 0;
+	}
+	t->outbound_ack[branch] = srb;
+	UNLOCK_ACK( t );
+	return 1;
+}
+
+inline int static relay_ack( struct cell *t, int branch, 
 	struct retrans_buff *srb, int len )
 {
 	memset( srb, 0, sizeof( struct retrans_buff ) );
@@ -287,18 +302,10 @@ inline int static send_ack( struct cell *t, int branch,
 	srb->branch = branch;
 	srb->retr_buffer = (char *) srb + sizeof( struct retrans_buff );
 	srb->bufflen = len;
-	LOCK_ACK( t );
-	if (t->outbound_ack[branch]) {
-		UNLOCK_ACK(t);
-		shm_free( srb );	
-		LOG(L_WARN, "send_ack: Warning: ACK already sent out\n");
-		return 0;
-	}
-	t->outbound_ack[branch] = srb;
 	SEND_BUFFER( srb );
-	UNLOCK_ACK( t );
-	return 1;
+	return attach_ack( t, branch, srb );
 }
 
+struct retrans_buff *build_ack( struct sip_msg* rpl, struct cell *trans, int branch );
 
 #endif

+ 1 - 1
modules/tm/t_fwd.c

@@ -224,7 +224,7 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 	memcpy( (char *) srb + sizeof ( struct retrans_buff ), buf, len );
 	free( buf );
 
-	send_ack( T, branch, srb, len );
+	relay_ack( T, branch, srb, len );
 	return 1;
 
 fwd_sl: /* some strange conditions occured; try statelessly */

+ 96 - 42
modules/tm/t_reply.c

@@ -418,13 +418,17 @@ int t_on_reply( struct sip_msg  *p_msg )
 {
 	unsigned int branch,len, msg_status, msg_class, save_clone;
 	unsigned int local_cancel;
-	struct sip_msg *clone, *backup;
+	struct sip_msg *clone;
 	int relay;
 	int start_fr;
 	int is_invite;
-	struct retrans_buff *rb;
+	/* retransmission structure of outbound reply and request */
+	struct retrans_buff *orq_rb, *orp_rb, *ack_rb;
 	char *buf;
-	unsigned int buf_len;
+	/* length of outbound reply */
+	unsigned int orp_len;
+	/* buffer length (might be somewhat larger than message size */
+	unsigned int alloc_len;
 
 
 	/* make sure we know the assosociated tranaction ... */
@@ -448,6 +452,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 
 	/* it can take quite long -- better do it now than later 
 	   inside a reply_lock */
+													/* CLONE alloc'ed */
 	if (!(clone=sip_msg_cloner( p_msg ))) {
 		goto error;
 	}
@@ -462,22 +467,25 @@ int t_on_reply( struct sip_msg  *p_msg )
 	work to be done out of criticial lock region */
 	if (msg_status==100) buf=0;
 	else {
-		buf = build_res_buf_from_sip_res ( p_msg, &buf_len);
+												/* buf maybe allo'ed*/
+
+		buf = build_res_buf_from_sip_res ( p_msg, &orp_len);
 		if (!buf) {
 			LOG(L_ERR, "ERROR: t_on_reply_received: "
 			"no mem for outbound reply buffer\n");
-			sip_msg_free( clone );
-			goto error;
+			goto error1;
 		}
 	}
 
 	/* *** stop timers *** */
-	rb=T->outbound_request[branch];
+	orq_rb=T->outbound_request[branch];
 	/* stop retransmission */
-	reset_timer( hash_table, &(rb->retr_timer));
+												/* timers reset */
+
+	reset_timer( hash_table, &(orq_rb->retr_timer));
 	/* stop final response timer only if I got a final response */
 	if ( msg_class>1 )
-		reset_timer( hash_table, &(rb->fr_timer));
+		reset_timer( hash_table, &(orq_rb->fr_timer));
 
 	LOCK_REPLIES( T );
    	/* if a got the first prov. response for an INVITE ->
@@ -487,58 +495,104 @@ int t_on_reply( struct sip_msg  *p_msg )
 	/* *** store and relay message as needed *** */
 	relay = t_should_relay_response( T , msg_status, branch, &save_clone );
 
+	if (relay >= 0 ) {
+		orp_rb= & T->outbound_response;
+		/* if there is no reply yet, initialize the structure */
+		if ( ! orp_rb->retr_buffer ) {
+			/*init retrans buffer*/
+			memset( orp_rb , 0 , sizeof (struct retrans_buff) );
+			if (update_sock_struct_from_via(  &(orp_rb->to), p_msg->via2 )==-1) {
+					UNLOCK_REPLIES( T );
+					start_fr = 1;
+					LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
+						"cannot lookup reply dst: %s\n",
+						p_msg->via2->host.s );
+					save_clone = 0;
+					goto error2;
+			}
+			orp_rb->retr_timer.tg=TG_RT;
+			orp_rb->fr_timer.tg=TG_FR;
+			orp_rb->retr_timer.payload = orp_rb;
+			orp_rb->fr_timer.payload =  orp_rb;
+			orp_rb->to.sin_family = AF_INET;
+			orp_rb->my_T = T;
+			orp_rb->status = p_msg->REPLY_STATUS;
+			/* allocate something more for the first message;
+			   subsequent messages will be longer and buffer
+			   reusing will save us a malloc lock */
+			alloc_len = orp_len + REPLY_OVERBUFFER_LEN ;
+		} else {
+			alloc_len = orp_len;
+		};
+
+		if (! (orp_rb->retr_buffer = (char *) shm_resize( orp_rb->retr_buffer, alloc_len ))) {
+			UNLOCK_REPLIES( T );
+			start_fr = 1;
+			save_clone = 0;
+			LOG(L_ERR, "ERROR: t_on_reply: cannot alloc shmem\n");
+			goto error2;
+		};
+
+		orp_rb->bufflen=orp_len;
+		memcpy( orp_rb->retr_buffer, buf, orp_len );
+	}; /* if relay ... */
+
 	if (save_clone) {
-		/* release previously hold message */
-		backup = T->inbound_response[branch];
-		T->inbound_response[branch] = clone;
+		T->inbound_response[branch]=clone;
 		T->tag=&(get_to(clone)->tag_value);
-	} else {
-		backup = NULL;
-		sip_msg_free( clone );
 	}
 
-	if (relay>=0 &&  
-	push_reply( T, relay , buf, buf_len ) == -1 ) {
-		/* restore original state first */
-		if (save_clone) T->inbound_response[branch] = backup;
-		/* restart FR */
-		start_fr=1;
-		goto cleanup;
+	/* update the status ... */
+	if ((T->status = p_msg->REPLY_STATUS) >=200 &&
+	/* ... and dst for a possible ACK if we are sending final downstream */
+		T->relaied_reply_branch==-1 ) {
+			memcpy( & T->ack_to, & T->outbound_request[ branch ]->to,
+			sizeof( struct sockaddr_in ) );
+   			T->relaied_reply_branch = branch;
 	}
 
+cleanup:
+	UNLOCK_REPLIES( T );
+	if (relay >= 0) {
+		SEND_PR_BUFFER( orp_rb, buf, orp_len );
+		t_update_timers_after_sending_reply( orp_rb );
+	}
 
 	/* *** ACK handling *** */
 	if ( is_invite )
 	{
 		if ( T->outbound_ack[branch] )
 		{   /*retransmit*/
+			/* I don't need any additional syncing here -- after ack
+			   is introduced it's never changed */
 			SEND_BUFFER( T->outbound_ack[branch] );
-		} else if (msg_class>2 ) {   
-			/*on a non-200 reply to INVITE*/
-			DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE:"
-				" send ACK\n");
-			if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
-			{
-				LOG( L_ERR , "ERROR: t_on_reply_received:"
-					" unable to send ACK\n" );
-				/* restart FR */
-				start_fr=1;
-			}
+		} else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
+           		DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
+				ack_rb = build_ack( p_msg, T, branch );
+				if (ack_rb) {
+					SEND_BUFFER( ack_rb );
+					/* append to transaction structure */
+					attach_ack( T, branch, ack_rb );
+				} else {
+					/* restart FR */
+					start_fr=1;
+					DBG("ERROR: t_on_reply: build_ack failed\n");
+				}
 		}
-	}
-cleanup:
-	UNLOCK_REPLIES( T );
-	if (backup) sip_msg_free(backup);
-	if (buf) free( buf );
-	t_update_timers_after_sending_reply( rb );
-	if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
+	} /* is_invite */
+
    	/* restart retransmission if a provisional response came for 
 	   a non_INVITE -> retrasmit at RT_T2*/
 	if ( msg_class==1 && !is_invite )
 	{
-		rb->retr_list = RT_T2;
-		set_timer( hash_table, &(rb->retr_timer), RT_T2 );
+		orq_rb->retr_list = RT_T2;
+		set_timer( hash_table, &(orq_rb->retr_timer), RT_T2 );
 	}
+error2:
+	if (start_fr) set_timer( hash_table, &(orq_rb->fr_timer), FR_INV_TIMER_LIST );
+	if (buf) free( buf );
+error1:
+	if (!save_clone) sip_msg_free( clone );
 error:
 	T_UNREF( T );
 	/* don't try to relay statelessly on error; on troubles, simply do nothing;