From 02ce749229a110b8e8fdad004e64999f651ce82e Mon Sep 17 00:00:00 2001 From: Thomas Ries Date: Wed, 17 Dec 2003 21:22:50 +0000 Subject: [PATCH] - full duplex RTP proxy (many thanks to Chris Ross for his work on this). Up to now, only the RTP *Relay* has been tested (works with KPhone, BudgeTone) - fix: SIP phones that allocate a random port for incomming SIP traffic should now work (like BudgeTone) - fix: some SIP phones do change the RTP port number during a session (like KPhone during HOLD/unHOLD) --- ChangeLog | 7 +++ src/proxy.c | 102 +++++++++++++++++++++++++++++++++---------- src/register.c | 23 ++++++++-- src/rtpproxy.c | 17 ++++---- src/rtpproxy.h | 11 +++-- src/rtpproxy_masq.c | 45 +++++++++++-------- src/rtpproxy_relay.c | 49 +++++++++++++++------ src/siproxd.h | 13 ++++-- src/sock.c | 7 +-- 9 files changed, 197 insertions(+), 77 deletions(-) diff --git a/ChangeLog b/ChangeLog index e229bb0..1d4ac8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 0.5.1 ===== + 17-Dec-2003: - full duplex RTP proxy (many thanks to Chris Ross for + his work on this). Up to now, only the RTP *Relay* + has been tested (works with KPhone, BudgeTone) + - fix: SIP phones that allocate a random port for + incomming SIP traffic should now work (like BudgeTone) + - fix: some SIP phones do change the RTP port number + during a session (like KPhone during HOLD/unHOLD) 15-Dec-2003: - use even port numbers for RTP traffic 05-Dec-2003: - some changes & enhancements inspired by Chris Ross: * 183 Trying *may* contain SDP data diff --git a/src/proxy.c b/src/proxy.c index 0f1a475..ad303bf 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -167,12 +167,22 @@ INFO("stopping RTP proxy stream for: %s@%s", osip_message_get_call_id(request)->number, osip_message_get_call_id(request)->host); #endif - /* stop the RTP proxying stream */ - rtp_stop_fwd(osip_message_get_call_id(request)); + /* stop the RTP proxying stream(s) */ + rtp_stop_fwd(osip_message_get_call_id(request), incoming); + rtp_stop_fwd(osip_message_get_call_id(request), outgoing); - /* check for incomming request */ + /* check for incoming request */ } else if (MSG_IS_INVITE(request)) { osip_uri_t *contact; + + /* First, rewrite the body */ + sts = proxy_rewrite_invitation_body(request, incoming); + + /* + * Note: Incoming request has no need to rewrite Contact + * header as we are not masquerading something there + */ + contact=((osip_contact_t*)(request->contacts->node->element))->url; if (contact) { INFO("Incomming Call from: %s:%s", @@ -219,7 +229,7 @@ INFO("stopping RTP proxy stream for: %s@%s", /* if an INVITE, rewrite body */ if (MSG_IS_INVITE(request)) { - sts = proxy_rewrite_invitation_body(request); + sts = proxy_rewrite_invitation_body(request, outgoing); } /* rewrite Contact header to represent the masqued address */ @@ -259,7 +269,8 @@ INFO("stopping RTP proxy stream for: %s@%s", /* if this is CANCEL/BYE request, stop RTP proxying */ if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { - rtp_stop_fwd(osip_message_get_call_id(request)); + rtp_stop_fwd(osip_message_get_call_id(request), incoming); + rtp_stop_fwd(osip_message_get_call_id(request), outgoing); } break; @@ -410,6 +421,17 @@ int proxy_response (osip_message_t *response) { * from an external host to the internal masqueraded host */ case RESTYP_INCOMING: + if ((MSG_IS_RESPONSE_FOR(response,"INVITE")) && + ((MSG_TEST_CODE(response, 200)) || + (MSG_TEST_CODE(response, 183)))) { + /* This is an incoming response, therefore we need an incoming stream */ + sts = proxy_rewrite_invitation_body(response, incoming); + + /* + * Note: Incoming request has no need to rewrite Contact + * header as we are not masquerading something there + */ + } break; /* @@ -422,7 +444,8 @@ int proxy_response (osip_message_t *response) { if ((MSG_IS_RESPONSE_FOR(response,"INVITE")) && ((MSG_TEST_CODE(response, 200)) || (MSG_TEST_CODE(response, 183)))) { - sts = proxy_rewrite_invitation_body(response); + /* This is an outgoing response, therefore an outgoing stream */ + sts = proxy_rewrite_invitation_body(response, outgoing); } /* rewrite Contact header to represent the masqued address */ @@ -518,14 +541,14 @@ int proxy_response (osip_message_t *response) { * STS_SUCCESS on success * STS_FAILURE on error */ -int proxy_rewrite_invitation_body(osip_message_t *mymsg){ +int proxy_rewrite_invitation_body(osip_message_t *mymsg, rtp_direction dir){ osip_body_t *body; sdp_message_t *sdp; - struct in_addr outb_addr, lcl_clnt_addr; + struct in_addr map_addr, msg_addr, outside_addr, inside_addr; int sts; char *bodybuff; char clen[8]; /* content length: probably never more than 7 digits !*/ - int outb_rtp_port, inb_clnt_port; + int map_port, msg_port; int media_stream_no; sdp_connection_t *sdp_conn; sdp_media_t *sdp_med; @@ -552,7 +575,7 @@ int proxy_rewrite_invitation_body(osip_message_t *mymsg){ sts = sdp_message_parse (sdp, bodybuff); osip_free(bodybuff); if (sts != 0) { - ERROR("rewrite_invitation_body: unable to sdp_parse body"); + ERROR("rewrite_invitation_body: unable to sdp_message_parse body"); return STS_FAILURE; } @@ -573,28 +596,54 @@ if (configuration.debuglevel) * RTP proxy: get ready and start forwarding * start forwarding for each media stream ('m=' item in SIP message) */ - sts = get_ip_by_host(sdp_message_c_addr_get(sdp,-1,0), &lcl_clnt_addr); + sts = get_ip_by_host(sdp_message_c_addr_get(sdp,-1,0), &msg_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: cannot resolve " "m= (media) host [%s]", sdp_message_c_addr_get(sdp,-1,0)); return STS_FAILURE; } - sts = get_ip_by_ifname(configuration.outbound_if, &outb_addr); + sts = get_ip_by_ifname(configuration.outbound_if, &outside_addr); if (sts == STS_FAILURE) { ERROR("can't find outbound interface %s - configuration error?", - configuration.inbound_if); + configuration.outbound_if); return STS_FAILURE; } + sts = get_ip_by_ifname(configuration.inbound_if, &inside_addr); + if (sts == STS_FAILURE) { + ERROR("can't find inbound interface %s - configuration error?", + configuration.inbound_if); + return STS_FAILURE; + } + + /* figure out what address to use for RTP masquerading */ + if (MSG_IS_REQUEST(mymsg)) { + if (dir == incoming) + map_addr = inside_addr; + else + map_addr = outside_addr; + } else /* MSG_IS_REPONSE(mymsg) */ { + if (dir == incoming) + map_addr = inside_addr; + else + map_addr = outside_addr; + } /* * rewrite c= address + * !! an IP address of 0.0.0.0 means *MUTE*, don't rewrite such one */ sdp_conn = sdp_message_connection_get (sdp, -1, 0); if (sdp_conn && sdp_conn->c_addr) { - osip_free(sdp_conn->c_addr); - sdp_conn->c_addr=osip_malloc(HOSTNAME_SIZE); - sprintf(sdp_conn->c_addr, "%s", utils_inet_ntoa(outb_addr)); + if (strcmp(sdp_conn->c_addr, "0.0.0.0") != 0) { + /* have a valid address */ + osip_free(sdp_conn->c_addr); + sdp_conn->c_addr=osip_malloc(HOSTNAME_SIZE); + sprintf(sdp_conn->c_addr, "%s", utils_inet_ntoa(map_addr)); + } else { + /* 0.0.0.0 - don't rewrite */ + DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: got a MUTE c= record"); + } } else { ERROR("got NULL c= address record - can't rewrite"); } @@ -609,20 +658,20 @@ if (configuration.debuglevel) /* start an RTP proxying stream */ if (sdp_message_m_port_get(sdp, media_stream_no)) { - inb_clnt_port=atoi(sdp_message_m_port_get(sdp, media_stream_no)); + msg_port=atoi(sdp_message_m_port_get(sdp, media_stream_no)); - if (inb_clnt_port > 0) { - rtp_start_fwd(osip_message_get_call_id(mymsg), media_stream_no, - outb_addr, &outb_rtp_port, - lcl_clnt_addr, inb_clnt_port); + if (msg_port > 0) { + rtp_start_fwd(osip_message_get_call_id(mymsg), dir, media_stream_no, + map_addr, &map_port, + msg_addr, msg_port); /* and rewrite the port */ sdp_med=osip_list_get(sdp->m_medias, media_stream_no); if (sdp_med && sdp_med->m_port) { osip_free(sdp_med->m_port); sdp_med->m_port=osip_malloc(8); - sprintf(sdp_med->m_port, "%i", outb_rtp_port); + sprintf(sdp_med->m_port, "%i", map_port); DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " - "m= rewrote port to [%i]",outb_rtp_port); + "m= rewrote port to [%i]",map_port); } else { ERROR("rewriting port in m= failed sdp_med=%p, " @@ -686,10 +735,12 @@ int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx){ DEBUGC(DBCLASS_PROXY,"rewriting incoming Request URI"); url=osip_message_get_uri(mymsg); - osip_free(url->host);url->host=NULL; /* set the true host */ if(urlmap[idx].true_url->host) { + osip_free(url->host);url->host=NULL; + DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: host=%s", + urlmap[idx].true_url->host); host = (char *)malloc(strlen(urlmap[idx].true_url->host)+1); memcpy(host, urlmap[idx].true_url->host, strlen(urlmap[idx].true_url->host)); host[strlen(urlmap[idx].true_url->host)]='\0'; @@ -698,6 +749,9 @@ int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx){ /* set the true port */ if(urlmap[idx].true_url->port) { + osip_free(url->port);url->port=NULL; + DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: port=%s", + urlmap[idx].true_url->port); port = (char *)malloc(strlen(urlmap[idx].true_url->port)+1); memcpy(port, urlmap[idx].true_url->port, strlen(urlmap[idx].true_url->port)); port[strlen(urlmap[idx].true_url->port)]='\0'; diff --git a/src/register.c b/src/register.c index a7252f5..22952b4 100644 --- a/src/register.c +++ b/src/register.c @@ -252,10 +252,12 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) { /* write entry */ urlmap[i].active=1; + /* Contact: field */ osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url, - &urlmap[i].true_url); /* Contact: field */ + &urlmap[i].true_url); + /* To: field */ osip_uri_clone( my_msg->to->url, - &urlmap[i].reg_url); /* To: field */ + &urlmap[i].reg_url); DEBUGC(DBCLASS_REG,"create new entry for %s@%s <-> %s@%s at slot=%i", (url1_contact->username) ? url1_contact->username : "*NULL*", @@ -318,8 +320,21 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) { /* remember the VIA for later use */ // osip_via_clone( ((osip_via_t*)(my_msg->vias->node->element)), // &urlmap[i].via); - } /* if new entry */ - + } else { /* if new entry */ + /* + * Some phones (like BudgeTones *may* dynamically grab a SIP port + * so we might want to update the true_url and reg_url each time + * we get an REGISTER + */ + /* Contact: field */ + osip_uri_free(urlmap[i].true_url); + osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url, + &urlmap[i].true_url); + /* To: field */ + osip_uri_free(urlmap[i].reg_url); + osip_uri_clone( my_msg->to->url, + &urlmap[i].reg_url); + } /* give some safety margin for the next update */ if (expires > 0) expires+=30; diff --git a/src/rtpproxy.c b/src/rtpproxy.c index 7d06741..08e8522 100644 --- a/src/rtpproxy.c +++ b/src/rtpproxy.c @@ -68,7 +68,8 @@ int rtpproxy_init( void ) { * STS_SUCCESS on success * STS_FAILURE on error */ -int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, +int rtp_start_fwd (osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport) { int sts=STS_FAILURE; @@ -76,15 +77,15 @@ int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, if (configuration.rtp_proxy_enable == 0) { sts = STS_SUCCESS; } else if (configuration.rtp_proxy_enable == 1) { // Relay - sts = rtp_relay_start_fwd (callid, media_stream_no, + sts = rtp_relay_start_fwd (callid, dir, media_stream_no, outbound_ipaddr, outboundport, lcl_client_ipaddr, lcl_clientport); } else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains) - sts = rtp_masq_start_fwd (callid, media_stream_no, + sts = rtp_masq_start_fwd (callid, dir, media_stream_no, outbound_ipaddr, outboundport, lcl_client_ipaddr, lcl_clientport); } else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter) - sts = rtp_masq_start_fwd (callid, media_stream_no, + sts = rtp_masq_start_fwd (callid, dir, media_stream_no, outbound_ipaddr, outboundport, lcl_client_ipaddr, lcl_clientport); } else { @@ -103,17 +104,17 @@ int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, * STS_SUCCESS on success * STS_FAILURE on error */ -int rtp_stop_fwd (osip_call_id_t *callid) { +int rtp_stop_fwd (osip_call_id_t *callid, rtp_direction dir) { int sts = STS_FAILURE; if (configuration.rtp_proxy_enable == 0) { sts = STS_SUCCESS; } else if (configuration.rtp_proxy_enable == 1) { // Relay - sts = rtp_relay_stop_fwd(callid, 0); + sts = rtp_relay_stop_fwd(callid, dir, 0); } else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains) - sts = rtp_masq_stop_fwd(callid); + sts = rtp_masq_stop_fwd(callid, dir); } else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter) - sts = rtp_masq_stop_fwd(callid); + sts = rtp_masq_stop_fwd(callid, dir); } else { ERROR("CONFIG: rtp_proxy_enable has invalid value", configuration.rtp_proxy_enable); diff --git a/src/rtpproxy.h b/src/rtpproxy.h index 54bfc0f..b96dd4b 100644 --- a/src/rtpproxy.h +++ b/src/rtpproxy.h @@ -25,6 +25,7 @@ typedef struct { int sock; char callid_number[CALLIDNUM_SIZE]; /* call ID */ char callid_host[CALLIDHOST_SIZE]; /* --"-- */ + rtp_direction direction; /* Direction of RTP stream */ int media_stream_no; struct in_addr outbound_ipaddr; /* lcl outbound IP */ int outboundport; /* lcl allocd outbound port */ @@ -37,20 +38,22 @@ typedef struct { * RTP relay */ int rtp_relay_init(void); -int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, +int rtp_relay_start_fwd (osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport); -int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock); +int rtp_relay_stop_fwd (osip_call_id_t *callid, rtp_direction dir, int nolock); /* * RTP masquerading */ int rtp_masq_init(void); -int rtp_masq_start_fwd (osip_call_id_t *callid, int media_stream_no, +int rtp_masq_start_fwd (osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport); -int rtp_masq_stop_fwd (osip_call_id_t *callid); +int rtp_masq_stop_fwd (osip_call_id_t *callid, rtp_direction dir); /* * RTP masquerading (ipchains part) diff --git a/src/rtpproxy_masq.c b/src/rtpproxy_masq.c index 29cc9f2..5a57b01 100644 --- a/src/rtpproxy_masq.c +++ b/src/rtpproxy_masq.c @@ -85,7 +85,8 @@ int rtp_masq_init( void ) { } -int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, +int rtp_masq_start_fwd(osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, int *outbound_lcl_port, struct in_addr lcl_client_ipaddr, int lcl_clientport) { int sts=STS_FAILURE; @@ -95,7 +96,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, osip_call_id_t cid; if (callid == NULL) { - ERROR("rtp_relay_start_fwd: callid is NULL!"); + ERROR("rtp_masq_start_fwd: callid is NULL!"); return STS_FAILURE; } @@ -107,13 +108,13 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, * the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE. */ if (callid->number && strlen(callid->number) > CALLIDNUM_SIZE) { - ERROR("rtp_relay_start_fwd: received callid number " + ERROR("rtp_masq_start_fwd: received callid number " "has too many characters (%i, max=%i)", strlen(callid->number),CALLIDNUM_SIZE); return STS_FAILURE; } if (callid->host && strlen(callid->host) > CALLIDHOST_SIZE) { - ERROR("rtp_relay_start_fwd: received callid host " + ERROR("rtp_masq_start_fwd: received callid host " "has too many characters (%i, max=%i)", strlen(callid->host),CALLIDHOST_SIZE); return STS_FAILURE; @@ -149,7 +150,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, /* this one has expired, delete it */ cid.number = rtp_proxytable[i].callid_number; cid.host = rtp_proxytable[i].callid_host; - rtp_masq_stop_fwd(&cid); + rtp_masq_stop_fwd(&cid, rtp_proxytable[i].direction); DEBUGC(DBCLASS_RTP,"deleting expired proxy slot #%i %s@%s", i, rtp_proxytable[i].callid_number, rtp_proxytable[i].callid_host); @@ -157,15 +158,14 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, } } - - DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: starting RTP proxy " - "stream for: %s@%s #=%i", - callid->number, callid->host, media_stream_no); + "stream for: %s@%s (%s) #=%i", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing"), media_stream_no); /* * figure out, if this is an request to start an RTP proxy stream - * that is already existing (identified by SIP Call-ID and + * that is already existing (identified by SIP Call-ID, direction and * media_stream_no). This can be due to UDP repetitions of the * INVITE request... */ @@ -175,6 +175,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, cid.host = rtp_proxytable[i].callid_host; if (rtp_proxytable[i].sock != 0) { if((compare_callid(callid, &cid) == STS_SUCCESS) && + (rtp_proxytable[i].direction == dir) && (rtp_proxytable[i].media_stream_no == media_stream_no)) { /* return the already known port number */ *outbound_lcl_port=rtp_proxytable[i].outboundport; @@ -250,6 +251,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, rtp_proxytable[freeidx].callid_host[0]='\0'; } + rtp_proxytable[freeidx].direction = dir; rtp_proxytable[freeidx].media_stream_no = media_stream_no; memcpy(&rtp_proxytable[freeidx].outbound_ipaddr, &outbound_ipaddr, sizeof(struct in_addr)); @@ -266,7 +268,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, } -int rtp_masq_stop_fwd(osip_call_id_t *callid) { +int rtp_masq_stop_fwd (osip_call_id_t *callid, rtp_direction dir) { int sts=STS_FAILURE; int i; int got_match=0; @@ -275,16 +277,22 @@ int rtp_masq_stop_fwd(osip_call_id_t *callid) { /* let the UDP tunnel time-out */ if (callid == NULL) { - ERROR("rtp_relay_stop_fwd: callid is NULL!"); + ERROR("rtp_masq_stop_fwd: callid is NULL!"); return STS_FAILURE; } + DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: stopping RTP proxy " + "stream for: %s@%s (%s)", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing")); + for (i=0; inumber, callid->host); + DEBUGC(DBCLASS_RTP, + "rtp_masq_stop_fwd: can't find active stream for %s@%s (%s)", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing")); return STS_FAILURE; } @@ -332,13 +342,14 @@ int rtp_masq_init( void ) { ERROR("Masquerading support is not enabled (compile time config option)"); return STS_FAILURE; } -int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, +int rtp_masq_start_fwd(osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, int *outbound_lcl_port, struct in_addr lcl_client_ipaddr, int lcl_clientport) { outbound_lcl_port=0; return STS_FAILURE; } -int rtp_masq_stop_fwd(osip_call_id_t *callid) { +int rtp_masq_stop_fwd (osip_call_id_t *callid, rtp_direction dir) { return STS_FAILURE; } #endif diff --git a/src/rtpproxy_relay.c b/src/rtpproxy_relay.c index 0e5f012..a84a18d 100644 --- a/src/rtpproxy_relay.c +++ b/src/rtpproxy_relay.c @@ -201,8 +201,8 @@ if (sts != STS_SUCCESS) {WARN("sipsock_send_udp() returned error");} DEBUGC(DBCLASS_RTP,"RTP stream sock=%i %s@%s (idx=%i) " "has expired", rtp_proxytable[i].sock, callid.number, callid.host, i); - rtp_relay_stop_fwd(&callid, 1); /* don't lock the mutex, as we own - the lock already here */ + /* don't lock the mutex, as we own the lock already here */ + rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction, 1); } } } /* if (t>...) */ @@ -228,9 +228,10 @@ if (sts != STS_SUCCESS) {WARN("sipsock_send_udp() returned error");} * STS_SUCCESS on success * STS_FAILURE on error */ -int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, - struct in_addr outbound_ipaddr, int *outboundport, - struct in_addr lcl_client_ipaddr, int lcl_clientport) { +int rtp_relay_start_fwd (osip_call_id_t *callid, rtp_direction dir, + int media_stream_no, struct in_addr outbound_ipaddr, + int *outboundport, struct in_addr lcl_client_ipaddr, + int lcl_clientport) { int i, j; int sock, port; int freeidx; @@ -262,8 +263,10 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, return STS_FAILURE; } - DEBUGC(DBCLASS_RTP,"starting RTP proxy stream for: %s@%s #=%i", - callid->number, callid->host, media_stream_no); + DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: starting RTP proxy " + "stream for: %s@%s (%s) #=%i", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing"), media_stream_no); /* lock mutex */ #define return is_forbidden_in_this_code_section @@ -279,7 +282,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, /* * figure out, if this is an request to start an RTP proxy stream - * that is already existing (identified by SIP Call-ID and + * that is already existing (identified by SIP Call-ID, direction and * media_stream_no). This can be due to UDP repetitions of the * INVITE request... */ @@ -288,7 +291,18 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, cid.host = rtp_proxytable[i].callid_host; if (rtp_proxytable[i].sock && (compare_callid(callid, &cid) == STS_SUCCESS) && + (rtp_proxytable[i].direction == dir) && (rtp_proxytable[i].media_stream_no == media_stream_no) ) { + /* + * The RTP port number reported by the UA MAY change + * for a given media stream + * (seen with KPhone during HOLD/unHOLD) + */ + if (rtp_proxytable[i].inbound_client_port != lcl_clientport) { + DEBUGC(DBCLASS_RTP,"RTP port number changed %i -> %i", + rtp_proxytable[i].inbound_client_port, lcl_clientport); + rtp_proxytable[i].inbound_client_port = lcl_clientport; + } /* return the already known port number */ DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, " "id=%s, #=%i)", rtp_proxytable[i].outboundport, @@ -369,6 +383,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, rtp_proxytable[freeidx].callid_host[0]='\0'; } + rtp_proxytable[freeidx].direction = dir; rtp_proxytable[freeidx].media_stream_no = media_stream_no; memcpy(&rtp_proxytable[freeidx].outbound_ipaddr, &outbound_ipaddr, sizeof(struct in_addr)); @@ -403,7 +418,8 @@ unlock_and_exit: * STS_SUCCESS on success * STS_FAILURE on error */ -int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { +int rtp_relay_stop_fwd (osip_call_id_t *callid, rtp_direction dir, + int nolock) { int i, sts; int retsts=STS_SUCCESS; int got_match=0; @@ -414,8 +430,10 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { return STS_FAILURE; } - DEBUGC(DBCLASS_RTP,"stopping RTP proxy stream for: %s@%s", - callid->number, callid->host); + DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: stopping RTP proxy " + "stream for: %s@%s (%s)", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing")); /* * lock mutex - only if not requested to skip the lock. @@ -452,7 +470,8 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { cid.number = rtp_proxytable[i].callid_number; cid.host = rtp_proxytable[i].callid_host; if (rtp_proxytable[i].sock && - (compare_callid(callid, &cid) == STS_SUCCESS)) { + (compare_callid(callid, &cid) == STS_SUCCESS) && + (rtp_proxytable[i].direction == dir)) { sts = close(rtp_proxytable[i].sock); DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream " "%s:%s == %s:%s (idx=%i) sts=%i", @@ -474,8 +493,10 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { /* did not find an active stream... */ if (!got_match) { - DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: can't find active stream for %s@%s", - callid->number, callid->host); + DEBUGC(DBCLASS_RTP, + "rtp_relay_stop_fwd: can't find active stream for %s@%s (%s)", + callid->number, callid->host, + ((dir == incoming) ? "incoming" : "outgoing")); retsts = STS_FAILURE; goto unlock_and_exit; } diff --git a/src/siproxd.h b/src/siproxd.h index ad339c7..58ed2bb 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -22,6 +22,12 @@ #include #endif +/* typedef for specifying the direction of an RTP stream [being proxied] */ +typedef enum { + incoming, + outgoing, +} rtp_direction; + /* function returns STS_* status values vvv */ /* sock.c */ @@ -42,7 +48,7 @@ int register_response(osip_message_t *request, int flag); /*X*/ /* proxy.c */ int proxy_request (osip_message_t *request); /*X*/ int proxy_response (osip_message_t *response); /*X*/ -int proxy_rewrite_invitation_body(osip_message_t *mymsg); /*X*/ +int proxy_rewrite_invitation_body(osip_message_t *m, rtp_direction d); /*X*/ int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx); /*X*/ /* utils.c */ @@ -71,10 +77,11 @@ int read_config(char *name, int search); /*X*/ /* rtpproxy.c */ int rtpproxy_init( void ); /*X*/ -int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, /*X*/ +int rtp_start_fwd (osip_call_id_t *callid, rtp_direction dir, /*X*/ + int media_stream_no, struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport); -int rtp_stop_fwd (osip_call_id_t *callid); /*X*/ +int rtp_stop_fwd (osip_call_id_t *callid, rtp_direction dir); /*X*/ void rtpproxy_kill( void ); /*X*/ /* accessctl.c */ diff --git a/src/sock.c b/src/sock.c index 7518009..66193b5 100644 --- a/src/sock.c +++ b/src/sock.c @@ -155,11 +155,12 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, if (sts == -1) { if (errno != ECONNREFUSED) { - ERROR("sendto() [%s] call failed: %s", utils_inet_ntoa(addr), - strerror(errno)); + ERROR("sendto() [%s:%i] call failed: %s", utils_inet_ntoa(addr), + port, strerror(errno)); return STS_FAILURE; } - DEBUGC(DBCLASS_BABBLE,"sendto() call failed:%s",strerror(errno)); + DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s", + utils_inet_ntoa(addr), port, strerror(errno)); } return STS_SUCCESS;