From 25875e49a62e2df48f6c95b2a2fd4fcb329672c3 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 8 Jul 2009 12:50:39 +0000 Subject: [PATCH] First part of the outbound proxy / 200 ACK patch: - moved 200 ACK from sipctrl into the UA. - [request|dialog].next_hop ("host:port") can be used to set the outbound host/port. - 200 ACKs are passed to the UA. git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1460 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- core/AmSipDialog.cpp | 80 +++++- core/AmSipDialog.h | 6 + core/plug-in/sipctrl/SipCtrlInterface.cpp | 64 +++-- core/plug-in/sipctrl/hash_table.cpp | 3 +- core/plug-in/sipctrl/resolver.h | 6 - core/plug-in/sipctrl/sip_trans.cpp | 16 +- core/plug-in/sipctrl/trans_layer.cpp | 293 +++++++++------------- core/plug-in/sipctrl/trans_layer.h | 19 +- 8 files changed, 249 insertions(+), 238 deletions(-) diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index e1e177db..67183efa 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -189,8 +189,6 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) AmSipTransaction& t = t_it->second; - //t->reply_code = reply.code; - // rfc3261 12.1 // && method==INVITE // Dialog established only by 101-199 or 2xx @@ -252,8 +250,18 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) break; } - if(reply.code >= 200) + // TODO: remove the transaction only after the dedicated timer has hit + // this would help taking care of multiple 2xx replies. + if(reply.code >= 200){ uac_trans.erase(t_it); + + // TODO: + // - place this somewhere else. + // (probably in AmSession...) + if(reply.code < 300){ + send_200_ack(t); + } + } } string AmSipDialog::getContactHdr() @@ -607,12 +615,12 @@ int AmSipDialog::sendRequest(const string& method, if (AmServer::sendRequest(req, serKey, serKeyLen)) return -1; - + uac_trans[cseq] = AmSipTransaction(method,cseq); // increment for next request cseq++; - + return 0; } @@ -675,3 +683,65 @@ int AmSipDialog::drop() status = Disconnected; return 1; } + +int AmSipDialog::send_200_ack(const AmSipTransaction& t, + const string& content_type, + const string& body, + const string& hdrs, + int flags) +{ + // TODO: implement missing pieces from RFC 3261: + // "The ACK MUST contain the same credentials as the INVITE. If + // the 2xx contains an offer (based on the rules above), the ACK MUST + // carry an answer in its body. If the offer in the 2xx response is not + // acceptable, the UAC core MUST generate a valid answer in the ACK and + // then send a BYE immediately." + + string m_hdrs = hdrs; + + if(hdl) + hdl->onSendRequest("ACK",content_type,body,m_hdrs,flags,t.cseq); + + AmSipRequest req; + + req.method = "ACK"; + req.r_uri = remote_uri; + req.next_hop = next_hop; + + req.from = "From: " + local_party; + if(!local_tag.empty()) + req.from += ";tag=" + local_tag; + + req.to = "To: " + remote_party; + if(!remote_tag.empty()) + req.to += ";tag=" + remote_tag; + + req.cseq = t.cseq;// should be the same as the INVITE + req.callid = callid; + req.contact = getContactHdr(); + + if(!m_hdrs.empty()) + req.hdrs = m_hdrs; + + if (!(flags&SIP_FLAGS_VERBATIM)) { + // add Signature + if (AmConfig::Signature.length()) + req.hdrs += SIP_HDR_COLSP(SIP_HDR_USER_AGENT) + AmConfig::Signature + CRLF; + + req.hdrs += SIP_HDR_COLSP(SIP_HDR_MAX_FORWARDS) /*TODO: configurable?!*/MAX_FORWARDS CRLF; + + } + + if(!route.empty()) + req.route = getRoute(); + + if(!body.empty()) { + req.content_type = content_type; + req.body = body; + } + + if (AmServer::sendRequest(req, serKey, serKeyLen)) + return -1; + + return 0; +} diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index 67f96074..ecd69436 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -166,6 +166,12 @@ class AmSipDialog const string& body = "", const string& hdrs = "", int flags = 0); + + int send_200_ack(const AmSipTransaction& t, + const string& content_type = "", + const string& body = "", + const string& hdrs = "", + int flags = 0); int bye(const string& hdrs = ""); int cancel(); diff --git a/core/plug-in/sipctrl/SipCtrlInterface.cpp b/core/plug-in/sipctrl/SipCtrlInterface.cpp index 9fff999f..df52b3b9 100644 --- a/core/plug-in/sipctrl/SipCtrlInterface.cpp +++ b/core/plug-in/sipctrl/SipCtrlInterface.cpp @@ -319,6 +319,41 @@ int SipCtrlInterface::send(const AmSipRequest &req, char* serKey, unsigned int& } } + string next_hop; + unsigned int next_port_i = 0; + + if(!req.next_hop.empty()){ + string next_port; + const char* c = req.next_hop.c_str(); + while(*c != 0){ + if(*c == ':'){ + next_port = string(c+1); + if(str2i(next_port,next_port_i)){ + ERROR("Could not convert port number in req.next_hop"); + ERROR("Using default outbound proxy"); + next_hop = SipCtrlInterfaceFactory::outbound_host; + next_port_i = SipCtrlInterfaceFactory::outbound_port; + } + break; + } + next_hop += *(c++); + } + } + else if(!SipCtrlInterfaceFactory::outbound_host.empty()){ + next_hop = SipCtrlInterfaceFactory::outbound_host; + next_port_i = SipCtrlInterfaceFactory::outbound_port; + } + + cstring c_next_hop = stl2cstr(next_hop); + if(tl->set_next_hop(msg->route,msg->u.request->ruri_str, + c_next_hop,(unsigned short)next_port_i, + &msg->remote_ip) < 0){ + // TODO: error handling + DBG("set_next_hop failed\n"); + //delete msg; + return -1; + } + int res = tl->send_request(msg,serKey,serKeyLen); delete msg; @@ -441,29 +476,7 @@ void SipCtrlInterface::handleSipMsg(AmSipRequest &req) DBG("body = <%s>\n",req.body.c_str()); } - if(req.method == "ACK") - return; - -#ifdef _STANDALONE - // Debug code - begin - AmSipReply reply; - - reply.method = req.method; - reply.code = 200; - reply.reason = "OK"; - reply.serKey = req.serKey; - reply.local_tag = "12345"; - reply.contact = "Contact: sip:" + req.dstip + ":" + req.port; - - int err = send(reply); - if(err < 0){ - DBG("send failed with err code %i\n",err); - } - // Debug code - end -#else - AmSipDispatcher::instance()->handleSipMsg(req); -#endif } void SipCtrlInterface::handleSipMsg(AmSipReply &rep) @@ -474,10 +487,7 @@ void SipCtrlInterface::handleSipMsg(AmSipReply &rep) DBG_PARAM(rep.remote_tag); DBG("cseq = <%i>\n",rep.cseq); -#ifndef _STANDALONE - AmSipDispatcher::instance()->handleSipMsg(rep); -#endif } void SipCtrlInterface::handle_sip_request(const char* tid, sip_msg* msg) @@ -539,7 +549,9 @@ void SipCtrlInterface::handle_sip_request(const char* tid, sip_msg* msg) req.to_tag = c2stlstr(((sip_from_to*)msg->to->p)->tag); req.cseq = get_cseq(msg)->num; req.body = c2stlstr(msg->body); - req.serKey = tid; + + if(tid != NULL) + req.serKey = tid; if (msg->content_type) req.content_type = c2stlstr(msg->content_type->value); diff --git a/core/plug-in/sipctrl/hash_table.cpp b/core/plug-in/sipctrl/hash_table.cpp index 7552f462..51fd2c77 100644 --- a/core/plug-in/sipctrl/hash_table.cpp +++ b/core/plug-in/sipctrl/hash_table.cpp @@ -107,8 +107,7 @@ sip_trans* trans_bucket::match_request(sip_msg* msg) trans_list::iterator it = elmts.begin(); for(;it!=elmts.end();++it) { - if( ((*it)->type != TT_UAS) || - ((*it)->msg->type != SIP_REQUEST)){ + if( (*it)->msg->type != SIP_REQUEST ){ continue; } diff --git a/core/plug-in/sipctrl/resolver.h b/core/plug-in/sipctrl/resolver.h index 29a89549..86ed2f75 100644 --- a/core/plug-in/sipctrl/resolver.h +++ b/core/plug-in/sipctrl/resolver.h @@ -29,12 +29,6 @@ struct sockaddr_storage; -/* struct name_entry */ -/* { */ -/* string name; */ -/* string address; */ -/* }; */ - enum address_type { IPv4=1, diff --git a/core/plug-in/sipctrl/sip_trans.cpp b/core/plug-in/sipctrl/sip_trans.cpp index ba36ce72..fb182fa2 100644 --- a/core/plug-in/sipctrl/sip_trans.cpp +++ b/core/plug-in/sipctrl/sip_trans.cpp @@ -35,7 +35,7 @@ #include -int _timer_type_lookup[] = { -1, 0,1,2, 0,1,2, 0,1,2, 0 }; +int _timer_type_lookup[] = { -1, 0,1,2, 0,1,2, 0,1,2, 0,2 }; inline timer** fetch_timer(unsigned int timer_type, timer** base) { @@ -89,6 +89,9 @@ timer* sip_trans::get_timer(unsigned int timer_type) return *fetch_timer(timer_type,timers); } + +char _timer_name_lookup[] = {'0','A','B','D','E','F','K','G','H','I','J','L'}; + /** * Resets a specific timer * @@ -101,8 +104,7 @@ void sip_trans::reset_timer(timer* t, unsigned int timer_type) if(*tp != NULL){ - DBG("Clearing old timer of type %c\n", - (*tp)->type?'A'+(*tp)->type-1:'0'); + DBG("Clearing old timer of type %c\n",_timer_name_lookup[(*tp)->type]); wheeltimer::instance()->remove_timer(*tp); } @@ -118,13 +120,13 @@ void trans_timer_cb(timer* t, unsigned int bucket_id, sip_trans* tr) if(bucket){ bucket->lock(); if(bucket->exist(tr)){ - DBG("Transaction timer expired: type=0x%x, trans=%p, eta=%i, t=%i\n", - t->type,tr,t->expires,wheeltimer::instance()->wall_clock); + DBG("Transaction timer expired: type=%c, trans=%p, eta=%i, t=%i\n", + _timer_name_lookup[t->type],tr,t->expires,wheeltimer::instance()->wall_clock); trans_layer::instance()->timer_expired(t,bucket,tr); } else { WARN("Transaction %p does not exist anymore\n",tr); - WARN("Timer type=0x%x will be deleted without further processing\n",t->type); + WARN("Timer type=%c will be deleted without further processing\n",_timer_name_lookup[t->type]); } bucket->unlock(); } @@ -148,7 +150,7 @@ void sip_trans::reset_timer(unsigned int timer_type, unsigned int expire_delay / expires += wt->wall_clock; DBG("New timer of type %c at time=%i\n", - timer_type?'A'+timer_type-1:'0',expires); + _timer_name_lookup[timer_type],expires); timer* t = new timer(timer_type,expires, (timer_cb)trans_timer_cb, diff --git a/core/plug-in/sipctrl/trans_layer.cpp b/core/plug-in/sipctrl/trans_layer.cpp index 729a27dc..2c88fc47 100644 --- a/core/plug-in/sipctrl/trans_layer.cpp +++ b/core/plug-in/sipctrl/trans_layer.cpp @@ -273,11 +273,12 @@ int trans_layer::send_reply(trans_bucket* bucket, sip_trans* t, // Ref. RFC 3261 "12.2.1.1 Generating the Request" // int trans_layer::set_next_hop(list& route_hdrs, - cstring& r_uri, + cstring& r_uri, cstring& next_hop, + unsigned short next_port, sockaddr_storage* remote_ip) { - string next_hop; - unsigned short next_port=0; + //string next_hop; + //unsigned short next_port=0; //assert(msg->type == SIP_REQUEST); @@ -317,12 +318,9 @@ int trans_layer::set_next_hop(list& route_hdrs, } - if (SipCtrlInterfaceFactory::outbound_host.empty()) { - next_hop = c2stlstr(na.uri.host); + if (next_hop.len == 0) { + next_hop = na.uri.host; next_port = na.uri.port; - } else { - next_hop = SipCtrlInterfaceFactory::outbound_host; - next_port = SipCtrlInterfaceFactory::outbound_port; } if(!is_lr){ @@ -411,27 +409,20 @@ int trans_layer::set_next_hop(list& route_hdrs, } } - else { - - if (SipCtrlInterfaceFactory::outbound_host.empty()) { - sip_uri parsed_r_uri; - err = parse_uri(&parsed_r_uri,r_uri.s,r_uri.len); - if(err < 0){ - ERROR("Invalid Request URI\n"); - return -1; - } - next_hop = c2stlstr(parsed_r_uri.host); - next_port = parsed_r_uri.port; - } else { - next_hop = SipCtrlInterfaceFactory::outbound_host; - next_port = SipCtrlInterfaceFactory::outbound_port; + else if (next_hop.len == 0) { + sip_uri parsed_r_uri; + err = parse_uri(&parsed_r_uri,r_uri.s,r_uri.len); + if(err < 0){ + ERROR("Invalid Request URI\n"); + return -1; } + next_hop = parsed_r_uri.host; + next_port = parsed_r_uri.port; } - DBG("next_hop:next_port is <%s:%u>\n", next_hop.c_str(), next_port); + DBG("next_hop:next_port is <%.*s:%u>\n", next_hop.len, next_hop.s, next_port); - err = resolver::instance()->resolve_name(next_hop.c_str(), - remote_ip,IPv4,UDP); + err = resolver::instance()->resolve_name(c2stlstr(next_hop).c_str(),remote_ip,IPv4,UDP); if(err < 0){ ERROR("Unresolvable Request URI\n"); return -1; @@ -484,14 +475,6 @@ int trans_layer::send_request(sip_msg* msg, char* tid, unsigned int& tid_len) tid_len = 0; - if(set_next_hop(msg->route,msg->u.request->ruri_str, - &msg->remote_ip) < 0){ - // TODO: error handling - DBG("set_next_hop failed\n"); - //delete msg; - return -1; - } - // assume that msg->route headers are not in msg->hdrs msg->hdrs.insert(msg->hdrs.begin(),msg->route.begin(),msg->route.end()); @@ -570,21 +553,9 @@ int trans_layer::send_request(sip_msg* msg, char* tid, unsigned int& tid_len) } else { - sip_trans* t = bucket->add_trans(p_msg,TT_UAC); - if(p_msg->u.request->method == sip_request::INVITE){ - - // if transport == UDP - t->reset_timer(STIMER_A,A_TIMER,bucket->get_id()); - // for any transport type - t->reset_timer(STIMER_B,B_TIMER,bucket->get_id()); - } - else { - - // if transport == UDP - t->reset_timer(STIMER_E,E_TIMER,bucket->get_id()); - // for any transport type - t->reset_timer(STIMER_F,F_TIMER,bucket->get_id()); - + sip_trans* t = 0; + if(update_uac_request(bucket,t,p_msg) < 0){ + ERROR("Could not update UAC state for request.\n"); } string t_id = int2hex(bucket->get_id()).substr(5,string::npos) @@ -696,28 +667,27 @@ int trans_layer::cancel(trans_bucket* bucket, sip_trans* t) ntohs(((sockaddr_in*)&p_msg->remote_ip)->sin_port), p_msg->len,p_msg->buf); + trans_bucket* n_bucket = get_trans_bucket(p_msg->callid->value, + get_cseq(p_msg)->num_str); + + if(bucket != n_bucket) + n_bucket->lock(); + int send_err = transport->send(&p_msg->remote_ip,p_msg->buf,p_msg->len); if(send_err < 0){ ERROR("Error from transport layer\n"); delete p_msg; } else { - trans_bucket* n_bucket = get_trans_bucket(p_msg->callid->value, - get_cseq(p_msg)->num_str); - if(bucket != n_bucket) - n_bucket->lock(); - - sip_trans* t = n_bucket->add_trans(p_msg,TT_UAC); - - // if transport == UDP - t->reset_timer(STIMER_E,E_TIMER,bucket->get_id()); - // for any transport type - t->reset_timer(STIMER_F,F_TIMER,bucket->get_id()); - - if(bucket != n_bucket) - n_bucket->unlock(); + sip_trans* t=NULL; + if(update_uac_request(bucket,t,p_msg)<0){ + ERROR("Could not update state for UAC transaction\n"); + } } + + if(bucket != n_bucket) + n_bucket->unlock(); bucket->unlock(); return send_err; @@ -762,16 +732,27 @@ void trans_layer::received_msg(sip_msg* msg) DBG("ACK matched INVITE transaction\n"); err = update_uas_request(bucket,t,msg); + DBG("update_uas_request(bucket,t,msg) = %i\n",err); if(err<0){ DBG("trans_layer::update_uas_trans() failed!\n"); // Anyway, there is nothing we can do... } - else if(err == TS_TERMINATED){ + else if((err == TS_TERMINATED) || + (err == TS_REMOVED)){ // do not touch the transaction anymore: // it could have been deleted !!! // should we forward the ACK to SEMS-App upstream? Yes + bucket->unlock(); + + // let's pass the request to + // the UA. + assert(ua); + DBG("Passing ACK to the UA.\n"); + ua->handle_sip_request(NULL,msg); + + DROP_MSG; } } else { @@ -816,7 +797,7 @@ void trans_layer::received_msg(sip_msg* msg) // Reply matched UAC transaction DBG("Reply matched an existing transaction\n"); - if(update_uac_trans(bucket,t,msg) < 0){ + if(update_uac_reply(bucket,t,msg) < 0){ ERROR("update_uac_trans() failed, so what happens now???\n"); break; } @@ -851,7 +832,7 @@ void trans_layer::received_msg(sip_msg* msg) } -int trans_layer::update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* msg) +int trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg* msg) { assert(msg->type == SIP_REPLY); @@ -920,17 +901,18 @@ int trans_layer::update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* m } else { + DBG("Positive final reply to INVITE transaction (state=%i)\n",t->state); + // Positive final reply to INVITE transaction switch(t->state){ case TS_CALLING: case TS_PROCEEDING: + // TODO: - // we should take care of 200 ACKs + // we should take care of 200 ACK re-transmissions // - on first reply: // - save to-tag. - // - use route-set included in the INV req (if applicable). - // - save ACK for retransmitions. // - compare to-tag on subsequent replies. // - (if different): // - (generate new 200 ACK based on reply). @@ -948,8 +930,6 @@ int trans_layer::update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* m t->to_tag.len = to_tag.len; memcpy((void*)t->to_tag.s,to_tag.s,to_tag.len); - send_200_ack(msg,t); - goto pass_reply; case TS_TERMINATED_200: @@ -959,14 +939,16 @@ int trans_layer::update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* m // TODO: // (this should be implemented in the UA) - // we should send 200 ACK also here, + // we should also send a 200 ACK here, // but this would mean that we should - // also be sending a BYE also to quit - // this dialog. + // also be sending a BYE to quit + // this dialog... // + DBG("Received 200 reply with different To-tag as the previous one.\n"); goto end; } + DBG("Received 200 reply retransmission\n"); retransmit(t); goto end; @@ -1011,10 +993,62 @@ int trans_layer::update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* m return 0; } +int trans_layer::update_uac_request(trans_bucket* bucket, sip_trans*& t, sip_msg* msg) +{ + if(msg->u.request->method != sip_request::ACK){ + t = bucket->add_trans(msg,TT_UAC); + } + else { + // 200 ACK + t = bucket->match_request(msg); + if(t == NULL){ + DBG("While sending 200 ACK: no matching transaction\n"); + return -1; + } + + delete [] t->retr_buf; + t->retr_buf = msg->buf; + t->retr_len = msg->len; + msg->buf = NULL; + msg->len = 0; + memcpy(&t->retr_addr,&msg->remote_ip,sizeof(sockaddr_storage)); + } + + switch(msg->u.request->method){ + + case sip_request::INVITE: + // if transport == UDP + t->reset_timer(STIMER_A,A_TIMER,bucket->get_id()); + // for any transport type + t->reset_timer(STIMER_B,B_TIMER,bucket->get_id()); + break; + + case sip_request::ACK: + // we do not need any timer here: + // -> TIMER L is already started. + + delete msg; + + // test code + retransmit(t); + + break; + + default: + // if transport == UDP + t->reset_timer(STIMER_E,E_TIMER,bucket->get_id()); + // for any transport type + t->reset_timer(STIMER_F,F_TIMER,bucket->get_id()); + break; + } + + return 0; +} + int trans_layer::update_uas_reply(trans_bucket* bucket, sip_trans* t, int reply_code) { if(t->reply_status >= 200){ - ERROR("Trying to send a reply whereby reply_status >= 300\n"); + ERROR("Transaction has already been closed with a final reply\n"); return -1; } @@ -1072,7 +1106,7 @@ int trans_layer::update_uas_reply(trans_bucket* bucket, sip_trans* t, int reply_ int trans_layer::update_uas_request(trans_bucket* bucket, sip_trans* t, sip_msg* msg) { if(msg->u.request->method != sip_request::ACK){ - ERROR("Bug? Recvd non-ACK for existing UAS transaction\n"); + ERROR("Bug? Recvd non-ACK request for existing UAS transaction!?\n"); return -1; } @@ -1155,111 +1189,6 @@ void trans_layer::send_non_200_ack(sip_msg* reply, sip_trans* t) } } -void trans_layer::send_200_ack(sip_msg* reply, sip_trans* t) -{ - // Set request URI - // TODO: use correct R-URI instead of just 'Contact' - if(!get_contact(reply)) { - DBG("Sorry, reply has no Contact header: could not send ACK\n"); - return; - } - - sip_nameaddr na; - const char* c = get_contact(reply)->value.s; - if(parse_nameaddr(&na,&c,get_contact(reply)->value.len) < 0){ - DBG("Sorry, reply's Contact parsing failed: could not send ACK\n"); - return; - } - - cstring r_uri = na.addr; - list route_hdrs; - - if(t && !t->msg->route.empty()){ - for(list::iterator it = t->msg->route.begin(); - it != t->msg->route.end(); ++it) { - - route_hdrs.push_back(new sip_header(0,"Route",(*it)->value)); - } - } - else { - for(list::reverse_iterator it = reply->record_route.rbegin(); - it != reply->record_route.rend(); ++it) { - - route_hdrs.push_back(new sip_header(0,"Route",(*it)->value)); - } - } - - sockaddr_storage remote_ip; - set_next_hop(route_hdrs,r_uri,&remote_ip); - - int request_len = request_line_len(cstring("ACK",3),r_uri); - - char branch_buf[BRANCH_BUF_LEN]; - compute_branch(branch_buf,reply->callid->value,reply->cseq->value); - cstring branch(branch_buf,BRANCH_BUF_LEN); - - sip_header* max_forward = new sip_header(0,cstring("Max-Forwards"),cstring("10")); - - //cstring via((char*)transport->get_local_ip()); - //request_len += via_len(via,branch); - - string via(transport->get_local_ip()); - if(transport->get_local_port() != 5060) - via += ":" + int2str(transport->get_local_port()); - - request_len += via_len(stl2cstr(via),branch); - - request_len += copy_hdrs_len(route_hdrs); - - request_len += copy_hdr_len(reply->to); - request_len += copy_hdr_len(reply->from); - request_len += copy_hdr_len(reply->callid); - request_len += copy_hdr_len(max_forward); - request_len += cseq_len(get_cseq(reply)->num_str,cstring("ACK",3)); - request_len += 2/* CRLF end-of-headers*/; - - // Allocate new message - char* ack_buf = new char[request_len]; - - // generate it - char* msg = ack_buf; - - request_line_wr(&msg,cstring("ACK",3),r_uri); - via_wr(&msg,stl2cstr(via),branch); - - copy_hdrs_wr(&msg,route_hdrs); - // clear route headers list - for (list::iterator it=route_hdrs.begin(); - it!= route_hdrs.end(); it++) - delete *it; - - copy_hdr_wr(&msg,reply->from); - copy_hdr_wr(&msg,reply->to); - copy_hdr_wr(&msg,reply->callid); - copy_hdr_wr(&msg,max_forward); - delete max_forward; - cseq_wr(&msg,get_cseq(reply)->num_str,cstring("ACK",3)); - - *msg++ = CR; - *msg++ = LF; - - DBG("About to send 200 ACK\n"); - // DBG("About to send 200 ACK: \n<%.*s>\n",request_len,ack_buf); - - assert(transport); - int send_err = transport->send(&remote_ip,ack_buf,request_len); - if(send_err < 0){ - ERROR("Error from transport layer\n"); - delete [] ack_buf; - } - else if(t){ - delete [] t->retr_buf; - t->retr_buf = ack_buf; - t->retr_len = request_len; - memcpy(&t->retr_addr,&remote_ip,sizeof(sockaddr_storage)); - } -} - void trans_layer::retransmit(sip_trans* t) { assert(transport); @@ -1333,6 +1262,10 @@ void trans_layer::timer_expired(timer* t, trans_bucket* bucket, sip_trans* tr) case STIMER_I: // Confirmed: -> Terminated case STIMER_L: // Terminated_200 -> Terminated + // TODO: + // - check if the UA has sent the ACK. + // else, send ACK & BYE. + tr->clear_timer(type); tr->state = TS_TERMINATED; bucket->remove_trans(tr); diff --git a/core/plug-in/sipctrl/trans_layer.h b/core/plug-in/sipctrl/trans_layer.h index a34d9b16..c8bd4f51 100644 --- a/core/plug-in/sipctrl/trans_layer.h +++ b/core/plug-in/sipctrl/trans_layer.h @@ -70,7 +70,8 @@ class trans_layer * @return -1 if errors * @return transaction state if successfull */ - int update_uac_trans(trans_bucket* bucket, sip_trans* t, sip_msg* msg); + int update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg* msg); + int update_uac_request(trans_bucket* bucket, sip_trans*& t, sip_msg* msg); /** * Implements the state changes for the UAS state machine @@ -93,13 +94,6 @@ class trans_layer */ void send_non_200_ack(sip_msg* reply, sip_trans* t); - /** - * Fills the address structure passed and modifies - * R-URI and Route headers as needed. - */ - int set_next_hop(list& route_hdrs, cstring& r_uri, - sockaddr_storage* remote_ip); - /** * Transaction timeout */ @@ -161,11 +155,12 @@ class trans_layer void received_msg(sip_msg* msg); /** - * Sends an end-to-end ACK for the reply - * passed as a parameter. + * Fills the address structure passed and modifies + * R-URI and Route headers as needed. */ - void send_200_ack(sip_msg* reply, sip_trans* t=NULL); - + int set_next_hop(list& route_hdrs, cstring& r_uri, + cstring& next_hop, unsigned short next_port, + sockaddr_storage* remote_ip); /** * This is called by the transaction timer callback.