Tristan | 22 Feb 15:47 2008
Picon

Re: Siproxd and patch

Hi thomas ( and list :) )

I made a quick hack to relay rtp through one thread by relay, using pjmedia abstraction ( as it provides other convenient functions that might be usefull for me, like recording, conferencing,... )

Attached is an untested cleaned patch of my source tree if you want to review it ( and maybe correct it, as it should be integrated in siproxd itself, not like I did to gain time... ).

needed is the pjmedia lib found there: http://www.pjsip.org/release/0.8.0/pjproject-0.8.0.tar.gz

My TODO/Wishlist:

1) Change the way you designed outbound and inbound iface. It should be network based and not interface based, to support multiple incoming network for multiple outgoing.
2) Support recording ( should be easy with pjmedia conference design ).
3) Support intrusive calls ( IE someone gets in the middle of a existing call to speak to one end only, or to both... ).
4) Topology hiding / ereg based incoming number hiding ( so that agents in a call-center don't get the client number ).
5) Load balancing/ HA support ( I have some ideas on how to do this we could discuss ).

The base of your software is clear so I hope I 'll be able to make it evolve to a complete media-enabled SBC with a lot of features :)

Maybe you could lead me to one direction or another, as I'll use this here for my remote call-centers relay ( and to keep UA under control ).

Regards,

Tristan.

Thomas Ries a écrit :
Hello Tristan, Please see my answers below: On 17 Jan, Tristan wrote:
Hi Thomas, I'm a french developper searching for an rtp proxy solution and found your project. I 'm currently migrating all my enterprise ( 160 seats call-center + 100 administratives phones ) to voip ( Using sipX as a proxy and registrar ), and need an rtp proxy to keep control of what's going on in the phone system and have some questions regarding your work. - Do you use it in production actually ?
I use it in my environment, but I have quite low SIP activity ;-) Unfortunately I don't get a lot of feedback from people that do use siproxd in different setups. What I am aware of is siproxd is used mostly in SOHO and home environments with the goal to get across the local NAT router/firewall that connects the local network to the Internet - that's exactly what siproxd was developed for.
- How does it scale ?
I have no data on how well it scales. However, the design is made in a way that assumes a low number of concurrent calls. All SIP traffic is handled by one single thread and that may lead to delays in processing call signalling. Also all RTP traffic is relayed by one thread (thus delays in the RTP data are also possible). There are a number of fixed constants (compile time) that limit the total number of RTP streams as well as number of SIP User Agents. Those values can easily be increased.
- Can I use many inbound interface for one outbound iface ?
Currently not. This may be implemented in one of the future releases, it is currently on the to-be-investigated list.
I currently need also: - some phones to not display who's calling them, I made a quick hack on your project for this using a plugin I wrote. I can send you the patch if you want to review it.
Plugins are the right choise for this. The plugin interface will be redesigned/rewritten to allow dynamic loading of plugins (a plugin will be built as shared library that can be loaded during runtime).
- all conversations must be recorded, I use oreka for this, but I should write a plugin for your project to directly let siproxd handle this, do you think it is a good approach ?
This would introduce more processing (= delay + jitter) in the RTP proxy part. As all RTP traffic is processed in a single proxy thread this could easily lead to drop-outs when many concurrent calls are active.
- I need live listening of conversations, and also the capacity to speak to one end of a conversation without the other end hearing it. I should also patch siproxd for this.
See below.
Do you have some advices ? Maybe we should collaborate on improving siproxd ?
Siproxd was designed to get SIP working across a local NAT router/firewall. If NAT is not the main issue for you, maybe you should look into other solutions, possibly most of your points might be covered by Asterisk (should scale better, recording features, can be configured so RTP is always processed/proxied by Asterisk, etc). Currently my time available to development work on siproxd is limited (means that myself, I will not be available for major functional extensions to be done in a tight schedule). If you (or anyone) likes to contribute code/functionality I'll be happy to include it into the siproxd project as far as it makes sense. As mentioned above, the plugin API is waiting to be redesigned to make the plugins more easy and dynamic to handle.
What about High Availability ? Do you think failover or load balancing should be used ?
The design of siproxd was made *without* any considerations regarding HA and/or load balancing mechanisms. I doubt that this can be added without fundamental design changes.
Briefly I hope to hear you soon, because I have many questions and idea to help this project that seems so far the best for my needs. Regards, Tristan
Regards, /Thomas
diff -rdEbU3 -ruN siproxd-0.7.0.orig/src/Makefile siproxd-0.7.0/src/Makefile
--- siproxd-0.7.0.orig/src/Makefile	2008-02-22 15:27:13.000000000 +0100
+++ siproxd-0.7.0/src/Makefile	2008-02-20 15:44:04.000000000 +0100
 <at>  <at>  -34,6 +34,14  <at>  <at> 
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #

+# PJSIP stuff
+PJBASE=/root/src/pjproject-0.8.0
+include $(PJBASE)/build.mak
+#
+# LDFLAGS = ${APP_LDFLAGS}
+# LDLIBS  = ${APP_LDLIBS}
+# CFLAGS  = ${APP_CFLAGS}
+# CPPFLAGS= ${CFLAGS}

 srcdir = .
 <at>  <at>  -88,7 +96,7  <at>  <at> 
 	accessctl.$(OBJEXT) route_processing.$(OBJEXT) \
 	security.$(OBJEXT) auth.$(OBJEXT) fwapi.$(OBJEXT) \
 	resolve.$(OBJEXT) plugin_shortdial.$(OBJEXT) \
-	dejitter.$(OBJEXT)
+	dejitter.$(OBJEXT) plugin_mediarelay.$(OBJEXT)
 siproxd_OBJECTS = $(am_siproxd_OBJECTS)
 siproxd_LDADD = $(LDADD)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
 <at>  <at>  -131,10 +139,11  <at>  <at> 
 INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
 LDFLAGS =
 LIBOBJS =
-LIBS = -lresolv -lresolv -losipparser2 -losip2
+# PATCH PJLIB
+LIBS = -lresolv -lresolv -losipparser2 -losip2 ${APP_LDFLAGS} $(APP_LDLIBS)
 LN_S = ln -s
 LTLIBOBJS =
-MAKEINFO = ${SHELL} /root/src/siproxd-0.7.0.orig/scripts/missing --run makeinfo
+MAKEINFO = ${SHELL} /root/src/siproxd-0.7.0/scripts/missing --run makeinfo
 OBJEXT = o
 PACKAGE = siproxd
 PACKAGE_BUGREPORT =
 <at>  <at>  -204,12 +213,11  <at>  <at> 
 target_vendor = redhat
 AM_CFLAGS = -Wall -D_GNU_SOURCE \
             -DBUILDSTR="\"`cat .buildno`\""
-
 siproxd_SOURCES = siproxd.c proxy.c register.c sock.c utils.c \
 		  sip_utils.c sip_layer.c log.c readconf.c rtpproxy.c \
 		  rtpproxy_relay.c accessctl.c route_processing.c \
 		  security.c auth.c fwapi.c resolve.c \
-		  plugin_shortdial.c dejitter.c
+		  plugin_shortdial.c dejitter.c plugin_mediarelay.c

 #		  addrcache.c

diff -rdEbU3 -ruN siproxd-0.7.0.orig/src/plugin_mediarelay.c siproxd-0.7.0/src/plugin_mediarelay.c
--- siproxd-0.7.0.orig/src/plugin_mediarelay.c	1970-01-01 01:00:00.000000000 +0100
+++ siproxd-0.7.0/src/plugin_mediarelay.c	2008-02-22 15:16:32.000000000 +0100
 <at>  <at>  -0,0 +1,960  <at>  <at> 
+/*
+   Copyright (C) 2008  Tristan Mahé <tristan.mahe@...>
+
+    This file is part of Siproxd.
+
+    Siproxd is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    Siproxd is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Siproxd; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "plugin_mediarelay.h"
+
+static char const ident[]="$Id: plugin_mediarelay.c,v 0.2$";
+
+/* RTP proxy with advanced functions
+ * Process INVITE, 200/ok, BYE, CANCEL...
+ * don't forget to NEVER activate proxy_rtp in siproxd configuration as it will mess up everything
+ */
+
+int plugin_mediarelay(sip_ticket_t *ticket)
+{
+   int sts=STS_SUCCESS;
+   int direction;int tableidx;int idx;int status_code;
+
+   if (!ticket || !ticket->sipmsg) return STS_FAILURE;
+
+   status_code = osip_message_get_status_code(ticket->sipmsg);
+
+   /* We have an sdp, create or start relay */
+   if ( MSG_IS_INVITE(ticket->sipmsg)
+        || ( MSG_IS_RESPONSE_FOR(ticket->sipmsg,"INVITE")  && status_code == 200) )
+   {
+      direction = rtp_find_direction(ticket);
+      tableidx = is_in_mediatable(ticket);
+      if (tableidx < -1) return STS_FAILURE; // something wrong happened ?! should be logged
+
+      if ( tableidx == -1 && MSG_IS_INVITE(ticket->sipmsg) )
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "INVITE callid is not in mediatable, filling table");
+         idx = add_mediatable_t(ticket);
+         {
+            pthread_mutex_lock(&mediatable_mutex);
+            sts = media_rewrite_sdp(ticket,direction,idx);
+            pthread_mutex_unlock(&mediatable_mutex);
+         }
+      }
+      else if ( tableidx > -1 && mediatable[tableidx].local_port_dst == 0
+                &&  MSG_IS_RESPONSE_FOR(ticket->sipmsg,"INVITE")  )
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "200/OK received [%d]",tableidx);
+         {
+            pthread_mutex_lock(&mediatable_mutex);
+            sts = media_rewrite_sdp(ticket,direction,tableidx);
+            pthread_mutex_unlock(&mediatable_mutex);
+         }
+         launch_rtp_thread(tableidx);
+      }
+      return sts;
+   } /* We have to delete created conference */
+   else if ( MSG_IS_BYE(ticket->sipmsg) || MSG_IS_CANCEL(ticket->sipmsg) )
+   {
+      DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+            "BYE|CANCEL received, stopping forward");
+      while ( (tableidx = is_in_mediatable(ticket)) > -1 )
+      {
+            {
+               pthread_mutex_lock(&mediatable_mutex);
+               memset(&mediatable[tableidx], 0, sizeof(mediatable[0]));
+               pthread_mutex_unlock(&mediatable_mutex);
+            }
+      }
+   } /* catch all errors corresponding to an invite */
+   else if (MSG_IS_RESPONSE_FOR(ticket->sipmsg,"INVITE") &&
+            (status_code >= 300 && status_code <= 699 )
+           )
+   {
+      DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "ERROR for invite received, deleting entries");
+      while ( (tableidx = is_in_mediatable(ticket)) > -1 )
+      {
+         {
+            pthread_mutex_lock(&mediatable_mutex);
+            memset(&mediatable[tableidx], 0, sizeof(mediatable[0]));
+            pthread_mutex_unlock(&mediatable_mutex);
+         }
+      }
+   }
+   return sts;
+}
+
+/* is called by media_rewrite_sdp which is within a mutex so no problems */
+static int get_local_port() {
+   int local_port;int i;
+   for (local_port=configuration.rtp_port_low;local_port<configuration.rtp_port_high;local_port+=2)
+   {
+      for (i=0; i<RTPPROXY_SIZE; i++)
+      {
+         if (local_port == mediatable[i].local_port_orig || local_port == mediatable[i].local_port_dst)
+            break;
+      } /* for i */
+      if (i<RTPPROXY_SIZE)
+         continue;
+      else
+         break;
+   } /* for (local_port)*/
+
+   if (local_port >= configuration.rtp_port_high)
+      local_port = 0;
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "local port allocated: %d",local_port);
+   return local_port;
+}
+
+static int is_local_uri(osip_uri_t *url) {
+   int i;
+   /* search for an entry */
+   {
+      for (i=0;i<URLMAP_SIZE;i++){
+         if (urlmap[i].active == 0) continue;
+         if ( compare_url(url, urlmap[i].true_url)==STS_SUCCESS) break;
+         if ( compare_url(url, urlmap[i].reg_url)==STS_SUCCESS) break;
+         if ( compare_url(url, urlmap[i].masq_url)==STS_SUCCESS) break;
+      }
+   }
+
+   /* found a mapping entry */
+   if (i<URLMAP_SIZE)
+      return 1;
+   else
+      return 0;
+}
+
+
+static int add_mediatable_t(sip_ticket_t *ticket)
+{
+   int freeidx=-1;int j;
+   osip_call_id_t *callid=NULL;
+
+   pthread_mutex_lock(&mediatable_mutex);
+
+   for (j=0; j<RTPPROXY_SIZE; j++)
+   {
+      if (mediatable[j].active==0)
+      {
+         freeidx=j;
+         break;
+      }
+   }
+   if (freeidx == -1)
+   {
+      ERROR("plugin_mediarelay: mediatable is full!");
+   }
+   else
+   {
+      callid = osip_message_get_call_id(ticket->sipmsg);
+      if (!callid)
+         freeidx = -1;
+      else
+      {
+         mediatable[freeidx].active=1;
+
+         if (callid->number) {
+            strcpy(mediatable[freeidx].callid_number, callid->number);
+         } else {
+            mediatable[freeidx].callid_number[0]='\0';
+         }
+
+         if (callid->host) {
+            strcpy(mediatable[freeidx].callid_host, callid->host);
+         } else {
+            mediatable[freeidx].callid_host[0]='\0';
+         }
+      }
+   }
+   pthread_mutex_unlock(&mediatable_mutex);
+
+   return freeidx;
+}
+
+static int is_in_mediatable(sip_ticket_t *ticket)
+{
+   osip_call_id_t *callid=NULL;
+   osip_call_id_t cid;
+   int ret = -1;int i;
+   callid = osip_message_get_call_id(ticket->sipmsg);
+
+   /* very important sanity checks */
+   if ( ! callid )
+      return -2;
+   if (callid->number && (strlen(callid->number) >= CALLIDNUM_SIZE)) {
+      ERROR("media_rewrite_sdp: received callid number [%s] "
+            "has too many characters (%ld, max=%i)",
+            callid->number, (long)strlen(callid->number),CALLIDNUM_SIZE);
+      return -2;
+   }
+   if (callid->host && (strlen(callid->host) >= CALLIDHOST_SIZE)) {
+      ERROR("media_rewrite_sdp: received callid host [%s] "
+            "has too many characters (%ld, max=%i)",
+            callid->host, (long)strlen(callid->host),CALLIDHOST_SIZE);
+      return -2;
+   }
+   {
+      pthread_mutex_lock(&mediatable_mutex);
+      for (i=0; i<RTPPROXY_SIZE; i++)
+      {
+         cid.number = mediatable[i].callid_number;
+         cid.host = mediatable[i].callid_host;
+         if (compare_callid(callid, &cid) == STS_SUCCESS )
+         {
+            ret = i;
+            break;
+         }
+      }
+      pthread_mutex_unlock(&mediatable_mutex);
+   }
+   return ret;
+}
+
+void destroy_mediatable()
+{
+   int i;
+   pthread_mutex_lock(&mediatable_mutex);
+   for (i=0; i<RTPPROXY_SIZE; i++)
+   {
+      if (mediatable[i].active==1)
+      {
+         memset(&mediatable[i], 0, sizeof(mediatable[0]));
+      }
+   }
+   pthread_mutex_unlock(&mediatable_mutex);
+}
+
+static int rtp_find_direction(sip_ticket_t *ticket)
+{
+   int direction;
+   direction = sip_find_direction(ticket, NULL);
+
+   if ( is_local_uri(ticket->sipmsg->to->url) && is_local_uri(ticket->sipmsg->from->url) )
+   {
+      DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+            "%s to local from local",MSG_IS_INVITE(ticket->sipmsg) ? "INVITE" :"200/OK" );
+      direction = DIR_INCOMING;
+   }
+   else if (  is_local_uri(ticket->sipmsg->to->url) ) // && ! is_local(ticket->sipmsg->from->url) )
+   {
+      if ( MSG_IS_INVITE(ticket->sipmsg) )
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "INVITE to local from ext");
+         direction = DIR_INCOMING;
+      }
+      else // 200/OK
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "200/OK to local from ext");
+         direction = DIR_OUTGOING;
+      }
+   }
+   else
+   {
+      if ( MSG_IS_INVITE(ticket->sipmsg) )
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "INVITE to ext from local");
+         direction = DIR_OUTGOING;
+      }
+      else // 200/OK
+      {
+         DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+               "200/OK to ext from local");
+         direction = DIR_INCOMING;
+      }
+   }
+   return direction;
+}
+
+static pj_status_t create_stream( pj_pool_t *pool,
+                                  pjmedia_endpt *med_endpt,
+                                  const pjmedia_codec_info *codec_info,
+                                  pjmedia_dir dir,
+                                  pj_uint16_t local_port,
+                                  char *remote_addr,
+                                  pj_uint16_t remote_port,
+                                  pjmedia_stream **p_stream )
+{
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "entering create_stream()");
+   pjmedia_stream_info info;
+   pjmedia_transport *transport;
+   pj_status_t status;
+
+   /* Reset stream info. */
+   pj_bzero(&info, sizeof(info));
+
+   /* Initialize stream info formats */
+   info.type = PJMEDIA_TYPE_AUDIO;
+//    info.proto = PJMEDIA_TP_PROTO_RTP_AVP;
+   info.dir = dir;
+   pj_memcpy(&info.fmt, codec_info, sizeof(pjmedia_codec_info));
+   info.tx_pt = codec_info->pt;
+   info.ssrc = pj_rand();
+
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "create_stream() copying remote_addr now  [%s:%d]",remote_addr,remote_port);
+
+   /* Copy remote address */
+   pj_str_t ip = pj_str(remote_addr);
+   status = pj_sockaddr_in_init (  &info.rem_addr,&ip,remote_port );
+   if (status != PJ_SUCCESS)
+      ERROR("Invalid remote address [%s:%d] [%d]",remote_addr,remote_port, status);
+
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "create_stream() creating udp transport");
+   /* Create media transport */
+   status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
+                                         0, &transport);
+   if (status != PJ_SUCCESS) {
+      DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+            "create_stream() FAILURE creating udp transport");
+      return status;
+   }
+    /* Now that the stream info is initialized, we can create the
+   * stream.
+    */
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "create_stream() stream creation final step");
+   status = pjmedia_stream_create( med_endpt, pool, &info,
+                                   transport, NULL, p_stream);
+
+   if (status != PJ_SUCCESS) {
+      ERROR("Error creating stream [%d]", status);
+      pjmedia_transport_udp_close(transport);
+      return status;
+   }
+
+   return PJ_SUCCESS;
+}
+
+
+int media_rewrite_sdp(sip_ticket_t *ticket, int direction, int url_map_idx) {
+   int map_port = 0; /* Default */
+   osip_message_t *mymsg=ticket->sipmsg;
+   osip_body_t *body;
+   sdp_message_t  *sdp;
+   struct in_addr map_addr, addr_sess, addr_media, outside_addr, inside_addr;
+   int sts;
+   char *buff;
+   size_t buflen;
+   char clen[8]; /* content length: probably never more than 7 digits !*/
+   int msg_port;
+   int media_stream_no;
+   sdp_connection_t *sdp_conn;
+   sdp_media_t *sdp_med;
+   int rtp_direction=0;
+   int have_c_media=0;
+   int isrtp = 0 ;
+
+   map_port = get_local_port();
+   if (map_port == 0)
+      return STS_FAILURE;
+
+   /*
+   * get SDP structure
+   */
+   sts = osip_message_get_body(mymsg, 0, &body);
+   if (sts != 0) {
+      DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+            "no body found in message");
+      return STS_FAILURE;
+   }
+
+   sts = sip_body_to_str(body, &buff, &buflen);
+   if (sts != 0) {
+      ERROR("media_rewrite_sdp: unable to sip_body_to_str");
+      return STS_FAILURE;
+   }
+
+   DEBUGC(-1, "media_rewrite_sdp: payload %ld bytes", (long)buflen);
+   DUMP_BUFFER(-1, buff, buflen);
+
+
+   sts = sdp_message_init(&sdp);
+   sts = sdp_message_parse (sdp, buff);
+   if (sts != 0) {
+      ERROR("media_rewrite_sdp: unable to sdp_message_parse body");
+      DUMP_BUFFER(-1, buff, buflen);
+      osip_free(buff);
+      sdp_message_free(sdp);
+      return STS_FAILURE;
+   }
+   osip_free(buff);
+
+   /*
+   * RTP proxy: get ready and process
+   * rewrite for each media stream ('m=' item in SIP message)
+   */
+
+   /* get outbound address */
+   if (get_interface_ip(IF_OUTBOUND, &outside_addr) != STS_SUCCESS) {
+      sdp_message_free(sdp);
+      return STS_FAILURE;
+   }
+
+   /* get inbound address */
+   if (get_interface_ip(IF_INBOUND, &inside_addr) != STS_SUCCESS) {
+      sdp_message_free(sdp);
+      return STS_FAILURE;
+   }
+
+   /* figure out what address to use for RTP masquerading TO REWRITE !!! */
+   /*
+   if (MSG_IS_INVITE && ticket->direction == DIR_INCOMING)
+            // rewrite using internal iface. ( vl16 )
+   else if (MSG_IS_RESPONSE_FOR(ticket->sipmsg,"INVITE") && ticket->direction == DIR_OUTGOING)
+            // 200/OK
+   */
+   if (MSG_IS_REQUEST(mymsg)) {
+      if (direction == DIR_INCOMING) {
+         memcpy(&map_addr, &inside_addr, sizeof (map_addr));
+         rtp_direction = DIR_OUTGOING;
+      } else {
+         memcpy(&map_addr, &outside_addr, sizeof (map_addr));
+         rtp_direction = DIR_INCOMING;
+      }
+   } else /* MSG_IS_REPONSE(mymsg) */ {
+      if (direction == DIR_INCOMING) {
+         memcpy(&map_addr, &inside_addr, sizeof (map_addr));
+         rtp_direction = DIR_OUTGOING;
+      } else {
+         memcpy(&map_addr, &outside_addr, sizeof (map_addr));
+         rtp_direction = DIR_INCOMING;
+      }
+   }
+
+   if ( MSG_IS_INVITE(ticket->sipmsg) )
+   {
+      memcpy(&mediatable[url_map_idx].local_ipaddr_orig, &map_addr, sizeof (mediatable[url_map_idx].local_ipaddr_orig));
+      mediatable[url_map_idx].local_port_orig = map_port;
+   }
+   else
+   {
+      memcpy(&mediatable[url_map_idx].local_ipaddr_dst, &map_addr, sizeof (mediatable[url_map_idx].local_ipaddr_dst));
+      mediatable[url_map_idx].local_port_dst = map_port;
+   }
+
+   DEBUGC(DBCLASS_PLUGIN, "proxy_media_rewrite_sdp: SIP[%s %s] RTP[%s %s]",
+          MSG_IS_REQUEST(mymsg)? "RQ" : "RS",
+                         (direction==DIR_INCOMING)? "IN" : "OUT",
+                          (rtp_direction==DIR_INCOMING)? "IN" : "OUT",
+                           utils_inet_ntoa(map_addr));
+
+
+   /*
+   * first, check presence of a 'c=' item on session level
+   */
+   if (sdp->c_connection==NULL || sdp->c_connection->c_addr==NULL) {
+      /*
+      * No 'c=' on session level, search on media level now
+      *
+      * According to RFC2327, ALL media description must
+       * include a 'c=' item now:
+      */
+      media_stream_no=0;
+      while (!sdp_message_endof_media(sdp, media_stream_no)) {
+         /* check if n'th media stream is present */
+         if (sdp_message_c_addr_get(sdp, media_stream_no, 0) == NULL) {
+            ERROR("SDP: have no 'c=' on session level and neither "
+                  "on media level (media=%i)",media_stream_no);
+            sdp_message_free(sdp);
+            return STS_FAILURE;
+         }
+         media_stream_no++;
+      } /* while */
+   }
+
+   /* Required 'c=' items ARE present */
+
+   /*
+   * rewrite 'c=' item on session level if present and not yet done.
+   * remember the original address in addr_sess
+   */
+   memset(&addr_sess, 0, sizeof(addr_sess));
+   if (sdp->c_connection && sdp->c_connection->c_addr) {
+      sts = get_ip_by_host(sdp->c_connection->c_addr, &addr_sess);
+      if (sts == STS_FAILURE) {
+         ERROR("SDP: cannot resolve session 'c=' host [%s]",
+               sdp->c_connection->c_addr);
+         sdp_message_free(sdp);
+         return STS_FAILURE;
+      }
+      if ( MSG_IS_INVITE(ticket->sipmsg) )
+      {
+         sprintf(mediatable[url_map_idx].remote_ipaddr_orig,"%s", sdp->c_connection->c_addr);
+      }
+      else
+      {
+         sprintf(mediatable[url_map_idx].remote_ipaddr_dst,"%s", sdp->c_connection->c_addr);
+      }
+      /*
+      * Rewrite
+      * an IP address of 0.0.0.0 means *MUTE*, don't rewrite such
+      */
+      if (strcmp(sdp->c_connection->c_addr, "0.0.0.0") != 0) {
+         osip_free(sdp->c_connection->c_addr);
+         sdp->c_connection->c_addr=osip_malloc(HOSTNAME_SIZE);
+         sprintf(sdp->c_connection->c_addr, "%s", utils_inet_ntoa(map_addr));
+      } else {
+         /* 0.0.0.0 - don't rewrite */
+         DEBUGC(DBCLASS_PLUGIN, "proxy_mdia_rewrite_sdp: "
+               "got a MUTE c= record (on session level - legal?)");
+      }
+   }
+
+
+   /*
+   * rewrite 'o=' item (originator) on session level if present.
+   */
+   if (sdp->o_addrtype && sdp->o_addr) {
+      if (strcmp(sdp->o_addrtype, "IP4") != 0) {
+         ERROR("got IP6 in SDP originator - not yet suported by siproxd");
+         sdp_message_free(sdp);
+         return STS_FAILURE;
+      }
+
+      osip_free(sdp->o_addr);
+      sdp->o_addr=osip_malloc(HOSTNAME_SIZE);
+      sprintf(sdp->o_addr, "%s", utils_inet_ntoa(map_addr));
+   }
+
+   /*
+   * loop through all media descritions,rewrite them
+   */
+   for (media_stream_no=0;;media_stream_no++) {
+      /* check if n'th media stream is present */
+      if (sdp_message_m_port_get(sdp, media_stream_no) == NULL) break;
+
+      /*
+      * check if a 'c=' item is present in this media description,
+      * if so -> rewrite it
+      */
+      memset(&addr_media, 0, sizeof(addr_media));
+      have_c_media=0;
+      sdp_conn=sdp_message_connection_get(sdp, media_stream_no, 0);
+      if (sdp_conn && sdp_conn->c_addr) {
+         if (strcmp(sdp_conn->c_addr, "0.0.0.0") != 0) {
+            sts = get_ip_by_host(sdp_conn->c_addr, &addr_media);
+            have_c_media=1;
+            /* 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_PLUGIN, "media_rewrite_sdp: got a "
+                  "MUTE c= record (media level)");
+         }
+      }
+
+      /* start an RTP proxying stream */
+      if (sdp_message_m_port_get(sdp, media_stream_no)) {
+         msg_port=atoi(sdp_message_m_port_get(sdp, media_stream_no));
+         if ((msg_port > 0) && (msg_port <= 65535)) {
+            if ( MSG_IS_INVITE(ticket->sipmsg) )
+            {
+               mediatable[url_map_idx].remote_port_orig = msg_port;
+            }
+            else
+            {
+               mediatable[url_map_idx].remote_port_dst = msg_port;
+            }
+            client_id_t client_id;
+            osip_contact_t *contact = NULL;
+            char *tmp=NULL;
+            char *protocol=NULL;
+
+            /* try to get some additional UA specific unique ID.
+            * This Client-ID should be guaranteed persistent
+            * and not depend on if a UA/Server does include a
+            * particular Header (Contact) or not.
+            * I should just go for the remote IP address here, no?
+            */
+            /* &&& NO, using the sender IP will cause troubles if
+            * the remote peer (Proxy/registrar) is thrown out of
+            * the signalling path. Then suddenly the IP address changes.
+            *
+            * I should probably go back to the Contact Header based idea,
+            * with fallback to IP.
+            * I must use a n-item structure, including all things that
+            * can be used for comparing. Then, in the RTP proxy, comparison
+            * must take place according to priorities with the item
+            * with highest priority present in the RTP table *and*
+            * extracted from the SIP message.
+            * To start with, this can be just 2 things, the Contact header
+            * and the Layer 3 IP address. As long as the UAs include the
+            * Contact header, we survive IP changes (e.g. when the SIP
+            * Registrar/Proxy is removed from signalling path within an
+            * ongoing call. This may happen if the Registrar/Proxy does
+            * not explicitely ask to stay in the signalling path using
+            * Record-Route headers - which is perfectly legal
+            *
+            */
+
+            memset(&client_id, 0, sizeof(client_id));
+
+            /* get the Contact Header if present */
+            osip_message_get_contact(mymsg, 0, &contact);
+            if (contact) osip_contact_to_str(contact, &tmp);
+            if (tmp) strncpy(client_id.contact, tmp, CLIENT_ID_SIZE-1);
+
+            /* store the IP address of the sender */
+            memcpy(&client_id.from_ip, &ticket->from.sin_addr,
+                    sizeof(client_id.from_ip));
+
+            /*
+            * is this an RTP stream ? If yes, set 'isrtp=1'
+            */
+            protocol = sdp_message_m_proto_get (sdp, media_stream_no);
+            if (protocol == NULL) {
+               DEBUGC(DBCLASS_PLUGIN, "no protocol definition found!");
+            } else {
+               char *check;
+               char *cmp;
+               isrtp = 1;
+               check = protocol ;
+               cmp = "RTP/" ;
+               while (*cmp && (isrtp = isrtp && *check) &&
+                       (isrtp = isrtp && (*cmp++ == toupper(*check++))) ) {} ;
+               if (isrtp) {
+                  DEBUGC(DBCLASS_PLUGIN, "found RTP protocol [%s]!", protocol);
+               } else {
+                  DEBUGC(DBCLASS_PLUGIN, "found non RTP protocol [%s]!", protocol);
+               }
+            }
+
+            /*
+            * do we have a 'c=' item on media level?
+            * if not, use the same as on session level
+            */
+            if (have_c_media == 0) {
+               memcpy(&addr_media, &addr_sess, sizeof(addr_sess));
+            }
+
+            /*
+            * Am I running in front of the routing device? Then I cannot
+            * use the external IP to bind a listen socket to, but should
+            * use my real IP on the outbound interface (which may legally
+            * be the same as the inbound interface if only one interface
+            * is used).
+            */
+            if ((rtp_direction == DIR_INCOMING) &&
+                 (configuration.outbound_host) &&
+                 (strcmp(configuration.outbound_host, "")!=0)) {
+               DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+                     "in-front-of-NAT-Router, use real outboud IP");
+               if (get_interface_real_ip(IF_OUTBOUND, &map_addr)
+                   != STS_SUCCESS) {
+                  ERROR("cannot get my real outbound interface address");
+                  /* as we do not know better, take the internal address */
+                  memcpy(&map_addr, &inside_addr, sizeof (map_addr));
+                   }
+                 }
+
+                 /* 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); /* 5 digits, \0 + align */
+                    sprintf(sdp_med->m_port, "%i", map_port);
+                    DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+                          "m= rewrote port to [%i]",map_port);
+                 } else {
+                    ERROR("rewriting port in m= failed sdp_med=%p, "
+                          "m_number_of_port=%p", sdp_med, sdp_med->m_port);
+                 }
+         } /* if msg_port > 0 */
+      } else {
+         /* no port defined - skip entry */
+         WARN("no port defined in m=(media) stream_no=%i", media_stream_no);
+         continue;
+      }
+   } /* for media_stream_no */
+
+
+
+   /* remove old body */
+   sts = osip_list_remove(&(mymsg->bodies), 0);
+   osip_body_free(body);
+
+   /* dump new body */
+   sdp_message_to_str(sdp, &buff);
+   buflen=strlen(buff);
+
+   /* free sdp structure */
+   sdp_message_free(sdp);
+
+   /* include new body */
+   sip_message_set_body(mymsg, buff, buflen);
+   if (sts != 0) {
+      ERROR("media_rewrite_sdp: unable to sip_message_set_body body");
+   }
+
+   /* free content length resource and include new one*/
+   osip_content_length_free(mymsg->content_length);
+   mymsg->content_length=NULL;
+   sprintf(clen,"%ld",(long)buflen);
+   sts = osip_message_set_content_length(mymsg, clen);
+
+   /* free old body */
+   osip_free(buff);
+
+   return STS_SUCCESS;
+}
+
+static void launch_rtp_thread(int tableidx) {
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: launch_rtp_thread [%d]",tableidx);
+   pthread_t thread;
+   int ret;
+   ret = pthread_create( &thread, NULL, run_rtp_proxy, (void*)  &tableidx); /* is not unallocated */
+   pj_thread_sleep(500); /* 500 ms to wait for run_rtp_proxy to get tableidx value */
+}
+
+/* Main thread for running conference bridge.
+   - We should export conf to enable other relay to start
+   - we should add record support
+*/
+static void *run_rtp_proxy(void *ptr)
+{
+   /* thread stuff */
+   pj_thread_desc  tdesc;
+   pj_thread_t *thread;
+
+   int url_map_idx;
+   url_map_idx = (int) *((int *) ptr);
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: starting rtp_proxy with index [%d]",url_map_idx);
+
+   /* REGISTER new thread into PJLIB*/
+   pj_thread_register(NULL,tdesc,&thread);
+
+   /* PJMEDIA declarations */
+   pjmedia_dir dir = PJMEDIA_DIR_ENCODING_DECODING;
+   pj_status_t status;pjmedia_transport *tp;
+
+   pjmedia_conf *conf;
+   pjmedia_port *conf_port;
+   pjmedia_port *null;                  /* null port for the master to operate correctly */
+   pjmedia_master_port *master_port;	/* Global master port for the conf */
+   const pjmedia_codec_info *codec_info;
+   pj_pool_t *pool;
+
+   /* for streams */
+   pjmedia_stream *stream_orig;                      /* Unique RTP stream */
+   pjmedia_port *stream_port_orig;
+   unsigned  media_slot_orig; /* slot index of the port in the conference bridge */
+
+   pjmedia_stream *stream_dst;                      /* Unique RTP stream */
+   pjmedia_port *stream_port_dst;
+   unsigned  media_slot_dst; /* slot index of the port in the conference bridge */
+
+   /*
+   * start PJMEDIA relay by creating a conf, easier to extend than just a buffer based relay
+   */
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: get codec mgr for alaw");
+   pjmedia_codec_mgr_get_codec_info( pjmedia_endpt_get_codec_mgr(med_endpt),
+                                     8, &codec_info);
+
+   /* Create memory pool for application purpose */
+   pool = pj_pool_create( &pjPoolFactory.factory,     /* pool factory         */
+                           mediatable[url_map_idx].callid_number,       /* pool name.           */
+                           4000,                                        /* init size            */
+                           4000,                                        /* increment size       */
+                           NULL                                         /* callback on error    */
+                        );
+
+   status = pjmedia_conf_create( pool,                   /* pool to use          */
+                                 NCONFPORTS,             /* number of ports     */
+                                 CLOCK_RATE,
+                                 NCHANNELS,
+                                 NSAMPLES,
+                                 NBITS,
+                                 PJMEDIA_CONF_NO_DEVICE, /* options              */
+                                 &conf                   /* result               */
+                               );
+   if (status != PJ_SUCCESS)
+   {
+      conf = NULL;
+      ERROR("Unable to create conference bridge: %d",status);
+      goto on_exit;
+   }
+
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "conference ready");
+   conf_port = pjmedia_conf_get_master_port(conf);
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "creating null port");
+   status = pjmedia_null_port_create(pool, CLOCK_RATE,
+                                     NCHANNELS, NSAMPLES, NBITS, &null);
+   if (status != PJ_SUCCESS)
+   {
+      ERROR("Unable to create NULL port: %d",status);
+   }
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "creating master port");
+   status = pjmedia_master_port_create(pool, null, conf_port, 0, &master_port);
+   if (status != PJ_SUCCESS)
+   {
+      ERROR("Unable to create MASTER port: %d",status);
+   }
+   /* INIT RTP STREAMS */
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "now creating orig stream [%d] [%s:%d]",
+         mediatable[url_map_idx].local_port_orig,
+         mediatable[url_map_idx].remote_ipaddr_orig,
+         mediatable[url_map_idx].remote_port_orig);
+   status = create_stream( pool,
+                           med_endpt,
+                           codec_info,
+                           dir,
+                           mediatable[url_map_idx].local_port_orig,
+                           mediatable[url_map_idx].remote_ipaddr_orig,
+                           mediatable[url_map_idx].remote_port_orig,
+                           &stream_orig
+                         );
+   if (status != PJ_SUCCESS)
+   {
+      ERROR("Unable to create stream: %d",status);
+   }
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "getting stream port");
+   status = pjmedia_stream_get_port( stream_orig, &stream_port_orig);
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "now creating dst stream [%d] [%s:%d]",
+         mediatable[url_map_idx].local_port_dst,
+         mediatable[url_map_idx].remote_ipaddr_dst,
+         mediatable[url_map_idx].remote_port_dst);
+   status = create_stream( pool,
+                           med_endpt,
+                           codec_info,
+                           dir,
+                           mediatable[url_map_idx].local_port_dst,
+                           mediatable[url_map_idx].remote_ipaddr_dst,
+                           mediatable[url_map_idx].remote_port_dst,
+                           &stream_dst
+                         );
+   if (status != PJ_SUCCESS)
+   {
+      ERROR("Unable to create stream: %d",status);
+   }
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "getting stream port");
+   status = pjmedia_stream_get_port( stream_dst, &stream_port_dst);
+
+   if (status != PJ_SUCCESS)
+   {
+      ERROR("Unable to get stream port: %d",status);
+//          return STS_FAILURE;
+   }
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "adding stream port to conf");
+   status = pjmedia_conf_add_port( conf,
+                                   pool,
+                                   stream_port_orig,
+                                   NULL,
+                                   &media_slot_orig
+                                 );
+   status = pjmedia_conf_add_port( conf,
+                                   pool,
+                                   stream_port_dst,
+                                   NULL,
+                                   &media_slot_dst
+                                 );
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: "
+         "starting stream");
+   pjmedia_stream_start(stream_orig);
+   pjmedia_stream_start(stream_dst);
+
+   status = pjmedia_master_port_start(master_port);
+   // Connect the two streams in unidirectionnal way
+   pjmedia_conf_connect_port(conf,media_slot_orig,media_slot_dst,0);
+   pjmedia_conf_connect_port(conf,media_slot_dst,media_slot_orig,0);
+
+   /* wait there for BYE */
+   for (;;)
+   {
+      pthread_mutex_lock(&mediatable_mutex);
+      if ( mediatable[url_map_idx].active == 0 )
+         break;
+      pthread_mutex_unlock(&mediatable_mutex);
+      pj_thread_sleep(500); /* sleep for 500ms waiting for bye */
+   }
+   pthread_mutex_unlock(&mediatable_mutex);
+
+   /* Deinit right now */
+on_exit:
+      DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+      "disconnecting conf ports");
+   pjmedia_conf_disconnect_port(conf,media_slot_orig,media_slot_dst);
+   pjmedia_conf_disconnect_port(conf,media_slot_dst,media_slot_orig);
+
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "destroying streams now");
+   if (media_slot_orig)
+      status = pjmedia_conf_remove_port( conf, media_slot_orig);
+   if (stream_port_orig)
+      pjmedia_port_destroy(stream_port_orig);
+   if (stream_orig)
+   {
+      tp = pjmedia_stream_get_transport(stream_orig);
+      pjmedia_stream_destroy(stream_orig);
+      pjmedia_transport_udp_close(tp);
+   }
+   if (media_slot_dst)
+      status = pjmedia_conf_remove_port( conf, media_slot_dst);
+   if (stream_port_dst)
+      pjmedia_port_destroy(stream_port_dst);
+   if (stream_dst)
+   {
+      tp = pjmedia_stream_get_transport(stream_dst);
+      pjmedia_stream_destroy(stream_dst);
+      pjmedia_transport_udp_close(tp);
+   }
+
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "destroying master port");
+   if (master_port)
+   {
+      pjmedia_master_port_stop(master_port);
+      pjmedia_master_port_destroy(master_port, PJ_FALSE);
+   }
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "destroying conference");
+   if (conf)
+      status = pjmedia_conf_destroy( conf );
+
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "destroying null port");
+   if (null)
+   {
+      pjmedia_port_destroy(null);
+   }
+   DEBUGC(DBCLASS_PLUGIN, "plugin_mediarelay: "
+         "destroying pool");
+   if (pool)
+      pj_pool_release( pool );
+
+   pj_thread_destroy(thread);
+
+   pthread_exit(NULL);
+}
diff -rdEbU3 -ruN siproxd-0.7.0.orig/src/plugin_mediarelay.h siproxd-0.7.0/src/plugin_mediarelay.h
--- siproxd-0.7.0.orig/src/plugin_mediarelay.h	1970-01-01 01:00:00.000000000 +0100
+++ siproxd-0.7.0/src/plugin_mediarelay.h	2008-02-22 15:11:31.000000000 +0100
 <at>  <at>  -0,0 +1,125  <at>  <at> 
+/*
+   Copyright (C) 2008  Tristan Mahé <tristan.mahe@...>
+
+    This file is part of Siproxd.
+
+    Siproxd is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    Siproxd is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Siproxd; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <osipparser2/osip_parser.h>
+#include <osipparser2/sdp_message.h>
+#include "siproxd.h"
+#include "log.h"
+#include <pthread.h>
+
+#define PJMEDIA_SOUND_IMPLEMENTATION 0
+#define PJMEDIA_CODEC_MAX_SILENCE_PERIOD   16000
+#define PJMEDIA_MAX_MTU   1500
+#define PJMEDIA_PASOUND_MAX_LATENCY   100
+
+/*Pjsip stuff */
+#include <pjlib.h>
+#include <pjlib-util.h>
+#include <pjmedia.h>
+#include <pjmedia-codec.h>
+
+#include <pjmedia/session.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/endpoint.h>
+#include <pjmedia/stream.h>
+#include <pjmedia/sdp.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/rand.h>
+
+#include <pjsua-lib/pjsua.h>
+
+#define CALLIDNUM_SIZE	256
+#define CALLIDHOST_SIZE	128
+
+/* Constants */
+#define CLOCK_RATE      8000
+#define NSAMPLES        (CLOCK_RATE * 20 / 1000)
+#define NCHANNELS       1
+#define NBITS           16
+/*Maximum ports in the conf (1 for master, 2 for streams, 1 for recorder and 1 for listener) */
+#define NCONFPORTS      5
+
+extern pj_caching_pool pjPoolFactory;
+extern pjmedia_endpt *med_endpt;
+
+extern struct siproxd_config configuration;
+extern struct urlmap_s urlmap[];		/* URL mapping table     */
+
+/* contains the stream for ONE phone. opposite_entry contains the index for the nated relay */
+typedef struct {
+   int  active;                                 /* (0 -> free slot)*/
+   char callid_number[CALLIDNUM_SIZE];		/* call ID */
+   char callid_host[CALLIDHOST_SIZE];		/*  --"--  */
+
+   /* For call originator*/
+   struct in_addr local_ipaddr_orig;			/* local IP */
+   int  local_port_orig;				/* local allocated port */
+   char remote_ipaddr_orig[32];                   	/* remote IP */
+   int  remote_port_orig;				/* remote port */
+
+   /* For call destination */
+   struct in_addr local_ipaddr_dst;			/* local IP */
+   int  local_port_dst;				/* local allocated port */
+   char remote_ipaddr_dst[32];                   	/* remote IP */
+   int  remote_port_dst;				/* remote port */
+} mediatable_t;
+
+mediatable_t mediatable[RTPPROXY_SIZE];
+
+static pthread_mutex_t mediatable_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *run_rtp_proxy(void *ptr);
+
+static void launch_rtp_thread(int tableidx);
+
+/* is called by media_rewrite_sdp which is within a mutex so no problems */
+static int get_local_port();
+
+static int is_local_uri(osip_uri_t *url);
+
+static int add_mediatable_t(sip_ticket_t *ticket);
+
+static int is_in_mediatable(sip_ticket_t *ticket);
+
+void destroy_mediatable();
+
+static int rtp_find_direction(sip_ticket_t *ticket);
+
+static pj_status_t create_stream( pj_pool_t *pool,
+                                  pjmedia_endpt *med_endpt,
+                                  const pjmedia_codec_info *codec_info,
+                                  pjmedia_dir dir,
+                                  pj_uint16_t local_port,
+                                  char *remote_addr,
+                                  pj_uint16_t remote_port,
+                                  pjmedia_stream **p_stream );
+/*
+ * is called within a mediatable mutex, so no problem to update mediatable entry
+ */
+int media_rewrite_sdp(sip_ticket_t *ticket, int direction, int url_map_idx);
diff -rdEbU3 -ruN siproxd-0.7.0.orig/src/plugins.h siproxd-0.7.0/src/plugins.h
--- siproxd-0.7.0.orig/src/plugins.h	2005-12-26 17:39:12.000000000 +0100
+++ siproxd-0.7.0/src/plugins.h	2008-02-22 14:34:49.000000000 +0100
 <at>  <at>  -24,3 +24,9  <at>  <at> 

 /* short Dial plugin */
 int plugin_shortdial(sip_ticket_t *ticket);
+
+/* replace RTP proxy with full media control */
+int plugin_mediarelay(sip_ticket_t *ticket);
+
+/* current media rtp destroyer */
+void destroy_mediatable();
diff -rdEbU3 -ruN siproxd-0.7.0.orig/src/siproxd.c siproxd-0.7.0/src/siproxd.c
--- siproxd-0.7.0.orig/src/siproxd.c	2007-11-28 21:51:45.000000000 +0100
+++ siproxd-0.7.0/src/siproxd.c	2008-02-22 14:41:47.000000000 +0100
 <at>  <at>  -40,6 +40,15  <at>  <at> 
 #include "plugins.h"
 #include "log.h"

+
+// #include <pjsua-lib/pjsua.h>
+#include <pjlib.h>
+#include <pjmedia.h>
+#include <pjmedia-codec.h>
+// #include <pjlib-util.h>
+
+#define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_NULL_SOUND
+
 static char const ident[]="$Id: siproxd.c,v 1.72 2007/11/28 20:51:45 hb9xar Exp $";

 /* configuration storage */
 <at>  <at>  -73,6 +82,8  <at>  <at> 
  */
 static  int dmalloc_dump=0;
 static  int exit_program=0;
+struct pj_caching_pool pjPoolFactory;
+struct pjmedia_endpt *med_endpt;

 /*
  * local prototypes
 <at>  <at>  -80,6 +91,7  <at>  <at> 
 static void sighandler(int sig);

+
 int main (int argc, char *argv[])
 {
    int sts;
 <at>  <at>  -97,6 +109,18  <at>  <at> 
    int  cmdline_debuglevel=0;
    char *pidfilename=NULL;
    struct sigaction act;
+   pj_status_t pj_status;
+
+   pj_status = pj_init();
+   pj_caching_pool_init(&pjPoolFactory, &pj_pool_factory_default_policy, 0);
+   pj_status = pjmedia_endpt_create(&pjPoolFactory.factory, NULL, 2, &med_endpt);
+   if (pj_status != PJ_SUCCESS)
+      ERROR("Unable to create media endpoint: %d",pj_status);
+
+   DEBUGC(DBCLASS_PLUGIN, "media_rewrite_sdp: init codec");
+   pj_status = pjmedia_codec_g711_init(med_endpt);
+//    status = init_codecs( med_endpt);
+//    pjsua_set_no_snd_dev();

    log_init();

 <at>  <at>  -456,7 +480,8  <at>  <at> 
          sts = plugin_shortdial(&ticket);
          if (sts == STS_SIP_SENT) goto end_loop;
       }
-
+      sts = plugin_mediarelay(&ticket);
+      if (sts == STS_SIP_SENT) goto end_loop;

       /*********************************
        * finally proxy the message.
 <at>  <at>  -583,6 +608,17  <at>  <at> 
       }
    }

+   /* Destroy mediatable going on to remove objects */
+   destroy_mediatable();
+   sleep(1);
+   DEBUGC(DBCLASS_PLUGIN, "PJMEDIA: "
+         "destroying endpoint");
+   pjmedia_endpt_destroy( med_endpt );
+   DEBUGC(DBCLASS_PLUGIN, "PJMEDIA: "
+         "destroying pool factory");
+   pj_caching_pool_destroy( &pjPoolFactory );
+   pj_shutdown();
+
    /* END */
    log_end();
    return 0;
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Siproxd-users mailing list
Siproxd-users@...
https://lists.sourceforge.net/lists/listinfo/siproxd-users
Picon

[PATCH] fix compilation against libosip2-3.1.0

Hi,

Building siproxd against libosip2-3.1.0 will fail because of changes in 
osip_md5.h. Attached patch makes it compile again.
Note that the patch breaks compatibility to liposip2-3.0.3-2 and earlier.

Regards,
Chi-Thanh Christopher Nguyen

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Siproxd-users mailing list
Siproxd-users@...
https://lists.sourceforge.net/lists/listinfo/siproxd-users

Gmane