Skip to content
Permalink
Browse files

Enclose every JsSIP component with an inmediate function

- An alement cannot pollute the global namespace
- An element can make use of private variables or methods if required
- Each element has its own 'C' (constant) namespace, if required
  • Loading branch information
jmillan committed Feb 22, 2013
1 parent d830251 commit 6029e4533e986950e2af9d888ca77dbb4ab97645
Showing with 1,067 additions and 944 deletions.
  1. +15 −110 src/Constants.js
  2. +27 −16 src/Dialogs.js
  3. +14 −9 src/DigestAuthentication.js
  4. +23 −14 src/EventEmitter.js
  5. +8 −4 src/Exceptions.js
  6. +12 −3 src/InDialogRequestSender.js
  7. +21 −15 src/MediaSession.js
  8. +17 −13 src/Message.js
  9. +14 −5 src/NameAddrHeader.js
  10. +210 −208 src/Parser.js
  11. +13 −7 src/Registrator.js
  12. +9 −5 src/RequestSender.js
  13. +31 −19 src/SIPMessage.js
  14. +165 −158 src/SanityCheck.js
  15. +142 −116 src/Session.js
  16. +3 −3 src/Subscriber.js
  17. +25 −21 src/Timers.js
  18. +106 −91 src/Transactions.js
  19. +34 −24 src/Transport.js
  20. +120 −73 src/UA.js
  21. +15 −5 src/URI.js
  22. +17 −8 src/Utils.js
  23. +26 −17 src/WebRTC.js
@@ -1,4 +1,3 @@

/**
* @fileoverview JsSIP Constants
*/
@@ -11,88 +10,19 @@
JsSIP.C= {
USER_AGENT: JsSIP.name() +' '+ JsSIP.version(),

// Modules and Classes names for logging purposes
// Modules
LOG_PARSER: JsSIP.name() +' | '+ 'PARSER' +' | ',
LOG_DIGEST_AUTHENTICATION: JsSIP.name() +' | '+ 'DIGEST AUTHENTICATION' +' | ',
LOG_SANITY_CHECK: JsSIP.name() +' | '+ 'SANITY CHECK' +' | ',
LOG_UTILS: JsSIP.name() +' | '+ 'UTILS' +' | ',

// Classes
LOG_TRANSPORT: JsSIP.name() +' | '+ 'TRANSPORT' +' | ',
LOG_TRANSACTION: JsSIP.name() +' | '+ 'TRANSACTION' +' | ',
LOG_DIALOG: JsSIP.name() +' | '+ 'DIALOG' +' | ',
LOG_UA: JsSIP.name() +' | '+ 'UA' +' | ',
LOG_URI: JsSIP.name() +' | '+ 'URI' +' | ',
LOG_NAME_ADDR_HEADER: JsSIP.name() +' | '+ 'NAME ADDR HEADER' +' | ',
LOG_INVITE_SESSION: JsSIP.name() +' | '+ 'INVITE SESSION' +' | ',
LOG_CLIENT_INVITE_SESSION: JsSIP.name() +' | '+ 'CLIENT INVITE SESSION' +' | ',
LOG_SERVER_INVITE_SESSION: JsSIP.name() +' | '+ 'SERVER INVITE SESSION' +' | ',
LOG_EVENT_EMITTER: JsSIP.name() +' | '+ 'EVENT EMITTER' +' | ',
LOG_MEDIA_SESSION: JsSIP.name() +' | '+ 'MEDIA SESSION' +' | ',
LOG_MESSAGE: JsSIP.name() +' | '+ 'MESSAGE' +' | ',
LOG_MESSAGE_RECEIVER: JsSIP.name() +' | '+ 'MESSAGE_RECEIVER' +' | ',
LOG_MESSAGE_SENDER: JsSIP.name() +' | '+ 'MESSAGE_SENDER' +' | ',
LOG_REGISTRATOR: JsSIP.name() +' | '+ 'REGISTRATOR' +' | ',
LOG_REQUEST_SENDER: JsSIP.name() +' | '+ 'REQUEST SENDER' +' | ',
LOG_SUBSCRIBER: JsSIP.name() +' | '+ 'SUBSCRIBER' +' | ',
LOG_PRESENCE: JsSIP.name() +' | '+ 'PRESENCE' +' | ',
LOG_MESSAGE_SUMMARY: JsSIP.name() +' | '+ 'MESSAGE_SUMMARY' +' | ',


// SIP schemes
// SIP scheme
SIP: 'sip',

// Invalid target
INVALID_TARGET_URI: 'sip:invalid@invalid',

// Transaction states
TRANSACTION_TRYING: 1,
TRANSACTION_PROCEEDING: 2,
TRANSACTION_CALLING: 3,
TRANSACTION_ACCEPTED: 4,
TRANSACTION_COMPLETED: 5,
TRANSACTION_TERMINATED: 6,
TRANSACTION_CONFIRMED: 7,

// Dialog states
DIALOG_EARLY: 1,
DIALOG_CONFIRMED: 2,

// Invite Session states
SESSION_NULL: 0,
SESSION_INVITE_SENT: 1,
SESSION_1XX_RECEIVED: 2,
SESSION_INVITE_RECEIVED: 3,
SESSION_WAITING_FOR_ANSWER: 4,
SESSION_WAITING_FOR_ACK: 5,
SESSION_CANCELED: 6,
SESSION_TERMINATED: 7,
SESSION_CONFIRMED: 8,

// Global error codes
CONNECTION_ERROR: 1,
REQUEST_TIMEOUT: 2,

// End and failure causes
// End and Failure causes
causes: {

// Generic error causes
INVALID_TARGET: 'Invalid Target',
WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported',

// Invite session end causes
BYE: 'Terminated',
CANCELED: 'Canceled',
NO_ANSWER: 'No Answer',
EXPIRES: 'Expires',
CONNECTION_ERROR: 'Connection Error',
REQUEST_TIMEOUT: 'Request Timeout',
NO_ACK: 'No ACK',
USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
IN_DIALOG_408_OR_481: 'In-dialog 408 or 481',
SIP_FAILURE_CODE: 'SIP Failure Code',
INVALID_TARGET: 'Invalid Target',

// SIP error causes
BUSY: 'Busy',
@@ -102,7 +32,17 @@ JsSIP.C= {
NOT_FOUND: 'Not Found',
ADDRESS_INCOMPLETE: 'Address Incomplete',
INCOMPATIBLE_SDP: 'Incompatible SDP',
AUTHENTICATION_ERROR: 'Authentication Error'
AUTHENTICATION_ERROR: 'Authentication Error',
IN_DIALOG_408_OR_481: 'In-dialog 408 or 481',

// Session error causes
WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported',
CANCELED: 'Canceled',
NO_ANSWER: 'No Answer',
EXPIRES: 'Expires',
NO_ACK: 'No ACK',
USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
BAD_MEDIA_DESCRIPTION: 'Bad Media Description'
},

SIP_ERROR_CAUSES: {
@@ -116,21 +56,6 @@ JsSIP.C= {
AUTHENTICATION_ERROR:[401,407]
},

// UA status codes
UA_STATUS_INIT : 0,
UA_STATUS_READY: 1,
UA_STATUS_USER_CLOSED: 2,
UA_STATUS_NOT_READY: 3,

// UA error codes
UA_CONFIGURATION_ERROR: 1,
UA_NETWORK_ERROR: 2,

// WS server status codes
WS_SERVER_READY: 0,
WS_SERVER_DISCONNECTED: 1,
WS_SERVER_ERROR: 2,

// SIP Methods
ACK: 'ACK',
BYE: 'BYE',
@@ -193,7 +118,7 @@ JsSIP.C= {
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
470: 'Consent Needed', // RFC 5360
478: 'Unresolvable Destination', // Custom code copied from Kamailio.
480: 'Temporarily Unavailable',
481: 'Call/Transaction Does Not Exist',
@@ -220,25 +145,5 @@ JsSIP.C= {
603: 'Decline',
604: 'Does Not Exist Anywhere',
606: 'Not Acceptable'
},

// DTMF
DTMF_DEFAULT_DURATION: 100,
DTMF_MIN_DURATION: 70,
DTMF_MAX_DURATION: 6000,
DTMF_DEFAULT_INTER_TONE_GAP: 500,
DTMF_MIN_INTER_TONE_GAP: 50,

// SIP Attributes
MAX_FORWARDS: 69,
ALLOWED_METHODS: 'INVITE, ACK, CANCEL, BYE, OPTIONS, MESSAGE, SUBSCRIBE',
SUPPORTED: 'path, outbound, gruu',
ACCEPTED_BODY_TYPES: 'application/sdp, application/dtmf-relay',
TAG_LENGTH: 10,

// User Agent EVENT METHODS
UA_EVENT_METHODS: {
'newSession': 'INVITE',
'newMessage': 'MESSAGE'
}
};
@@ -1,6 +1,5 @@

/**
* @fileoverview SIP dialog
* @fileoverview SIP Dialog
*/

/**
@@ -9,25 +8,33 @@
* @param {JsSIP.Session} session
* @param {JsSIP.IncomingRequest|JsSIP.IncomingResponse} msg
* @param {Enum} type UAC / UAS
* @param {Enum} state JsSIP.C.DIALOG_EARLY / JsSIP.C.DIALOG_CONFIRMED
* @param {Enum} state JsSIP.Dialog.C.STATUS_EARLY / JsSIP.Dialog.C.STATUS_CONFIRMED
*/
(function(JsSIP) {
var Dialog,
LOG_PREFIX = JsSIP.name() +' | '+ 'DIALOG' +' | ',
C = {
// Dialog states
STATUS_EARLY: 1,
STATUS_CONFIRMED: 2
};

// RFC 3261 12.1
JsSIP.Dialog = function(session, msg, type, state) {
Dialog = function(session, msg, type, state) {
var contact;

if(msg.countHeader('contact') === 0) {
console.warn(JsSIP.C.LOG_DIALOG + 'no Contact header field, silently discarded');
console.warn(LOG_PREFIX + 'no Contact header field, silently discarded');
return false;
}

if(msg instanceof JsSIP.IncomingResponse) {
state = (msg.status_code < 200) ? JsSIP.C.DIALOG_EARLY : JsSIP.C.DIALOG_CONFIRMED;
state = (msg.status_code < 200) ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
} else if (msg instanceof JsSIP.IncomingRequest) {
// Create confirmed dialog if state is not defined
state = state || JsSIP.C.DIALOG_CONFIRMED;
state = state || C.STATUS_CONFIRMED;
} else {
console.warn(JsSIP.C.LOG_DIALOG + 'received message is not a SIP request neither a response, silently discarded');
console.warn(LOG_PREFIX + 'received message is not a SIP request neither a response, silently discarded');
return false;
}

@@ -70,18 +77,18 @@ JsSIP.Dialog = function(session, msg, type, state) {

this.session = session;
session.ua.dialogs[this.id.toString()] = this;
console.log(JsSIP.C.LOG_DIALOG +'new ' + type + ' dialog created: ' + this.state);
console.log(LOG_PREFIX +'new ' + type + ' dialog created with status ' + (this.state === C.STATUS_EARLY ? 'EARLY': 'CONFIRMED'));
};

JsSIP.Dialog.prototype = {
Dialog.prototype = {
/**
* @param {JsSIP.IncomingMessage} message
* @param {Enum} UAC/UAS
*/
update: function(message, type) {
this.state = JsSIP.C.DIALOG_CONFIRMED;
this.state = C.STATUS_CONFIRMED;

console.log(JsSIP.C.LOG_DIALOG +'dialog state changed to CONFIRMED');
console.log(LOG_PREFIX +'dialog '+ this.id.toString() +' changed to CONFIRMED state');

if(type === 'UAC') {
// RFC 3261 13.2.2.4
@@ -90,7 +97,7 @@ JsSIP.Dialog.prototype = {
},

terminate: function() {
console.log(JsSIP.C.LOG_DIALOG +'dialog ' + this.id.toString() + ' deleted');
console.log(LOG_PREFIX +'dialog ' + this.id.toString() + ' deleted');
delete this.session.ua.dialogs[this.id.toString()];
},

@@ -150,7 +157,7 @@ JsSIP.Dialog.prototype = {
// RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-
case JsSIP.C.INVITE:
if(request.cseq < this.remote_seqnum) {
if(this.state === JsSIP.C.DIALOG_EARLY) {
if(this.state === C.STATUS_EARLY) {
var retryAfter = (Math.random() * 10 | 0) + 1;
request.reply(500, null, ['Retry-After:'+ retryAfter]);
} else {
@@ -159,7 +166,7 @@ JsSIP.Dialog.prototype = {
return false;
}
// RFC3261 14.2
if(this.state === JsSIP.C.DIALOG_EARLY) {
if(this.state === C.STATUS_EARLY) {
request.reply(491);
return false;
}
@@ -190,4 +197,8 @@ JsSIP.Dialog.prototype = {

this.session.receiveRequest(request);
}
};
};

Dialog.C = C;
JsSIP.Dialog = Dialog;
}(JsSIP));
@@ -1,17 +1,19 @@

/**
* @fileoverview DigestAuthentication
* @fileoverview SIP Digest Authentication
*/

/**
* SIP Digest Authentication.
* @augments JsSIP.
* @function Digest Authentication
* @param {JsSIP.UA} ua
* @param {JsSIP.OutgoingRequest} request
* @param {JsSIP.IncomingResponse} response
*/
JsSIP.DigestAuthentication = function (ua, request, response) {
(function(JsSIP) {
var DigestAuthentication,
LOG_PREFIX = JsSIP.name() +' | '+ 'DIGEST AUTHENTICATION' +' | ';

DigestAuthentication = function (ua, request, response) {
var authenticate, realm, qop, nonce, opaque,
username = ua.configuration.authorization_user,
password = ua.configuration.password;
@@ -42,7 +44,7 @@ JsSIP.DigestAuthentication = function (ua, request, response) {
this.nc = 0;
};

JsSIP.DigestAuthentication.prototype.authenticate = function(password) {
DigestAuthentication.prototype.authenticate = function(password) {
var ha1, ha2;

password = password || this.password;
@@ -52,7 +54,7 @@ JsSIP.DigestAuthentication.prototype.authenticate = function(password) {

// nc-value = 8LHEX. Max value = 'FFFFFFFF'
if (this.nc === 4294967296) {
console.log(JsSIP.C.LOG_DIGEST_AUTHENTICATION + 'maximum "nc" value has been reached, resetting "nc"');
console.log(LOG_PREFIX + 'maximum "nc" value has been reached, resetting "nc"');
this.nc = 1;
}

@@ -80,7 +82,7 @@ JsSIP.DigestAuthentication.prototype.authenticate = function(password) {
};


JsSIP.DigestAuthentication.prototype.update = function(response) {
DigestAuthentication.prototype.update = function(response) {
var authenticate, nonce;

if(response.status_code === 401) {
@@ -102,7 +104,7 @@ JsSIP.DigestAuthentication.prototype.update = function(response) {
};


JsSIP.DigestAuthentication.prototype.toString = function() {
DigestAuthentication.prototype.toString = function() {
var authorization = 'Digest ';

authorization += 'username="' + this.username + '",';
@@ -120,7 +122,10 @@ JsSIP.DigestAuthentication.prototype.toString = function() {
};


JsSIP.DigestAuthentication.prototype.decimalToHex = function(decimal) {
DigestAuthentication.prototype.decimalToHex = function(decimal) {
var hex = Number(decimal).toString(16);
return '00000000'.substr(0, 8-hex.length) + hex;
};

JsSIP.DigestAuthentication = DigestAuthentication;
}(JsSIP));

1 comment on commit 6029e45

@jmillan

This comment has been minimized.

Copy link
Member Author

jmillan commented on 6029e45 Feb 22, 2013

Every JsSIP element is enclosed in an immediate function:

(function(JsSIP) {
var ElementName,

// Start of Auxiliary functions and variables
...
...
// End of Auxiliary functions and variables

ElementName = function(){
  ...
  ...
}

JsSIP.ElementName = ElementName; // Attach only Elementname to JsSIP. Everything else coocked in this closure is not reflected enywhere else.
}(JsSIP));
Please sign in to comment.
You can’t perform that action at this time.