/*! \brief parse_register_contact: Parse contact header and save registration ---*/ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req) { char contact[80]; char data[256]; char iabuf[INET_ADDRSTRLEN]; char *expires = get_header(req, "Expires"); int expiry = atoi(expires); char *c, *n, *pt; int port; char *useragent; struct hostent *hp; struct ast_hostent ahp; struct sockaddr_in oldsin; if (ast_strlen_zero(expires)) { /* No expires header */ expires = strcasestr(get_header(req, "Contact"), ";expires="); if (expires) { char *ptr; if ((ptr = strchr(expires, ';'))) *ptr = '\0'; if (sscanf(expires + 9, "%d", &expiry) != 1) expiry = default_expiry; } else { /* Nothing has been specified */ expiry = default_expiry; } } /* Look for brackets */ ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); if (strchr(contact, '<') == NULL) { /* No <, check for ; and strip it */ char *ptr = strchr(contact, ';'); /* This is Header options, not URI options */ if (ptr) *ptr = '\0'; } c = get_in_brackets(contact); /* if they did not specify Contact: or Expires:, they are querying what we currently have stored as their contact address, so return it */ if (ast_strlen_zero(c) && ast_strlen_zero(expires)) { if ((p->expire > -1) && !ast_strlen_zero(p->fullcontact)) { /* tell them when the registration is going to expire */ pvt->expiry = ast_sched_when(sched, p->expire); return PARSE_REGISTER_QUERY; } else { return PARSE_REGISTER_FAILED; } } else if (!strcasecmp(c, "*") || !expiry) { /* Unregister this peer */ /* This means remove all registrations and return OK */ memset(&p->addr, 0, sizeof(p->addr)); if (p->expire > -1) ast_sched_del(sched, p->expire); p->expire = -1; destroy_association(p); register_peer_exten(p, 0); p->fullcontact[0] = '\0'; p->useragent[0] = '\0'; p->sipoptions = 0; p->lastms = 0; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Unregistered SIP '%s'\n", p->name); manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\n", p->name); return PARSE_REGISTER_UPDATE; } ast_copy_string(p->fullcontact, c, sizeof(p->fullcontact)); /* For the 200 OK, we should use the received contact */ snprintf(pvt->our_contact, sizeof(pvt->our_contact) - 1, "<%s>", c); /* Make sure it's a SIP URL */ if (strncasecmp(c, "sip:", 4)) { ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", c); } else c += 4; /* Ditch q */ n = strchr(c, ';'); if (n) { *n = '\0'; } /* Grab host */ n = strchr(c, '@'); if (!n) { n = c; c = NULL; } else { *n = '\0'; n++; } pt = strchr(n, ':'); if (pt) { *pt = '\0'; pt++; port = atoi(pt); } else port = DEFAULT_SIP_PORT; memcpy(&oldsin, &p->addr, sizeof(oldsin)); if (!(ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)) { /* XXX This could block for a long time XXX */ hp = ast_gethostbyname(n, &ahp); if (!hp) { ast_log(LOG_WARNING, "Invalid host '%s'\n", n); return PARSE_REGISTER_FAILED; } p->addr.sin_family = AF_INET; memcpy(&p->addr.sin_addr, hp->h_addr, sizeof(p->addr.sin_addr)); p->addr.sin_port = htons(port); } else { /* Don't trust the contact field. Just use what they came to us with */ memcpy(&p->addr, &pvt->recv, sizeof(p->addr)); } if (c) /* Overwrite the default username from config at registration */ ast_copy_string(p->username, c, sizeof(p->username)); else p->username[0] = '\0'; if (p->expire > -1) ast_sched_del(sched, p->expire); if ((expiry < 1) || (expiry > max_expiry)) expiry = max_expiry; if (!ast_test_flag(p, SIP_REALTIME)) p->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, p); else p->expire = -1; pvt->expiry = expiry; snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), expiry, p->username, p->fullcontact); if (!ast_test_flag((&p->flags_page2), SIP_PAGE2_RT_FROMCONTACT)) ast_db_put("SIP/Registry", p->name, data); manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", p->name); if (inaddrcmp(&p->addr, &oldsin)) { sip_poke_peer(p); if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s port %d expires %d\n", p->name, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port) , expiry); register_peer_exten(p, 1); } /* Save SIP options profile */ p->sipoptions = pvt->sipoptions; /* Save User agent */ useragent = get_header(req, "User-Agent"); if (useragent && strcasecmp(useragent, p->useragent)) { ast_copy_string(p->useragent, useragent, sizeof(p->useragent)); if (option_verbose > 3) { ast_log(LOG_NOTIFY, "Saved useragent \"%s\" for peer %s\n",p->useragent,p->name); } } return PARSE_REGISTER_UPDATE; }