Make the sip_proxy struct reference counted. This is
authorMark Michelson <mmichelson@digium.com>
Wed, 15 Oct 2008 20:55:42 +0000 (20:55 +0000)
committerMark Michelson <mmichelson@digium.com>
Wed, 15 Oct 2008 20:55:42 +0000 (20:55 +0000)
necessary to allow for a sip_pvt to maintain a reference
to a sip_peer's outboundproxy even after the peer has
been freed.

(closes issue #13700)
Reported by: fnordian
Patches:
      13700.patch uploaded by putnopvut (license 60)
Tested by: fnordian

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@149802 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 2d7cd6a..994c37f 100644 (file)
@@ -469,9 +469,10 @@ enum sip_transport {
 
 /*! \brief definition of a sip proxy server
  *
- * For outbound proxies, this is allocated in the SIP peer dynamically or
- * statically as the global_outboundproxy. The pointer in a SIP message is just
- * a pointer and should *not* be de-allocated.
+ * For outbound proxies, a sip_peer will contain a reference to a 
+ * dynamically allocated instance of a sip_proxy. A sip_pvt may also
+ * contain a reference to a peer's outboundproxy, or it may contain
+ * a reference to the global_outboundproxy.
  */
 struct sip_proxy {
        char name[MAXHOSTNAMELEN];      /*!< DNS name of domain/host or IP */
@@ -1319,7 +1320,7 @@ struct sip_pvt {
        int jointnoncodeccapability;            /*!< Joint Non codec capability */
        int redircodecs;                        /*!< Redirect codecs */
        int maxcallbitrate;                     /*!< Maximum Call Bitrate for Video Calls */    
-       struct sip_proxy *outboundproxy;        /*!< Outbound proxy for this dialog */
+       struct sip_proxy *outboundproxy;        /*!< Outbound proxy for this dialog. Use ref_proxy to set this instead of setting it directly*/
        struct t38properties t38;               /*!< T38 settings */
        struct sockaddr_in udptlredirip;        /*!< Where our T.38 UDPTL should be going if not to us */
        struct ast_udptl *udptl;                /*!< T.38 UDPTL session */
@@ -2513,6 +2514,32 @@ static struct sip_peer *ref_peer(struct sip_peer *peer, char *tag)
        return peer;
 }
 
+/*! \brief maintain proper refcounts for a sip_pvt's outboundproxy
+ *
+ * This function sets pvt's outboundproxy pointer to the one referenced
+ * by the proxy parameter. Because proxy may be a refcounted object, and
+ * because pvt's old outboundproxy may also be a refcounted object, we need
+ * to maintain the proper refcounts.
+ *
+ * \param pvt The sip_pvt for which we wish to set the outboundproxy
+ * \param proxy The sip_proxy which we will point pvt towards.
+ * \return Returns void
+ */
+static void ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy)
+{
+       struct sip_proxy *old_obproxy = pvt->outboundproxy;
+       /* The global_outboundproxy is statically allocated, and so
+        * we don't ever need to adjust refcounts for it
+        */
+       if (proxy && proxy != &global_outboundproxy) {
+               ao2_ref(proxy, +1);
+       }
+       pvt->outboundproxy = proxy;
+       if (old_obproxy && old_obproxy != &global_outboundproxy) {
+               ao2_ref(old_obproxy, -1);
+       }
+}
+
 /*!
  * \brief Unlink a dialog from the dialogs container, as well as any other places
  * that it may be currently stored.
@@ -2647,7 +2674,7 @@ static int proxy_update(struct sip_proxy *proxy)
 static struct sip_proxy *proxy_allocate(char *name, char *port, int force)
 {
        struct sip_proxy *proxy;
-       proxy = ast_calloc(1, sizeof(*proxy));
+       proxy = ao2_alloc(sizeof(*proxy), NULL);
        if (!proxy)
                return NULL;
        proxy->force = force;
@@ -3303,8 +3330,9 @@ static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
          If obforcing is set, we will keep the outbound proxy during the whole
          dialog, regardless of what the SIP rfc says
        */
-       if (p->outboundproxy && !p->outboundproxy->force)
-               p->outboundproxy = NULL;
+       if (p->outboundproxy && !p->outboundproxy->force){
+               ref_proxy(p, NULL);
+       }
 
        for (cur = p->packets; cur; prev = cur, cur = cur->next) {
                if (cur->seqno != seqno || cur->is_resp != resp)
@@ -3839,7 +3867,7 @@ static void sip_destroy_peer(struct sip_peer *peer)
 {
        ast_debug(3, "Destroying SIP peer %s\n", peer->name);
        if (peer->outboundproxy)
-               ast_free(peer->outboundproxy);
+               ao2_ref(peer->outboundproxy, -1);
        peer->outboundproxy = NULL;
 
        /* Delete it, it needs to disappear */
@@ -4322,7 +4350,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        ast_string_field_set(dialog, fullcontact, peer->fullcontact);
        ast_string_field_set(dialog, context, peer->context);
        ast_string_field_set(dialog, parkinglot, peer->parkinglot);
-       dialog->outboundproxy = obproxy_get(dialog, peer);
+       ref_proxy(dialog, obproxy_get(dialog, peer));
        dialog->callgroup = peer->callgroup;
        dialog->pickupgroup = peer->pickupgroup;
        dialog->allowtransfer = peer->allowtransfer;
@@ -4418,7 +4446,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd
        ast_string_field_set(dialog, tohost, peername);
 
        /* Get the outbound proxy information */
-       dialog->outboundproxy = obproxy_get(dialog, NULL);
+       ref_proxy(dialog, obproxy_get(dialog, NULL));
 
        /* If we have an outbound proxy, don't bother with DNS resolution at all */
        if (dialog->outboundproxy)
@@ -9478,7 +9506,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
                return -1;
        }
 
-       mwi->call->outboundproxy = obproxy_get(mwi->call, NULL);
+       ref_proxy(mwi->call, obproxy_get(mwi->call, NULL));
 
        if (!mwi->us.sin_port && mwi->portno) {
                mwi->us.sin_port = htons(mwi->portno);
@@ -10045,7 +10073,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
                if (p->do_history)
                        append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
 
-               p->outboundproxy = obproxy_get(p, NULL);
+               ref_proxy(p, obproxy_get(p, NULL));
 
                /* Use port number specified if no SRV record was found */
                if (!r->us.sin_port && r->portno)