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));