Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.739 diff -u -r1.739 chan_sip.c --- channels/chan_sip.c 20 May 2005 03:14:41 -0000 1.739 +++ channels/chan_sip.c 21 May 2005 21:51:51 -0000 @@ -103,8 +103,8 @@ #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 MAX_RETRANS 5 /* Try only 5 times for retransmissions */ +#define DEFAULT_RETRANS 1000 /* How frequently to retransmit (2*500 ms RFC 3261) */ +#define MAX_RETRANS 7 /* Try only 7 times for retransmissions */ #define DEBUG_READ 0 /* Recieved data */ @@ -115,21 +115,21 @@ static const char config[] = "sip.conf"; static const char notify_config[] = "sip_notify.conf"; -#define SIP_REGISTER 1 -#define SIP_OPTIONS 2 -#define SIP_NOTIFY 3 -#define SIP_INVITE 4 -#define SIP_ACK 5 -#define SIP_PRACK 6 -#define SIP_BYE 7 -#define SIP_REFER 8 -#define SIP_SUBSCRIBE 9 -#define SIP_MESSAGE 10 -#define SIP_UPDATE 11 -#define SIP_INFO 12 -#define SIP_CANCEL 13 -#define SIP_PUBLISH 14 -#define SIP_RESPONSE 100 +#define SIP_RESPONSE 1 +#define SIP_REGISTER 2 +#define SIP_OPTIONS 3 +#define SIP_NOTIFY 4 +#define SIP_INVITE 5 +#define SIP_ACK 6 +#define SIP_PRACK 7 +#define SIP_BYE 8 +#define SIP_REFER 9 +#define SIP_SUBSCRIBE 10 +#define SIP_MESSAGE 11 +#define SIP_UPDATE 12 +#define SIP_INFO 13 +#define SIP_CANCEL 14 +#define SIP_PUBLISH 15 #define RTP 1 #define NO_RTP 0 @@ -139,6 +139,7 @@ char *text; } sip_methods[] = { { 0, RTP, "-UNKNOWN-" }, + { SIP_RESPONSE, NO_RTP, "SIP/2.0" }, { SIP_REGISTER, NO_RTP, "REGISTER" }, { SIP_OPTIONS, NO_RTP, "OPTIONS" }, { SIP_NOTIFY, NO_RTP, "NOTIFY" }, @@ -305,6 +306,7 @@ int lines; /* SDP Content */ char *line[SIP_MAX_LINES]; char data[SIP_MAX_PACKET]; + int debug; /* Debug flag for this packet */ }; struct sip_pkt; @@ -397,6 +399,7 @@ ast_group_t pickupgroup; /* Pickup group */ int lastinvite; /* Last Cseq of invite */ unsigned int flags; /* SIP_ flags */ + int timer_t1; /* SIP timer T1, ms rtt */ int capability; /* Special capability (codec) */ int jointcapability; /* Supported capability at both ends (codecs ) */ int peercapability; /* Supported peer capability */ @@ -494,11 +497,14 @@ /* sip packet - read in sipsock_read, transmitted in send_request */ struct sip_pkt { struct sip_pkt *next; /* Next packet */ + int method; /* SIP method */ int retrans; /* Retransmission number */ int seqno; /* Sequence number */ unsigned int flags; /* non-zero if this is a response packet (e.g. 200 OK) */ struct sip_pvt *owner; /* Owner call */ int retransid; /* Retransmission ID */ + int timer_a; /* SIP timer A, retransmission timer */ + int timer_t1; /* SIP T1 timer, estimated RTT or 500 ms */ int packetlen; /* Length of packet */ char data[0]; }; @@ -691,7 +697,7 @@ static int expire_register(void *data); static int callevents = 0; -static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause); +static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause); static int sip_devicestate(void *data); static int sip_sendtext(struct ast_channel *ast, const char *text); static int sip_call(struct ast_channel *ast, char *dest, int timeout); @@ -713,7 +719,7 @@ .description = "Session Initiation Protocol (SIP)", .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), .properties = AST_CHAN_TP_WANTSJITTER, - .requester = sip_request, + .requester = sip_request_call, .devicestate = sip_devicestate, .call = sip_call, .hangup = sip_hangup, @@ -733,6 +739,10 @@ int find_sip_method(char *msg) { int i, res = 0; + + if (!msg || ast_strlen_zero(msg)) + return 0; + /* Strictly speaking, SIP methods are case SENSITIVE, but we don't check */ for (i=1;(i < (sizeof(sip_methods) / sizeof(sip_methods[0]))) && !res; i++) { if (!strcasecmp(sip_methods[i].text, msg)) @@ -867,88 +877,120 @@ /*--- retrans_pkt: Retransmit SIP message if no answer ---*/ static int retrans_pkt(void *data) { - struct sip_pkt *pkt=data, *prev, *cur; - int res = 0; + struct sip_pkt *pkt=data, *prev, *cur = NULL; char iabuf[INET_ADDRSTRLEN]; + ast_mutex_lock(&pkt->owner->lock); if (pkt->retrans < MAX_RETRANS) { + ast_log(LOG_DEBUG, "** OEJ SIP retransmit: Rescheduling retransmission\n" ); pkt->retrans++; + if (pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */ + int siptimer_a; + if (!pkt->timer_a) + pkt->timer_a = 2 ; + else + pkt->timer_a = 2 * pkt->timer_a; + siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */ + /* Reschedule re-transmit */ + if (pkt->retransid > -1) { /* Do we have a transmit scheduled ? */ + ast_log(LOG_DEBUG, "*** SIP timer: Cancelling schedule #%d\n", pkt->retransid); + ast_sched_del(sched, pkt->retransid); + } + pkt->retransid = ast_sched_add(sched, siptimer_a, retrans_pkt, pkt); + if (sipdebug && option_debug > 3) + ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid); + } if (sip_debug_test_pvt(pkt->owner)) { if (ast_test_flag(pkt->owner, SIP_NAT) & SIP_NAT_ROUTE) ast_verbose("Retransmitting #%d (NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port), pkt->data); else ast_verbose("Retransmitting #%d (no NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port), pkt->data); } - append_history(pkt->owner, "ReTx", pkt->data); + ast_log(LOG_DEBUG, "** OEJ SIP retransmit: Sending packet\n" ); + append_history(pkt->owner, "Re-Transmit", pkt->data); __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); - res = 1; - } else { + if (pkt) + ast_mutex_unlock(&pkt->owner->lock); + return -1; + } + + /* We've exceeded maximum transmits - stop sending packet */ + if (pkt->owner) { ast_log(LOG_WARNING, "Maximum retries exceeded on call %s for seqno %d (%s %s)\n", pkt->owner->callid, pkt->seqno, (ast_test_flag(pkt, FLAG_FATAL)) ? "Critical" : "Non-critical", (ast_test_flag(pkt, FLAG_RESPONSE)) ? "Response" : "Request"); append_history(pkt->owner, "MaxRetries", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)"); - pkt->retransid = -1; - if (ast_test_flag(pkt, FLAG_FATAL)) { - while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) { - ast_mutex_unlock(&pkt->owner->lock); - usleep(1); - ast_mutex_lock(&pkt->owner->lock); - } - if (pkt->owner->owner) { - ast_set_flag(pkt->owner, SIP_ALREADYGONE); - ast_queue_hangup(pkt->owner->owner); - ast_mutex_unlock(&pkt->owner->owner->lock); - } else { - /* If no owner, destroy now */ - ast_set_flag(pkt->owner, SIP_NEEDDESTROY); - } + } else + ast_log(LOG_WARNING, "Maximum retries exceeded for packet. seqno %d (%s %s)\n", pkt->seqno, (ast_test_flag(pkt, FLAG_FATAL)) ? "Critical" : "Non-critical", (ast_test_flag(pkt, FLAG_RESPONSE)) ? "Response" : "Request"); + pkt->retransid = -1; /* Do not retransmit any more */ + if (ast_test_flag(pkt, FLAG_FATAL)) { /* Critical packet lost */ + while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) { + ast_mutex_unlock(&pkt->owner->lock); + usleep(1); + ast_mutex_lock(&pkt->owner->lock); } - /* In any case, go ahead and remove the packet */ - prev = NULL; - cur = pkt->owner->packets; - while(cur) { - if (cur == pkt) - break; - prev = cur; - cur = cur->next; + /* Any bridged channel ? Tell them we are gone */ + if (pkt->owner->owner) { + ast_set_flag(pkt->owner, SIP_ALREADYGONE); + ast_queue_hangup(pkt->owner->owner); /* Hangup call */ + ast_mutex_unlock(&pkt->owner->owner->lock); + } else { + /* If no owner, destroy now */ + ast_set_flag(pkt->owner, SIP_NEEDDESTROY); } - if (cur) { - if (prev) - prev->next = cur->next; - else - pkt->owner->packets = cur->next; - ast_mutex_unlock(&pkt->owner->lock); - free(cur); - pkt = NULL; - } else - ast_log(LOG_WARNING, "Weird, couldn't find packet owner!\n"); } + /* In any case, go ahead and remove the packet */ + prev = NULL; + cur = pkt->owner->packets; + while(cur) { + if (cur == pkt) + break; + prev = cur; + cur = cur->next; + } + if (cur) { /* Found packet, remove it */ + if (prev) + prev->next = cur->next; + else + pkt->owner->packets = cur->next; + ast_mutex_unlock(&pkt->owner->lock); + free(cur); + pkt = NULL; + } else + ast_log(LOG_WARNING, "Weird, couldn't find packet in owners list! (Maybe notify or so) \n"); if (pkt) ast_mutex_unlock(&pkt->owner->lock); - return res; + return 0; } /*--- __sip_reliable_xmit: transmit packet with retransmits ---*/ -static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal) +static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod) { struct sip_pkt *pkt; + int siptimer_a = DEFAULT_RETRANS; + pkt = malloc(sizeof(struct sip_pkt) + len + 1); if (!pkt) return -1; memset(pkt, 0, sizeof(struct sip_pkt)); memcpy(pkt->data, data, len); + pkt->method = sipmethod; pkt->packetlen = len; pkt->next = p->packets; pkt->owner = p; pkt->seqno = seqno; pkt->flags = resp; pkt->data[len] = '\0'; + pkt->timer_t1 = p->timer_t1; /* Set SIP timer T1 */ if (fatal) ast_set_flag(pkt, FLAG_FATAL); + if (pkt->timer_t1) + siptimer_a = pkt->timer_t1 * 2; + /* Schedule retransmission */ - pkt->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, pkt); + pkt->retransid = ast_sched_add(sched, siptimer_a, retrans_pkt, pkt); pkt->next = p->packets; p->packets = pkt; __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); - if (!strncasecmp(pkt->data, "INVITE", 6)) { + if (sipmethod == SIP_INVITE) { /* Note this is a pending invite */ p->pendinginvite = seqno; } @@ -1007,10 +1049,11 @@ /* Just in case... */ char *msg; - if (sipmethod > 0) { - msg = sip_methods[sipmethod].text; - } else - msg = "___NEVER___"; + msg = sip_methods[sipmethod].text; + if (sipmethod < 0 || sipmethod > 15) { + ast_log(LOG_WARNING, "*** Unknown SIP method %d\n", sipmethod); + sipmethod = 0; + } cur = p->packets; while(cur) { if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) && @@ -1085,7 +1128,7 @@ return res; } -static void parse(struct sip_request *req); +static void parse_request(struct sip_request *req); static char *get_header(struct sip_request *req, char *name); static void copy_request(struct sip_request *dst,struct sip_request *src); @@ -1095,7 +1138,7 @@ memset(dst, 0, sizeof(*dst)); memcpy(dst->data, src->data, sizeof(dst->data)); dst->len = src->len; - parse(dst); + parse_request(dst); } /*--- send_response: Transmit response on SIP request---*/ @@ -1117,7 +1160,7 @@ snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq")); append_history(p, "TxRespRel", tmpmsg); } - res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable > 1)); + res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable > 1), SIP_RESPONSE); } else { if (recordhistory) { parse_copy(&tmp, req); @@ -1151,7 +1194,7 @@ snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq")); append_history(p, "TxReqRel", tmpmsg); } - res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1)); + res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1), req->method); } else { if (recordhistory) { parse_copy(&tmp, req); @@ -1504,6 +1547,7 @@ port++; } r->sa.sin_family = AF_INET; + r->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC3261) */ p = find_peer(peer, NULL, 1); if (p) { @@ -1553,6 +1597,10 @@ r->rtptimeout = p->rtptimeout; r->rtpholdtimeout = p->rtpholdtimeout; r->rtpkeepalive = p->rtpkeepalive; + /* Set timer T1 to RTT for this peer or 500 ms if unknown */ + if (p->maxms && p->lastms) + r->timer_t1 = p->lastms; + if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && (!p->maxms || ((p->lastms >= 0) && (p->lastms <= p->maxms)))) { if (p->addr.sin_addr.s_addr) { @@ -2063,7 +2111,9 @@ ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); - ast_set_flag(&locflags, SIP_NEEDDESTROY); + + sip_scheddestroy(p, 32000); /* Destroy this dialog if no response */ + /* RFC 3261 says wait 64 T1 for Cancel, T1 defaults to 500 ms */ /* Start the process if it's not already started */ if (!ast_test_flag(p, SIP_ALREADYGONE) && !ast_strlen_zero(p->initreq.data)) { if (needcancel) { @@ -2071,8 +2121,6 @@ transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, 1, 0); /* Actually don't destroy us yet, wait for the 487 on our original INVITE, but do set an autodestruct just in case we never get it. */ - ast_clear_flag(&locflags, SIP_NEEDDESTROY); - sip_scheddestroy(p, 15000); if ( p->initid != -1 ) { /* channel still up - reverse dec of inUse counter only if the channel is not auto-congested */ @@ -2720,27 +2768,21 @@ struct sip_pvt *p; char *callid; char tmp[256] = ""; - char iabuf[INET_ADDRSTRLEN]; - char *cmd; char *tag = "", *c; callid = get_header(req, "Call-ID"); if (pedanticsipchecking) { - /* In principle Call-ID's uniquely identify a call, however some vendors - (i.e. Pingtel) send multiple calls with the same Call-ID and different - tags in order to simplify billing. The RFC does state that we have to - compare tags in addition to the call-id, but this generate substantially - more overhead which is totally unnecessary for the vast majority of sane - SIP implementations, and thus Asterisk does not enable this behavior - by default. Short version: You'll need this option to support conferencing - on the pingtel */ - ast_copy_string(tmp, req->header[0], sizeof(tmp)); - cmd = tmp; - c = strchr(tmp, ' '); - if (c) - *c = '\0'; - if (!strcasecmp(cmd, "SIP/2.0")) + /* + In principle Call-ID's uniquely identify a call, but with a forking SIP proxy + we need more to identify a branch - so we have to check + from and To tags as well as Call ID to uniquely identify a + SIP dialog. + For Asterisk to correctly follow the RFC in this regards, + you need to turn on pedanticsipchecking in sip.conf. + + */ + if (req->method == SIP_RESPONSE) ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp)); else ast_copy_string(tmp, get_header(req, "From"), sizeof(tmp)); @@ -2754,15 +2796,15 @@ } - if (ast_strlen_zero(callid)) { - ast_log(LOG_WARNING, "Call missing call ID from '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr)); - return NULL; - } ast_mutex_lock(&iflock); p = iflist; while(p) { - if (!strcmp(p->callid, callid) && - (!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))) { + int found = 0; + if (req->method == SIP_REGISTER) + found = (!strcmp(p->callid, callid)); + else + found = (!strcmp(p->callid, callid) && (!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))); + if (found) { /* Found the call */ ast_mutex_lock(&p->lock); ast_mutex_unlock(&iflock); @@ -2896,12 +2938,15 @@ return t; } -/*--- parse: Parse a SIP message ----*/ -static void parse(struct sip_request *req) +static int determine_firstline_parts( struct sip_request *req ); + +/*--- parse_request: Parse a SIP message ----*/ +static void parse_request(struct sip_request *req) { /* Divide fields by NULL's */ char *c; int f = 0; + c = req->data; /* First header starts immediately */ @@ -2911,16 +2956,15 @@ /* We've got a new header */ *c = 0; -#if 0 - printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f])); -#endif + if(option_debug > 4) + ast_log(LOG_DEBUG, "Header: %s (%d)\n", req->header[f], strlen(req->header[f])); if (ast_strlen_zero(req->header[f])) { /* Line by itself means we're now in content */ c++; break; } if (f >= SIP_MAX_HEADERS - 1) { - ast_log(LOG_WARNING, "Too many SIP headers...\n"); + ast_log(LOG_WARNING, "Too many SIP headers. Ignoring\n" ); } else f++; req->header[f] = c + 1; @@ -2941,9 +2985,8 @@ if (*c == '\n') { /* We've got a new line */ *c = 0; -#if 0 - printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f])); -#endif + if(option_debug > 4) + ast_log(LOG_DEBUG, "Line: %s (%d)\n", req->line[f], strlen(req->line[f])); if (f >= SIP_MAX_LINES - 1) { ast_log(LOG_WARNING, "Too many SDP lines...\n"); } else @@ -2961,6 +3004,8 @@ req->lines = f; if (*c) ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c); + /* Split up the first line parts */ + determine_firstline_parts(req); } /*--- process_sdp: Process SIP SDP and activate RTP channels---*/ @@ -3484,6 +3529,7 @@ ast_log(LOG_WARNING, "Request already initialized?!?\n"); return -1; } + req->method = SIP_RESPONSE; req->header[req->headers] = req->data + req->len; snprintf(req->header[req->headers], sizeof(req->data) - req->len, "SIP/2.0 %s\r\n", resp); req->len += strlen(req->header[req->headers]); @@ -3682,13 +3728,13 @@ return __transmit_response(p, msg, req, 0); } -/*--- transmit_response: Transmit response, Make sure you get a reply */ +/*--- transmit_response_reliable: Transmit response, Make sure you get a reply */ static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req, int fatal) { return __transmit_response(p, msg, req, fatal ? 2 : 1); } -/*--- append_date: Append date to SIP message ---*/ +/*--- append_date: Append date header to SIP message ---*/ static void append_date(struct sip_request *req) { char tmpdat[256]; @@ -3992,20 +4038,23 @@ } /*--- determine_firstline_parts: parse first line of incoming SIP request */ +/* For a response, rlPart1 is SIP/2.0, rlPart2 is response code + for a request, rlPart1 is method, rlPart2 is URI. + */ static int determine_firstline_parts( struct sip_request *req ) { char *e, *cmd; int len; - cmd = req->header[0]; - while(*cmd && (*cmd < 33)) { + cmd = req->header[0]; /* First header line */ + while(*cmd && (*cmd < 33)) { /* Skip spaces */ cmd++; } if (!*cmd) { - return -1; + return -1; /* Nothing? return error */ } e = cmd; - while(*e && (*e > 32)) { + while(*e && (*e > 32)) { /* Find next part */ e++; } /* Get the command */ @@ -4013,26 +4062,25 @@ *e = '\0'; e++; } - req->rlPart1 = cmd; + req->rlPart1 = cmd; /* We have the first part - either "SIP/2.0" or a method name */ while( *e && ( *e < 33 ) ) { e++; } if ( !*e ) { - return -1; + return -1; /* No second part? return error */ } - if ( !strcasecmp(cmd, "SIP/2.0") ) { - /* We have a response */ - req->rlPart2 = e; + if ( !strcasecmp(cmd, "SIP/2.0") ) { /* We have a response */ + req->rlPart2 = e; /* Response code and text */ len = strlen( req->rlPart2 ); - if ( len < 2 ) { + if ( len < 2 ) { /* Too short, error */ return -1; } e+= len - 1; while( *e && *e < 33 ) { e--; } - *(++e)= '\0'; + *(++e)= '\0'; /* Separate text from the response code */ } else { /* We have a request */ if ( *e == '<' ) { @@ -4074,10 +4122,9 @@ add_sdp(&req, p); /* Use this as the basis */ copy_request(&p->initreq, &req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); p->lastinvite = p->ocseq; ast_set_flag(p, SIP_OUTGOING); return send_request(p, &req, 1, p->ocseq); @@ -4233,6 +4280,7 @@ { struct sip_request req; + req.method = sipmethod; if (init) { /* Bump branch even on initial requests */ p->branch ^= rand(); @@ -4254,14 +4302,11 @@ if (osptoken && !ast_strlen_zero(osptoken)) { ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", osptoken); add_header(&req, "P-OSP-Auth-Token", osptoken); - } - else - { + } else { ast_log(LOG_DEBUG,"NOT Adding OSP Token\n"); } #endif - if (distinctive_ring && !ast_strlen_zero(distinctive_ring)) - { + if (distinctive_ring && !ast_strlen_zero(distinctive_ring)) { add_header(&req, "Alert-Info",distinctive_ring); } add_header(&req, "Allow", ALLOWED_METHODS); @@ -4317,10 +4362,9 @@ if (!p->initreq.headers) { /* Use this as the basis */ copy_request(&p->initreq, &req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); } p->lastinvite = p->ocseq; return send_request(p, &req, init ? 2 : 1, p->ocseq); @@ -4461,10 +4505,9 @@ if (!p->initreq.headers) { /* Use this as the basis */ copy_request(&p->initreq, &req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); } return send_request(p, &req, 1, p->ocseq); @@ -4476,10 +4519,9 @@ if (!p->initreq.headers) { /* Use this as the basis */ copy_request(&p->initreq, req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); } return send_request(p, req, 0, p->ocseq); @@ -4509,15 +4551,15 @@ if (!p->initreq.headers) { /* Use this as the basis */ copy_request(&p->initreq, &req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); } return send_request(p, &req, 1, p->ocseq); } +/*--- regstate2str: Convert registration state to string for sip show registry */ static char *regstate2str(int regstate) { switch(regstate) { @@ -4765,10 +4807,9 @@ add_header(&req, "Content-Length", "0"); add_blank_header(&req); copy_request(&p->initreq, &req); - parse(&p->initreq); + parse_request(&p->initreq); if (sip_debug_test_pvt(p)) - ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - determine_firstline_parts(&p->initreq); + ast_verbose("REGISTER %d headers, %d lines\n", p->initreq.headers, p->initreq.lines); r->regstate=auth?REG_STATE_AUTHSENT:REG_STATE_REGSENT; return send_request(p, &req, 2, p->ocseq); } @@ -5371,6 +5412,7 @@ char *response =""; char *resp_uri =""; + /* Find their response among the mess that we'r sent for comparison */ ast_copy_string(tmp, authtoken, sizeof(tmp)); c = tmp; @@ -8659,6 +8701,7 @@ /* We do NOT destroy p here, so that our response will be accepted */ return 0; } + if (!ignore) { /* Use this as the basis */ if (debug) @@ -8684,7 +8727,7 @@ } } } else if (debug) - ast_verbose("Ignoring this request\n"); + ast_verbose("Ignoring this INVITE request\n"); if (!p->lastinvite && !ignore && !p->owner) { /* Handle authentication if this is our first invite */ res = check_user(p, req, SIP_INVITE, e, 1, sin, ignore); @@ -9130,23 +9173,25 @@ int res = 0; char iabuf[INET_ADDRSTRLEN]; + /* Go ahead and free RTP port */ + if (p->rtp) { + ast_rtp_destroy(p->rtp); + p->rtp = NULL; + } + if (p->vrtp) { + ast_rtp_destroy(p->vrtp); + p->vrtp = NULL; + } + /* Use this as the basis */ if (debug) ast_verbose("Using latest 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'\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr)); if (res < 1) { - /* Go ahead and free RTP port */ - if (p->rtp) { - ast_rtp_destroy(p->rtp); - p->rtp = NULL; - } - if (p->vrtp) { - ast_rtp_destroy(p->vrtp); - p->vrtp = NULL; - } /* Destroy the session, but keep us around for just a bit in case they don't get our 200 OK */ sip_scheddestroy(p, 15*1000); @@ -9155,6 +9200,7 @@ } /*--- handle_request: Handle SIP requests (methods) ---*/ /* this is where all incoming requests go first */ +/* Returns -1 on error */ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock) { /* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things @@ -9181,7 +9227,7 @@ cmd = req->header[0]; /* Must have Cseq */ - if (ast_strlen_zero(cmd) || ast_strlen_zero(cseq)) + if (ast_strlen_zero(cseq)) return -1; if (sscanf(cseq, "%d%n", &seqno, &len) != 1) { ast_log(LOG_DEBUG, "No seqno in '%s'\n", cmd); @@ -9195,10 +9241,11 @@ /* Save useragent of the client */ useragent = get_header(req, "User-Agent"); - ast_copy_string(p->useragent, useragent, sizeof(p->useragent)); + if (!ast_strlen_zero(useragent)) + ast_copy_string(p->useragent, useragent, sizeof(p->useragent)); /* Find out SIP method for incoming request */ - if (!strcasecmp(cmd, "SIP/2.0")) { /* Response to our request */ + if (req->method == SIP_RESPONSE) { /* Response to our request */ p->method = SIP_RESPONSE; /* Response to our request -- Do some sanity checks */ if (!p->initreq.headers) { @@ -9228,25 +9275,28 @@ /* New SIP request coming in (could be new request in existing SIP dialog as well...) */ - p->method = find_sip_method(cmd); /* Find out which SIP method they are using */ + p->method = req->method; /* Find out which SIP method they are using */ + if (option_debug > 2) ast_log(LOG_DEBUG, "**** Received %s (%d) - Command in SIP %s\n", sip_methods[p->method].text, sip_methods[p->method].id, cmd); if (p->icseq && (p->icseq > seqno)) { - ast_log(LOG_DEBUG, "Ignoring too old SIP packet packet %d (expecting >= %d)\n", seqno, p->icseq); + ast_log(LOG_DEBUG, "Ignoring too old SIP %s packet packet with seqno %d (expecting >= %d)\n", cmd, seqno, p->icseq); return -1; - } else if (p->icseq && (p->icseq == seqno) && (strcasecmp(cmd, "CANCEL") || ast_test_flag(p, SIP_ALREADYGONE))) { + } else if (p->icseq && (p->icseq == seqno) && (p->method != SIP_CANCEL || ast_test_flag(p, SIP_ALREADYGONE))) { /* ignore means "don't do anything with it" but still have to respond appropriately. We do this if we receive a repeat of the last sequence number */ - ignore=1; + ast_log(LOG_DEBUG, "Ignoring SIP message because of retransmit (%s Seqno %d, ours %d)\n", sip_methods[p->method].text, p->icseq, seqno); + ignore=2; } - + if (seqno >= p->icseq) /* Next should follow monotonically (but not necessarily incrementally -- thanks again to the genius authors of SIP -- increasing */ p->icseq = seqno; + /* Find their tag if we haven't got it */ if (ast_strlen_zero(p->theirtag)) { @@ -9341,7 +9391,6 @@ socklen_t len; int nounlock; int recount = 0; - int debug; char iabuf[INET_ADDRSTRLEN]; len = sizeof(sin); @@ -9359,13 +9408,14 @@ } req.data[res] = '\0'; req.len = res; - debug = sip_debug_test_addr(&sin); + req.debug = sip_debug_test_addr(&sin); if (pedanticsipchecking) - req.len = lws2sws(req.data, req.len); - if (debug) + req.len = lws2sws(req.data, req.len); /* Fix multiline headers */ + if (req.debug) ast_verbose("\n<-- SIP read from %s:%d: \n%s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), req.data); - parse(&req); - if (debug) { + parse_request(&req); + req.method = find_sip_method(req.rlPart1); + if (req.debug) { ast_verbose("--- (%d headers %d lines)", req.headers, req.lines); if (req.headers + req.lines == 0) ast_verbose(" Nat keepalive "); @@ -9377,10 +9427,6 @@ return 1; } - /* Determine the request URI for sip, sips or tel URIs */ - if (determine_firstline_parts(&req) < 0) - return 1; - /* Process request, with netlock held */ retrylock: ast_mutex_lock(&netlock); @@ -9746,7 +9792,7 @@ /*--- sip_request: PBX interface function -build SIP pvt structure ---*/ /* SIP calls initiated by the PBX arrive here */ -static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause) +static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause) { int oldformat; struct sip_pvt *p;