static void set_peer_defaults(struct sip_peer *peer);
static struct sip_peer *temp_peer(const char *name);
static void register_peer_exten(struct sip_peer *peer, int onoff);
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime);
+static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only);
static struct sip_user *find_user(const char *name, int realtime);
static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
static int expire_register(const void *data);
static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey);
static struct sip_user *realtime_user(const char *username);
static void update_peer(struct sip_peer *p, int expiry);
-static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
+static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only);
static int sip_prune_realtime(int fd, int argc, char *argv[]);
/*--- Internal UA client handling (outbound registrations) */
* \todo Consider adding check of port address when matching here to follow the same
* algorithm as for static peers. Will we break anything by adding that?
*/
-static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin)
+static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin, int devstate_only)
{
struct sip_peer *peer=NULL;
struct ast_variable *var = NULL;
return NULL;
}
- if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
+ if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) && !devstate_only) {
/* Cache peer */
ast_copy_flags(&peer->flags[1],&global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
/*! \brief Locate peer by name or ip address
* This is used on incoming SIP message to find matching peer on ip
or outgoing message to find matching peer on name */
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
+static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only)
{
struct sip_peer *p = NULL;
else
p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp);
- if (!p && realtime)
- p = realtime_peer(peer, sin);
+ if (!p && (realtime || devstate_only))
+ p = realtime_peer(peer, sin, devstate_only);
return p;
}
*port++ = '\0';
dialog->sa.sin_family = AF_INET;
dialog->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
- p = find_peer(peer, NULL, 1);
+ p = find_peer(peer, NULL, 1, 0);
if (p) {
int res = create_addr_from_peer(dialog, p);
inuse = &u->inUse;
call_limit = &u->call_limit;
inringing = NULL;
- } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1) ) ) { /* Try to find peer */
+ } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1, 0) ) ) { /* Try to find peer */
inuse = &p->inUse;
call_limit = &p->call_limit;
inringing = &p->inRinging;
return TRUE;
}
-/*! \brief Change the other partys IP address based on given contact */
-static int set_address_from_contact(struct sip_pvt *pvt)
+static int __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin)
{
struct hostent *hp;
struct ast_hostent ahp;
char contact_buf[256];
char *contact;
- if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
- /* NAT: Don't trust the contact field. Just use what they came to us
- with. */
- pvt->sa = pvt->recv;
- return 0;
- }
-
/* Work on a copy */
- ast_copy_string(contact_buf, pvt->fullcontact, sizeof(contact_buf));
+ ast_copy_string(contact_buf, fullcontact, sizeof(contact_buf));
contact = contact_buf;
/* Make sure it's a SIP URL */
ast_log(LOG_WARNING, "Invalid host name in Contact: (can't resolve in DNS) : '%s'\n", host);
return -1;
}
- pvt->sa.sin_family = AF_INET;
- memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
- pvt->sa.sin_port = htons(port);
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
+ sin->sin_port = htons(port);
return 0;
}
+/*! \brief Change the other partys IP address based on given contact */
+static int set_address_from_contact(struct sip_pvt *pvt)
+{
+ if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
+ /* NAT: Don't trust the contact field. Just use what they came to us
+ with. */
+ pvt->sa = pvt->recv;
+ return 0;
+ }
+
+ return __set_address_from_contact(pvt->fullcontact, &pvt->sa);
+}
+
/*! \brief Parse contact header and save registration (peer registration) */
static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
/*! \brief Change onhold state of a peer using a pvt structure */
static void sip_peer_hold(struct sip_pvt *p, int hold)
{
- struct sip_peer *peer = find_peer(p->peername, NULL, 1);
+ struct sip_peer *peer = find_peer(p->peername, NULL, 1, 0);
if (!peer)
return;
ast_string_field_set(p, exten, name);
build_contact(p);
- peer = find_peer(name, NULL, 1);
+ peer = find_peer(name, NULL, 1, 0);
if (!(peer && ast_apply_ha(peer->ha, sin))) {
/* Peer fails ACL check */
if (peer) {
/* If we didn't find a user match, check for peers */
if (sipmethod == SIP_SUBSCRIBE)
/* For subscribes, match on peer name only */
- peer = find_peer(of, NULL, 1);
+ peer = find_peer(of, NULL, 1, 0);
else
/* Look for peer based on the IP address we received data from */
/* If peer is registered from this IP address or have this as a default
IP address, this call is from the peer
*/
- peer = find_peer(NULL, &p->recv, 1);
+ peer = find_peer(NULL, &p->recv, 1, 0);
if (peer) {
/* Set Frame packetization */
return RESULT_SHOWUSAGE;
load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
- peer = find_peer(argv[3], NULL, load_realtime);
+ peer = find_peer(argv[3], NULL, load_realtime, 0);
if (s) { /* Manager */
if (peer) {
const char *id = astman_get_header(m,"ActionID");
struct sip_peer *peer;
if (argc != 5)
return RESULT_SHOWUSAGE;
- peer = find_peer(argv[4], NULL, 1);
+ peer = find_peer(argv[4], NULL, 1, 0);
if (peer) {
if (peer->addr.sin_addr.s_addr) {
debugaddr.sin_family = AF_INET;
else
colname = "ip";
- if (!(peer = find_peer(data, NULL, 1)))
+ if (!(peer = find_peer(data, NULL, 1, 0)))
return -1;
if (!strcasecmp(colname, "ip")) {
* load it BACK into memory, thus defeating the point of trying to trying to
* clear dead hosts out of memory.
*/
- if ((p = find_peer(host, NULL, 0))) {
+ if ((p = find_peer(host, NULL, 0, 1))) {
if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) {
/* we have an address for the peer */
}
if (!ast_strlen_zero(fullcontact)) {
ast_copy_string(peer->fullcontact, fullcontact, sizeof(peer->fullcontact));
+ /* We have a hostname in the fullcontact, but if we don't have an
+ * address listed on the entry (or if it's 'dynamic'), then we need to
+ * parse the entry to obtain the IP address, so a dynamic host can be
+ * contacted immediately after reload (as opposed to waiting for it to
+ * register once again). */
+ __set_address_from_contact(fullcontact, &peer->addr);
}
if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE) && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) && realtime) {