diff --git a/src/Dialogs.js b/src/Dialogs.js index 69fe3cd17..b97485d79 100644 --- a/src/Dialogs.js +++ b/src/Dialogs.js @@ -139,7 +139,7 @@ JsSIP.Dialog.prototype = { } else if(request.method !== JsSIP.c.INVITE && request.cseq < this.remote_seqnum) { //Do not try to reply to an ACK request. if (request.method !== JsSIP.c.ACK) { - request.reply(500, JsSIP.c.REASON_500); + request.reply(500); } return false; } else if(request.cseq > this.remote_seqnum) { @@ -152,17 +152,17 @@ JsSIP.Dialog.prototype = { if(request.cseq < this.remote_seqnum) { if(this.state === JsSIP.c.DIALOG_EARLY) { var retryAfter = (Math.random() * 10 | 0) + 1; - request.reply(500, JsSIP.c.REASON_500, [ + request.reply(500, JsSIP.c.REASON_PHRASE[500], [ 'Retry-After:'+ retryAfter ]); } else { - request.reply(500, JsSIP.c.REASON_500); + request.reply(500); } return false; } // RFC3261 14.2 if(this.state === JsSIP.c.DIALOG_EARLY) { - request.reply(491, JsSIP.c.REASON_491); + request.reply(491); return false; } // RFC3261 12.2.2 Replace the dialog`s remote target URI diff --git a/src/Message.js b/src/Message.js index 12687ec25..e5160c692 100644 --- a/src/Message.js +++ b/src/Message.js @@ -167,14 +167,14 @@ JsSIP.Message.prototype.init_incoming = function(request) { this.remote_identity = request.s('from').uri; this.accept = function() { - request.reply(200, JsSIP.c.REASON_200); + request.reply(200); }; this.reject = function(status_code, reason_phrase) { if (status_code && reason_phrase) { request.reply(status_code, reason_phrase); } else { - request.reply(480, JsSIP.c.REASON_480); + request.reply(480); } }; @@ -188,9 +188,9 @@ JsSIP.Message.prototype.init_incoming = function(request) { transaction = this.ua.transactions.nist[request.via_branch]; if (transaction && (transaction.state === JsSIP.c.TRANSACTION_TRYING || transaction.state === JsSIP.c.TRANSACTION_PROCEEDING)) { - request.reply(200, JsSIP.c.REASON_200); + request.reply(200); } } else { - request.reply(415, JsSIP.c.REASON_415, ["Accept: text/plain, text/html"]); + request.reply(415, JsSIP.c.REASON_PHRASE[415], ["Accept: text/plain, text/html"]); } }; diff --git a/src/SIPMessage.js b/src/SIPMessage.js index a93c68cb9..c67b5cc1f 100644 --- a/src/SIPMessage.js +++ b/src/SIPMessage.js @@ -343,14 +343,16 @@ JsSIP.IncomingRequest.prototype = new JsSIP.IncomingMessage(); * @param {Function} [onFailure] onFailure callback */ JsSIP.IncomingRequest.prototype.reply = function(code, reason, extraHeaders, body, onSuccess, onFailure) { - var rr, vias, header, length, idx, - response = 'SIP/2.0 ' + code + ' ' + reason + '\r\n', + var rr, vias, header, length, idx, response, to = this.getHeader('To'), r = 0, v = 0; + reason = reason || JsSIP.c.REASON_PHRASE[code] || ' '; extraHeaders = extraHeaders || []; + response = 'SIP/2.0 ' + code + ' ' + reason + '\r\n'; + if(this.method === JsSIP.c.INVITE && code > 100 && code <= 200) { rr = this.countHeader('record-route'); @@ -401,10 +403,13 @@ JsSIP.IncomingRequest.prototype.reply = function(code, reason, extraHeaders, bod * @param {String} reason reason phrase */ JsSIP.IncomingRequest.prototype.reply_sl = function(code, reason) { - var to, - response = 'SIP/2.0 ' + code + ' ' + reason + '\r\n', + var to, response, vias = this.countHeader('via'); + reason = reason || JsSIP.c.REASON_PHRASE[code] || ' '; + + response = 'SIP/2.0 ' + code + ' ' + reason + '\r\n'; + for(var v = 0; v < vias; v++) { response += 'Via: ' + this.getHeader('via', v) + '\r\n'; } diff --git a/src/SanityCheck.js b/src/SanityCheck.js index ad0227237..939562afa 100644 --- a/src/SanityCheck.js +++ b/src/SanityCheck.js @@ -37,7 +37,7 @@ JsSIP.sanityCheck = (function() { // Sanity Check functions for requests function rfc3261_8_2_2_1() { if(message.s('to').scheme !== 'sip') { - reply(416, JsSIP.c.REASON_416); + reply(416); return false; } } @@ -45,7 +45,7 @@ JsSIP.sanityCheck = (function() { function rfc3261_16_3_4() { if(!message.to_tag) { if(message.call_id.substr(0, 5) === ua.configuration.jssip_id) { - reply(482, JsSIP.c.REASON_482); + reply(482); return false; } } @@ -56,7 +56,7 @@ JsSIP.sanityCheck = (function() { contentLength = message.getHeader('content-length'); if(len < contentLength) { - reply(400, JsSIP.c.REASON_400); + reply(400); return false; } } @@ -76,7 +76,7 @@ JsSIP.sanityCheck = (function() { 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, JsSIP.c.REASON_482); + reply(482); return false; } } @@ -89,7 +89,7 @@ JsSIP.sanityCheck = (function() { 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, JsSIP.c.REASON_482); + reply(482); return false; } } @@ -136,9 +136,9 @@ JsSIP.sanityCheck = (function() { } // Reply - function reply(status_code, reason_phrase) { + function reply(status_code) { var to, - response = "SIP/2.0 " + status_code + " " + reason_phrase + "\r\n", + response = "SIP/2.0 " + status_code + " " + JsSIP.c.REASON_PHRASE[status_code] + "\r\n", via_length = message.countHeader('via'), idx = 0; diff --git a/src/Session.js b/src/Session.js index 1786653d2..4f9d93a27 100644 --- a/src/Session.js +++ b/src/Session.js @@ -310,7 +310,7 @@ JsSIP.Session.prototype.receiveRequest = function(request) { // Transaction layer already responded 487 to the initial request. // Reply 200 to CANCEL - request.reply(200, JsSIP.c.REASON_200); + request.reply(200); /* * Terminate the whole session in case the user didn't accept nor reject the @@ -332,7 +332,7 @@ JsSIP.Session.prototype.receiveRequest = function(request) { break; case JsSIP.c.BYE: if(this.status === JsSIP.c.SESSION_CONFIRMED) { - request.reply(200, JsSIP.c.REASON_200); + request.reply(200); this.ended('remote', request, JsSIP.c.causes.BYE); } break; @@ -408,7 +408,7 @@ JsSIP.Session.prototype.receiveInitialRequest = function(ua, request) { return; } - request.reply(200, JsSIP.c.REASON_200, [ + request.reply(200, JsSIP.c.REASON_PHRASE[200], [ 'Contact: <' + session.contact + '>'], sdp, // onSuccess @@ -437,7 +437,7 @@ JsSIP.Session.prototype.receiveInitialRequest = function(ua, request) { onMediaFailure = function(e) { // Unable to get User Media - request.reply(486, JsSIP.c.REASON_486); + request.reply(486); session.failed('local', null, JsSIP.c.causes.USER_DENIED_MEDIA_ACCESS); }; @@ -446,7 +446,7 @@ JsSIP.Session.prototype.receiveInitialRequest = function(ua, request) { * peerConnection.setRemoteDescription throws an exception */ console.log(JsSIP.c.LOG_SERVER_INVITE_SESSION +'PeerConnection Creation Failed: --'+e+'--'); - request.reply(488, JsSIP.c.REASON_488); + request.reply(488); session.failed('remote', request, JsSIP.c.causes.BAD_MEDIA_DESCRIPTION); }; @@ -461,7 +461,7 @@ JsSIP.Session.prototype.receiveInitialRequest = function(ua, request) { */ this.reject = function() { if (this.status === JsSIP.c.SESSION_WAITING_FOR_ANSWER) { - request.reply(486, JsSIP.c.REASON_486); + request.reply(486); this.failed('local', null, JsSIP.c.causes.REJECTED); } @@ -474,12 +474,12 @@ JsSIP.Session.prototype.receiveInitialRequest = function(ua, request) { if (this.status !== JsSIP.c.SESSION_TERMINATED) { this.progress('local'); - request.reply(180, JsSIP.c.REASON_180, [ + request.reply(180, JsSIP.c.REASON_PHRASE[180], [ 'Contact: <' + this.contact + '>' ]); } } else { - request.reply(415, JsSIP.c.REASON_415); + request.reply(415); } }; @@ -639,7 +639,7 @@ JsSIP.Session.prototype.ackTimeout = function() { */ JsSIP.Session.prototype.expiresTimeout = function(request) { if(this.status === JsSIP.c.SESSION_WAITING_FOR_ANSWER) { - request.reply(487, JsSIP.c.REASON_487); + request.reply(487); this.failed('system', null, JsSIP.c.causes.EXPIRES); } @@ -660,7 +660,7 @@ JsSIP.Session.prototype.invite2xxRetransmission = function(retransmissions, requ if((retransmissions * JsSIP.Timers.T1) <= JsSIP.Timers.T2) { retransmissions += 1; - request.reply(200, JsSIP.c.REASON_200, [ + request.reply(200, JsSIP.c.REASON_PHRASE[200], [ 'Contact: <' + this.contact + '>'], body); @@ -678,7 +678,7 @@ JsSIP.Session.prototype.invite2xxRetransmission = function(retransmissions, requ * @private */ JsSIP.Session.prototype.userNoAnswerTimeout = function(request) { - request.reply(408, JsSIP.c.REASON_408); + request.reply(408); this.failed('local',null, JsSIP.c.causes.NO_ANSWER); }; diff --git a/src/Transactions.js b/src/Transactions.js index 336ef66ef..50674a0af 100644 --- a/src/Transactions.js +++ b/src/Transactions.js @@ -552,7 +552,7 @@ JsSIP.Transactions.InviteServerTransaction = function(request, ua) { this.reliableProvisionalTimer = null; - request.reply(100, JsSIP.c.REASON_100); + request.reply(100); }; JsSIP.Transactions.InviteServerTransaction.prototype = new InviteServerTransactionPrototype(); @@ -622,13 +622,13 @@ JsSIP.Transactions.checkTransaction = function(ua, request) { tr = ua.transactions.ist[request.via_branch]; if(tr) { if(tr.state === JsSIP.c.TRANSACTION_PROCEEDING) { - tr.request.reply(487, JsSIP.c.REASON_487); + tr.request.reply(487); return false; } else { return true; } } else { - request.reply_sl(481, JsSIP.c.REASON_481); + request.reply_sl(481); return true; } break; diff --git a/src/UA.js b/src/UA.js index 3e8525664..1ab54493b 100644 --- a/src/UA.js +++ b/src/UA.js @@ -362,7 +362,7 @@ JsSIP.UA.prototype.receiveRequest = function(request) { //Check that Ruri points to us if(request.ruri.user !== this.configuration.user) { console.log(JsSIP.c.LOG_UA +'Request URI does not point to us'); - request.reply_sl(404, JsSIP.c.REASON_404); + request.reply_sl(404); return; } @@ -384,13 +384,13 @@ JsSIP.UA.prototype.receiveRequest = function(request) { * They are processed as if they had been received outside the dialog. */ if(method === JsSIP.c.OPTIONS) { - request.reply(200, JsSIP.c.REASON_200, [ + request.reply(200, JsSIP.c.REASON_PHRASE[200], [ 'Allow: '+ JsSIP.utils.getAllowedMethods(this), 'Accept: '+ JsSIP.c.ACCEPTED_BODY_TYPES ]); } else if (method === JsSIP.c.MESSAGE) { if (!this.checkEvent('newMessage') || this.listeners('newMessage').length === 0) { - request.reply(405, JsSIP.c.REASON_405, ['Allow: '+ JsSIP.utils.getAllowedMethods(this)]); + request.reply(405, JsSIP.c.REASON_PHRASE[405], ['Allow: '+ JsSIP.utils.getAllowedMethods(this)]); return; } message = new JsSIP.Message(this); @@ -401,7 +401,7 @@ JsSIP.UA.prototype.receiveRequest = function(request) { if(!request.to_tag) { if(!this.registrator || (this.registrator && !this.registrator.registered)) { // High user does not want to be contacted - request.reply(410, JsSIP.c.REASON_410); + request.reply(410); return; } @@ -416,7 +416,7 @@ JsSIP.UA.prototype.receiveRequest = function(request) { break; case JsSIP.c.BYE: // Out of dialog BYE received - request.reply(481, JsSIP.c.REASON_481); + request.reply(481); break; case JsSIP.c.CANCEL: session = this.findSession(request); @@ -433,7 +433,7 @@ JsSIP.UA.prototype.receiveRequest = function(request) { */ break; default: - request.reply(405, JsSIP.c.REASON_405); + request.reply(405); break; } } @@ -459,7 +459,7 @@ JsSIP.UA.prototype.receiveRequest = function(request) { */ else { if(method !== JsSIP.c.ACK) { - request.reply(481, JsSIP.c.REASON_481); + request.reply(481); } } } diff --git a/src/constants.js b/src/constants.js index 0d5bc35dd..b40e39842 100644 --- a/src/constants.js +++ b/src/constants.js @@ -130,68 +130,83 @@ JsSIP.c = { UPDATE: 'UPDATE', SUBSCRIBE: 'SUBSCRIBE', - // SIP Response Reasons - - // Provisional - REASON_100: 'Trying', - REASON_180: 'Ringing', - REASON_181: 'Call Is Being Forwarded', - REASON_182: 'Queued', - REASON_183: 'Session Progress', - - // Successful - REASON_200: 'OK', - - // Redirection - REASON_300: 'Multiple Choices', - REASON_301: 'Moved Permanently', - REASON_302: 'Moved Temporarily', - REASON_305: 'Use Proxy', - REASON_380: 'Alternative Service', - - // Request Failure - REASON_400: 'Bad Request', - REASON_401: 'Unauthorized', - REASON_402: 'Payment Required', - REASON_403: 'Forbidden', - REASON_404: 'Not Found', - REASON_405: 'Method Not Allowed', - REASON_406: 'Not Acceptable', - REASON_407: 'Proxy Authentication Required ', - REASON_408: 'Request Timeout', - REASON_410: 'Gone', - REASON_413: 'Request Entity Too Large', - REASON_414: 'Request-URI Too Long', - REASON_415: 'Unsupported Media Type', - REASON_416: 'Unsupported URI Scheme', - REASON_420: 'Bad Extension', - REASON_421: 'Extension Required', - REASON_423: 'Interval Too Brief', - REASON_480: 'Temporarily Unavailable', - REASON_481: 'Call/Transaction Does Not Exist', - REASON_482: 'Loop Detected', - REASON_483: 'Too Many Hops', - REASON_484: 'Address Incomplete', - REASON_485: 'Ambiguous', - REASON_486: 'Busy Here', - REASON_487: 'Request Terminated', - REASON_488: 'Not Acceptable Here', - REASON_491: 'Request Pending ', - REASON_493: 'Undecipherable', - - // Server Failure - REASON_500: 'Server Internal Error', - REASON_501: 'Not Implemented', - REASON_502: 'Bad Gateway', - REASON_503: 'Service Unavailable', - REASON_504: 'Server Time-out', - REASON_505: 'Version Not Supported', - REASON_513: 'Message Too Large', - - // Global Failure - REASON_600: 'Busy Everywhere', - REASON_603: 'Decline', - REASON_604: 'Does Not Exist Anywhere', + /* SIP Response Reasons + * DOC: http://www.iana.org/assignments/sip-parameters + * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7 + */ + REASON_PHRASE: { + 100: 'Trying', + 180: 'Ringing', + 181: 'Call Is Being Forwarded', + 182: 'Queued', + 183: 'Session Progress', + 199: 'Early Dialog Terminated', // draft-ietf-sipcore-199 + 200: 'OK', + 202: 'Accepted', // RFC 3265 + 204: 'No Notification', //RFC 5839 + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Moved Temporarily', + 305: 'Use Proxy', + 380: 'Alternative Service', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 410: 'Gone', + 412: 'Conditional Request Failed', // RFC 3903 + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Unsupported URI Scheme', + 417: 'Unknown Resource-Priority', // RFC 4412 + 420: 'Bad Extension', + 421: 'Extension Required', + 422: 'Session Interval Too Small', // RFC 4028 + 423: 'Interval Too Brief', + 428: 'Use Identity Header', // RFC 4474 + 429: 'Provide Referrer Identity', // RFC 3892 + 430: 'Flow Failed', // RFC 5626 + 433: 'Anonymity Disallowed', // RFC 5079 + 436: 'Bad Identity-Info', // RFC 4474 + 437: 'Unsupported Certificate', // RFC 4744 + 438: 'Invalid Identity Header', // RFC 4744 + 439: 'First Hop Lacks Outbound Support', // RFC 5626 + 440: 'Max-Breadth Exceeded', // RFC 5393 + 469: 'Bad Info Package', // draft-ietf-sipcore-info-events + 470: 'Consent Needed', // RF C5360 + 478: 'Unresolvable Destination', // Custom code copied from Kamailio. + 480: 'Temporarily Unavailable', + 481: 'Call/Transaction Does Not Exist', + 482: 'Loop Detected', + 483: 'Too Many Hops', + 484: 'Address Incomplete', + 485: 'Ambiguous', + 486: 'Busy Here', + 487: 'Request Terminated', + 488: 'Not Acceptable Here', + 489: 'Bad Event', // RFC 3265 + 491: 'Request Pending', + 493: 'Undecipherable', + 494: 'Security Agreement Required', // RFC 3329 + 500: 'Server Internal Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Server Time-out', + 505: 'Version Not Supported', + 513: 'Message Too Large', + 580: 'Precondition Failure', // RFC 3312 + 600: 'Busy Everywhere', + 603: 'Decline', + 604: 'Does Not Exist Anywhere', + 606: 'Not Acceptable' + }, // SIP Attributes MAX_FORWARDS: 69,