Index: chan_sip.c===================================================================--- chan_sip.c (.../tags/1.2.18/channels/chan_sip.c) (revision 143963)+++ chan_sip.c (.../branches/1.2/channels/chan_sip.c) (revision 143963)@@ -78,7 +78,6 @@ #include "asterisk/utils.h" #include "asterisk/file.h" #include "asterisk/astobj.h"-#include "asterisk/dnsmgr.h" #include "asterisk/devicestate.h" #include "asterisk/linkedlists.h"@@ -788,7 +787,6 @@ int rtpkeepalive; /*!< Send RTP packets for keepalive */ ast_group_t callgroup; /*!< Call group */ ast_group_t pickupgroup; /*!< Pickup group */- struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */ struct sockaddr_in addr; /*!< IP address of peer */ /* Qualification */@@ -1671,8 +1669,6 @@ speerobjs--; clear_realm_authentication(peer->auth); peer->auth = (struct sip_auth *) NULL;- if (peer->dnsmgr)- ast_dnsmgr_release(peer->dnsmgr); free(peer); }@@ -1692,22 +1688,47 @@ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin) { struct sip_peer *peer=NULL;- struct ast_variable *var;+ struct ast_variable *var = NULL; struct ast_variable *tmp; char *newpeername = (char *) peername; char iabuf[80]; /* First check on peer name */- if (newpeername) - var = ast_load_realtime("sippeers", "name", peername, NULL);- else if (sin) { /* Then check on IP address */+ if (newpeername) {+ var = ast_load_realtime("sippeers", "name", newpeername, "host", "dynamic", NULL);+ if (!var && sin)+ var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), NULL);+ if (!var) {+ var = ast_load_realtime("sippeers", "name", newpeername, NULL);+ /*!\note+ * If this one loaded something, then we need to ensure that the host+ * field matched. The only reason why we can't have this as a criteria+ * is because we only have the IP address and the host field might be+ * set as a name (and the reverse PTR might not match).+ */+ if (var) {+ for (tmp = var; tmp; tmp = tmp->next) {+ if (!strcasecmp(var->name, "host")) {+ struct hostent *hp;+ struct ast_hostent ahp;+ if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(&hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {+ /* No match */+ ast_variables_destroy(var);+ var = NULL;+ }+ break;+ }+ }+ }+ }+ }++ if (!var && sin) { /* Then check on IP address */ ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr); var = ast_load_realtime("sippeers", "host", iabuf, NULL); /* First check for fixed IP hosts */ if (!var) var = ast_load_realtime("sippeers", "ipaddr", iabuf, NULL); /* Then check for registred hosts */- - } else- return NULL;+ } if (!var) return NULL;@@ -1893,7 +1914,7 @@ ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(r->vrtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); }- ast_copy_string(r->peername, peer->username, sizeof(r->peername));+ ast_copy_string(r->peername, peer->name, sizeof(r->peername)); ast_copy_string(r->authname, peer->username, sizeof(r->authname)); ast_copy_string(r->username, peer->username, sizeof(r->username)); ast_copy_string(r->peersecret, peer->secret, sizeof(r->peersecret));@@ -1915,6 +1936,8 @@ ast_copy_string(r->fromdomain, peer->fromdomain, sizeof(r->fromdomain)); if (!ast_strlen_zero(peer->fromuser)) ast_copy_string(r->fromuser, peer->fromuser, sizeof(r->fromuser));+ if (!ast_strlen_zero(peer->language))+ ast_copy_string(r->language, peer->language, sizeof(r->language)); r->maxtime = peer->maxms; r->callgroup = peer->callgroup; r->pickupgroup = peer->pickupgroup;@@ -2880,6 +2903,11 @@ pbx_builtin_setvar_helper(tmp, "OSPPEER", peer); #endif ast_setstate(tmp, state);++ /* Set channel variables for this call from configuration */+ for (v = i->chanvars ; v ; v = v->next)+ pbx_builtin_setvar_helper(tmp, v->name, v->value);+ if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);@@ -2887,10 +2915,7 @@ tmp = NULL; } }- /* Set channel variables for this call from configuration */- for (v = i->chanvars ; v ; v = v->next)- pbx_builtin_setvar_helper(tmp,v->name,v->value);- + ast_mutex_lock(&usecnt_lock); usecnt++; ast_mutex_unlock(&usecnt_lock);@@ -3041,7 +3066,7 @@ return &null_frame; if (p->owner) { /* We already hold the channel lock */- if (f->frametype == AST_FRAME_VOICE) {+ if (f && f->frametype == AST_FRAME_VOICE) { if (f->subclass != p->owner->nativeformats) { if (!(f->subclass & p->jointcapability)) { ast_log(LOG_DEBUG, "Bogus frame of format '%s' received from '%s'!\n",@@ -3180,6 +3205,7 @@ p->capability = global_capability; if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833) || (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_AUTO)) p->noncodeccapability |= AST_RTP_DTMF;+ p->jointnoncodeccapability = p->noncodeccapability; strcpy(p->context, default_context); /* Add to active dialog list */@@ -4066,9 +4092,9 @@ ++h; else { h = uri;- if (strncmp(h, "sip:", 4) == 0)+ if (strncasecmp(h, "sip:", 4) == 0) h += 4;- else if (strncmp(h, "sips:", 5) == 0)+ else if (strncasecmp(h, "sips:", 5) == 0) h += 5; } hn = strcspn(h, ":;>") + 1;@@ -4492,6 +4518,9 @@ if (codec == AST_FORMAT_G729A) /* Indicate that we don't support VAD (G.729 annex B) */ ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);+ else if (codec == AST_FORMAT_G723_1)+ /* Indicate that we don't support VAD (G.723.1 annex A) */+ ast_build_string(a_buf, a_size, "a=fmtp:%d annexa=no\r\n", rtp_code); } static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,@@ -4717,6 +4746,8 @@ dst->header[x] += offset; for (x=0; x < src->lines; x++) dst->line[x] += offset;+ dst->rlPart1 += offset;+ dst->rlPart2 += offset; } /*! \brief transmit_response_with_sdp: Used for 200 OK and 183 early media ---*/@@ -5228,17 +5259,20 @@ /* Check which device/devices we are watching and if they are registered */ if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {- /* If they are not registered, we will override notification and show no availability */- if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) {- local_state = NOTIFY_CLOSED;- pidfstate = "away";- pidfnote = "Not online";+ char *hint2 = hint, *individual_hint = NULL;+ while ((individual_hint = strsep(&hint2, "&"))) {+ /* If they are not registered, we will override notification and show no availability */+ if (ast_device_state(individual_hint) == AST_DEVICE_UNAVAILABLE) {+ local_state = NOTIFY_CLOSED;+ pidfstate = "away";+ pidfnote = "Not online";+ } } } ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from)); c = get_in_brackets(from);- if (strncmp(c, "sip:", 4)) {+ if (strncasecmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); return -1; }@@ -5248,7 +5282,7 @@ ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to)); c = get_in_brackets(to);- if (strncmp(c, "sip:", 4)) {+ if (strncasecmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); return -1; }@@ -5746,7 +5780,7 @@ ast_copy_string(from, of, sizeof(from)); of = get_in_brackets(from); ast_copy_string(p->from,of,sizeof(p->from));- if (strncmp(of, "sip:", 4)) {+ if (strncasecmp(of, "sip:", 4)) { ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n"); } else of += 4;@@ -6136,10 +6170,8 @@ memcpy(&p->addr, &pvt->recv, sizeof(p->addr)); }- if (c) /* Overwrite the default username from config at registration */+ if (c && ast_strlen_zero(p->username)) ast_copy_string(p->username, c, sizeof(p->username));- else- p->username[0] = '\0'; if (p->expire > -1) { ast_sched_del(sched, p->expire);@@ -6549,6 +6581,8 @@ { struct sip_pvt *p = data;+ ast_mutex_lock(&p->lock);+ switch(state) { case AST_EXTENSION_DEACTIVATED: /* Retry after a while */ case AST_EXTENSION_REMOVED: /* Extension is gone */@@ -6568,6 +6602,9 @@ if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->username);++ ast_mutex_unlock(&p->lock);+ return 0; }@@ -6607,7 +6644,7 @@ if (name) *name = '\0';- if (!strncmp(c, "sip:", 4)) {+ if (!strncasecmp(c, "sip:", 4)) { name = c + 4; } else { name = c;@@ -6636,10 +6673,12 @@ if (peer) ASTOBJ_UNREF(peer,sip_destroy_peer); peer = NULL;+ res = -4; } if (peer) { if (!ast_test_flag(&peer->flags_page2, SIP_PAGE2_DYNAMIC)) { ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);+ res = -5; } else { ast_copy_flags(p, peer, SIP_NAT); transmit_response(p, "100 Trying", req);@@ -6713,22 +6752,20 @@ proper authentication by digest auth name */ transmit_response(p, "403 Authentication user name does not match account name", &p->initreq); break;- case -3:+ case -3: /* Unknown domain */+ case -4: /* ACL error */+ case -5: /* Peer is not supposed to register with us at all */ if (global_alwaysauthreject) { transmit_fake_auth_response(p, &p->initreq, p->randdata, sizeof(p->randdata), 1); } else { /* URI not found */- transmit_response(p, "404 Not found", &p->initreq);+ if (res == -5)+ transmit_response(p, "403 Forbidden", &p->initreq);+ else+ transmit_response(p, "404 Not found", &p->initreq); }- /* Set res back to -2 because we don't want to return an invalid domain message. That check already happened up above. */- res = -2; break; }- if (option_debug > 1) {- ast_log(LOG_DEBUG, "SIP REGISTER attempt failed for %s : %s\n",- peer->name,- (res == -1) ? "Bad password" : ((res == -2 ) ? "Bad digest user" : "Peer not found"));- } } if (peer) ASTOBJ_UNREF(peer,sip_destroy_peer);@@ -6749,7 +6786,7 @@ if (ast_strlen_zero(tmp)) return 0; c = get_in_brackets(tmp);- if (strncmp(c, "sip:", 4)) {+ if (strncasecmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not an RDNIS SIP header (%s)?\n", c); return -1; }@@ -6783,23 +6820,25 @@ from = get_in_brackets(tmpf);- if (strncmp(uri, "sip:", 4)) {+ if (strncasecmp(uri, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", uri); return -1; } uri += 4; if (!ast_strlen_zero(from)) {- if (strncmp(from, "sip:", 4)) {+ if (strncasecmp(from, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", from); return -1; } from += 4;+ if (pedanticsipchecking) {+ ast_uri_decode(from);+ } } else from = NULL; if (pedanticsipchecking) { ast_uri_decode(uri);- ast_uri_decode(from); } /* Get the target domain first and user */@@ -6931,12 +6970,12 @@ } h_contact = get_header(req, "Contact");- if (strncmp(refer_to, "sip:", 4)) {+ if (strncasecmp(refer_to, "sip:", 4)) { ast_log(LOG_WARNING, "Refer-to: Huh? Not a SIP header (%s)?\n", refer_to); return -1; }- if (strncmp(referred_by, "sip:", 4)) {+ if (strncasecmp(referred_by, "sip:", 4)) { ast_log(LOG_WARNING, "Referred-by: Huh? Not a SIP header (%s) Ignoring?\n", referred_by); referred_by = NULL; }@@ -7052,7 +7091,7 @@ c = get_in_brackets(tmp);- if (strncmp(c, "sip:", 4)) {+ if (strncasecmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); return -1; }@@ -7224,11 +7263,10 @@ while(*t && (*t > 32) && (*t != ';')) t++; *t = '\0';- of = get_header(req, "From");++ ast_copy_string(from, get_header(req, "From"), sizeof(from)); if (pedanticsipchecking)- ast_uri_decode(of);-- ast_copy_string(from, of, sizeof(from));+ ast_uri_decode(from); memset(calleridname,0,sizeof(calleridname)); get_calleridname(from, calleridname, sizeof(calleridname));@@ -7243,7 +7281,7 @@ of = get_in_brackets(from); if (ast_strlen_zero(p->exten)) { t = uri2;- if (!strncmp(t, "sip:", 4))+ if (!strncasecmp(t, "sip:", 4)) t+= 4; ast_copy_string(p->exten, t, sizeof(p->exten)); t = strchr(p->exten, '@');@@ -7254,7 +7292,7 @@ } /* save the URI part of the From header */ ast_copy_string(p->from, of, sizeof(p->from));- if (strncmp(of, "sip:", 4)) {+ if (strncasecmp(of, "sip:", 4)) { ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n"); } else of += 4;@@ -7266,8 +7304,6 @@ ast_copy_string(p->cid_num, of, sizeof(p->cid_num)); ast_shrink_phone_number(p->cid_num); }- if (ast_strlen_zero(of))- return 0; if (!mailbox) /* If it's a mailbox SUBSCRIBE, don't check users */ user = find_user(of, 1);@@ -7466,6 +7502,11 @@ ast_copy_flags(p, &global_flags, SIP_OSPAUTH); res = check_auth(p, req, p->randdata, sizeof(p->randdata), "", "", "", sipmethod, uri2, reliable, ignore); #endif+ } else if (!ast_strlen_zero(rpid_num) && ast_test_flag(p, SIP_TRUSTRPID)) {+ if (*calleridname)+ ast_copy_string(p->cid_name, calleridname, sizeof(p->cid_name));+ ast_copy_string(p->cid_num, rpid_num, sizeof(p->cid_num));+ ast_shrink_phone_number(p->cid_num); } }@@ -9663,8 +9704,10 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req) { char tmp[256];- char *s, *e;+ char *s, *e, *t; ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));+ if ((t = strchr(tmp, ',')))+ *t = '\0'; s = get_in_brackets(tmp); e = strchr(s, ';'); if (e)@@ -9866,10 +9909,15 @@ This transaction is already scheduled to be killed by sip_hangup(). */ transmit_request(p, SIP_ACK, seqno, 0, 0);- if (p->owner && !ignore)+ if (p->owner && !ignore) { ast_queue_hangup(p->owner);- else if (!ignore)+ append_history(p, "Hangup", "Got 487 on CANCEL request from us. Queued AST hangup request");+ } else if (!ignore) { update_call_counter(p, DEC_CALL_LIMIT);+ append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog.");+ ast_set_flag(p, SIP_NEEDDESTROY); + ast_set_flag(p, SIP_ALREADYGONE); + } break; case 491: /* Pending */ /* we have to wait a while, then retransmit */@@ -10171,10 +10219,11 @@ if (sipmethod == SIP_INVITE) { handle_response_invite(p, resp, rest, req, ignore, seqno); } else if (sipmethod == SIP_BYE || sipmethod == SIP_REFER) {- if (ast_strlen_zero(p->authname))+ if (ast_strlen_zero(p->authname)) { ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n", msg, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port)); ast_set_flag(p, SIP_NEEDDESTROY); + } if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", sipmethod, 0)) { ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From")); ast_set_flag(p, SIP_NEEDDESTROY); @@ -10581,6 +10630,7 @@ char *supported; char *required; unsigned int required_profile = 0;+ int reinvite = 0; /* Find out what they support */ if (!p->sipoptions) {@@ -10721,6 +10771,7 @@ } else { if (option_debug > 1 && sipdebug) ast_log(LOG_DEBUG, "Got a SIP re-invite for call %s\n", p->callid);+ reinvite = 1; c = p->owner; } if (!ignore && p)@@ -10797,7 +10848,8 @@ transmit_response(p, "180 Ringing", req); break; case AST_STATE_UP:- transmit_response_with_sdp(p, "200 OK", req, 1);+ /* If this is not a re-invite or something to ignore - it's critical */+ transmit_response_with_sdp(p, "200 OK", req, (ignore || reinvite) ? 1 : 2); break; default: ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state);@@ -10894,6 +10946,10 @@ check_via(p, req); ast_set_flag(p, SIP_ALREADYGONE); ++ if (ast_test_flag(p, SIP_INC_COUNT)) + update_call_counter(p, DEC_CALL_LIMIT);+ if (p->rtp) { /* Immediately stop RTP */ ast_rtp_stop(p->rtp);@@ -11160,8 +11216,11 @@ ast_set_flag(p, SIP_NEEDDESTROY); return 0; }- if (p->subscribed != NONE)+ if (p->subscribed != NONE) {+ if (p->stateid > -1)+ ast_extension_state_del(p->stateid, cb_extensionstate); p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p);+ } } }@@ -11238,8 +11297,24 @@ ast_verbose("Using latest REGISTER request as basis request\n"); copy_request(&p->initreq, req); check_via(p, req);- if ((res = register_verify(p, sin, req, e, ignore)) < 0) - ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), (res == -1) ? "Wrong password" : (res == -2 ? "Username/auth name mismatch" : "Not a local SIP domain"));+ if ((res = register_verify(p, sin, req, e, ignore)) < 0) {+ const char *error;+ switch (res) {+ case -1: error = "Wrong password";+ break;+ case -2: error = "Username/auth name mismatch";+ break;+ case -3: error = "Not a local SIP domain";+ break;+ case -4: error = "ACL error (permit/deny)";+ break;+ case -5: error = "Peer is not supposed to register";+ break;+ default: error = "Unknown error";+ break;+ }+ ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), error);+ } if (res < 1) { /* Destroy the session, but keep us around for just a bit in case they don't get our 200 OK */@@ -11557,6 +11632,10 @@ struct sip_pvt *p; int newmsgs, oldmsgs;+ /* Do we have an IP address? If not, skip this peer */+ if (!peer->addr.sin_addr.s_addr && !peer->defaddr.sin_addr.s_addr) + return 0;+ /* Check for messages */ ast_app_messagecount(peer->mailbox, &newmsgs, &oldmsgs);@@ -11621,8 +11700,12 @@ sip_do_reload(); /* Change the I/O fd of our UDP socket */- if (sipsock > -1)- sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL);+ if (sipsock > -1) {+ if (sipsock_read_id)+ sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL);+ else+ sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);+ } } /* Check for interfaces needing to be killed */ ast_mutex_lock(&iflock);@@ -12461,6 +12544,9 @@ ast_variables_destroy(peer->chanvars); peer->chanvars = NULL; }+ /* If we have realm authentication information, remove them (reload) */+ clear_realm_authentication(peer->auth);+ peer->auth = (struct sip_auth *) NULL; strcpy(peer->context, default_context); strcpy(peer->subscribecontext, default_subscribecontext); strcpy(peer->vmexten, global_vmexten);@@ -12697,6 +12783,7 @@ /* Reset IP addresses */ memset(&bindaddr, 0, sizeof(bindaddr));+ ast_free_ha(localaddr); memset(&localaddr, 0, sizeof(localaddr)); memset(&externip, 0, sizeof(externip)); memset(&prefs, 0 , sizeof(prefs));@@ -12974,6 +13061,7 @@ if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) { peer = build_peer(cat, ast_variable_browse(cfg, cat), 0); if (peer) {+ ast_device_state_changed("SIP/%s", peer->name); ASTOBJ_CONTAINER_LINK(&peerl,peer); ASTOBJ_UNREF(peer, sip_destroy_peer); }@@ -13358,7 +13446,7 @@ ast_log(LOG_ERROR, "Cannot retrieve the 'To' header from the original SIP request!\n"); return 0; }- if ((localtmp = strstr(tmp, "sip:")) && (localtmp = strchr(localtmp, '@'))) {+ if ((localtmp = strcasestr(tmp, "sip:")) && (localtmp = strchr(localtmp, '@'))) { char lhost[80], lport[80]; memset(lhost, 0, sizeof(lhost)); memset(lport, 0, sizeof(lport));