/src/SanityCheck.js
https://bitbucket.org/anadalg/jssip · JavaScript · 225 lines · 158 code · 31 blank · 36 comment · 31 complexity · e479591d19fa7e3d8172f97de9bfaf78 MD5 · raw file
- /**
- * @fileoverview Incoming SIP Message Sanity Check
- */
- /**
- * SIP message sanity check.
- * @augments JsSIP
- * @function
- * @param {JsSIP.IncomingMessage} message
- * @param {JsSIP.UA} ua
- * @param {JsSIP.Transport} transport
- * @returns {Boolean}
- */
- (function(JsSIP) {
- var sanityCheck,
- LOG_PREFIX = JsSIP.name +' | '+ 'SANITY CHECK' +' | ',
- message, ua, transport,
- requests = [],
- responses = [],
- all = [];
- /*
- * Sanity Check for incoming Messages
- *
- * Requests:
- * - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme
- * - _rfc3261_16_3_4_ Receive a Request already sent by us
- * Does not look at via sent-by but at jssip_id, which is inserted as
- * a prefix in all initial requests generated by the ua
- * - _rfc3261_18_3_request_ Body Content-Length
- * - _rfc3261_8_2_2_2_ Merged Requests
- *
- * Responses:
- * - _rfc3261_8_1_3_3_ Multiple Via headers
- * - _rfc3261_18_1_2_ sent-by mismatch
- * - _rfc3261_18_3_response_ Body Content-Length
- *
- * All:
- * - Minimum headers in a SIP message
- */
- // Sanity Check functions for requests
- function rfc3261_8_2_2_1() {
- if(message.s('to').uri.scheme !== 'sip') {
- reply(416);
- return false;
- }
- }
- function rfc3261_16_3_4() {
- if(!message.to_tag) {
- if(message.call_id.substr(0, 5) === ua.configuration.jssip_id) {
- reply(482);
- return false;
- }
- }
- }
- function rfc3261_18_3_request() {
- var len = JsSIP.Utils.str_utf8_length(message.body),
- contentLength = message.getHeader('content-length');
- if(len < contentLength) {
- reply(400);
- return false;
- }
- }
- function rfc3261_8_2_2_2() {
- var tr, idx,
- fromTag = message.from_tag,
- call_id = message.call_id,
- cseq = message.cseq;
- if(!message.to_tag) {
- if(message.method === JsSIP.C.INVITE) {
- tr = ua.transactions.ist[message.via_branch];
- if(!tr) {
- return;
- } else {
- for(idx in ua.transactions.ist) {
- tr = ua.transactions.ist[idx];
- if(tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
- reply(482);
- return false;
- }
- }
- }
- } else {
- tr = ua.transactions.nist[message.via_branch];
- if(!tr) {
- return;
- } else {
- for(idx in ua.transactions.nist) {
- tr = ua.transactions.nist[idx];
- if(tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
- reply(482);
- return false;
- }
- }
- }
- }
- }
- }
- // Sanity Check functions for responses
- function rfc3261_8_1_3_3() {
- if(message.countHeader('via') > 1) {
- console.warn(LOG_PREFIX +'More than one Via header field present in the response. Dropping the response');
- return false;
- }
- }
- function rfc3261_18_1_2() {
- var via_host = ua.configuration.via_host;
- if(message.via.host !== via_host) {
- console.warn(LOG_PREFIX +'Via host in the response does not match UA Via host value. Dropping the response');
- return false;
- }
- }
- function rfc3261_18_3_response() {
- var
- len = JsSIP.Utils.str_utf8_length(message.body),
- contentLength = message.getHeader('content-length');
- if(len < contentLength) {
- console.warn(LOG_PREFIX +'Message body length is lower than the value in Content-Length header field. Dropping the response');
- return false;
- }
- }
- // Sanity Check functions for requests and responses
- function minimumHeaders() {
- var
- mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'],
- idx = mandatoryHeaders.length;
- while(idx--) {
- if(!message.hasHeader(mandatoryHeaders[idx])) {
- console.warn(LOG_PREFIX +'Missing mandatory header field : '+ mandatoryHeaders[idx] +'. Dropping the response');
- return false;
- }
- }
- }
- // Reply
- function reply(status_code) {
- var to,
- response = "SIP/2.0 " + status_code + " " + JsSIP.C.REASON_PHRASE[status_code] + "\r\n",
- via_length = message.countHeader('via'),
- idx = 0;
- for(idx; idx < via_length; idx++) {
- response += "Via: " + message.getHeader('via', idx) + "\r\n";
- }
- to = message.getHeader('To');
- if(!message.to_tag) {
- to += ';tag=' + JsSIP.Utils.newTag();
- }
- response += "To: " + to + "\r\n";
- response += "From: " + message.getHeader('From') + "\r\n";
- response += "Call-ID: " + message.call_id + "\r\n";
- response += "CSeq: " + message.cseq + " " + message.method + "\r\n";
- response += "\r\n";
- transport.send(response);
- }
- requests.push(rfc3261_8_2_2_1);
- requests.push(rfc3261_16_3_4);
- requests.push(rfc3261_18_3_request);
- requests.push(rfc3261_8_2_2_2);
- responses.push(rfc3261_8_1_3_3);
- responses.push(rfc3261_18_1_2);
- responses.push(rfc3261_18_3_response);
- all.push(minimumHeaders);
- sanityCheck = function(m, u, t) {
- var len, pass;
- message = m;
- ua = u;
- transport = t;
- len = all.length;
- while(len--) {
- pass = all[len](message);
- if(pass === false) {
- return false;
- }
- }
- if(message instanceof JsSIP.IncomingRequest) {
- len = requests.length;
- while(len--) {
- pass = requests[len](message);
- if(pass === false) {
- return false;
- }
- }
- }
- else if(message instanceof JsSIP.IncomingResponse) {
- len = responses.length;
- while(len--) {
- pass = responses[len](message);
- if(pass === false) {
- return false;
- }
- }
- }
- //Everything is OK
- return true;
- };
- JsSIP.sanityCheck = sanityCheck;
- }(JsSIP));