/*BUGGY*/ char* parse_cseq(char* const buf, const char* const end, struct cseq_body* const cb) { char *t, *m, *m_end; cb->error=PARSE_ERROR; t=buf; cb->number.s=t; t=eat_token_end(t, end); if (t>=end) goto error; cb->number.len=t-cb->number.s; m=eat_space_end(t, end); m_end=eat_token_end(m, end); if (m_end>=end) { LOG(L_ERR, "ERROR: parse_cseq: " "method terminated unexpectedly\n"); goto error; } if (m_end==m){ /* null method*/ LOG(L_ERR, "ERROR:parse_cseq: no method found\n"); goto error; } cb->method.s=m; t=m_end; cb->method.len=t-cb->method.s; /* Cache method id */ if (parse_method_name(&cb->method, &cb->method_id)!=0){ LOG(L_ERR, "Cannot parse method string\n"); goto error; } /* there may be trailing LWS * (it was not my idea to put it in SIP; -jiri ) */ t=eat_lws_end(t, end); /*check if the header ends here*/ if (t>=end) { LOG(L_ERR, "ERROR: parse_cseq: strange EoHF\n"); goto error; } if (*t=='\r' && t+1<end && *(t+1)=='\n') { cb->error=PARSE_OK; return t+2; } if (*t=='\n') { cb->error=PARSE_OK; return t+1; } LOG(L_ERR, "ERROR: CSeq EoL expected\n"); error: LOG(L_ERR, "ERROR: parse_cseq: bad cseq\n"); return t; }
char* parse_cseq(char *buf, char* end, struct cseq_body* cb) { char *t, *m, *m_end; cb->error=PARSE_ERROR; t=buf; cb->number.s=t; t=eat_token_end(t, end); if (t>=end) goto error; cb->number.len=t-cb->number.s; m=eat_space_end(t, end); m_end=eat_token_end(m, end); if (m_end>=end) { LM_ERR("method terminated unexpectedly\n"); goto error; } if (m_end==m){ /* null method*/ LM_ERR("no method found\n"); goto error; } cb->method.s=m; t=m_end; cb->method.len=t-cb->method.s; /* cache the method id */ if(parse_method(cb->method.s, t, (unsigned int*)&cb->method_id)==0) { LM_ERR("cannot parse the method\n"); goto error; } /* there may be trailing LWS * (it was not my idea to put it in SIP; -jiri ) */ t=eat_lws_end(t, end); /*check if the header ends here*/ if (t>=end) { LM_ERR("strange EoHF\n"); goto error; } if (*t=='\r' && t+1<end && *(t+1)=='\n') { cb->error=PARSE_OK; return t+2; } if (*t=='\n') { cb->error=PARSE_OK; return t+1; } LM_ERR("expecting CSeq EoL\n"); error: LM_ERR("bad cseq\n"); return t; }
static int extract_mediaport(str *body, str *mediaport) { char *cp, *cp1; int len; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = ser_memmem(cp, "m=", len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) { LOG(L_ERR, "ERROR: extract_mediaport: no `m=' in SDP\n"); return -1; } mediaport->s = cp1 + 2; mediaport->len = eat_line(mediaport->s, body->s + body->len - mediaport->s) - mediaport->s; trim_len(mediaport->len, mediaport->s, *mediaport); if (mediaport->len < 7 || memcmp(mediaport->s, "audio", 5) != 0 || !isspace((int)mediaport->s[5])) { LOG(L_ERR, "ERROR: extract_mediaport: can't parse `m=' in SDP\n"); return -1; } cp = eat_space_end(mediaport->s + 5, mediaport->s + mediaport->len); mediaport->len = eat_token_end(cp, mediaport->s + mediaport->len) - cp; mediaport->s = cp; return 1; }
int extract_mediaip(str *body, str *mediaip, int *pf, char *line) { char *cp, *cp1; int len, nextisip; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = (char*)ser_memmem(cp, line, len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) return -1; mediaip->s = cp1 + 2; mediaip->len = eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s; trim_len(mediaip->len, mediaip->s, *mediaip); nextisip = 0; for (cp = mediaip->s; cp < mediaip->s + mediaip->len;) { len = eat_token_end(cp, mediaip->s + mediaip->len) - cp; if (nextisip == 1) { mediaip->s = cp; mediaip->len = len; nextisip++; break; } if (len == 3 && memcmp(cp, "IP", 2) == 0) { switch (cp[2]) { case '4': nextisip = 1; *pf = AF_INET; break; case '6': nextisip = 1; *pf = AF_INET6; break; default: break; } } /* consume all spaces starting from the second char after the token First char after the token is the char that stoped the token parsing, so it is space or \r / \n, so we simply skip it */ cp = eat_space_end(cp + len + 1, mediaip->s + mediaip->len); } if (nextisip != 2 || mediaip->len == 0) { LM_ERR("no `IP[4|6]' in `%s' field\n",line); return -1; } return 1; }
static int extract_mediaip(str *body, str *mediaip, int *pf) { char *cp, *cp1; int len, nextisip; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = ser_memmem(cp, "c=", len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) { LOG(L_ERR, "ERROR: extract_mediaip: no `c=' in SDP\n"); return -1; } mediaip->s = cp1 + 2; mediaip->len = eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s; trim_len(mediaip->len, mediaip->s, *mediaip); nextisip = 0; for (cp = mediaip->s; cp < mediaip->s + mediaip->len;) { len = eat_token_end(cp, mediaip->s + mediaip->len) - cp; if (nextisip == 1) { mediaip->s = cp; mediaip->len = len; nextisip++; break; } if (len == 3 && memcmp(cp, "IP", 2) == 0) { switch (cp[2]) { case '4': nextisip = 1; *pf = AF_INET; break; case '6': nextisip = 1; *pf = AF_INET6; break; default: break; } } cp = eat_space_end(cp + len, mediaip->s + mediaip->len); } if (nextisip != 2 || mediaip->len == 0) { LOG(L_ERR, "ERROR: extract_mediaip: " "no `IP[4|6]' in `c=' field\n"); return -1; } return 1; }
int extract_fmtp( str *body, str *fmtp_payload, str *fmtp_string ) { char *cp, *cp1; int len; if (strncasecmp(body->s, "a=fmtp:", 7) !=0) { /*LM_DBG("We are not pointing to an a=fmtp: attribute =>`%.*s'\n", body->len, body->s); */ return -1; } cp1 = body->s; fmtp_payload->s = cp1 + 7; /* skip `a=fmtp:' */ fmtp_payload->len = eat_line(fmtp_payload->s, body->s + body->len - fmtp_payload->s) - fmtp_payload->s; trim_len(fmtp_payload->len, fmtp_payload->s, *fmtp_payload); len = fmtp_payload->len; /* */ cp = eat_token_end(fmtp_payload->s, fmtp_payload->s + fmtp_payload->len); fmtp_payload->len = cp - fmtp_payload->s; if (fmtp_payload->len <= 0 || cp == fmtp_payload->s) { LM_ERR("no encoding in `a=fmtp:'\n"); return -1; } len -= fmtp_payload->len; fmtp_string->s = cp; cp = eat_space_end(fmtp_string->s, fmtp_string->s + len); len -= cp - fmtp_string->s; if (len <= 0 || cp == fmtp_string->s) { LM_ERR("no encoding in `a=fmtp:'\n"); return -1; } fmtp_string->s = cp; fmtp_string->len = eat_line(fmtp_string->s, body->s + body->len - fmtp_string->s) - fmtp_string->s; trim_len(fmtp_string->len, fmtp_string->s, *fmtp_string); return 0; }
/* parses the first line, returns pointer to next line & fills fl; also modifies buffer (to avoid extra copy ops) */ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) { char *tmp; char* second; char* third; char* nl; int offset; /* int l; */ char* end; char s1,s2,s3; char *prn; unsigned int t; /* grammar: request = method SP uri SP version CRLF response = version SP status SP reason CRLF (version = "SIP/2.0") */ end=buffer+len; /* see if it's a reply (status) */ /* jku -- parse well-known methods */ /* drop messages which are so short they are for sure useless; utilize knowledge of minimum size in parsing the first token */ if (len <=16 ) { LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len); goto error1; } tmp=buffer; /* is it perhaps a reply, ie does it start with "SIP...." ? */ if ( (*tmp=='S' || *tmp=='s') && strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 && (*(tmp+SIP_VERSION_LEN)==' ')) { fl->type=SIP_REPLY; fl->u.reply.version.len=SIP_VERSION_LEN; tmp=buffer+SIP_VERSION_LEN; } else IFISMETHOD( INVITE, 'I' ) else IFISMETHOD( CANCEL, 'C') else IFISMETHOD( ACK, 'A' ) else IFISMETHOD( BYE, 'B' ) /* if you want to add another method XXX, include METHOD_XXX in H-file (this is the value which you will take later in processing and define XXX_LEN as length of method name; then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first latter; everything must be capitals */ else { /* neither reply, nor any of known method requests, let's believe it is an unknown method request */ tmp=eat_token_end(buffer,buffer+len); if ((tmp==buffer)||(tmp>=end)){ LOG(L_INFO, "ERROR:parse_first_line: empty or bad first line\n"); goto error1; } if (*tmp!=' ') { LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n"); goto error1; } fl->type=SIP_REQUEST; fl->u.request.method_value=METHOD_OTHER; fl->u.request.method.len=tmp-buffer; } /* identifying type of message over now; tmp points at space after; go ahead */ fl->u.request.method.s=buffer; /* store ptr to first token */ second=tmp+1; /* jump to second token */ offset=second-buffer; /* EoJku */ /* next element */ tmp=eat_token_end(second, second+len-offset); if (tmp>=end){ goto error; } offset+=tmp-second; third=eat_space_end(tmp, tmp+len-offset); offset+=third-tmp; if ((third==tmp)||(tmp>=end)){ goto error; } fl->u.request.uri.s=second; fl->u.request.uri.len=tmp-second; /* jku: parse status code */ if (fl->type==SIP_REPLY) { if (fl->u.request.uri.len!=3) { LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n", fl->u.request.uri.len, ZSW(second) ); goto error; } s1=*second; s2=*(second+1);s3=*(second+2); if (s1>='0' && s1<='9' && s2>='0' && s2<='9' && s3>='0' && s3<='9' ) { fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0'); } else { LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n", fl->u.request.uri.len, ZSW(second) ); goto error; } } /* EoJku */ /* last part: for a request it must be the version, for a reply * it can contain almost anything, including spaces, so we don't care * about it*/ if (fl->type==SIP_REQUEST){ tmp=eat_token_end(third,third+len-offset); offset+=tmp-third; if ((tmp==third)||(tmp>=end)){ goto error; } if (! is_empty_end(tmp, tmp+len-offset)){ goto error; } }else{ tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line ('\n' or '\r') */ if (tmp>=end){ /* no crlf in packet => invalid */ goto error; } offset+=tmp-third; } nl=eat_line(tmp,len-offset); if (nl>=end){ /* no crlf in packet or only 1 line > invalid */ goto error; } fl->u.request.version.s=third; fl->u.request.version.len=tmp-third; fl->len=nl-buffer; return nl; error: LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n", (fl->type==SIP_REPLY)?"reply(status)":"request"); LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset ); prn=pkg_malloc( offset ); if (prn) { for (t=0; t<offset; t++) if (*(buffer+t)) *(prn+t)=*(buffer+t); else *(prn+t)='°'; LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, ZSW(prn) ); pkg_free( prn ); }; error1: fl->type=SIP_INVALID; LOG(L_INFO, "ERROR:parse_first_line: bad message\n"); /* skip line */ nl=eat_line(buffer,len); return nl; }
int extract_media_attr(str *body, str *mediamedia, str *mediaport, str *mediatransport, str *mediapayload, int *is_rtp) { char *cp, *cp1; int len, i; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = (char*)ser_memmem(cp, "m=", len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) { LM_ERR("no `m=' in SDP\n"); return -1; } mediaport->s = cp1 + 2; /* skip `m=' */ mediaport->len = eat_line(mediaport->s, body->s + body->len - mediaport->s) - mediaport->s; trim_len(mediaport->len, mediaport->s, *mediaport); mediapayload->len = mediaport->len; mediamedia->s = mediaport->s; /* Skip media supertype and spaces after it */ cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); mediaport->len -= cp - mediaport->s; mediamedia->len = mediapayload->len - mediaport->len; if (mediaport->len <= 0 || cp == mediaport->s) { LM_ERR("no port in `m='\n"); return -1; } mediaport->s = cp; cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len); mediaport->len -= cp - mediaport->s; if (mediaport->len <= 0 || cp == mediaport->s) { LM_ERR("no port in `m='\n"); return -1; } /* Extract port */ mediaport->s = cp; cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); mediatransport->len = mediaport->len - (cp - mediaport->s); if (mediatransport->len <= 0 || cp == mediaport->s) { LM_ERR("no port in `m='\n"); return -1; } mediatransport->s = cp; mediaport->len = cp - mediaport->s; /* Skip spaces after port */ cp = eat_space_end(mediatransport->s, mediatransport->s + mediatransport->len); mediatransport->len -= cp - mediatransport->s; if (mediatransport->len <= 0 || cp == mediatransport->s) { LM_ERR("no protocol type in `m='\n"); return -1; } /* Extract protocol type */ mediatransport->s = cp; cp = eat_token_end(mediatransport->s, mediatransport->s + mediatransport->len); if (cp == mediatransport->s) { LM_ERR("no protocol type in `m='\n"); return -1; } mediatransport->len = cp - mediatransport->s; mediapayload->s = mediatransport->s + mediatransport->len; mediapayload->len -= mediapayload->s - mediamedia->s; cp = eat_space_end(mediapayload->s, mediapayload->s + mediapayload->len); mediapayload->len -= cp - mediapayload->s; mediapayload->s = cp; for (i = 0; sup_ptypes[i].s != NULL; i++) if (mediatransport->len == sup_ptypes[i].len && strncasecmp(mediatransport->s, sup_ptypes[i].s, mediatransport->len) == 0) { *is_rtp = sup_ptypes[i].is_rtp; return 0; } /* Unproxyable protocol type. Generally it isn't error. */ return 0; }
int extract_mediaip(str *body, str *mediaip, int *pf, char *line) { char *cp, *cp1; int len; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = (char*)ser_memmem(cp, line, len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) return -1; mediaip->s = cp1 + 2; mediaip->len = eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s; trim_len(mediaip->len, mediaip->s, *mediaip); if (mediaip->len == 0) { LM_ERR("no [%s] line in SDP\n",line); return -1; } /* search reverse for IP[4|6] in c=/o= line */ cp = (char*)ser_memrmem(mediaip->s, " IP", mediaip->len, 3); if (cp == NULL) { LM_ERR("no `IP[4|6]' in `%s' field\n",line); return -1; } /* safety checks: * - for length, at least 6: ' IP[4|6] x...' * - white space after */ if(cp + 6 > mediaip->s + mediaip->len && cp[4]!=' ') { LM_ERR("invalid content for `%s' line\n",line); return -1; } switch(cp[3]) { case '4': *pf = AF_INET; break; case '6': *pf = AF_INET6; break; default: LM_ERR("invalid addrtype IPx for `%s' line\n",line); return -1; } cp += 5; /* next token is the IP address */ cp = eat_space_end(cp, mediaip->s + mediaip->len); len = eat_token_end(cp, mediaip->s + mediaip->len) - cp; mediaip->s = cp; mediaip->len = len; if (mediaip->len == 0) { LM_ERR("no `IP[4|6]' address in `%s' field\n",line); return -1; } LM_DBG("located IP address [%.*s] in `%s' field\n", mediaip->len, mediaip->s, line); return 1; }
/** * rfc4566: * a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>] */ int extract_rtpmap(str *body, str *rtpmap_payload, str *rtpmap_encoding, str *rtpmap_clockrate, str *rtpmap_parmas) { char *cp, *cp1; int len; if (strncasecmp(body->s, "a=rtpmap:", 9) !=0) { /*LM_DBG("We are not pointing to an a=rtpmap: attribute =>`%.*s'\n", body->len, body->s); */ return -1; } cp1 = body->s; rtpmap_payload->s = cp1 + 9; /* skip `a=rtpmap:' */ rtpmap_payload->len = eat_line(rtpmap_payload->s, body->s + body->len - rtpmap_payload->s) - rtpmap_payload->s; trim_len(rtpmap_payload->len, rtpmap_payload->s, *rtpmap_payload); len = rtpmap_payload->len; /* */ cp = eat_token_end(rtpmap_payload->s, rtpmap_payload->s + rtpmap_payload->len); rtpmap_payload->len = cp - rtpmap_payload->s; if (rtpmap_payload->len <= 0 || cp == rtpmap_payload->s) { LM_ERR("no encoding in `a=rtpmap'\n"); return -1; } len -= rtpmap_payload->len; rtpmap_encoding->s = cp; cp = eat_space_end(rtpmap_encoding->s, rtpmap_encoding->s + len); len -= cp - rtpmap_encoding->s; if (len <= 0 || cp == rtpmap_encoding->s) { LM_ERR("no encoding in `a=rtpmap:'\n"); return -1; } rtpmap_encoding->s = cp; cp1 = (char*)ser_memmem(cp, "/", len, 1); if(cp1==NULL) { LM_ERR("invalid encoding in `a=rtpmap' at [%.*s]\n", len, cp); return -1; } len -= cp1 - cp; rtpmap_encoding->len = cp1 - cp; cp = cp1+1; /* skip '/' */ len--; rtpmap_clockrate->s = cp; cp1 = (char*)ser_memmem(cp, "/", len, 1); if(cp1==NULL) { /* no encoding parameters */ rtpmap_clockrate->len = len; rtpmap_parmas->s = NULL; rtpmap_parmas->len = 0; return 0; } rtpmap_clockrate->len = cp1 - cp; len -= cp1 - cp; rtpmap_parmas->s = cp1 + 1; /* skip '/' */ rtpmap_parmas->len = len - 1; return 0; }
/* Returns 0 - nothing found * 1 - T found */ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) { struct cell* p_cell; unsigned int hash_index = 0; unsigned int entry_label = 0; unsigned int branch_id = 0; char *hashi, *branchi, *p, *n; int hashl, branchl; int scan_space; str cseq_method; str req_method; char *loopi; int loopl; char *syni; int synl; short is_cancel; /* make compiler warnings happy */ loopi=0; loopl=0; syni=0; synl=0; /* split the branch into pieces: loop_detection_check(ignored), hash_table_id, synonym_id, branch_id */ if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s)) goto nomatch2; /* we do RFC 3261 tid matching and want to see first if there is * magic cookie in branch */ if (p_msg->via1->branch->value.len<=MCOOKIE_LEN) goto nomatch2; if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0) goto nomatch2; p=p_msg->via1->branch->value.s+MCOOKIE_LEN; scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN; /* hash_id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); hashl=n-p; scan_space-=hashl; if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; hashi=p; p=n+1;scan_space--; if (!syn_branch) { /* md5 value */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR ); loopl = n-p; scan_space-= loopl; if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; loopi=p; p=n+1; scan_space--; } else { /* synonym id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); synl=n-p; scan_space-=synl; if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; syni=p; p=n+1;scan_space--; } /* branch id - should exceed the scan_space */ n=eat_token_end( p, p+scan_space ); branchl=n-p; if (!branchl ) goto nomatch2; branchi=p; /* sanity check */ if (reverse_hex2int(hashi, hashl, &hash_index)<0 ||hash_index>=TABLE_ENTRIES || reverse_hex2int(branchi, branchl, &branch_id)<0 ||branch_id>=MAX_BRANCHES || (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 : loopl!=MD5_LEN ) ) { DBG("DEBUG: t_reply_matching: poor reply labels %d label %d " "branch %d\n", hash_index, entry_label, branch_id ); goto nomatch2; } DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n", hash_index, entry_label, branch_id ); /* search the hash table list at entry 'hash_index'; lock the entry first */ cseq_method=get_cseq(p_msg)->method; is_cancel=cseq_method.len==CANCEL_LEN && memcmp(cseq_method.s, CANCEL, CANCEL_LEN)==0; LOCK_HASH(hash_index); for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell=p_cell->next_cell) { /* first look if branch matches */ if (syn_branch) { if (p_cell->label != entry_label) continue; } else { if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0) continue; } /* sanity check ... too high branch ? */ if ( branch_id>=p_cell->nr_of_outgoings ) continue; /* does method match ? (remember -- CANCELs have the same branch as canceled transactions) */ req_method=p_cell->method; if ( /* method match */ ! ((cseq_method.len==req_method.len && memcmp( cseq_method.s, req_method.s, cseq_method.len )==0) /* or it is a local cancel */ || (is_cancel && is_invite(p_cell) /* commented out -- should_cancel_branch set it to BUSY_BUFFER to avoid collisions with replies; thus, we test here by buffer size */ /* && p_cell->uac[branch_id].local_cancel.buffer ))) */ && p_cell->uac[branch_id].local_cancel.buffer_len ))) continue; /* we passed all disqualifying factors .... the transaction has been matched ! */ set_t(p_cell); *p_branch =(int) branch_id; REF_UNSAFE( T ); UNLOCK_HASH(hash_index); DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T); /* if this is a 200 for INVITE, we will wish to store to-tags to be * able to distinguish retransmissions later and not to call * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are * enabled -- except callback customers, nobody cares about * retransmissions of multiple 200/INV or ACK/200s */ if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 && p_msg->REPLY_STATUS<300 && ( (!is_local(p_cell) && has_tran_tmcbs(p_cell,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) ) || (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED)) )) { if (parse_headers(p_msg, HDR_TO_F, 0)==-1) { LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n"); } } if (!is_local(p_cell)) { run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg, p_msg->REPLY_STATUS); } return 1; } /* for cycle */ /* nothing found */ UNLOCK_HASH(hash_index); DBG("DEBUG: t_reply_matching: no matching transaction exists\n"); nomatch2: DBG("DEBUG: t_reply_matching: failure to match a transaction\n"); *p_branch = -1; set_t(0); return -1; }
/* Returns 0 - nothing found * 1 - T found */ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) { struct cell* p_cell; unsigned int hash_index = 0; unsigned int entry_label = 0; unsigned int branch_id = 0; char *hashi, *branchi, *p, *n; int hashl, branchl; int scan_space; struct cseq_body *cseq; char *loopi; int loopl; char *syni; int synl; /* make compiler warnings happy */ loopi=0; loopl=0; syni=0; synl=0; /* split the branch into pieces: loop_detection_check(ignored), hash_table_id, synonym_id, branch_id */ if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s)) goto nomatch2; /* we do RFC 3261 tid matching and want to see first if there is * magic cookie in branch */ if (p_msg->via1->branch->value.len<=MCOOKIE_LEN) goto nomatch2; if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0) goto nomatch2; p=p_msg->via1->branch->value.s+MCOOKIE_LEN; scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN; /* hash_id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); hashl=n-p; scan_space-=hashl; if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; hashi=p; p=n+1;scan_space--; if (!syn_branch) { /* md5 value */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR ); loopl = n-p; scan_space-= loopl; if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; loopi=p; p=n+1; scan_space--; } else { /* synonym id */ n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); synl=n-p; scan_space-=synl; if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; syni=p; p=n+1;scan_space--; } /* branch id - should exceed the scan_space */ n=eat_token_end( p, p+scan_space ); branchl=n-p; if (!branchl ) goto nomatch2; branchi=p; /* sanity check */ if (reverse_hex2int(hashi, hashl, &hash_index)<0 ||hash_index>=TM_TABLE_ENTRIES || reverse_hex2int(branchi, branchl, &branch_id)<0 ||branch_id>=MAX_BRANCHES || (syn_branch ? reverse_hex2int(syni, synl, &entry_label)<0 : loopl!=MD5_LEN ) ) { LM_DBG("poor reply labels %u label %u branch %u\n", hash_index, entry_label, branch_id ); goto nomatch2; } LM_DBG("hash %u label %d branch %u\n",hash_index, entry_label, branch_id); cseq = get_cseq(p_msg); /* search the hash table list at entry 'hash_index'; lock the entry first */ LOCK_HASH(hash_index); for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell=p_cell->next_cell) { /* first look if branch matches */ if (syn_branch) { if (p_cell->label != entry_label) continue; } else { if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0) continue; } /* sanity check ... too high branch ? */ if ( branch_id>=p_cell->nr_of_outgoings ) continue; /* does method match ? (remember -- CANCELs have the same branch as canceled transactions) */ if (!( /* it's a local cancel */ (cseq->method_id==METHOD_CANCEL && is_invite(p_cell) && p_cell->uac[branch_id].local_cancel.buffer.len ) /* method match */ || ((cseq->method_id!=METHOD_OTHER && p_cell->uas.request)? (cseq->method_id==REQ_LINE(p_cell->uas.request).method_value) :(EQ_STRS(cseq->method,p_cell->method))) )) continue; /* we passed all disqualifying factors .... the transaction has been matched ! */ set_t(p_cell); *p_branch = branch_id; REF_UNSAFE( T ); UNLOCK_HASH(hash_index); LM_DBG("reply matched (T=%p)!\n",T); /* if this is a 200 for INVITE, we will wish to store to-tags to be * able to distinguish retransmissions later and not to call * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are * enabled -- except callback customers, nobody cares about * retransmissions of multiple 200/INV or ACK/200s */ if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 && p_msg->REPLY_STATUS<300 && ( (!is_local(p_cell) && has_tran_tmcbs(p_cell, TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) ) || (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED)) )) { if (parse_headers(p_msg, HDR_TO_F, 0)==-1) { LM_ERR("to parsing failed\n"); } } return 1; } /* for cycle */ /* nothing found */ UNLOCK_HASH(hash_index); LM_DBG("no matching transaction exists\n"); nomatch2: LM_DBG("failure to match a transaction\n"); *p_branch = -1; set_t(0); return -1; }
static int force_rtp_proxy2_f(struct sip_msg* msg, char* str1, char* str2) { str body, body1, oldport, oldip, newport, newip; str callid, from_tag, to_tag, tmp; int create, port, len, asymmetric, flookup, argc, proxied, real; int oidx, pf=0, pf1, force, node_idx; char opts[16]; char *cp, *cp1; char *cpend, *next; char **ap, *argv[10]; struct lump* anchor; struct rtpp_node *node; struct iovec v[14] = { {NULL, 0}, /* command */ {NULL, 0}, /* options */ {" ", 1}, /* separator */ {NULL, 0}, /* callid */ {" ", 1}, /* separator */ {NULL, 7}, /* newip */ {" ", 1}, /* separator */ {NULL, 1}, /* oldport */ {" ", 1}, /* separator */ {NULL, 0}, /* from_tag */ {";", 1}, /* separator */ {NULL, 0}, /* medianum */ {" ", 1}, /* separator */ {NULL, 0} /* to_tag */ }; char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit; char medianum_buf[20]; int medianum, media_multi; str medianum_str, tmpstr1; int c1p_altered; v[1].iov_base=opts; asymmetric = flookup = force = real = 0; oidx = 1; node_idx = -1; for (cp = str1; *cp != '\0'; cp++) { switch (*cp) { case ' ': case '\t': break; case 'a': case 'A': opts[oidx++] = 'A'; asymmetric = 1; real = 1; break; case 'i': case 'I': opts[oidx++] = 'I'; break; case 'e': case 'E': opts[oidx++] = 'E'; break; case 'l': case 'L': flookup = 1; break; case 'f': case 'F': force = 1; break; case 'r': case 'R': real = 1; break; case 'n': case 'N': cp++; for (len = 0; isdigit(cp[len]); len++) continue; if (len == 0) { LOG(L_ERR, "ERROR: force_rtp_proxy2: non-negative integer" "should follow N option\n"); return -1; } node_idx = strtoul(cp, NULL, 10); cp += len - 1; break; default: LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp); return -1; } } if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE) { create = 1; } else if (msg->first_line.type == SIP_REPLY) { create = 0; } else { return -1; } /* extract_body will also parse all the headers in the message as * a side effect => don't move get_callid/get_to_tag in front of it * -- andrei */ if (extract_body(msg, &body) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract body " "from the message\n"); return -1; } if (get_callid(msg, &callid) == -1 || callid.len == 0) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get Call-Id field\n"); return -1; } if (get_to_tag(msg, &to_tag) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get To tag\n"); return -1; } if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get From tag\n"); return -1; } if (flookup != 0) { if (create == 0 || to_tag.len == 0) return -1; create = 0; tmp = from_tag; from_tag = to_tag; to_tag = tmp; } proxied = 0; for (cp = body.s; (len = body.s + body.len - cp) >= ANORTPPROXY_LEN;) { cp1 = ser_memmem(cp, ANORTPPROXY, len, ANORTPPROXY_LEN); if (cp1 == NULL) break; if (cp1[-1] == '\n' || cp1[-1] == '\r') { proxied = 1; break; } cp = cp1 + ANORTPPROXY_LEN; } if (proxied != 0 && force == 0) return -1; /* * Parsing of SDP body. * It can contain a few session descriptions (each starts with * v-line), and each session may contain a few media descriptions * (each starts with m-line). * We have to change ports in m-lines, and also change IP addresses in * c-lines which can be placed either in session header (fallback for * all medias) or media description. * Ports should be allocated for any media. IPs all should be changed * to the same value (RTP proxy IP), so we can change all c-lines * unconditionally. */ bodylimit = body.s + body.len; v1p = find_sdp_line(body.s, bodylimit, 'v'); if (v1p == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: no sessions in SDP\n"); return -1; } v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); media_multi = (v2p != bodylimit); v2p = v1p; medianum = 0; for(;;) { /* Per-session iteration. */ v1p = v2p; if (v1p == NULL || v1p >= bodylimit) break; /* No sessions left */ v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); /* v2p is text limit for session parsing. */ m1p = find_sdp_line(v1p, v2p, 'm'); /* Have this session media description? */ if (m1p == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: no m= in session\n"); return -1; } /* * Find c1p only between session begin and first media. * c1p will give common c= for all medias. */ c1p = find_sdp_line(v1p, m1p, 'c'); c1p_altered = 0; /* Have session. Iterate media descriptions in session */ m2p = m1p; for (;;) { m1p = m2p; if (m1p == NULL || m1p >= v2p) break; m2p = find_next_sdp_line(m1p, v2p, 'm', v2p); /* c2p will point to per-media "c=" */ c2p = find_sdp_line(m1p, m2p, 'c'); /* Extract address and port */ tmpstr1.s = c2p ? c2p : c1p; if (tmpstr1.s == NULL) { /* No "c=" */ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't" " find media IP in the message\n"); return -1; } tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */ if (extract_mediaip(&tmpstr1, &oldip, &pf) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't" " extract media IP from the message\n"); return -1; } tmpstr1.s = m1p; tmpstr1.len = m2p - m1p; if (extract_mediaport(&tmpstr1, &oldport) == -1) { LOG(L_ERR, "ERROR: force_rtp_proxy2: can't" " extract media port from the message\n"); return -1; } ++medianum; if (asymmetric != 0 || real != 0) { newip = oldip; } else { newip.s = ip_addr2a(&msg->rcv.src_ip); newip.len = strlen(newip.s); } /* XXX must compare address families in all addresses */ if (pf == AF_INET6) { opts[oidx] = '6'; oidx++; } snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum); medianum_str.s = medianum_buf; medianum_str.len = strlen(medianum_buf); opts[0] = (create == 0) ? 'L' : 'U'; v[1].iov_len = oidx; STR2IOVEC(callid, v[3]); STR2IOVEC(newip, v[5]); STR2IOVEC(oldport, v[7]); STR2IOVEC(from_tag, v[9]); if (1 || media_multi) /* XXX netch: can't choose now*/ { STR2IOVEC(medianum_str, v[11]); } else { v[10].iov_len = v[11].iov_len = 0; } STR2IOVEC(to_tag, v[13]); do { node = select_rtpp_node(callid, 1, node_idx); if (!node) { LOG(L_ERR, "ERROR: force_rtp_proxy2: no available proxies\n"); return -1; } cp = send_rtpp_command(node, v, (to_tag.len > 0) ? 14 : 12); } while (cp == NULL); /* Parse proxy reply to <argc,argv> */ argc = 0; memset(argv, 0, sizeof(argv)); cpend=cp+strlen(cp); next=eat_token_end(cp, cpend); for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){ *next=0; if (*cp != '\0') { *ap=cp; argc++; if ((char*)++ap >= ((char*)argv+sizeof(argv))) break; } } if (argc < 1) { LOG(L_ERR, "force_rtp_proxy2: no reply from rtp proxy\n"); return -1; } port = atoi(argv[0]); if (port <= 0 || port > 65535) { LOG(L_ERR, "force_rtp_proxy2: incorrect port in reply from rtp proxy\n"); return -1; } pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET; if (isnulladdr(&oldip, pf)) { if (pf1 == AF_INET6) { newip.s = "::"; newip.len = 2; } else { newip.s = "0.0.0.0"; newip.len = 7; } } else { newip.s = (argc < 2) ? str2 : argv[1]; newip.len = strlen(newip.s); } newport.s = int2str(port, &newport.len); /* beware static buffer */ /* Alter port. */ body1.s = m1p; body1.len = bodylimit - body1.s; if (alter_mediaport(msg, &body1, &oldport, &newport, 0) == -1) return -1; /* * Alter IP. Don't alter IP common for the session * more than once. */ if (c2p != NULL || !c1p_altered) { body1.s = c2p ? c2p : c1p; body1.len = bodylimit - body1.s; if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0) == -1) return -1; if (!c2p) c1p_altered = 1; } } /* Iterate medias in session */ } /* Iterate sessions */ if (proxied == 0) { cp = pkg_malloc(ANORTPPROXY_LEN * sizeof(char)); if (cp == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: out of memory\n"); return -1; } anchor = anchor_lump(msg, body.s + body.len - msg->buf, 0, 0); if (anchor == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: anchor_lump failed\n"); pkg_free(cp); return -1; } memcpy(cp, ANORTPPROXY, ANORTPPROXY_LEN); if (insert_new_lump_after(anchor, cp, ANORTPPROXY_LEN, 0) == NULL) { LOG(L_ERR, "ERROR: force_rtp_proxy2: insert_new_lump_after failed\n"); pkg_free(cp); return -1; } } return 1; }
static int extract_mediaport(str *body, str *mediaport) { char *cp, *cp1; int len, i; str ptype; cp1 = NULL; for (cp = body->s; (len = body->s + body->len - cp) > 0;) { cp1 = ser_memmem(cp, "m=", len, 2); if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') break; cp = cp1 + 2; } if (cp1 == NULL) { LOG(L_ERR, "ERROR: extract_mediaport: no `m=' in SDP\n"); return -1; } mediaport->s = cp1 + 2; /* skip `m=' */ mediaport->len = eat_line(mediaport->s, body->s + body->len - mediaport->s) - mediaport->s; trim_len(mediaport->len, mediaport->s, *mediaport); /* Skip media supertype and spaces after it */ cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); mediaport->len -= cp - mediaport->s; if (mediaport->len <= 0 || cp == mediaport->s) { LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); return -1; } mediaport->s = cp; cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len); mediaport->len -= cp - mediaport->s; if (mediaport->len <= 0 || cp == mediaport->s) { LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); return -1; } /* Extract port */ mediaport->s = cp; cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); ptype.len = mediaport->len - (cp - mediaport->s); if (ptype.len <= 0 || cp == mediaport->s) { LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); return -1; } ptype.s = cp; mediaport->len = cp - mediaport->s; /* Skip spaces after port */ cp = eat_space_end(ptype.s, ptype.s + ptype.len); ptype.len -= cp - ptype.s; if (ptype.len <= 0 || cp == ptype.s) { LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n"); return -1; } /* Extract protocol type */ ptype.s = cp; cp = eat_token_end(ptype.s, ptype.s + ptype.len); if (cp == ptype.s) { LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n"); return -1; } ptype.len = cp - ptype.s; for (i = 0; sup_ptypes[i].s != NULL; i++) if (ptype.len == sup_ptypes[i].len && strncasecmp(ptype.s, sup_ptypes[i].s, ptype.len) == 0) return 0; /* Unproxyable protocol type. Generally it isn't error. */ return -1; }