Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 258227) +++ channels/chan_sip.c (working copy) @@ -11511,8 +11511,7 @@ struct sip_pvt *p; struct sip_peer *peer = NULL; int res; - char *fromdomain; - char *domainport = NULL; + int portno = 0; /* exit if we are already in process with this registrar ?*/ if (r == NULL || ((auth == NULL) && (r->regstate == REG_STATE_REGSENT || r->regstate == REG_STATE_AUTHSENT))) { @@ -11593,12 +11592,13 @@ /* Copy back Call-ID in case create_addr changed it */ ast_string_field_set(r, callid, p->callid); + if (!r->dnsmgr && r->portno) { p->sa.sin_port = htons(r->portno); p->recv.sin_port = htons(r->portno); - } else { /* Set registry port to the port set from the peer definition/srv or default */ - r->portno = ntohs(p->sa.sin_port); } + portno = (r->regdomainport) ? r->regdomainport : ntohs(p->sa.sin_port); + ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Registration is outgoing call */ r->call = dialog_ref(p, "copying dialog into registry r->call"); /* Save pointer to SIP dialog */ p->registry = registry_addref(r, "transmit_register: addref to p->registry in transmit_register"); /* Add pointer to registry in packet */ @@ -11649,55 +11649,21 @@ ast_debug(1, "Scheduled a registration timeout for %s id #%d \n", r->hostname, r->timeout); } - if ((fromdomain = strchr(r->username, '@'))) { - /* the domain name is just behind '@' */ - fromdomain++ ; - /* We have a domain in the username for registration */ - snprintf(from, sizeof(from), ";tag=%s", r->username, p->tag); - if (!ast_strlen_zero(p->theirtag)) - snprintf(to, sizeof(to), ";tag=%s", r->username, p->theirtag); - else - snprintf(to, sizeof(to), "", r->username); - - /* If the registration username contains '@', then the domain should be used as - the equivalent of "fromdomain" for the registration */ - if (ast_strlen_zero(p->fromdomain)) { - ast_string_field_set(p, fromdomain, fromdomain); - } + snprintf(from, sizeof(from), ";tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->tag); + if (!ast_strlen_zero(p->theirtag)) { + snprintf(to, sizeof(to), ";tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->theirtag); } else { - snprintf(from, sizeof(from), ";tag=%s", r->username, p->tohost, p->tag); - if (!ast_strlen_zero(p->theirtag)) - snprintf(to, sizeof(to), ";tag=%s", r->username, p->tohost, p->theirtag); - else - snprintf(to, sizeof(to), "", r->username, p->tohost); + snprintf(to, sizeof(to), "", r->username, S_OR(r->regdomain,p->tohost)); } /* Fromdomain is what we are registering to, regardless of actual host name from SRV */ - if (!ast_strlen_zero(p->fromdomain)) { - domainport = strrchr(p->fromdomain, ':'); - if (domainport) { - *domainport++ = '\0'; /* trim off domainport from p->fromdomain */ - if (ast_strlen_zero(domainport)) - domainport = NULL; - } - if (domainport) { - if (atoi(domainport) != STANDARD_SIP_PORT) - snprintf(addr, sizeof(addr), "sip:%s:%s", p->fromdomain, domainport); - else - snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); - } else { - if (r->portno && r->portno != STANDARD_SIP_PORT) - snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno); - else - snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); - } + if (portno && portno != STANDARD_SIP_PORT) { + snprintf(addr, sizeof(addr), "sip:%s:%d", S_OR(r->regdomain,S_OR(p->fromdomain,r->hostname)), portno); } else { - if (r->portno && r->portno != STANDARD_SIP_PORT) - snprintf(addr, sizeof(addr), "sip:%s:%d", r->hostname, r->portno); - else - snprintf(addr, sizeof(addr), "sip:%s", r->hostname); + snprintf(addr, sizeof(addr), "sip:%s", S_OR(r->regdomain,S_OR(p->fromdomain,r->hostname))); } + ast_string_field_set(p, uri, addr); p->branch ^= ast_random(); @@ -11732,7 +11698,7 @@ ast_debug(1, " >>> Re-using Auth data for %s@%s\n", r->username, r->hostname); ast_string_field_set(p, realm, r->realm); ast_string_field_set(p, nonce, r->nonce); - ast_string_field_set(p, domain, r->domain); + ast_string_field_set(p, domain, r->authdomain); ast_string_field_set(p, opaque, r->opaque); ast_string_field_set(p, qop, r->qop); p->noncecount = ++r->noncecount; @@ -14627,11 +14593,21 @@ "Host: %s\r\n" "Port: %d\r\n" "Username: %s\r\n" + "Domain: %s\r\n" + "DomainPort: %d\r\n" "Refresh: %d\r\n" "State: %s\r\n" "RegistrationTime: %ld\r\n" - "\r\n", idtext, iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT, - iterator->username, iterator->refresh, regstate2str(iterator->regstate), (long) iterator->regtime.tv_sec); + "\r\n", + idtext, + iterator->hostname, + iterator->portno ? iterator->portno : STANDARD_SIP_PORT, + iterator->username, + S_OR(iterator->regdomain,iterator->hostname), + iterator->regdomainport ? iterator->regdomainport : STANDARD_SIP_PORT, + iterator->refresh, + regstate2str(iterator->regstate), + (long) iterator->regtime.tv_sec); ASTOBJ_UNLOCK(iterator); total++; } while(0)); @@ -15803,6 +15779,7 @@ #define FORMAT2 "%-30.30s %-6.6s %-12.12s %8.8s %-20.20s %-25.25s\n" #define FORMAT "%-30.30s %-6.6s %-12.12s %8d %-20.20s %-25.25s\n" char host[80]; + char user[80]; char tmpdat[256]; struct ast_tm tm; int counter = 0; @@ -15825,12 +15802,15 @@ ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do { ASTOBJ_RDLOCK(iterator); snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT); + snprintf(user, sizeof(user), "%s", iterator->username); + if (iterator->regdomain) {snprintf(user, sizeof(user), "%s@%s", user, iterator->regdomain);} + if (iterator->regdomainport) {snprintf(user, sizeof(user), "%s:%d", user, iterator->regdomainport);} if (iterator->regtime.tv_sec) { ast_localtime(&iterator->regtime, &tm, NULL); ast_strftime(tmpdat, sizeof(tmpdat), "%a, %d %b %Y %T", &tm); } else tmpdat[0] = '\0'; - ast_cli(a->fd, FORMAT, host, (iterator->dnsmgr) ? "Y" : "N", iterator->username, iterator->refresh, regstate2str(iterator->regstate), tmpdat); + ast_cli(a->fd, FORMAT, host, (iterator->dnsmgr) ? "Y" : "N", user, iterator->refresh, regstate2str(iterator->regstate), tmpdat); ASTOBJ_UNLOCK(iterator); counter++; } while(0)); @@ -17161,7 +17141,7 @@ if (strcmp(r->nonce, p->nonce)) { ast_string_field_set(r, realm, p->realm); ast_string_field_set(r, nonce, p->nonce); - ast_string_field_set(r, domain, p->domain); + ast_string_field_set(r, authdomain, p->domain); ast_string_field_set(r, opaque, p->opaque); ast_string_field_set(r, qop, p->qop); r->noncecount = 0; Index: channels/sip/config_parser.c =================================================================== --- channels/sip/config_parser.c (revision 258227) +++ channels/sip/config_parser.c (working copy) @@ -35,6 +35,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno) { int portnum = 0; + int domainport = 0; enum sip_transport transport = SIP_TRANSPORT_UDP; char buf[256] = ""; char *userpart = NULL, *hostpart = NULL; @@ -53,6 +54,14 @@ AST_APP_ARG(secret); AST_APP_ARG(authuser); ); + AST_DECLARE_APP_ARGS(user2, + AST_APP_ARG(user); + AST_APP_ARG(domainpart); + ); + AST_DECLARE_APP_ARGS(user3, + AST_APP_ARG(domain); + AST_APP_ARG(domainport); + ); AST_DECLARE_APP_ARGS(host1, AST_APP_ARG(hostpart); AST_APP_ARG(expiry); @@ -166,11 +175,46 @@ */ AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':'); + /*! + * pre1.peer => peer + * pre2.transport = transport + * user2.user => user + * user2.domainpart => domain + * user1.secret => secret + * user1.authuser => authuser + * host3.host => host + * host3.port => port + * host2.extension => extension + * host1.expiry => expiry + */ + AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@'); + + /*! + * pre1.peer => peer + * pre2.transport = transport + * user2.user => user + * user3.domain => domain + * user3.domainport => domainport + * user1.secret => secret + * user1.authuser => authuser + * host3.host => host + * host3.port => port + * host2.extension => extension + * host1.expiry => expiry + */ + AST_NONSTANDARD_RAW_ARGS(user3, user2.domainpart, ':'); + + if (host3.port) { if (!(portnum = port_str2int(host3.port, 0))) { ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno); } } + if (user3.domainport) { + if (!(domainport = port_str2int(user3.domainport, 0))) { + ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno); + } + } /* set transport type */ if (!pre2.transport) { @@ -197,15 +241,17 @@ /* copy into sip_registry object */ ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\"")); - ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user1.userpart, ""), "\"", "\"")); + ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\"")); ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\"")); ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user1.authuser, ""), "\"", "\"")); ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\"")); ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\"")); + ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user3.domain, ""), "\"", "\"")); reg->transport = transport; reg->timeout = reg->expire = -1; reg->portno = portnum; + reg->regdomainport = domainport; reg->callid_valid = FALSE; reg->ocseq = INITIAL_CSEQ; reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry); Index: channels/sip/include/sip.h =================================================================== --- channels/sip/include/sip.h (revision 258228) +++ channels/sip/include/sip.h (working copy) @@ -1222,22 +1222,24 @@ struct sip_registry { ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1); AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(callid); /*!< Global Call-ID */ - AST_STRING_FIELD(realm); /*!< Authorization realm */ - AST_STRING_FIELD(nonce); /*!< Authorization nonce */ - AST_STRING_FIELD(opaque); /*!< Opaque nonsense */ - AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */ - AST_STRING_FIELD(domain); /*!< Authorization domain */ - AST_STRING_FIELD(username); /*!< Who we are registering as */ - AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */ - AST_STRING_FIELD(hostname); /*!< Domain or host we register to */ - AST_STRING_FIELD(secret); /*!< Password in clear text */ - AST_STRING_FIELD(md5secret);/*!< Password in md5 */ - AST_STRING_FIELD(callback); /*!< Contact extension */ - AST_STRING_FIELD(peername); /*!< Peer registering to */ + AST_STRING_FIELD(callid); /*!< Global Call-ID */ + AST_STRING_FIELD(realm); /*!< Authorization realm */ + AST_STRING_FIELD(nonce); /*!< Authorization nonce */ + AST_STRING_FIELD(opaque); /*!< Opaque nonsense */ + AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */ + AST_STRING_FIELD(authdomain); /*!< Authorization domain */ + AST_STRING_FIELD(regdomain); /*!< Registration doamin */ + AST_STRING_FIELD(username); /*!< Who we are registering as */ + AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */ + AST_STRING_FIELD(hostname); /*!< Domain or host we register to */ + AST_STRING_FIELD(secret); /*!< Password in clear text */ + AST_STRING_FIELD(md5secret); /*!< Password in md5 */ + AST_STRING_FIELD(callback); /*!< Contact extension */ + AST_STRING_FIELD(peername); /*!< Peer registering to */ ); enum sip_transport transport; /*!< Transport for this registration UDP, TCP or TLS */ - int portno; /*!< Optional port override */ + int portno; /*!< Optional port override */ + int regdomainport; /*!< Port override for domainport */ int expire; /*!< Sched ID of expiration */ int configured_expiry; /*!< Configured value to use for the Expires header */ int expiry; /*!< Negotiated value used for the Expires header */