Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.692 diff -u -r1.692 chan_sip.c --- channels/chan_sip.c 24 Mar 2005 23:06:21 -0000 1.692 +++ channels/chan_sip.c 24 Mar 2005 23:47:21 -0000 @@ -74,6 +74,7 @@ #define DEFAULT_DEFAULT_EXPIRY 120 #define DEFAULT_MAX_EXPIRY 3600 #define DEFAULT_REGISTRATION_TIMEOUT 20 +#define DEFAULT_REGATTEMPTS_MAX 10 /* guard limit must be larger than guard secs */ /* guard min must be < 1000, and should be >= 250 */ @@ -102,7 +103,7 @@ #define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */ #define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */ -#define DEFAULT_RETRANS 1000 /* How frequently to retransmit */ +#define DEFAULT_RETRANS 2000 /* How frequently to retransmit */ #define MAX_RETRANS 5 /* Try only 5 times for retransmissions */ @@ -193,7 +194,8 @@ static int global_rtpkeepalive = 0; -static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; +static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; +static int global_regattempts_max = DEFAULT_REGATTEMPTS_MAX; /* Object counters */ static int suserobjs = 0; @@ -279,7 +281,7 @@ int headers; /* # of SIP Headers */ int method; /* Method of this request */ char *header[SIP_MAX_HEADERS]; - int lines; /* SDP Content */ + int lines; /* SDP Content */ char *line[SIP_MAX_LINES]; char data[SIP_MAX_PACKET]; }; @@ -577,6 +579,7 @@ #define REG_STATE_REJECTED 4 #define REG_STATE_TIMEOUT 5 #define REG_STATE_NOAUTH 6 +#define REG_STATE_GAVEUP 7 /* sip_registry: Registrations with other SIP proxies */ @@ -591,6 +594,7 @@ char contact[80]; /* Contact extension */ char random[80]; int expire; /* Sched ID of expiration */ + int regattempts; /* Number of attempts */ int timeout; /* sched id of sip_reg_timeout */ int refresh; /* How often to refresh */ struct sip_pvt *call; /* create a sip_pvt structure for each outbound "registration call" in progress */ @@ -748,12 +752,13 @@ { int res; char iabuf[INET_ADDRSTRLEN]; + if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); else - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); if (res != len) { - ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, strerror(errno)); + ast_log(LOG_WARNING, "Error: sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, strerror(errno)); } return res; } @@ -982,10 +987,8 @@ /* Just in case... */ char *msg; - if (sipmethod > 0) { - msg = sip_methods[sipmethod].text; - } else - msg = "___NEVER___"; + msg = sip_methods[sipmethod].text; + cur = p->packets; while(cur) { if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) && @@ -1313,9 +1316,6 @@ if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) { ast_copy_flags((&peer->flags_page2),(&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS); if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR)) { - if (peer->expire > -1) { - ast_sched_del(sched, peer->expire); - } peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_register, (void *)peer); } ASTOBJ_CONTAINER_LINK(&peerl,peer); @@ -1434,7 +1434,7 @@ /*--- create_addr: create address structure from peer definition ---*/ /* Or, if peer not found, find it in the global DNS */ -/* returns TRUE on failure, FALSE on success */ +/* returns TRUE (-1) on failure, FALSE on success */ static int create_addr(struct sip_pvt *r, char *opeer) { struct hostent *hp; @@ -1508,44 +1508,48 @@ r->sa.sin_port = p->defaddr.sin_port; } memcpy(&r->recv, &r->sa, sizeof(r->recv)); - } else { ASTOBJ_UNREF(p,sip_destroy_peer); - } - } - if (!p && !found) { - hostn = peer; - if (port) - portno = atoi(port); - else - portno = DEFAULT_SIP_PORT; - if (srvlookup) { - char service[256]; - int tportno; - int ret; - snprintf(service, sizeof(service), "_sip._udp.%s", peer); - ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service); - if (ret > 0) { - hostn = host; - portno = tportno; - } - } - hp = ast_gethostbyname(hostn, &ahp); - if (hp) { - strncpy(r->tohost, peer, sizeof(r->tohost) - 1); - memcpy(&r->sa.sin_addr, hp->h_addr, sizeof(r->sa.sin_addr)); - r->sa.sin_port = htons(portno); - memcpy(&r->recv, &r->sa, sizeof(r->recv)); return 0; } else { - ast_log(LOG_WARNING, "No such host: %s\n", peer); + + if (sipdebug) + ast_log(LOG_WARNING, "Can't reach peer (not registred, unreachable): %s\n", peer); + /* Peer unreachable */ + ASTOBJ_UNREF(p,sip_destroy_peer); return -1; } - } else if (!p) - return -1; - else { - ASTOBJ_UNREF(p,sip_destroy_peer); - return 0; } + /* No peer, check the DNS */ + hostn = peer; + if (port) + portno = atoi(port); + else + portno = DEFAULT_SIP_PORT; + + /* Do not do SRV lookup if port number is entered */ + /* RFC 3261 */ + if (srvlookup && !port) { + char service[256]; + int tportno; + int ret; + snprintf(service, sizeof(service), "_sip._udp.%s", peer); + ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service); + if (ret > 0) { + hostn = host; + portno = tportno; + } + } + hp = ast_gethostbyname(hostn, &ahp); + if (hp) { + /* Found host in DNS */ + strncpy(r->tohost, peer, sizeof(r->tohost) - 1); + memcpy(&r->sa.sin_addr, hp->h_addr, sizeof(r->sa.sin_addr)); + r->sa.sin_port = htons(portno); + memcpy(&r->recv, &r->sa, sizeof(r->recv)); + return 0; + } + ast_log(LOG_WARNING, "No such host in DNS or peer list: %s\n", peer); + return -1; } /*--- auto_congest: Scheduled congestion on a call ---*/ @@ -2485,7 +2489,7 @@ } /*--- sip_alloc: Allocate SIP_PVT structure and set defaults ---*/ -static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useglobal_nat) +static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useglobal_nat, int sipmethod) { struct sip_pvt *p; @@ -2496,6 +2500,7 @@ memset(p, 0, sizeof(struct sip_pvt)); ast_mutex_init(&p->lock); + p->method = sipmethod; p->initid = -1; p->autokillid = -1; p->stateid = -1; @@ -2540,7 +2545,8 @@ ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); } - strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1); + if (p->method != SIP_REGISTER) + strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1); build_via(p, p->via, sizeof(p->via)); if (!callid) build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); @@ -2562,7 +2568,7 @@ iflist = p; ast_mutex_unlock(&iflock); if (option_debug) - ast_log(LOG_DEBUG, "Allocating new SIP call for %s\n", callid); + ast_log(LOG_DEBUG, "Allocating new SIP call for %s\n", p->callid); return p; } @@ -2624,7 +2630,7 @@ p = p->next; } ast_mutex_unlock(&iflock); - p = sip_alloc(callid, sin, 1); + p = sip_alloc(callid, sin, 1, 0); if (p) ast_mutex_lock(&p->lock); return p; @@ -4354,6 +4360,8 @@ static char *regstate2str(int regstate) { switch(regstate) { + case REG_STATE_GAVEUP: + return "Gave up."; case REG_STATE_UNREGISTERED: return "Unregistered"; case REG_STATE_REGSENT: @@ -4417,7 +4425,7 @@ if (!r) return 0; - ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); + ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again (Try #%d)\n", r->username, r->hostname, r->regattempts); if (r->call) { /* Unlink us, destroy old call. Locking is not relevent here because all this happens in the single SIP manager thread. */ @@ -4427,12 +4435,21 @@ r->call = NULL; ast_set_flag(p, SIP_NEEDDESTROY); /* Pretend to ACK anything just in case */ + /* OEJ: Ack what??? */ __sip_pretend_ack(p); } - r->regstate=REG_STATE_UNREGISTERED; + /* If we have a limit, stop registration and give up */ + if (global_regattempts_max && r->regattempts > global_regattempts_max) { + /* Ok, enough is enough. Don't try any more */ + /* We could add an external notification here... + steal it from app_voicemail :-) */ + r->regstate=REG_STATE_GAVEUP; + } else { + r->regstate=REG_STATE_UNREGISTERED; + r->timeout = -1; + res=transmit_register(r, SIP_REGISTER, NULL, NULL); + } manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUser: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate)); - r->timeout = -1; - res=transmit_register(r, SIP_REGISTER, NULL, NULL); ASTOBJ_UNREF(r,sip_registry_destroy); return 0; } @@ -4450,13 +4467,13 @@ /* 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))) { - ast_log(LOG_NOTICE, "Strange, trying to register when registration already pending\n"); + ast_log(LOG_NOTICE, "Strange, trying to register %s@%s when registration already pending\n", r->username, r->hostname); return 0; } - if (r->call) { + if (r->call) { /* We have a registration */ if (!auth) { - ast_log(LOG_WARNING, "Already have a call??\n"); + ast_log(LOG_WARNING, "Already have a REGISTER going on to %s@%s?? \n", r->username, r->hostname); return 0; } else { p = r->call; @@ -4470,21 +4487,27 @@ r->callid_valid = 1; } /* Allocate SIP packet for registration */ - p=sip_alloc( r->callid, NULL, 0); + p=sip_alloc( r->callid, NULL, 0, SIP_REGISTER); if (!p) { - ast_log(LOG_WARNING, "Unable to allocate registration call\n"); + ast_log(LOG_WARNING, "Unable to allocate registration call for %s@%s \n", r->username, r->hostname); return 0; } /* Find address to hostname */ - if (create_addr(p,r->hostname)) { + /* Hostname is really domain */ + if (create_addr(p, r->hostname) != 0) { + /* Error */ /* we have what we hope is a temporary network error, * probably DNS. We need to reschedule a registration try */ sip_destroy(p); if (r->timeout > -1) { - ast_log(LOG_WARNING, "Still have a registration timeout (create_addr() error), %d\n", r->timeout); ast_sched_del(sched, r->timeout); + r->timeout = ast_sched_add(sched, global_reg_timeout*1000, sip_reg_timeout, r); + ast_log(LOG_WARNING, "Still have a registration timeout for %s@%s (create_addr() error), %d\n", r->username, r->hostname, r->timeout); + } else { + r->timeout = ast_sched_add(sched, global_reg_timeout*1000, sip_reg_timeout, r); + ast_log(LOG_WARNING, "Propably a DNS error for %s@%s , trying REGISTER again (after %d seconds)\n", r->username, r->hostname, global_reg_timeout * 1000); } - r->timeout = ast_sched_add(sched, global_reg_timeout*1000, sip_reg_timeout, r); + r->regattempts++; return 0; } @@ -4527,13 +4550,13 @@ } /* set up a timeout */ - if (auth==NULL) { + if (auth == NULL) { if (r->timeout > -1) { ast_log(LOG_WARNING, "Still have a registration timeout, %d\n", r->timeout); ast_sched_del(sched, r->timeout); } - r->timeout = ast_sched_add(sched, global_reg_timeout*1000, sip_reg_timeout, r); - ast_log(LOG_DEBUG, "Scheduled a registration timeout # %d\n", r->timeout); + r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, r); + ast_log(LOG_DEBUG, "Scheduled a registration timeout for %s : %d\n", r->hostname, r->timeout); } if (strchr(r->username, '@')) { @@ -4550,7 +4573,11 @@ snprintf(to, sizeof(to), "", r->username, p->tohost); } - snprintf(addr, sizeof(addr), "sip:%s", p->tohost); + //snprintf(addr, sizeof(addr), "sip:%s", p->tohost); + if (p->fromdomain && !ast_strlen_zero(p->fromdomain)) + snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); + else + snprintf(addr, sizeof(addr), "sip:%s", r->hostname); strncpy(p->uri, addr, sizeof(p->uri) - 1); p->branch ^= rand(); @@ -4599,10 +4626,14 @@ add_blank_header(&req); copy_request(&p->initreq, &req); parse(&p->initreq); - if (sip_debug_test_pvt(p)) - ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); + if (sip_debug_test_pvt(p)) { + ast_verbose("REGISTER %d headers, %d lines\n", p->initreq.headers, p->initreq.lines); + } determine_firstline_parts(&p->initreq); r->regstate=auth?REG_STATE_AUTHSENT:REG_STATE_REGSENT; + r->regattempts++; /* Another attempt */ + if (option_debug > 3) + ast_verbose("REGISTER attempt %d to %s@%s\n", r->regattempts, r->username, r->hostname); return send_request(p, &req, 2, p->ocseq); } @@ -7269,7 +7300,7 @@ struct sip_request req; struct ast_variable *var; - p = sip_alloc(NULL, NULL, 0); + p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY); if (!p) { ast_log(LOG_WARNING, "Unable to build sip pvt data for notify\n"); return RESULT_FAILURE; @@ -7716,17 +7747,187 @@ } } +/*--- handle_response_register: Handle responses on REGISTER to services ---*/ +static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno) +{ + struct sip_registry *r; + r=p->registry; + + switch (resp) { + case 401: /* Unauthorized */ + if ((p->authtries > 1) || do_register_auth(p, req, "WWW-Authenticate", "Authorization")) { + ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s@%s' (Tries %d)\n", p->registry->username, p->registry->hostname, p->authtries); + ast_set_flag(p, SIP_NEEDDESTROY); + } + break; + case 403: /* Forbidden */ + ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname); + p->registry->regattempts = global_regattempts_max+1; + ast_sched_del(sched, r->timeout); + ast_set_flag(p, SIP_NEEDDESTROY); + break; + case 404: /* Not found */ + ast_log(LOG_WARNING, "Got 404 Not found on SIP register to service %s@%s, giving up\n", p->registry->username,p->registry->hostname); + p->registry->regattempts = global_regattempts_max+1; + ast_set_flag(p, SIP_NEEDDESTROY); + r->call = NULL; + ast_sched_del(sched, r->timeout); + break; + case 407: /* Proxy auth */ + if ((p->authtries > 1) || do_register_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization")) { + ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries); + ast_set_flag(p, SIP_NEEDDESTROY); + } + break; + case 479: /* SER: Not able to process the URI */ + ast_log(LOG_WARNING, "Got error 479 on register to %s@%s, giving up (check config)\n", p->registry->username,p->registry->hostname); + p->registry->regattempts = global_regattempts_max+1; + ast_set_flag(p, SIP_NEEDDESTROY); + r->call = NULL; + ast_sched_del(sched, r->timeout); + break; + case 200: + if (r) { + int expires, expires_ms; + + r->regstate=REG_STATE_REGISTERED; + manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate)); + ast_log(LOG_DEBUG, "Registration successful\n"); + if (r->timeout > -1) { + ast_log(LOG_DEBUG, "Cancelling timeout %d\n", r->timeout); + ast_sched_del(sched, r->timeout); + } + r->timeout=-1; + r->call = NULL; + p->registry = NULL; + /* Let this one hang around until we have all the responses */ + sip_scheddestroy(p, 32000); + /* ast_set_flag(p, SIP_NEEDDESTROY); */ + + /* set us up for re-registering */ + /* figure out how long we got registered for */ + if (r->expire > -1) + ast_sched_del(sched, r->expire); + /* according to section 6.13 of RFC, contact headers override + expires headers, so check those first */ + expires = 0; + if (!ast_strlen_zero(get_header(req, "Contact"))) { + char *contact = NULL; + char *tmptmp = NULL; + int start = 0; + for(;;) { + contact = __get_header(req, "Contact", &start); + /* this loop ensures we get a contact header about our register request */ + if(!ast_strlen_zero(contact)) { + if( (tmptmp=strstr(contact, p->our_contact))) { + contact=tmptmp; + break; + } + } else + break; + } + tmptmp = strstr(contact, "expires="); + if (tmptmp) { + if (sscanf(tmptmp + 8, "%d;", &expires) != 1) + expires = 0; + } + } + if (!expires) + expires=atoi(get_header(req, "expires")); + if (!expires) + expires=default_expiry; + + expires_ms = expires * 1000; + if (expires <= EXPIRY_GUARD_LIMIT) + expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN); + else + expires_ms -= EXPIRY_GUARD_SECS * 1000; + if (sipdebug) + ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d ms)\n", r->hostname, expires, expires_ms); + + r->refresh= (int) expires_ms / 1000; + + /* Schedule re-registration before we expire */ + r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r); + ASTOBJ_UNREF(r, sip_registry_destroy); + } else { + if (r->expire) + ast_log(LOG_WARNING, "Got 200 OK on REGISTER that is already done\n"); + else + ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n"); + ast_set_flag(p, SIP_NEEDDESTROY); + return 0; + } + + } + return 1; +} + +/*--- handle_response_peerpoke: Handle qualification responses (OPTIONS) */ +static int handle_response_peerpoke(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno, int sipmethod) +{ + struct sip_peer *peer; + int pingtime; + struct timeval tv; + if (resp != 100) { + int statechanged = 0; + int newstate = 0; + peer = p->peerpoke; + gettimeofday(&tv, NULL); + pingtime = (tv.tv_sec - peer->ps.tv_sec) * 1000 + + (tv.tv_usec - peer->ps.tv_usec) / 1000; + if (pingtime < 1) + pingtime = 1; + if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) { + if (pingtime <= peer->maxms) { + ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! (%dms / %dms)\n", peer->name, pingtime, peer->maxms); + statechanged = 1; + newstate = 1; + } + } else if ((peer->lastms > 0) && (peer->lastms <= peer->maxms)) { + if (pingtime > peer->maxms) { + ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED! (%dms / %dms)\n", peer->name, pingtime, peer->maxms); + statechanged = 1; + newstate = 2; + } + } + if (!peer->lastms) + statechanged = 1; + peer->lastms = pingtime; + peer->call = NULL; + if (statechanged) { + ast_device_state_changed("SIP/%s", peer->name); + if (newstate == 2) { + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, pingtime); + } else { + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, pingtime); + } + } + + if (peer->pokeexpire > -1) + ast_sched_del(sched, peer->pokeexpire); + if (sipmethod == SIP_INVITE) /* Does this really happen? */ + transmit_request(p, SIP_ACK, seqno, 0, 0); + ast_set_flag(p, SIP_NEEDDESTROY); + + /* Try again eventually */ + if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) + peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer); + else + peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_OK, sip_poke_peer_s, peer); + } + return 1; +} + /*--- handle_response: Handle SIP response in dialogue ---*/ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno) { char *to; char *msg, *c; struct ast_channel *owner; - struct sip_peer *peer; - int pingtime; - struct timeval tv; char iabuf[INET_ADDRSTRLEN]; int sipmethod; + int res = 1; c = get_header(req, "Cseq"); msg = strchr(c, ' '); /* Find method */ @@ -7748,65 +7949,22 @@ __sip_ack(p, seqno, 0, sipmethod); /* Get their tag if we haven't already */ - to = get_header(req, "To"); - to = ast_strcasestr(to, "tag="); - if (to) { - to += 4; - strncpy(p->theirtag, to, sizeof(p->theirtag) - 1); - to = strchr(p->theirtag, ';'); - if (to) - *to = '\0'; + if (ast_strlen_zero(p->theirtag)) { + to = get_header(req, "To"); + to = ast_strcasestr(to, "tag="); + if (to) { + to += 4; + strncpy(p->theirtag, to, sizeof(p->theirtag) - 1); + to = strchr(p->theirtag, ';'); + if (to) + *to = '\0'; + } } if (p->peerpoke) { /* We don't really care what the response is, just that it replied back. Well, as long as it's not a 100 response... since we might need to hang around for something more "definitive" */ - if (resp != 100) { - int statechanged = 0; - int newstate = 0; - peer = p->peerpoke; - gettimeofday(&tv, NULL); - pingtime = (tv.tv_sec - peer->ps.tv_sec) * 1000 + - (tv.tv_usec - peer->ps.tv_usec) / 1000; - if (pingtime < 1) - pingtime = 1; - if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) { - if (pingtime <= peer->maxms) { - ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! (%dms / %dms)\n", peer->name, pingtime, peer->maxms); - statechanged = 1; - newstate = 1; - } - } else if ((peer->lastms > 0) && (peer->lastms <= peer->maxms)) { - if (pingtime > peer->maxms) { - ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED! (%dms / %dms)\n", peer->name, pingtime, peer->maxms); - statechanged = 1; - newstate = 2; - } - } - if (!peer->lastms) - statechanged = 1; - peer->lastms = pingtime; - peer->call = NULL; - if (statechanged) { - ast_device_state_changed("SIP/%s", peer->name); - if (newstate == 2) { - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, pingtime); - } else { - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, pingtime); - } - } - - if (peer->pokeexpire > -1) - ast_sched_del(sched, peer->pokeexpire); - if (!strcasecmp(msg, "INVITE")) - transmit_request(p, SIP_ACK, seqno, 0, 0); - ast_set_flag(p, SIP_NEEDDESTROY); - /* Try again eventually */ - if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) - peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer); - else - peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_OK, sip_poke_peer_s, peer); - } + res = handle_response_peerpoke(p, resp, rest, req, ignore, seqno, sipmethod); } else if (ast_test_flag(p, SIP_OUTGOING)) { /* Acknowledge sequence number */ if (p->initid > -1) { @@ -7881,73 +8039,9 @@ /* If I understand this right, the branch is different for a non-200 ACK only */ transmit_request(p, SIP_ACK, seqno, 0, 1); check_pendings(p); - } else if (sipmethod == SIP_REGISTER) { - int expires, expires_ms; - struct sip_registry *r; - r=p->registry; - if (r) { - r->regstate=REG_STATE_REGISTERED; - manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate)); - ast_log(LOG_DEBUG, "Registration successful\n"); - if (r->timeout > -1) { - ast_log(LOG_DEBUG, "Cancelling timeout %d\n", r->timeout); - ast_sched_del(sched, r->timeout); - } - r->timeout=-1; - r->call = NULL; - p->registry = NULL; - ast_set_flag(p, SIP_NEEDDESTROY); - /* set us up for re-registering */ - /* figure out how long we got registered for */ - if (r->expire > -1) - ast_sched_del(sched, r->expire); - /* according to section 6.13 of RFC, contact headers override - expires headers, so check those first */ - expires = 0; - if (!ast_strlen_zero(get_header(req, "Contact"))) { - char *contact = NULL; - char *tmptmp = NULL; - int start = 0; - for(;;) { - contact = __get_header(req, "Contact", &start); - /* this loop ensures we get a contact header about our register request */ - if(!ast_strlen_zero(contact)) { - if( (tmptmp=strstr(contact, p->our_contact))) { - contact=tmptmp; - break; - } - } else - break; - } - tmptmp = strstr(contact, "expires="); - if (tmptmp) { - if (sscanf(tmptmp + 8, "%d;", &expires) != 1) - expires = 0; - } - } - if (!expires) expires=atoi(get_header(req, "expires")); - if (!expires) expires=default_expiry; - - - expires_ms = expires * 1000; - if (expires <= EXPIRY_GUARD_LIMIT) - expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN); - else - expires_ms -= EXPIRY_GUARD_SECS * 1000; - if (sipdebug) - ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d ms)\n", r->hostname, expires, expires_ms); - - r->refresh= (int) expires_ms / 1000; - - /* Schedule re-registration before we expire */ - r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r); - ASTOBJ_UNREF(r, sip_registry_destroy); - } else - ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n"); - - } - break; - case 401: /* Not www-authorized on REGISTER */ + } else if (sipmethod == SIP_REGISTER) + res = handle_response_register(p, resp, rest, req, ignore, seqno); + case 401: /* Not www-authorized on REGISTER or INVITE */ if (sipmethod == SIP_INVITE) { /* First we ACK */ transmit_request(p, SIP_ACK, seqno, 0, 0); @@ -7957,12 +8051,11 @@ ast_set_flag(p, SIP_NEEDDESTROY); } } else if (p->registry && sipmethod == SIP_REGISTER) { - if ((p->authtries > 1) || do_register_auth(p, req, "WWW-Authenticate", "Authorization")) { - ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s'\n", get_header(&p->initreq, "From")); - ast_set_flag(p, SIP_NEEDDESTROY); - } - } else + res = handle_response_register(p, resp, rest, req, ignore, seqno); + } else { + ast_log(LOG_WARNING, "Got authentication request (401) on unknown %s to '%s'\n", sip_methods[sipmethod].text, get_header(req, "To")); ast_set_flag(p, SIP_NEEDDESTROY); + } break; case 403: /* Forbidden - we failed authentication */ if (sipmethod == SIP_INVITE) { @@ -7973,12 +8066,17 @@ ast_queue_control(p->owner, AST_CONTROL_CONGESTION); ast_set_flag(p, SIP_NEEDDESTROY); } else if (p->registry && sipmethod == SIP_REGISTER) { - ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname); - ast_set_flag(p, SIP_NEEDDESTROY); + res = handle_response_register(p, resp, rest, req, ignore, seqno); } else { ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for %s\n", msg); } break; + case 404: /* Not found */ + if (p->registry && sipmethod == SIP_REGISTER) { + res = handle_response_register(p, resp, rest, req, ignore, seqno); + } else if (owner) + ast_queue_control(p->owner, AST_CONTROL_CONGESTION); + break; case 407: /* Proxy auth required */ if (sipmethod == SIP_INVITE) { /* First we ACK */ @@ -7995,15 +8093,13 @@ 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 > 1) || 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); } } else if (p->registry && sipmethod == SIP_REGISTER) { - if ((p->authtries > 1) || do_register_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization")) { - ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries); - ast_set_flag(p, SIP_NEEDDESTROY); - } + res = handle_response_register(p, resp, rest, req, ignore, seqno); } else ast_set_flag(p, SIP_NEEDDESTROY); @@ -8095,13 +8191,19 @@ } else ast_log(LOG_NOTICE, "Dont know how to handle a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr)); } - } else { + } else { + /* Not outgoing - what is it? Unsolicited replies? */ + /* When do we get here? ---------??????????------------*/ + /* INCOMING Calls */ + if (option_debug > 2) { + ast_verbose("!!!!!!!---------------************* Why are we here with this packet???? %s\n", msg); + } if (sip_debug_test_pvt(p)) ast_verbose("Response message is %s\n", msg); switch(resp) { case 200: /* Change branch since this is a 200 response */ - if (sipmethod == SIP_INVITE || sipmethod == SIP_REGISTER) + if (sipmethod == SIP_INVITE) transmit_request(p, SIP_ACK, seqno, 0, 1); break; case 407: @@ -8117,6 +8219,7 @@ break; } } + return res; } struct sip_dual { @@ -8870,7 +8973,7 @@ p->method = SIP_RESPONSE; /* Response to our request -- Do some sanity checks */ if (!p->initreq.headers) { - ast_log(LOG_DEBUG, "That's odd... Got a response on a call we dont know about.\n"); + ast_log(LOG_DEBUG, "That's odd... Got a response on a call we dont know about. Cseq %d Cmd\n", seqno, cmd); ast_set_flag(p, SIP_NEEDDESTROY); return 0; } else if (p->ocseq && (p->ocseq < seqno)) { @@ -9096,7 +9199,7 @@ return 0; } - p = sip_alloc(NULL, NULL, 0); + p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY); if (!p) { ast_log(LOG_WARNING, "Unable to build sip pvt data for MWI\n"); return -1; @@ -9321,7 +9424,7 @@ ast_log(LOG_NOTICE, "Still have a call...\n"); sip_destroy(peer->call); } - p = peer->call = sip_alloc(NULL, NULL, 0); + p = peer->call = sip_alloc(NULL, NULL, 0, SIP_OPTIONS); if (!peer->call) { ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name); return -1; @@ -9351,6 +9454,7 @@ ast_set_flag(p, SIP_OUTGOING); #ifdef VOCAL_DATA_HACK strncpy(p->username, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->username) - 1); + p->method = SIP_INVITE; transmit_invite(p, SIP_INVITE, 0, NULL, NULL, NULL,NULL,NULL, 0, 1); #else transmit_invite(p, SIP_OPTIONS, 0, NULL, NULL, NULL,NULL,NULL, 0, 1); @@ -9424,7 +9528,7 @@ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", ast_getformatname(oldformat), ast_getformatname(global_capability)); return NULL; } - p = sip_alloc(NULL, NULL, 0); + p = sip_alloc(NULL, NULL, 0, SIP_INVITE); if (!p) { ast_log(LOG_WARNING, "Unable to build sip pvt data for '%s'\n", (char *)data); return NULL; @@ -9477,7 +9581,7 @@ #endif p->prefcodec = format; ast_mutex_lock(&p->lock); - tmpc = sip_new(p, AST_STATE_DOWN, host); + tmpc = sip_new(p, AST_STATE_DOWN, host); /* Place the call */ ast_mutex_unlock(&p->lock); if (!tmpc) sip_destroy(p); @@ -10108,6 +10212,7 @@ externhost[0] = '\0'; externexpire = 0; externrefresh = 10; + sipdebug = 0; strncpy(default_useragent, DEFAULT_USERAGENT, sizeof(default_useragent) - 1); strncpy(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime) - 1); strncpy(global_realm, DEFAULT_REALM, sizeof(global_realm) - 1); @@ -10124,8 +10229,9 @@ global_rtptimeout = 0; global_rtpholdtimeout = 0; global_rtpkeepalive = 0; - global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; pedanticsipchecking = 0; + global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; + global_regattempts_max = DEFAULT_REGATTEMPTS_MAX; ast_clear_flag(&global_flags, AST_FLAGS_ALL); ast_set_flag(&global_flags, SIP_DTMF_RFC2833); ast_set_flag(&global_flags, SIP_NAT_RFC3581); @@ -10231,10 +10337,14 @@ default_expiry = atoi(v->value); if (default_expiry < 1) default_expiry = DEFAULT_DEFAULT_EXPIRY; + } else if (!strcasecmp(v->name, "sipdebug")){ + sipdebug = ast_true(v->value); } else if (!strcasecmp(v->name, "registertimeout")){ global_reg_timeout = atoi(v->value); if (global_reg_timeout < 1) global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; + } else if (!strcasecmp(v->name, "registerattempts")){ + global_regattempts_max = atoi(v->value); } else if (!strcasecmp(v->name, "bindaddr")) { if (!(hp = ast_gethostbyname(v->value, &ahp))) { ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); Index: configs/sip.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/sip.conf.sample,v retrieving revision 1.61 diff -u -r1.61 sip.conf.sample --- configs/sip.conf.sample 24 Mar 2005 23:06:21 -0000 1.61 +++ configs/sip.conf.sample 24 Mar 2005 23:47:21 -0000 @@ -82,6 +82,8 @@ ; inband : Inband audio (requires 64 kbit codec -alaw, ulaw) ;compactheaders = yes ; send compact sip headers. +;sipdebug = yes ; Turn on SIP debugging by default, from + ; the moment the channel loads this configuration ; ; If regcontext is specified, Asterisk will dynamically @@ -121,6 +123,10 @@ ; (instead of type=friend) if you have calls in both directions ;registertimeout=20 ; retry registration calls every 20 seconds (default) +;registerattempts=10 ; Number of registration attempts before we give up + ; 0 = continue forever, hammering the other server until it + ; simply lets you in + ; Default is 10 tries ;callevents=no ; generate manager events when sip ua performs events (e.g. hold) ;---------------------------------------------- NAT SUPPORT ------------------------