-
Notifications
You must be signed in to change notification settings - Fork 704
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8cb7505
commit a8b14e1
Showing
39 changed files
with
35,303 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
"use strict"; | ||
module.exports = function (SIP) { | ||
var ClientContext; | ||
ClientContext = function (ua, method, target, options) { | ||
var originalTarget = target; | ||
// Validate arguments | ||
if (target === undefined) { | ||
throw new TypeError('Not enough arguments'); | ||
} | ||
this.ua = ua; | ||
this.logger = ua.getLogger('sip.clientcontext'); | ||
this.method = method; | ||
target = ua.normalizeTarget(target); | ||
if (!target) { | ||
throw new TypeError('Invalid target: ' + originalTarget); | ||
} | ||
/* Options | ||
* - extraHeaders | ||
* - params | ||
* - contentType | ||
* - body | ||
*/ | ||
options = Object.create(options || Object.prototype); | ||
options.extraHeaders = (options.extraHeaders || []).slice(); | ||
// Build the request | ||
this.request = new SIP.OutgoingRequest(this.method, target, this.ua, options.params, options.extraHeaders); | ||
if (options.body) { | ||
this.body = {}; | ||
this.body.body = options.body; | ||
if (options.contentType) { | ||
this.body.contentType = options.contentType; | ||
} | ||
this.request.body = this.body; | ||
} | ||
/* Set other properties from the request */ | ||
this.localIdentity = this.request.from; | ||
this.remoteIdentity = this.request.to; | ||
this.data = {}; | ||
}; | ||
ClientContext.prototype = Object.create(SIP.EventEmitter.prototype); | ||
ClientContext.prototype.send = function () { | ||
(new SIP.RequestSender(this, this.ua)).send(); | ||
return this; | ||
}; | ||
ClientContext.prototype.cancel = function (options) { | ||
options = options || {}; | ||
options.extraHeaders = (options.extraHeaders || []).slice(); | ||
var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase); | ||
this.request.cancel(cancel_reason, options.extraHeaders); | ||
this.emit('cancel'); | ||
}; | ||
ClientContext.prototype.receiveResponse = function (response) { | ||
var cause = SIP.Utils.getReasonPhrase(response.status_code); | ||
switch (true) { | ||
case /^1[0-9]{2}$/.test(response.status_code): | ||
this.emit('progress', response, cause); | ||
break; | ||
case /^2[0-9]{2}$/.test(response.status_code): | ||
if (this.ua.applicants[this]) { | ||
delete this.ua.applicants[this]; | ||
} | ||
this.emit('accepted', response, cause); | ||
break; | ||
default: | ||
if (this.ua.applicants[this]) { | ||
delete this.ua.applicants[this]; | ||
} | ||
this.emit('rejected', response, cause); | ||
this.emit('failed', response, cause); | ||
break; | ||
} | ||
}; | ||
ClientContext.prototype.onRequestTimeout = function () { | ||
this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); | ||
}; | ||
ClientContext.prototype.onTransportError = function () { | ||
this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); | ||
}; | ||
SIP.ClientContext = ClientContext; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
"use strict"; | ||
/** | ||
* @fileoverview SIP Constants | ||
*/ | ||
/** | ||
* SIP Constants. | ||
* @augments SIP | ||
*/ | ||
module.exports = function (name, version) { | ||
return { | ||
USER_AGENT: name + '/' + version, | ||
// SIP scheme | ||
SIP: 'sip', | ||
SIPS: 'sips', | ||
// End and Failure causes | ||
causes: { | ||
// Generic error causes | ||
CONNECTION_ERROR: 'Connection Error', | ||
REQUEST_TIMEOUT: 'Request Timeout', | ||
SIP_FAILURE_CODE: 'SIP Failure Code', | ||
INTERNAL_ERROR: 'Internal Error', | ||
// SIP error causes | ||
BUSY: 'Busy', | ||
REJECTED: 'Rejected', | ||
REDIRECTED: 'Redirected', | ||
UNAVAILABLE: 'Unavailable', | ||
NOT_FOUND: 'Not Found', | ||
ADDRESS_INCOMPLETE: 'Address Incomplete', | ||
INCOMPATIBLE_SDP: 'Incompatible SDP', | ||
AUTHENTICATION_ERROR: 'Authentication Error', | ||
DIALOG_ERROR: 'Dialog Error', | ||
// Session error causes | ||
WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported', | ||
WEBRTC_ERROR: 'WebRTC Error', | ||
CANCELED: 'Canceled', | ||
NO_ANSWER: 'No Answer', | ||
EXPIRES: 'Expires', | ||
NO_ACK: 'No ACK', | ||
NO_PRACK: 'No PRACK', | ||
USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access', | ||
BAD_MEDIA_DESCRIPTION: 'Bad Media Description', | ||
RTP_TIMEOUT: 'RTP Timeout' | ||
}, | ||
supported: { | ||
UNSUPPORTED: 'none', | ||
SUPPORTED: 'supported', | ||
REQUIRED: 'required' | ||
}, | ||
SIP_ERROR_CAUSES: { | ||
REDIRECTED: [300, 301, 302, 305, 380], | ||
BUSY: [486, 600], | ||
REJECTED: [403, 603], | ||
NOT_FOUND: [404, 604], | ||
UNAVAILABLE: [480, 410, 408, 430], | ||
ADDRESS_INCOMPLETE: [484], | ||
INCOMPATIBLE_SDP: [488, 606], | ||
AUTHENTICATION_ERROR: [401, 407] | ||
}, | ||
// SIP Methods | ||
ACK: 'ACK', | ||
BYE: 'BYE', | ||
CANCEL: 'CANCEL', | ||
INFO: 'INFO', | ||
INVITE: 'INVITE', | ||
MESSAGE: 'MESSAGE', | ||
NOTIFY: 'NOTIFY', | ||
OPTIONS: 'OPTIONS', | ||
REGISTER: 'REGISTER', | ||
UPDATE: 'UPDATE', | ||
SUBSCRIBE: 'SUBSCRIBE', | ||
PUBLISH: 'PUBLISH', | ||
REFER: 'REFER', | ||
PRACK: 'PRACK', | ||
/* 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', | ||
200: 'OK', | ||
202: 'Accepted', | ||
204: 'No Notification', | ||
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', | ||
413: 'Request Entity Too Large', | ||
414: 'Request-URI Too Long', | ||
415: 'Unsupported Media Type', | ||
416: 'Unsupported URI Scheme', | ||
417: 'Unknown Resource-Priority', | ||
420: 'Bad Extension', | ||
421: 'Extension Required', | ||
422: 'Session Interval Too Small', | ||
423: 'Interval Too Brief', | ||
428: 'Use Identity Header', | ||
429: 'Provide Referrer Identity', | ||
430: 'Flow Failed', | ||
433: 'Anonymity Disallowed', | ||
436: 'Bad Identity-Info', | ||
437: 'Unsupported Certificate', | ||
438: 'Invalid Identity Header', | ||
439: 'First Hop Lacks Outbound Support', | ||
440: 'Max-Breadth Exceeded', | ||
469: 'Bad Info Package', | ||
470: 'Consent Needed', | ||
478: 'Unresolvable Destination', | ||
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', | ||
491: 'Request Pending', | ||
493: 'Undecipherable', | ||
494: 'Security Agreement Required', | ||
500: 'Internal Server 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', | ||
600: 'Busy Everywhere', | ||
603: 'Decline', | ||
604: 'Does Not Exist Anywhere', | ||
606: 'Not Acceptable' | ||
}, | ||
/* SIP Option Tags | ||
* DOC: http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-4 | ||
*/ | ||
OPTION_TAGS: { | ||
'100rel': true, | ||
199: true, | ||
answermode: true, | ||
'early-session': true, | ||
eventlist: true, | ||
explicitsub: true, | ||
'from-change': true, | ||
'geolocation-http': true, | ||
'geolocation-sip': true, | ||
gin: true, | ||
gruu: true, | ||
histinfo: true, | ||
ice: true, | ||
join: true, | ||
'multiple-refer': true, | ||
norefersub: true, | ||
nosub: true, | ||
outbound: true, | ||
path: true, | ||
policy: true, | ||
precondition: true, | ||
pref: true, | ||
privacy: true, | ||
'recipient-list-invite': true, | ||
'recipient-list-message': true, | ||
'recipient-list-subscribe': true, | ||
replaces: true, | ||
'resource-priority': true, | ||
'sdp-anat': true, | ||
'sec-agree': true, | ||
tdialog: true, | ||
timer: true, | ||
uui: true // RFC 7433 | ||
}, | ||
dtmfType: { | ||
INFO: 'info', | ||
RTP: 'rtp' | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
"use strict"; | ||
/** | ||
* @fileoverview In-Dialog Request Sender | ||
*/ | ||
/** | ||
* @augments SIP.Dialog | ||
* @class Class creating an In-dialog request sender. | ||
* @param {SIP.Dialog} dialog | ||
* @param {Object} applicant | ||
* @param {SIP.OutgoingRequest} request | ||
*/ | ||
/** | ||
* @fileoverview in-Dialog Request Sender | ||
*/ | ||
module.exports = function (SIP) { | ||
var RequestSender; | ||
RequestSender = function (dialog, applicant, request) { | ||
this.dialog = dialog; | ||
this.applicant = applicant; | ||
this.request = request; | ||
// RFC3261 14.1 Modifying an Existing Session. UAC Behavior. | ||
this.reattempt = false; | ||
this.reattemptTimer = null; | ||
}; | ||
RequestSender.prototype = { | ||
send: function () { | ||
var self = this, request_sender = new SIP.RequestSender(this, this.dialog.owner.ua); | ||
request_sender.send(); | ||
// RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR- | ||
if (this.request.method === SIP.C.INVITE && request_sender.clientTransaction.state !== SIP.Transactions.C.STATUS_TERMINATED) { | ||
this.dialog.uac_pending_reply = true; | ||
request_sender.clientTransaction.on('stateChanged', function stateChanged() { | ||
if (this.state === SIP.Transactions.C.STATUS_ACCEPTED || | ||
this.state === SIP.Transactions.C.STATUS_COMPLETED || | ||
this.state === SIP.Transactions.C.STATUS_TERMINATED) { | ||
this.removeListener('stateChanged', stateChanged); | ||
self.dialog.uac_pending_reply = false; | ||
} | ||
}); | ||
} | ||
}, | ||
onRequestTimeout: function () { | ||
this.applicant.onRequestTimeout(); | ||
}, | ||
onTransportError: function () { | ||
this.applicant.onTransportError(); | ||
}, | ||
receiveResponse: function (response) { | ||
var self = this; | ||
// RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog. | ||
if (response.status_code === 408 || response.status_code === 481) { | ||
this.applicant.onDialogError(response); | ||
} | ||
else if (response.method === SIP.C.INVITE && response.status_code === 491) { | ||
if (this.reattempt) { | ||
this.applicant.receiveResponse(response); | ||
} | ||
else { | ||
this.request.cseq.value = this.dialog.local_seqnum += 1; | ||
this.reattemptTimer = setTimeout(function () { | ||
if (self.applicant.owner.status !== SIP.Session.C.STATUS_TERMINATED) { | ||
self.reattempt = true; | ||
self.request_sender.send(); | ||
} | ||
}, this.getReattemptTimeout()); | ||
} | ||
} | ||
else { | ||
this.applicant.receiveResponse(response); | ||
} | ||
} | ||
}; | ||
return RequestSender; | ||
}; |
Oops, something went wrong.