diff -NaurbB old/chan_sip.c new/chan_sip.c --- old/chan_sip.c 2009-01-14 16:08:08.000000000 +0000 +++ new/chan_sip.c 2009-01-14 16:12:37.000000000 +0000 @@ -1951,6 +1951,7 @@ /*! \brief The peer list: Users, Peers and Friends */ struct ao2_container *peers; struct ao2_container *peers_by_ip; +struct ao2_container *peers_by_proxy; /*! \brief The register list: Other SIP proxies we register with and place calls to */ static struct ast_register_list { @@ -2000,6 +2001,25 @@ } } +static int peer_proxyhash_cb(const void *obj, const int flags) +{ + const struct sip_peer *peer = obj; + + if (!peer->outboundproxy) { + ast_log(LOG_ERROR, "peer_proxyhash_cb: no proxy so cannot generate proxyhash\n"); + return 0; + } + int ret1 = peer->outboundproxy->ip.sin_addr.s_addr; + if (ret1 < 0) + ret1 = -ret1; + + if (ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT)) { + return ret1; + } else { + return ret1 + peer->outboundproxy->ip.sin_port; + } +} + /*! * \note the peer's addr struct provides to fields combined to make a key: the sin_addr.s_addr and sin_port fields. */ @@ -2019,6 +2039,22 @@ return CMP_MATCH | CMP_STOP; } +static int peer_proxycmp_cb(void *obj, void *arg, int flags) +{ + struct sip_peer *peer = obj, *peer2 = arg; + + if ((!peer->outboundproxy) || (!peer2->outboundproxy) || (peer->outboundproxy->ip.sin_addr.s_addr != peer2->outboundproxy->ip.sin_addr.s_addr)) + return 0; + + if (!ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) && !ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) { + if (peer->outboundproxy->ip.sin_port == peer2->outboundproxy->ip.sin_port) + return CMP_MATCH | CMP_STOP; + else + return 0; + } + return CMP_MATCH | CMP_STOP; +} + /*! * \note The only member of the dialog used here callid string */ @@ -4425,6 +4461,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_link(peers_by_proxy, peer, "link peer into peers_by_proxy table"); + } } peer->is_realtime = 1; if (peerlist) @@ -4469,6 +4508,7 @@ { struct sip_peer *p = NULL; struct sip_peer tmp_peer; + struct sip_proxy tmp_proxy; if (peer) { ast_copy_string(tmp_peer.name, peer, sizeof(tmp_peer.name)); @@ -4477,19 +4517,33 @@ tmp_peer.addr.sin_addr.s_addr = sin->sin_addr.s_addr; tmp_peer.addr.sin_port = sin->sin_port; tmp_peer.flags[0].flags = 0; + tmp_peer.outboundproxy = &tmp_proxy; + tmp_proxy.ip.sin_addr.s_addr = sin->sin_addr.s_addr; + tmp_proxy.ip.sin_port = sin->sin_port; + p = ao2_t_find(peers_by_ip, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_ip table"); /* WAS: p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */ - if (!p) { + if (p) + return p; ast_set_flag(&tmp_peer.flags[0], SIP_INSECURE_PORT); p = ao2_t_find(peers_by_ip, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_ip table 2"); /* WAS: p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */ - if (p) { + if (p) + return p; + + /* see if it matches outbound proxy of a peer */ + tmp_peer.flags[0].flags = 0; + p = ao2_t_find(peers_by_proxy, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_proxy table"); + if (p) + return p; + ast_set_flag(&tmp_peer.flags[0], SIP_INSECURE_PORT); + p = ao2_t_find(peers_by_proxy, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_proxy table"); + if (p) return p; - } - } } if (!p && (realtime || devstate_only)) { p = realtime_peer(peer, sin, devstate_only); } + return p; } @@ -10966,6 +11020,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_unlink(peers_by_proxy, peer, "ao2_unlink of peer from peers_by_proxy table"); + } } unref_peer(peer, "removing peer ref for expire_register"); @@ -11863,6 +11920,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_link(peers_by_ip, peer, "link peer into peers-by-ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_link(peers_by_proxy, peer, "link peer into peers_by_proxy table"); + } if (sip_cancel_destroy(p)) ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); @@ -13876,6 +13936,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_unlink(peers_by_ip, peer, "unlinking peer from peers_by_ip also"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_unlink(peers_by_proxy, peer, "unlinking peer from peers_by_proxy also"); + } if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) { ast_cli(a->fd, "Peer '%s' is not a Realtime peer, cannot be pruned.\n", name); /* put it back! */ @@ -13883,6 +13946,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_link(peers_by_proxy, peer, "link peer into peers_by_proxy table"); + } } else ast_cli(a->fd, "Peer '%s' pruned.\n", name); @@ -23291,6 +23357,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_link(peers_by_proxy, peer, "link peer into peers_by_proxy table"); + } unref_peer(peer, "unref_peer: from reload_config"); peer_count++; @@ -23355,6 +23424,9 @@ if (peer->addr.sin_addr.s_addr) { ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table"); } + if ((peer->outboundproxy) && (peer->outboundproxy->ip.sin_addr.s_addr)) { + ao2_t_link(peers_by_proxy, peer, "link peer into peers_by_proxy table"); + } unref_peer(peer, "unref the result of the build_peer call. Now, the links from the tables are the only ones left."); peer_count++; } @@ -24097,6 +24169,7 @@ /* if the number of objects gets above MAX_XXX_BUCKETS, things will slow down */ peers = ao2_t_container_alloc(hash_peer_size, peer_hash_cb, peer_cmp_cb, "allocate peers"); peers_by_ip = ao2_t_container_alloc(hash_peer_size, peer_iphash_cb, peer_ipcmp_cb, "allocate peers_by_ip"); + peers_by_proxy = ao2_t_container_alloc(hash_peer_size, peer_proxyhash_cb, peer_proxycmp_cb, "allocate peers_by_proxy"); dialogs = ao2_t_container_alloc(hash_dialog_size, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs"); ASTOBJ_CONTAINER_INIT(®l); /* Registry object list -- not searched for anything */ @@ -24288,6 +24361,7 @@ ao2_t_ref(peers, -1, "unref the peers table"); ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); + ao2_t_ref(peers_by_proxy, -1, "unref the peers_by_proxy table"); ao2_t_ref(dialogs, -1, "unref the dialogs table"); clear_sip_domains();