Dependency updates and new API for logging

This commit is contained in:
2018-08-22 17:05:29 +02:00
parent d9d3babe3b
commit 81be0a9aea
9 changed files with 198 additions and 172 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2017 Larv IT AB Copyright (c) 2018 Larv IT AB
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+21 -9
View File
@@ -19,7 +19,7 @@ npm install larvitsmpp
This will setup a client that connects to localhost, port 2775 without username or password and send a message. This will setup a client that connects to localhost, port 2775 without username or password and send a message.
```javascript ```javascript
var larvitsmpp = require('larvitsmpp'); const larvitsmpp = require('larvitsmpp');
larvitsmpp.client(function(err, clientSession) { larvitsmpp.client(function(err, clientSession) {
clientSession.sendSms({ clientSession.sendSms({
@@ -35,14 +35,20 @@ larvitsmpp.client(function(err, clientSession) {
### Some connection parameters and DLR ### Some connection parameters and DLR
This will setup a client that connects to given host, port with username and password, send a password and retrieve a DLR. This will setup a client that connects to given host, port with username and password, send a password and retrieve a DLR and with a custom log driver, compatible with winston.
```javascript ```javascript
const larvitsmpp = require('larvitsmpp');
const LUtils = require('larvitutils');
const lUtils = new LUtils();
const log = new lUtils.Log('debug');
larvitsmpp.client({ larvitsmpp.client({
'host': 'smpp.somewhere.com', 'host': 'smpp.somewhere.com',
'port': 2775, 'port': 2775,
'username': 'foo', 'username': 'foo',
'password': 'bar' 'password': 'bar',
'log': log
}, function(err, clientSession) { }, function(err, clientSession) {
if (err) { if (err) {
throw err; throw err;
@@ -82,7 +88,7 @@ larvitsmpp.client({
This will setup a password less server on localhost, port 2775 and console.log() incomming commands. This will setup a password less server on localhost, port 2775 and console.log() incomming commands.
```javascript ```javascript
var larvitsmpp = require('larvitsmpp'); const larvitsmpp = require('larvitsmpp');
larvitsmpp.server(function(err, serverSession) { larvitsmpp.server(function(err, serverSession) {
if (err) { if (err) {
@@ -95,23 +101,29 @@ larvitsmpp.server(function(err, serverSession) {
}); });
``` ```
### With auth, returning smsId and DLR ### With auth and custom logging, returning smsId and DLR
Example code below: Example code below:
```javascript ```javascript
const larvitsmpp = require('larvitsmpp');
const LUtils = require('larvitutils');
const lUtils = new LUtils();
const log = new lUtils.Log('debug');
// This should of course be replaced with your preferred auth system // This should of course be replaced with your preferred auth system
function checkuserpass(username, password, callback) { function checkuserpass(username, password, cb) {
if (username === 'foo' && password === 'bar') { if (username === 'foo' && password === 'bar') {
// The last parameter is just user meta data that will be attached to the session as "userData" and is optional // The last parameter is just user meta data that will be attached to the session as "userData" and is optional
callback(null, true, {'username': 'foo', 'userId': 123}); cb(null, true, {'username': 'foo', 'userId': 123});
} else { } else {
callback(null, false); cb(null, false);
} }
} }
larvitsmpp.server({ larvitsmpp.server({
'checkuserpass': checkuserpass 'checkuserpass': checkuserpass,
'log': log
}, function(err, serverSession) { }, function(err, serverSession) {
if (err) { if (err) {
throw err; throw err;
+16 -15
View File
@@ -2,12 +2,12 @@
const topLogPrefix = 'larvitsmpp: lib/client.js: ', const topLogPrefix = 'larvitsmpp: lib/client.js: ',
session = require(__dirname + '/session'), session = require(__dirname + '/session'),
LUtils = require('larvitutils'),
merge = require('utils-merge'), merge = require('utils-merge'),
log = require('winston'),
net = require('net'), net = require('net'),
tls = require('tls'); tls = require('tls');
function login() { function login(options) {
const logPrefix = topLogPrefix + 'login() - ', const logPrefix = topLogPrefix + 'login() - ',
that = this; that = this;
@@ -26,11 +26,11 @@ function login() {
if (err) return that.emit('loginFailed'); if (err) return that.emit('loginFailed');
if (retPduObj.cmdStatus === 'ESME_ROK') { if (retPduObj.cmdStatus === 'ESME_ROK') {
log.info(logPrefix + 'Successful login system_id: "' + loginPdu.params.system_id + '"'); options.log.info(logPrefix + 'Successful login system_id: "' + loginPdu.params.system_id + '"');
that.loggedIn = true; that.loggedIn = true;
that.emit('loggedIn'); that.emit('loggedIn');
} else { } else {
log.info(logPrefix + 'Login failed system_id: "' + loginPdu.params.system_id + '". Status msg: ' + retPduObj.cmdStatus); options.log.info(logPrefix + 'Login failed system_id: "' + loginPdu.params.system_id + '". Status msg: ' + retPduObj.cmdStatus);
that.emit('loginFailed'); that.emit('loginFailed');
} }
}); });
@@ -40,7 +40,7 @@ function resetEnqLinkTimer() {
const logPrefix = topLogPrefix + 'resetEnqLinkTimer() - ', const logPrefix = topLogPrefix + 'resetEnqLinkTimer() - ',
that = this; that = this;
log.silly(logPrefix + 'Resetting the kill timer'); that.log.silly(logPrefix + 'Resetting the kill timer');
if (that.enqLinkTimer) { if (that.enqLinkTimer) {
clearTimeout(that.enqLinkTimer); clearTimeout(that.enqLinkTimer);
} }
@@ -61,27 +61,27 @@ function resetEnqLinkTimer() {
* @return {object} (returnObj) * @return {object} (returnObj)
*/ */
function clientSession(sock, options) { function clientSession(sock, options) {
const returnObj = session(sock), const returnObj = session({'sock': sock, 'log': options.log}),
logPrefix = topLogPrefix + 'clientSession() - '; logPrefix = topLogPrefix + 'clientSession() - ';
returnObj.options = options; returnObj.options = options;
returnObj.login = login; returnObj.login = login;
returnObj.resetEnqLinkTimer = resetEnqLinkTimer; returnObj.resetEnqLinkTimer = resetEnqLinkTimer;
returnObj.login(); returnObj.login({'log': options.log});
returnObj.resetEnqLinkTimer(); returnObj.resetEnqLinkTimer({'log': options.log});
// Handle incoming Pdu Objects // Handle incoming Pdu Objects
returnObj.on('incomingPduObj', function (pduObj) { returnObj.on('incomingPduObj', function (pduObj) {
// Call the appropriate handleCmd function // Call the appropriate handleCmd function
if (typeof returnObj.handleCmd[pduObj.cmdName] === 'function') { if (typeof returnObj.handleCmd[pduObj.cmdName] === 'function') {
log.debug(logPrefix + 'returnObj.on(incomingPduObj) - Running cmd handling function returnObj.handleCmd.' + pduObj.cmdName + '()'); options.log.debug(logPrefix + 'returnObj.on(incomingPduObj) - Running cmd handling function returnObj.handleCmd.' + pduObj.cmdName + '()');
returnObj.handleCmd[pduObj.cmdName](pduObj); returnObj.handleCmd[pduObj.cmdName](pduObj);
} else { } else {
// No command handling function is registered, return error "invalid command" // No command handling function is registered, return error "invalid command"
log.info(logPrefix + 'returnObj.on(incomingPduObj) - No handling function found for command: "' + pduObj.cmdName + '"'); options.log.info(logPrefix + 'returnObj.on(incomingPduObj) - No handling function found for command: "' + pduObj.cmdName + '"');
returnObj.sendReturn(pduObj, 'ESME_RINVCMDID'); returnObj.sendReturn(pduObj, 'ESME_RINVCMDID');
} }
@@ -93,7 +93,7 @@ function clientSession(sock, options) {
/** /**
* Setup a client. * Setup a client.
* *
* @param {object} options - host, port, username, password, tls, enqLinkTiming * @param {object} options - host, port, username, password, tls, enqLinkTiming, log
* @param {function} cb(err, session) * @param {function} cb(err, session)
*/ */
function client(options, cb) { function client(options, cb) {
@@ -113,7 +113,8 @@ function client(options, cb) {
'username': 'user', 'username': 'user',
'password': 'pass', 'password': 'pass',
'tls': false, 'tls': false,
'enqLinkTiming': 20000 // 20 sec 'enqLinkTiming': 20000, // 20 sec
'log': new (new LUtils()).Log()
}, options || {}); }, options || {});
if (options && options.tls && options.tls === true) { if (options && options.tls && options.tls === true) {
@@ -122,11 +123,11 @@ function client(options, cb) {
sock = new net.Socket(); sock = new net.Socket();
} }
log.debug(logPrefix + 'Connecting to ' + options.host + ':' + options.port); options.log.debug(logPrefix + 'Connecting to ' + options.host + ':' + options.port);
sock.connect(options, function () { sock.connect(options, function () {
const session = clientSession(sock, options); const session = clientSession(sock, options);
log.info(logPrefix + 'Connected to ' + sock.remoteAddress + ':' + sock.remotePort); options.log.info(logPrefix + 'Connected to ' + sock.remoteAddress + ':' + sock.remotePort);
session.on('loggedIn', function () { session.on('loggedIn', function () {
cb(null, session); cb(null, session);
@@ -134,7 +135,7 @@ function client(options, cb) {
session.on('loginFailed', function () { session.on('loginFailed', function () {
const err = new Error('Remote host refused login.'); const err = new Error('Remote host refused login.');
log.warn(logPrefix + err.message); options.log.warn(logPrefix + err.message);
cb(err); cb(err);
}); });
}); });
+3 -1
View File
@@ -15,7 +15,9 @@ const topLogPrefix = 'larvitsmpp: lib/defs.js: ',
tlvs = {}, tlvs = {},
cmds = {}, cmds = {},
iconv = require('iconv-lite'), iconv = require('iconv-lite'),
log = require('winston'); LUtils = require('larvitutils'),
lUtils = new LUtils(),
log = new lUtils.Log('error');
consts.REGISTERED_DELIVERY = { consts.REGISTERED_DELIVERY = {
'FINAL': 0x01, 'FINAL': 0x01,
+19 -16
View File
@@ -3,8 +3,9 @@
const topLogPrefix = 'larvitsmpp: lib/server.js: ', const topLogPrefix = 'larvitsmpp: lib/server.js: ',
smppUtils = require(__dirname + '/utils'), smppUtils = require(__dirname + '/utils'),
session = require(__dirname + '/session'), session = require(__dirname + '/session'),
LUtils = require('larvitutils'),
lUtils = new LUtils(),
merge = require('utils-merge'), merge = require('utils-merge'),
log = require('winston'),
net = require('net'), net = require('net'),
tls = require('tls'); tls = require('tls');
@@ -17,14 +18,14 @@ function login(pduObj) {
const logPrefix = topLogPrefix + 'login() - ', const logPrefix = topLogPrefix + 'login() - ',
that = this; that = this;
log.debug(logPrefix + 'Data received and session is not loggedIn'); that.log.debug(logPrefix + 'Data received and session is not loggedIn');
// Pause socket so we do not receive any other commands until we have processed the login // Pause socket so we do not receive any other commands until we have processed the login
that.sock.pause(); that.sock.pause();
// Only bind_* is accepted when the client is not logged in // Only bind_* is accepted when the client is not logged in
if (pduObj.cmdName !== 'bind_transceiver' && pduObj.cmdName !== 'bind_receiver' && pduObj.cmdName !== 'bind_transmitter') { if (pduObj.cmdName !== 'bind_transceiver' && pduObj.cmdName !== 'bind_receiver' && pduObj.cmdName !== 'bind_transmitter') {
log.debug(logPrefix + 'Session is not loggedIn and no bind_* command is given. Return error "ESME_RINVBNDSTS'); that.log.debug(logPrefix + 'Session is not loggedIn and no bind_* command is given. Return error "ESME_RINVBNDSTS');
smppUtils.pduReturn(pduObj, 'ESME_RINVBNDSTS', function (err, retPdu) { smppUtils.pduReturn(pduObj, 'ESME_RINVBNDSTS', function (err, retPdu) {
if (err) return that.closeSocket(); if (err) return that.closeSocket();
@@ -42,13 +43,13 @@ function login(pduObj) {
if (err) return that.closeSocket(); if (err) return that.closeSocket();
if ( ! res) { if ( ! res) {
log.info(logPrefix + 'Login failed! Connected host: ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' system_id: "' + pduObj.params.system_id + '"'); that.log.info(logPrefix + 'Login failed! Connected host: ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' system_id: "' + pduObj.params.system_id + '"');
that.sock.resume(); that.sock.resume();
return that.sendReturn(pduObj, 'ESME_RBINDFAIL'); return that.sendReturn(pduObj, 'ESME_RBINDFAIL');
} }
log.verbose(logPrefix + 'Login successful! Connected host: ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' system_id: "' + pduObj.params.system_id + '"'); that.log.verbose(logPrefix + 'Login successful! Connected host: ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' system_id: "' + pduObj.params.system_id + '"');
that.loggedIn = true; that.loggedIn = true;
// Set additional user data to the session // Set additional user data to the session
@@ -77,13 +78,13 @@ function resetEnqLinkTimer() {
const logPrefix = topLogPrefix + 'resetEnqLinkTimer() - ', const logPrefix = topLogPrefix + 'resetEnqLinkTimer() - ',
that = this; that = this;
log.silly(logPrefix + 'Resetting the kill timer'); that.log.silly(logPrefix + 'Resetting the kill timer');
if (that.enqLinkTimer) { if (that.enqLinkTimer) {
clearTimeout(that.enqLinkTimer); clearTimeout(that.enqLinkTimer);
} }
that.enqLinkTimer = setTimeout(function () { that.enqLinkTimer = setTimeout(function () {
log.info(logPrefix + 'Closing session from ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' due to timeout'); that.log.info(logPrefix + 'Closing session from ' + that.sock.remoteAddress + ':' + that.sock.remotePort + ' due to timeout');
that.closeSocket(); that.closeSocket();
}, that.options.timeout); }, that.options.timeout);
} }
@@ -96,11 +97,12 @@ function resetEnqLinkTimer() {
* @return {object} (returnObj) * @return {object} (returnObj)
*/ */
function serverSession(sock, options) { function serverSession(sock, options) {
const returnObj = session(sock); const returnObj = session({'sock': sock, 'log': options.log});
returnObj.options = options; returnObj.options = options;
returnObj.login = login; returnObj.login = login;
returnObj.resetEnqLinkTimer = resetEnqLinkTimer; returnObj.resetEnqLinkTimer = resetEnqLinkTimer;
returnObj.log = options.log;
returnObj.resetEnqLinkTimer(); returnObj.resetEnqLinkTimer();
@@ -115,18 +117,18 @@ function serverSession(sock, options) {
// If client is not logged in, always run the login function // If client is not logged in, always run the login function
} else if (returnObj.loggedIn === false) { } else if (returnObj.loggedIn === false) {
log.debug(logPrefix + ' Not logged in, running login function'); options.log.debug(logPrefix + ' Not logged in, running login function');
returnObj.login(pduObj); returnObj.login(pduObj);
// Client is logged in, try to match a handling function // Client is logged in, try to match a handling function
} else if (typeof returnObj.handleCmd[pduObj.cmdName] === 'function') { } else if (typeof returnObj.handleCmd[pduObj.cmdName] === 'function') {
log.debug(logPrefix + 'Running cmd handling function returnObj.handleCmd.' + pduObj.cmdName + '()'); options.log.debug(logPrefix + 'Running cmd handling function returnObj.handleCmd.' + pduObj.cmdName + '()');
returnObj.handleCmd[pduObj.cmdName](pduObj); returnObj.handleCmd[pduObj.cmdName](pduObj);
// No command handling function is registered, return error "invalid command" // No command handling function is registered, return error "invalid command"
} else { } else {
log.info(logPrefix + 'No handling function found for command: "' + pduObj.cmdName + '"'); options.log.info(logPrefix + 'No handling function found for command: "' + pduObj.cmdName + '"');
returnObj.sendReturn(pduObj, 'ESME_RINVCMDID'); returnObj.sendReturn(pduObj, 'ESME_RINVCMDID');
} }
@@ -138,7 +140,7 @@ function serverSession(sock, options) {
/** /**
* Setup a server * Setup a server
* *
* @param {object} options - host, port, checkuserpass() etc (OPTIONAL) * @param {object} options - host, port, checkuserpass() etc (OPTIONAL), log
* @param {function} cb(err, session) * @param {function} cb(err, session)
*/ */
function server(options, cb) { function server(options, cb) {
@@ -155,7 +157,8 @@ function server(options, cb) {
options = merge({ options = merge({
'port': 2775, 'port': 2775,
'tls': false, 'tls': false,
'timeout': 40000 // 40 sec 'timeout': 40000, // 40 sec
'log': new lUtils.Log()
}, options || {}); }, options || {});
if (options && options.tls && options.tls === true) { if (options && options.tls && options.tls === true) {
@@ -171,15 +174,15 @@ function server(options, cb) {
const returnObj = serverSession(sock, options); const returnObj = serverSession(sock, options);
// We have a connection - a socket object is assigned to the connection automatically // We have a connection - a socket object is assigned to the connection automatically
log.verbose(logPrefix + 'Incoming connection! From: ' + sock.remoteAddress + ':' + sock.remotePort); options.log.verbose(logPrefix + 'Incoming connection! From: ' + sock.remoteAddress + ':' + sock.remotePort);
cb(null, returnObj); cb(null, returnObj);
}).listen(options.port, options.host); }).listen(options.port, options.host);
if (options.host !== undefined) { if (options.host !== undefined) {
log.info(logPrefix + 'Up and listening at ' + options.host + ':' + options.port); options.log.info(logPrefix + 'Up and listening at ' + options.host + ':' + options.port);
} else { } else {
log.info(logPrefix + 'Up and listening at *:' + options.port); options.log.info(logPrefix + 'Up and listening at *:' + options.port);
} }
} }
+76 -64
View File
@@ -1,13 +1,14 @@
'use strict'; 'use strict';
const topLogPrefix = 'larvitsmpp: lib/session.js: ', const topLogPrefix = 'larvitsmpp: lib/session.js: ',
LUtils = require('larvitutils'),
lUtils = new LUtils(),
events = require('events'), events = require('events'),
moment = require('moment'), moment = require('moment'),
utils = require('./utils'), utils = require('./utils'),
async = require('async'), async = require('async'),
defs = require('./defs'), defs = require('./defs'),
uuid = require('uuid/v1'), uuid = require('uuid/v1');
log = require('winston');
/** /**
* Send a response to an sms * Send a response to an sms
@@ -48,7 +49,7 @@ function smsResp(status, cb) {
if (sms.pduObjs === undefined) { if (sms.pduObjs === undefined) {
const err = new Error('No pdu objects found to base return PDU upon'); const err = new Error('No pdu objects found to base return PDU upon');
log.warn(logPrefix + err.message); sms.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -90,14 +91,15 @@ function incOurSeqNr() {
* Always use this function to close the socket so we get it on log * Always use this function to close the socket so we get it on log
*/ */
function closeSocket() { function closeSocket() {
const logPrefix = topLogPrefix + 'closeSocket() - '; const logPrefix = topLogPrefix + 'closeSocket() - ',
that = this;
log.verbose(logPrefix + 'Closing socket for ' + this.sock.remoteAddress + ':' + this.sock.remotePort); that.log.verbose(logPrefix + 'Closing socket for ' + this.sock.remoteAddress + ':' + this.sock.remotePort);
if (this.enqLinkTimer) { if (that.enqLinkTimer) {
log.debug(logPrefix + 'enqLinkTimer found, clearing.'); that.log.debug(logPrefix + 'enqLinkTimer found, clearing.');
clearTimeout(this.enqLinkTimer); clearTimeout(that.enqLinkTimer);
} }
this.sock.destroy(); that.sock.destroy();
} }
/** /**
@@ -113,7 +115,7 @@ function sockWrite(pdu, closeAfterSend) {
if ( ! Buffer.isBuffer(pdu)) { if ( ! Buffer.isBuffer(pdu)) {
utils.objToPdu(pdu, function (err, buffer) { utils.objToPdu(pdu, function (err, buffer) {
if (err) { if (err) {
log.warn(logPrefix + 'Could not convert PDU to buffer'); that.log.warn(logPrefix + 'Could not convert PDU to buffer');
return that.closeSocket(); return that.closeSocket();
} }
@@ -123,9 +125,9 @@ function sockWrite(pdu, closeAfterSend) {
} }
try { try {
log.verbose(logPrefix + 'sending PDU. SeqNr: ' + pdu.readUInt32BE(12) + ' cmd: ' + defs.cmdsById[pdu.readUInt32BE(4)].command + ' cmdStatus: ' + defs.errorsById[parseInt(pdu.readUInt32BE(8))] + ' hex: ' + pdu.toString('hex')); that.log.verbose(logPrefix + 'sending PDU. SeqNr: ' + pdu.readUInt32BE(12) + ' cmd: ' + defs.cmdsById[pdu.readUInt32BE(4)].command + ' cmdStatus: ' + defs.errorsById[parseInt(pdu.readUInt32BE(8))] + ' hex: ' + pdu.toString('hex'));
} catch (err) { } catch (err) {
log.error(logPrefix + 'PDU buffer is invalid. Buffer hex: "' + pdu.toString('hex') + '"'); that.log.error(logPrefix + 'PDU buffer is invalid. Buffer hex: "' + pdu.toString('hex') + '"');
return; return;
} }
@@ -161,7 +163,7 @@ function send(pdu, closeAfterSend, cb) {
// Make sure the sequence number is set and is correct // Make sure the sequence number is set and is correct
pduObj.seqNr = this.ourSeqNr; pduObj.seqNr = this.ourSeqNr;
log.debug(logPrefix + 'Sending PDU to remote. pduObj: ' + JSON.stringify(pduObj)); that.log.debug(logPrefix + 'Sending PDU to remote. pduObj: ' + JSON.stringify(pduObj));
// If closeAndSend is omitted, put cb in its place // If closeAndSend is omitted, put cb in its place
if (typeof closeAfterSend === 'function') { if (typeof closeAfterSend === 'function') {
@@ -177,13 +179,13 @@ function send(pdu, closeAfterSend, cb) {
// Response PDUs are not allowed with the send() command, they should use the sendReturn() // Response PDUs are not allowed with the send() command, they should use the sendReturn()
if (pduObj.cmdName.substring(pduObj.cmdName - 5) === '_resp') { if (pduObj.cmdName.substring(pduObj.cmdName - 5) === '_resp') {
const err = new Error('Given pduObj is a response, use sendReturn() instead. cmdName: ' + pduObj.cmdName); const err = new Error('Given pduObj is a response, use sendReturn() instead. cmdName: ' + pduObj.cmdName);
log.verbose(logPrefix + err.message); that.log.verbose(logPrefix + err.message);
return cb(err); return cb(err);
} }
// When the return is fetched, call the cb // When the return is fetched, call the cb
that.on('incomingPduObj' + pduObj.seqNr, function (incPduObj) { that.on('incomingPduObj' + pduObj.seqNr, function (incPduObj) {
log.debug(logPrefix + 'this.on(incomingPduObj) - cmdName: ' + incPduObj.cmdName + ' seqNr: ' + incPduObj.seqNr + ' cmdStatus: ' + incPduObj.cmdStatus); that.log.debug(logPrefix + 'this.on(incomingPduObj) - cmdName: ' + incPduObj.cmdName + ' seqNr: ' + incPduObj.seqNr + ' cmdStatus: ' + incPduObj.cmdStatus);
// Make sure this is the actual response to the sent PDU // Make sure this is the actual response to the sent PDU
if (incPduObj.isResp() && incPduObj.seqNr === pduObj.seqNr) { if (incPduObj.isResp() && incPduObj.seqNr === pduObj.seqNr) {
@@ -194,7 +196,7 @@ function send(pdu, closeAfterSend, cb) {
} }
} else { } else {
const err = new Error('Event triggered but incoming PDU is not a response or seqNr does not match. isResp: ' + incPduObj.isResp().toString() + ' incSeqNr: ' + incPduObj.seqNr + ' expected seqNr: ' + pduObj.seqNr); const err = new Error('Event triggered but incoming PDU is not a response or seqNr does not match. isResp: ' + incPduObj.isResp().toString() + ' incSeqNr: ' + incPduObj.seqNr + ' expected seqNr: ' + pduObj.seqNr);
log.warn(logPrefix + 'this.on(incomingPduObj) - ' + err.message); that.log.warn(logPrefix + 'this.on(incomingPduObj) - ' + err.message);
cb(err); cb(err);
} }
}); });
@@ -219,7 +221,7 @@ function sendReturn(pdu, status, params, closeAfterSend, cb) {
const logPrefix = topLogPrefix + 'sendReturn() - ', const logPrefix = topLogPrefix + 'sendReturn() - ',
that = this; that = this;
log.silly(logPrefix + 'ran'); that.log.silly(logPrefix + 'ran');
if (typeof params === 'function') { if (typeof params === 'function') {
cb = params; cb = params;
@@ -238,13 +240,13 @@ function sendReturn(pdu, status, params, closeAfterSend, cb) {
utils.pduReturn(pdu, status, params, function (err, retPdu) { utils.pduReturn(pdu, status, params, function (err, retPdu) {
if (err) { if (err) {
log.error(logPrefix + 'Could not create return PDU: ' + err.message); that.log.error(logPrefix + 'Could not create return PDU: ' + err.message);
that.closeSocket(); that.closeSocket();
return cb(err); return cb(err);
} }
log.silly(logPrefix + 'Sending return PDU: ' + retPdu.toString('hex')); that.log.silly(logPrefix + 'Sending return PDU: ' + retPdu.toString('hex'));
that.sockWrite(retPdu, closeAfterSend); that.sockWrite(retPdu, closeAfterSend);
cb(null, retPdu); cb(null, retPdu);
}); });
@@ -264,7 +266,8 @@ function sendReturn(pdu, status, params, closeAfterSend, cb) {
*/ */
function sendSms(smsOptions, cb) { function sendSms(smsOptions, cb) {
const logPrefix = topLogPrefix + 'sendSms() - ', const logPrefix = topLogPrefix + 'sendSms() - ',
pduObj = {}; pduObj = {},
that = this;
pduObj.cmdName = 'submit_sm'; pduObj.cmdName = 'submit_sm';
pduObj.params = { pduObj.params = {
@@ -276,7 +279,7 @@ function sendSms(smsOptions, cb) {
// Flash messages overrides default data_coding // Flash messages overrides default data_coding
if (smsOptions.flash) { if (smsOptions.flash) {
log.debug(logPrefix + 'Flash SMS detected, set data_coding to 0x10!'); that.log.debug(logPrefix + 'Flash SMS detected, set data_coding to 0x10!');
pduObj.params.data_coding = 0x10; pduObj.params.data_coding = 0x10;
} }
@@ -287,16 +290,16 @@ function sendSms(smsOptions, cb) {
// Check if we must split this message into multiple // Check if we must split this message into multiple
if (utils.bitCount(smsOptions.message) > 1120) { if (utils.bitCount(smsOptions.message) > 1120) {
log.debug(logPrefix + 'Message larger than 1120 bits, send it as long message!'); that.log.debug(logPrefix + 'Message larger than 1120 bits, send it as long message!');
this.sendLongSms(smsOptions, cb); that.sendLongSms(smsOptions, cb);
return; return;
} }
log.debug(logPrefix + 'pduObj: ' + JSON.stringify(pduObj)); that.log.debug(logPrefix + 'pduObj: ' + JSON.stringify(pduObj));
this.send(pduObj, function (err, retPduObj) { that.send(pduObj, function (err, retPduObj) {
if (typeof cb === 'function') { if (typeof cb === 'function') {
cb(err, [retPduObj.params.message_id], [retPduObj]); cb(err, [retPduObj.params.message_id], [retPduObj]);
} }
@@ -341,16 +344,16 @@ function sendLongSms(smsOptions, cb) {
pduObj.params.registered_delivery = 0x01; pduObj.params.registered_delivery = 0x01;
} }
log.debug(logPrefix + 'pduObj: ' + JSON.stringify(pduObj)); that.log.debug(logPrefix + 'pduObj: ' + JSON.stringify(pduObj));
that.send(pduObj, function (err, retPduObj) { that.send(pduObj, function (err, retPduObj) {
smsIds.push(retPduObj.params.message_id); smsIds.push(retPduObj.params.message_id);
retPduObjs.push(retPduObj); retPduObjs.push(retPduObj);
log.silly(logPrefix + 'Got cb from that.send()'); that.log.silly(logPrefix + 'Got cb from that.send()');
if (typeof cb === 'function' && smsIds.length === msgs.length) { if (typeof cb === 'function' && smsIds.length === msgs.length) {
log.silly(logPrefix + 'All cbs returned, run the parent cb.'); that.log.silly(logPrefix + 'All cbs returned, run the parent cb.');
cb(err, smsIds, retPduObjs); cb(err, smsIds, retPduObjs);
} }
}); });
@@ -420,7 +423,7 @@ function checkLongSmses() {
smsObj = {}, smsObj = {},
that = this; that = this;
log.silly(logPrefix + 'Running'); that.log.silly(logPrefix + 'Running');
// Call when complete SMS is received // Call when complete SMS is received
function smsReceived() { function smsReceived() {
@@ -436,7 +439,7 @@ function checkLongSmses() {
// All parts are accounted for! Emit sms event and clear from tmp storage // All parts are accounted for! Emit sms event and clear from tmp storage
if (smsGroup.partsCount === smsGroup.pduObjs.length) { if (smsGroup.partsCount === smsGroup.pduObjs.length) {
log.debug(logPrefix + 'All parts accounted for in smsGroupId "' + smsGroupId + '", emitting sms event.'); that.log.debug(logPrefix + 'All parts accounted for in smsGroupId "' + smsGroupId + '", emitting sms event.');
// These are needed for references here and there in functions // These are needed for references here and there in functions
smsObj.session = that; smsObj.session = that;
@@ -449,6 +452,7 @@ function checkLongSmses() {
smsObj.dlr = Boolean(smsGroup.pduObjs[0].pduObj.params.registered_delivery); smsObj.dlr = Boolean(smsGroup.pduObjs[0].pduObj.params.registered_delivery);
smsObj.sendResp = smsResp; smsObj.sendResp = smsResp;
smsObj.sendDlr = utils.smsDlr; smsObj.sendDlr = utils.smsDlr;
smsObj.log = that.log;
// Concatenate all the parts messages to one and set references to the session // Concatenate all the parts messages to one and set references to the session
@@ -464,7 +468,7 @@ function checkLongSmses() {
} }
smsReceived(); smsReceived();
} else if (moment(new Date()).diff(smsGroup.created, 'hours') > 24) { } else if (moment(new Date()).diff(smsGroup.created, 'hours') > 24) {
log.info(logPrefix + 'smsGroupId "' + smsGroupId + '" is removed from this.longSmses due to being older than 24 hours.'); that.log.info(logPrefix + 'smsGroupId "' + smsGroupId + '" is removed from this.longSmses due to being older than 24 hours.');
delete this.longSmses[smsGroupId]; delete this.longSmses[smsGroupId];
} }
@@ -474,18 +478,25 @@ function checkLongSmses() {
/** /**
* Generic session function * Generic session function
* *
* @param {object} sock - socket object * @param {object} options - {sock, log}
* @return {object} (returnObj) * @return {object} (returnObj)
*/ */
function session(sock) { function session(options) {
const logPrefix = topLogPrefix + 'session() - socket address: ' + sock.remoteAddress + ':' + sock.remotePort + ' - ', const logPrefix = topLogPrefix + 'session() - socket address: ' + options.sock.remoteAddress + ':' + options.sock.remotePort + ' - ',
returnObj = new events.EventEmitter(); returnObj = new events.EventEmitter();
log.silly(logPrefix + 'New session started'); if (! options.log) {
options.log = new lUtils.Log();
}
utils.log = options.log;
returnObj.log = options.log;
returnObj.log.silly(logPrefix + 'New session started');
returnObj.loggedIn = false; returnObj.loggedIn = false;
returnObj.ourSeqNr = 1; // Sequence number used for commands initiated from us returnObj.ourSeqNr = 1; // Sequence number used for commands initiated from us
returnObj.sock = sock; // Make the socket transparent via the returned emitter returnObj.sock = options.sock; // Make the socket transparent via the returned emitter
returnObj.incOurSeqNr = incOurSeqNr; returnObj.incOurSeqNr = incOurSeqNr;
returnObj.closeSocket = closeSocket; returnObj.closeSocket = closeSocket;
returnObj.sockWrite = sockWrite; returnObj.sockWrite = sockWrite;
@@ -517,7 +528,7 @@ function session(sock) {
// TLV message_state must exists // TLV message_state must exists
if (pduObj.tlvs.message_state === undefined) { if (pduObj.tlvs.message_state === undefined) {
log.info(thisLogPrefix + 'TLV message_state is missing. SeqNr: ' + pduObj.seqNr); returnObj.log.info(thisLogPrefix + 'TLV message_state is missing. SeqNr: ' + pduObj.seqNr);
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM'); returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
return; return;
@@ -525,7 +536,7 @@ function session(sock) {
// TLV message_state needs to be valid // TLV message_state needs to be valid
if (defs.constsById.MESSAGE_STATE[pduObj.tlvs.message_state.tagValue] === undefined) { if (defs.constsById.MESSAGE_STATE[pduObj.tlvs.message_state.tagValue] === undefined) {
log.info(thisLogPrefix + 'Invalid TLV message_state: "' + pduObj.tlvs.message_state.tagValue + '". SeqNr: ' + pduObj.seqNr); returnObj.log.info(thisLogPrefix + 'Invalid TLV message_state: "' + pduObj.tlvs.message_state.tagValue + '". SeqNr: ' + pduObj.seqNr);
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM'); returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
return; return;
@@ -533,7 +544,7 @@ function session(sock) {
// TLV receipted_message_id must exist // TLV receipted_message_id must exist
if (pduObj.tlvs.receipted_message_id === undefined) { if (pduObj.tlvs.receipted_message_id === undefined) {
log.info(thisLogPrefix + 'TLV receipted_message_id is missing. SeqNr: ' + pduObj.seqNr); returnObj.log.info(thisLogPrefix + 'TLV receipted_message_id is missing. SeqNr: ' + pduObj.seqNr);
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM'); returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
return; return;
@@ -551,7 +562,7 @@ function session(sock) {
returnObj.handleCmd.enquire_link = function enquire_link(pduObj) { returnObj.handleCmd.enquire_link = function enquire_link(pduObj) {
const thisLogPrefix = logPrefix + 'enquire_link() - '; const thisLogPrefix = logPrefix + 'enquire_link() - ';
log.silly(thisLogPrefix + 'Enquiring link'); returnObj.log.silly(thisLogPrefix + 'Enquiring link');
returnObj.resetEnqLinkTimer(); returnObj.resetEnqLinkTimer();
returnObj.sendReturn(pduObj); returnObj.sendReturn(pduObj);
}; };
@@ -561,13 +572,13 @@ function session(sock) {
const thisLogPrefix = logPrefix + 'submit_sm() - ', const thisLogPrefix = logPrefix + 'submit_sm() - ',
smsObj = {}; smsObj = {};
log.silly(thisLogPrefix + 'ran'); returnObj.log.silly(thisLogPrefix + 'ran');
// If esm_class is 0x40 it means this is just a part of a larger message // If esm_class is 0x40 it means this is just a part of a larger message
//if (pduObj.params.esm_class === 0x40) { //if (pduObj.params.esm_class === 0x40) {
// Fix: esm_class can be combination of bits. We need to extract 0x40 and then compare // Fix: esm_class can be combination of bits. We need to extract 0x40 and then compare
if ((pduObj.params.esm_class & 0x40) === 0x40) { if ((pduObj.params.esm_class & 0x40) === 0x40) {
log.debug(thisLogPrefix + 'long sms detected, esm_class 0x40.'); returnObj.log.debug(thisLogPrefix + 'long sms detected, esm_class 0x40.');
returnObj.longSms(pduObj); returnObj.longSms(pduObj);
return; // Long messages should not get handled here at all, so cancel execution here return; // Long messages should not get handled here at all, so cancel execution here
} }
@@ -582,12 +593,13 @@ function session(sock) {
smsObj.dlr = Boolean(pduObj.params.registered_delivery); smsObj.dlr = Boolean(pduObj.params.registered_delivery);
smsObj.sendResp = smsResp; smsObj.sendResp = smsResp;
smsObj.sendDlr = utils.smsDlr; smsObj.sendDlr = utils.smsDlr;
smsObj.log = returnObj.log;
if (pduObj.params.data_coding === 0x10) { if (pduObj.params.data_coding === 0x10) {
smsObj.flash = true; smsObj.flash = true;
} }
log.silly(thisLogPrefix + 'Emitting sms object'); returnObj.log.silly(thisLogPrefix + 'Emitting sms object');
returnObj.emit('sms', smsObj); returnObj.emit('sms', smsObj);
}; };
@@ -601,18 +613,18 @@ function session(sock) {
returnObj.login = function login() { returnObj.login = function login() {
const thisLogPrefix = logPrefix + 'login() - '; const thisLogPrefix = logPrefix + 'login() - ';
log.info(thisLogPrefix + 'Dummy login function ran, this might be a mistake'); returnObj.log.info(thisLogPrefix + 'Dummy login function ran, this might be a mistake');
returnObj.loggedIn = true; returnObj.loggedIn = true;
}; };
// Dummy method - should be used by serverSession or clientSession // Dummy method - should be used by serverSession or clientSession
returnObj.resetEnqLinkTimer = function resetEnqLinkTimer() { returnObj.resetEnqLinkTimer = function resetEnqLinkTimer() {
const thisLogPrefix = logPrefix + 'resetEnqLinkTimer() - '; const thisLogPrefix = logPrefix + 'resetEnqLinkTimer() - ';
log.silly(thisLogPrefix + 'Resetting the kill timer'); returnObj.log.silly(thisLogPrefix + 'Resetting the kill timer');
}; };
// Unbind this session // Unbind this session
returnObj.unbind = function () { returnObj.unbind = function unbind() {
returnObj.send({ returnObj.send({
'cmdName': 'unbind' 'cmdName': 'unbind'
}, true); }, true);
@@ -623,7 +635,7 @@ function session(sock) {
returnObj.dataQueue = new Buffer(0); returnObj.dataQueue = new Buffer(0);
// Add a 'data' event handler to this instance of socket // Add a 'data' event handler to this instance of socket
sock.on('data', function (data) { options.sock.on('data', function (data) {
const thisLogPrefix = logPrefix + 'sock.on(data) - '; const thisLogPrefix = logPrefix + 'sock.on(data) - ';
// Pass the data along to the returnObj // Pass the data along to the returnObj
@@ -632,7 +644,7 @@ function session(sock) {
// Reset the enquire link timer // Reset the enquire link timer
returnObj.resetEnqLinkTimer(); returnObj.resetEnqLinkTimer();
log.debug(thisLogPrefix + 'Incoming data: ' + data.toString('hex')); returnObj.log.debug(thisLogPrefix + 'Incoming data: ' + data.toString('hex'));
// Add this data to the dataQueue for processing // Add this data to the dataQueue for processing
returnObj.dataQueue = Buffer.concat([returnObj.dataQueue, data]); returnObj.dataQueue = Buffer.concat([returnObj.dataQueue, data]);
@@ -641,23 +653,23 @@ function session(sock) {
while (returnObj.dataQueue.length > 4) { while (returnObj.dataQueue.length > 4) {
const cmdLength = parseInt(returnObj.dataQueue.readUInt32BE(0)); // Get this commands length const cmdLength = parseInt(returnObj.dataQueue.readUInt32BE(0)); // Get this commands length
let pdu;
// Malformed PDU with command length 0 // Malformed PDU with command length 0
if (cmdLength <= 0) { if (cmdLength <= 0) {
// Since PDU is Malformed we need to discard buffer. // Since PDU is Malformed we need to discard buffer.
log.silly(thisLogPrefix + 'Malformed PDU with 0 Length. Discarding buffer.'); returnObj.log.silly(thisLogPrefix + 'Malformed PDU with 0 Length. Discarding buffer.');
returnObj.dataQueue = returnObj.dataQueue.slice(0, returnObj.dataQueue.length); returnObj.dataQueue = returnObj.dataQueue.slice(0, returnObj.dataQueue.length);
// Since PDU is malformed we need to close socket since we cannot trust data from now on. // Since PDU is malformed we need to close socket since we cannot trust data from now on.
returnObj.closeSocket(); returnObj.closeSocket();
} }
let pdu; returnObj.log.silly(thisLogPrefix + 'Processing ' + cmdLength + ' bytes of data');
log.silly(thisLogPrefix + 'Processing ' + cmdLength + ' bytes of data');
// If there is at least enough bytes in the dataQueue to fill this PDU, do it! // If there is at least enough bytes in the dataQueue to fill this PDU, do it!
if (cmdLength <= returnObj.dataQueue.length) { if (cmdLength <= returnObj.dataQueue.length) {
log.silly(thisLogPrefix + 'Full PDU found in dataQueue, processing ' + cmdLength + ' bytes of queue total ' + returnObj.dataQueue.length + ' bytes'); returnObj.log.silly(thisLogPrefix + 'Full PDU found in dataQueue, processing ' + cmdLength + ' bytes of queue total ' + returnObj.dataQueue.length + ' bytes');
// Slice up the dataQueue buffer to this commands length // Slice up the dataQueue buffer to this commands length
pdu = returnObj.dataQueue.slice(0, cmdLength); pdu = returnObj.dataQueue.slice(0, cmdLength);
@@ -667,19 +679,19 @@ function session(sock) {
returnObj.emit('incomingPdu', pdu); returnObj.emit('incomingPdu', pdu);
} else { } else {
log.debug(thisLogPrefix + 'Tried to process ' + cmdLength + ' bytes, but only ' + returnObj.dataQueue.length + ' bytes found. Awaiting more data. Current data in queue: ' + returnObj.dataQueue.toString('hex')); returnObj.log.debug(thisLogPrefix + 'Tried to process ' + cmdLength + ' bytes, but only ' + returnObj.dataQueue.length + ' bytes found. Awaiting more data. Current data in queue: ' + returnObj.dataQueue.toString('hex'));
break; break;
} }
if (returnObj.dataQueue.length === 0) { if (returnObj.dataQueue.length === 0) {
log.silly(thisLogPrefix + 'All queue handled, breaking while loop.'); returnObj.log.silly(thisLogPrefix + 'All queue handled, breaking while loop.');
break; break;
} }
// If the command length is larger than the queue, we need to wait for more data. Stop processing! // If the command length is larger than the queue, we need to wait for more data. Stop processing!
if (cmdLength > returnObj.dataQueue) { if (cmdLength > returnObj.dataQueue) {
log.debug(thisLogPrefix + 'Incomplete PDU found in dataQueue, waiting for more data to continue. Current cmdLength: ' + cmdLength + ' current queue: ' + returnObj.dataQueue.toString('hex')); returnObj.log.debug(thisLogPrefix + 'Incomplete PDU found in dataQueue, waiting for more data to continue. Current cmdLength: ' + cmdLength + ' current queue: ' + returnObj.dataQueue.toString('hex'));
break; break;
} }
} }
@@ -691,11 +703,11 @@ function session(sock) {
utils.pduToObj(pdu, function (err, pduObj) { utils.pduToObj(pdu, function (err, pduObj) {
if (err) { if (err) {
log.warn(thisLogPrefix + 'Invalid PDU, closing socket.'); returnObj.log.warn(thisLogPrefix + 'Invalid PDU, closing socket.');
returnObj.closeSocket(); returnObj.closeSocket();
} else { } else {
log.verbose(thisLogPrefix + 'Incoming PDU parsed. Seqnr: ' + pduObj.seqNr + ' cmd: ' + pduObj.cmdName + ' cmdStatus: ' + pduObj.cmdStatus + ' hex: ' + pdu.toString('hex')); returnObj.log.verbose(thisLogPrefix + 'Incoming PDU parsed. Seqnr: ' + pduObj.seqNr + ' cmd: ' + pduObj.cmdName + ' cmdStatus: ' + pduObj.cmdStatus + ' hex: ' + pdu.toString('hex'));
if (pduObj.isResp()) { if (pduObj.isResp()) {
// We do this so we can remove the dynamic event listeners to not have a memory leak // We do this so we can remove the dynamic event listeners to not have a memory leak
@@ -711,23 +723,23 @@ function session(sock) {
}); });
// Add a 'close' event handler to this instance of socket // Add a 'close' event handler to this instance of socket
sock.on('close', function () { options.sock.on('close', function () {
const thisLogPrefix = logPrefix + 'sock.on(close) - '; const thisLogPrefix = logPrefix + 'sock.on(close) - ';
returnObj.emit('close'); returnObj.emit('close');
if (returnObj.enqLinkTimer) { if (returnObj.enqLinkTimer) {
log.debug(thisLogPrefix + 'enqLinkTimer found, clearing.'); returnObj.log.debug(thisLogPrefix + 'enqLinkTimer found, clearing.');
clearTimeout(returnObj.enqLinkTimer); clearTimeout(returnObj.enqLinkTimer);
} }
log.debug(thisLogPrefix + 'socket closed'); returnObj.log.debug(thisLogPrefix + 'socket closed');
}); });
sock.on('error', function () { options.sock.on('error', function () {
const thisLogPrefix = logPrefix + 'sock.on(error) - '; const thisLogPrefix = logPrefix + 'sock.on(error) - ';
log.warn(thisLogPrefix + 'Socket error detected!'); returnObj.log.warn(thisLogPrefix + 'Socket error detected!');
if (returnObj.enqLinkTimer) { if (returnObj.enqLinkTimer) {
log.debug(thisLogPrefix + 'enqLinkTimer found, clearing.'); returnObj.log.debug(thisLogPrefix + 'enqLinkTimer found, clearing.');
clearTimeout(returnObj.enqLinkTimer); clearTimeout(returnObj.enqLinkTimer);
} }
}); });
+44 -42
View File
@@ -1,8 +1,9 @@
'use strict'; 'use strict';
const topLogPrefix = 'larvitsmpp: lib/utils.js: ', const topLogPrefix = 'larvitsmpp: lib/utils.js: ',
defs = require(__dirname + '/defs.js'), LUtils = require('larvitutils'),
log = require('winston'); lUtils = new LUtils(),
defs = require(__dirname + '/defs.js');
let bundleMsgId = 0; let bundleMsgId = 0;
@@ -29,7 +30,7 @@ function calcCmdLength(obj, cb) {
if (isNaN(paramType.size(obj.params[param]))) { if (isNaN(paramType.size(obj.params[param]))) {
const err = new Error('Invalid param value "' + obj.params[param] + '" for param "' + param + '" and command "' + obj.cmdName + '". Is it of the right type?'); const err = new Error('Invalid param value "' + obj.params[param] + '" for param "' + param + '" and command "' + obj.cmdName + '". Is it of the right type?');
log.error(logPrefix + err.message); exports.log.error(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -50,7 +51,7 @@ function calcCmdLength(obj, cb) {
cmdLength += tlvDef.type.size(tlvValue) + 4; cmdLength += tlvDef.type.size(tlvValue) + 4;
} catch (err) { } catch (err) {
const manErr = new Error('Could not get size of TLV parameter "' + tlvName + '" with value "' + tlvValue + '", err: ' + err.message); const manErr = new Error('Could not get size of TLV parameter "' + tlvName + '" with value "' + tlvValue + '", err: ' + err.message);
log.error(logPrefix + manErr.message); exports.log.error(logPrefix + manErr.message);
return cb(manErr); return cb(manErr);
} }
} }
@@ -73,13 +74,13 @@ function writeBuffer(obj, cmdLength, cb) {
if (isNaN(cmdLength)) { if (isNaN(cmdLength)) {
const err = new Error('cmdLength is NaN'); const err = new Error('cmdLength is NaN');
log.error(logPrefix + err.message); exports.log.error(logPrefix + err.message);
return cb(err); return cb(err);
} }
if (cmdLength < 16) { if (cmdLength < 16) {
const err = new Error('cmdLength is less than 16 (' + cmdLength + ')'); const err = new Error('cmdLength is less than 16 (' + cmdLength + ')');
log.error(logPrefix + err.message); exports.log.error(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -93,7 +94,7 @@ function writeBuffer(obj, cmdLength, cb) {
buff.writeUInt32BE(obj.seqNr, 12); // Sequence number as the fourth 4 octets buff.writeUInt32BE(obj.seqNr, 12); // Sequence number as the fourth 4 octets
} catch (err) { } catch (err) {
const manErr = new Error('Could not write PDU header, catched err: ' + err.message, obj); const manErr = new Error('Could not write PDU header, catched err: ' + err.message, obj);
log.error(logPrefix + manErr.message); exports.log.error(logPrefix + manErr.message);
return cb(manErr); return cb(manErr);
} }
@@ -103,13 +104,13 @@ function writeBuffer(obj, cmdLength, cb) {
paramSize = paramType.size(obj.params[param]); paramSize = paramType.size(obj.params[param]);
if (Buffer.isBuffer(obj.params[param])) { if (Buffer.isBuffer(obj.params[param])) {
log.silly(logPrefix + 'Writing param "' + param + '" with content "' + obj.params[param].toString('hex') + '" and size "' + paramSize + '"'); exports.log.silly(logPrefix + 'Writing param "' + param + '" with content "' + obj.params[param].toString('hex') + '" and size "' + paramSize + '"');
} else { } else {
if (param === 'sm_length') { if (param === 'sm_length') {
log.silly(logPrefix + 'sm_length is calculated by short_message: "' + obj.params.short_message.toString('hex') + '"'); exports.log.silly(logPrefix + 'sm_length is calculated by short_message: "' + obj.params.short_message.toString('hex') + '"');
} }
log.silly(logPrefix + 'Writing param "' + param + '" with content "' + obj.params[param] + '"'); exports.log.silly(logPrefix + 'Writing param "' + param + '" with content "' + obj.params[param] + '"');
} }
// Write parameter value to buffer using the types method write() // Write parameter value to buffer using the types method write()
@@ -133,7 +134,7 @@ function writeBuffer(obj, cmdLength, cb) {
tlvSize = tlvDef.type.size(tlvValue); tlvSize = tlvDef.type.size(tlvValue);
log.silly(logPrefix + 'Writing TLV "' + tlvName + '" offset: ' + offset + ' value: "' + tlvValue + '"'); exports.log.silly(logPrefix + 'Writing TLV "' + tlvName + '" offset: ' + offset + ' value: "' + tlvValue + '"');
buff.writeUInt16BE(tlvId, offset); buff.writeUInt16BE(tlvId, offset);
buff.writeUInt16BE(tlvSize, offset + 2); buff.writeUInt16BE(tlvSize, offset + 2);
@@ -142,7 +143,7 @@ function writeBuffer(obj, cmdLength, cb) {
offset += tlvDef.type.size(tlvValue) + 4; offset += tlvDef.type.size(tlvValue) + 4;
} }
log.silly(logPrefix + 'Complete PDU: "' + buff.toString('hex') + '"'); exports.log.silly(logPrefix + 'Complete PDU: "' + buff.toString('hex') + '"');
cb(null, buff); cb(null, buff);
} }
@@ -169,11 +170,11 @@ function decodeMsg(buffer, encoding, offset) {
} }
if (defs.encodings[encoding] === undefined) { if (defs.encodings[encoding] === undefined) {
log.info(logPrefix + 'Invalid encoding "' + encoding + '" given. Falling back to ASCII (0x01).'); exports.log.info(logPrefix + 'Invalid encoding "' + encoding + '" given. Falling back to ASCII (0x01).');
encoding = 'ASCII'; encoding = 'ASCII';
} }
log.debug(logPrefix + 'Decoding msg. Encoding: "' + encoding + '" offset: "' + offset + '" buffer: "' + buffer.toString('hex') + '"'); exports.log.debug(logPrefix + 'Decoding msg. Encoding: "' + encoding + '" offset: "' + offset + '" buffer: "' + buffer.toString('hex') + '"');
return defs.encodings[encoding].decode(buffer.slice(offset)); return defs.encodings[encoding].decode(buffer.slice(offset));
} }
@@ -208,11 +209,11 @@ function pduToObj(pdu, stupidNullByte, cb) {
return ! ! (this.cmdId & 0x80000000); return ! ! (this.cmdId & 0x80000000);
}; };
log.silly(logPrefix + 'Decoding PDU to Obj. PDU buff in hex: ' + pdu.toString('hex')); exports.log.silly(logPrefix + 'Decoding PDU to Obj. PDU buff in hex: ' + pdu.toString('hex'));
if (pdu.length < 16) { if (pdu.length < 16) {
const err = new Error('PDU is to small, minimum size is 16, given size is ' + pdu.length); const err = new Error('PDU is to small, minimum size is 16, given size is ' + pdu.length);
log.warn(logPrefix + '' + err.message); exports.log.warn(logPrefix + '' + err.message);
return cb(err); return cb(err);
} }
@@ -225,19 +226,19 @@ function pduToObj(pdu, stupidNullByte, cb) {
// Lookup the command id in the definitions // Lookup the command id in the definitions
if (defs.cmdsById[retObj.cmdId] === undefined) { if (defs.cmdsById[retObj.cmdId] === undefined) {
const err = new Error('Unknown PDU command id: ' + retObj.cmdId + ' PDU buff in hex: ' + pdu.toString('hex')); const err = new Error('Unknown PDU command id: ' + retObj.cmdId + ' PDU buff in hex: ' + pdu.toString('hex'));
log.warn(logPrefix + '' + err.message); exports.log.warn(logPrefix + '' + err.message);
return cb(err); return cb(err);
} }
if (isNaN(retObj.seqNr)) { if (isNaN(retObj.seqNr)) {
const err = new Error('Invalid seqNr, is not an interger: "' + retObj.seqNr + '"'); const err = new Error('Invalid seqNr, is not an interger: "' + retObj.seqNr + '"');
log.warn(logPrefix + '' + err.message); exports.log.warn(logPrefix + '' + err.message);
return cb(err); return cb(err);
} }
if (retObj.seqNr > 2147483646) { if (retObj.seqNr > 2147483646) {
const err = new Error('Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.'); const err = new Error('Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.');
log.warn(logPrefix + '' + err.message); exports.log.warn(logPrefix + '' + err.message);
return cb(err); return cb(err);
} }
@@ -254,12 +255,12 @@ function pduToObj(pdu, stupidNullByte, cb) {
retObj.params[param] = command.params[param].type.read(pdu, offset, retObj.params.sm_length); retObj.params[param] = command.params[param].type.read(pdu, offset, retObj.params.sm_length);
paramSize = command.params[param].type.size(retObj.params[param]); paramSize = command.params[param].type.size(retObj.params[param]);
log.silly(logPrefix + 'Reading param "' + param + '" at offset ' + offset + ' with calculated size: ' + paramSize + ' content in hex: ' + pdu.slice(offset, offset + paramSize).toString('hex')); exports.log.silly(logPrefix + 'Reading param "' + param + '" at offset ' + offset + ' with calculated size: ' + paramSize + ' content in hex: ' + pdu.slice(offset, offset + paramSize).toString('hex'));
if (param === 'short_message') { if (param === 'short_message') {
// Check if we have a trailing NULL octet after the short_message. Some idiot thought that would be a good idea // Check if we have a trailing NULL octet after the short_message. Some idiot thought that would be a good idea
// in some implementations, so we need to account for that. // in some implementations, so we need to account for that.
if (stupidNullByte === true) { if (stupidNullByte === true) {
log.silly(logPrefix + 'stupidNullByte is set, so short_message is followed by a NULL octet, increase paramSize one extra to account for that'); exports.log.silly(logPrefix + 'stupidNullByte is set, so short_message is followed by a NULL octet, increase paramSize one extra to account for that');
paramSize ++; paramSize ++;
} }
} }
@@ -268,7 +269,7 @@ function pduToObj(pdu, stupidNullByte, cb) {
offset += paramSize; offset += paramSize;
} catch (err) { } catch (err) {
const manErr = new Error('Failed to read param "' + param + '", err: ' + err.message); const manErr = new Error('Failed to read param "' + param + '", err: ' + err.message);
log.error(logPrefix + '' + manErr.message); exports.log.error(logPrefix + '' + manErr.message);
return cb(err); return cb(err);
} }
} }
@@ -285,7 +286,7 @@ function pduToObj(pdu, stupidNullByte, cb) {
tlvLength = pdu.readInt16BE(offset + 2); tlvLength = pdu.readInt16BE(offset + 2);
} catch (err) { } catch (err) {
const manErr = new Error('Unable to read TLV at offset "' + offset + '", given cmdLength: "' + retObj.cmdLength + '" pdu: ' + pdu.toString('hex') + ', err: ' + err.message); const manErr = new Error('Unable to read TLV at offset "' + offset + '", given cmdLength: "' + retObj.cmdLength + '" pdu: ' + pdu.toString('hex') + ', err: ' + err.message);
log.error(logPrefix + '' + manErr.message); exports.log.error(logPrefix + '' + manErr.message);
return cb(manErr); return cb(manErr);
} }
@@ -298,7 +299,7 @@ function pduToObj(pdu, stupidNullByte, cb) {
'tagValue': tlvValue 'tagValue': tlvValue
}; };
log.verbose(logPrefix + 'Unknown TLV found. Hex ID: ' + tlvCmdId.toString(16) + ' length: ' + tlvLength + ' hex value: ' + tlvValue); exports.log.verbose(logPrefix + 'Unknown TLV found. Hex ID: ' + tlvCmdId.toString(16) + ' length: ' + tlvLength + ' hex value: ' + tlvValue);
} else { } else {
tlvValue = defs.tlvsById[tlvCmdId].type.read(pdu, offset + 4, tlvLength); tlvValue = defs.tlvsById[tlvCmdId].type.read(pdu, offset + 4, tlvLength);
@@ -312,20 +313,20 @@ function pduToObj(pdu, stupidNullByte, cb) {
'tagValue': tlvValue 'tagValue': tlvValue
}; };
log.silly(logPrefix + 'TLV found: "' + defs.tlvsById[tlvCmdId].tag + '" ID: "' + tlvCmdId + '" value: "' + tlvValue + '"'); exports.log.silly(logPrefix + 'TLV found: "' + defs.tlvsById[tlvCmdId].tag + '" ID: "' + tlvCmdId + '" value: "' + tlvValue + '"');
} }
offset = offset + 4 + tlvLength; offset = offset + 4 + tlvLength;
} }
if (offset !== retObj.cmdLength && stupidNullByte === undefined) { if (offset !== retObj.cmdLength && stupidNullByte === undefined) {
log.verbose(logPrefix + 'Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr + ' - retry with the stupid NULL byte for short_message'); exports.log.verbose(logPrefix + 'Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr + ' - retry with the stupid NULL byte for short_message');
return pduToObj(pdu, true, cb); return pduToObj(pdu, true, cb);
} }
if (offset !== retObj.cmdLength) { if (offset !== retObj.cmdLength) {
log.warn(logPrefix + 'Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr); exports.log.warn(logPrefix + 'Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr);
} }
// Decode the short message if it is set and esm_class is 0 // Decode the short message if it is set and esm_class is 0
@@ -335,7 +336,7 @@ function pduToObj(pdu, stupidNullByte, cb) {
retObj.params.short_message = decodeMsg(retObj.params.short_message, retObj.params.data_coding); retObj.params.short_message = decodeMsg(retObj.params.short_message, retObj.params.data_coding);
} }
log.debug(logPrefix + 'Complete decoded PDU: ' + JSON.stringify(retObj)); exports.log.debug(logPrefix + 'Complete decoded PDU: ' + JSON.stringify(retObj));
cb(null, retObj); cb(null, retObj);
} }
@@ -353,7 +354,7 @@ function objToPdu(obj, cb) {
// Check so the command is ok // Check so the command is ok
if (defs.cmds[obj.cmdName] === undefined) { if (defs.cmds[obj.cmdName] === undefined) {
const err = new Error('Invalid cmdName: "' + obj.cmdName + '"'); const err = new Error('Invalid cmdName: "' + obj.cmdName + '"');
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -364,20 +365,20 @@ function objToPdu(obj, cb) {
if (defs.errors[obj.cmdStatus] === undefined) { if (defs.errors[obj.cmdStatus] === undefined) {
const err = new Error('Invalid cmdStatus: "' + obj.cmdStatus + '"'); const err = new Error('Invalid cmdStatus: "' + obj.cmdStatus + '"');
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
// Check so seqNr is ok // Check so seqNr is ok
if (isNaN(seqNr)) { if (isNaN(seqNr)) {
const err = new Error('Invalid seqNr, is not an interger: "' + obj.seqNr + '"'); const err = new Error('Invalid seqNr, is not an interger: "' + obj.seqNr + '"');
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
if (seqNr > 2147483646) { if (seqNr > 2147483646) {
const err = new Error('Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.'); const err = new Error('Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.');
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -394,7 +395,7 @@ function objToPdu(obj, cb) {
if (obj.params.data_coding === undefined) { if (obj.params.data_coding === undefined) {
obj.params.data_coding = defs.encodings.detect(obj.params.short_message); obj.params.data_coding = defs.encodings.detect(obj.params.short_message);
log.silly(logPrefix + 'data_coding "' + obj.params.data_coding + '" detected'); exports.log.silly(logPrefix + 'data_coding "' + obj.params.data_coding + '" detected');
// Now set the hex value // Now set the hex value
obj.params.data_coding = defs.consts.ENCODING[obj.params.data_coding]; obj.params.data_coding = defs.consts.ENCODING[obj.params.data_coding];
@@ -404,10 +405,10 @@ function objToPdu(obj, cb) {
shortMsg = obj.params.short_message; shortMsg = obj.params.short_message;
obj.params.short_message = encodeMsg(obj.params.short_message); obj.params.short_message = encodeMsg(obj.params.short_message);
obj.params.sm_length = obj.params.short_message.length; obj.params.sm_length = obj.params.short_message.length;
log.silly(logPrefix + 'Encoding message "' + shortMsg + '" to "' + obj.params.short_message.toString('hex') + '"'); exports.log.silly(logPrefix + 'Encoding message "' + shortMsg + '" to "' + obj.params.short_message.toString('hex') + '"');
} }
log.debug(logPrefix + 'Complete object to encode: ' + JSON.stringify(obj)); exports.log.debug(logPrefix + 'Complete object to encode: ' + JSON.stringify(obj));
calcCmdLength(obj, function (err, cmdLength) { calcCmdLength(obj, function (err, cmdLength) {
if (err) return cb(err); if (err) return cb(err);
@@ -432,7 +433,7 @@ function pduReturn(pdu, status, params, tlvs, cb) {
let err = null; let err = null;
if (Buffer.isBuffer(pdu)) { if (Buffer.isBuffer(pdu)) {
log.silly(logPrefix + 'Ran with pdu as buffer, run pduToObj() and retry'); exports.log.silly(logPrefix + 'Ran with pdu as buffer, run pduToObj() and retry');
pduToObj(pdu, function (err, pduObj) { pduToObj(pdu, function (err, pduObj) {
if (err) return cb(err); if (err) return cb(err);
@@ -442,7 +443,7 @@ function pduReturn(pdu, status, params, tlvs, cb) {
return; return;
} }
log.silly(logPrefix + 'ran'); exports.log.silly(logPrefix + 'ran');
if (typeof tlvs === 'function') { if (typeof tlvs === 'function') {
cb = tlvs; cb = tlvs;
@@ -481,7 +482,7 @@ function pduReturn(pdu, status, params, tlvs, cb) {
if (err === null && defs.cmds[pdu.cmdName + '_resp'] === undefined) err = new Error('This command does not have a response listed. Given command: "' + pdu.cmdName + '"'); if (err === null && defs.cmds[pdu.cmdName + '_resp'] === undefined) err = new Error('This command does not have a response listed. Given command: "' + pdu.cmdName + '"');
if (err !== null) { if (err !== null) {
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -580,7 +581,7 @@ function splitMsg(msg, encoding) {
// A single message could contain up to 1120 bits // A single message could contain up to 1120 bits
// Return directly if the message fits into that // Return directly if the message fits into that
if (totBitCount < 1121) { if (totBitCount < 1121) {
log.silly(logPrefix + 'bitCount below 1121 (' + totBitCount + ') return only one part'); exports.log.silly(logPrefix + 'bitCount below 1121 (' + totBitCount + ') return only one part');
return [defs.encodings[resolvedEncoding].encode(msg)]; return [defs.encodings[resolvedEncoding].encode(msg)];
} }
@@ -590,7 +591,7 @@ function splitMsg(msg, encoding) {
bundleMsgId = 1; bundleMsgId = 1;
} }
log.silly(logPrefix + 'bundleMsgId set to ' + bundleMsgId); exports.log.silly(logPrefix + 'bundleMsgId set to ' + bundleMsgId);
if (resolvedEncoding === 'ASCII') { if (resolvedEncoding === 'ASCII') {
partCharLimit = 153; partCharLimit = 153;
@@ -677,7 +678,7 @@ function smsDlr(status, cb) {
if (sms.smsId === undefined) { if (sms.smsId === undefined) {
const err = new Error('Trying to send DLR with no smsId.'); const err = new Error('Trying to send DLR with no smsId.');
log.warn(logPrefix + err.message); exports.log.warn(logPrefix + err.message);
return cb(err); return cb(err);
} }
@@ -696,7 +697,7 @@ function smsDlr(status, cb) {
shortMessage += ' stat:UNDELIVERABLE err:1 text:xxx'; shortMessage += ' stat:UNDELIVERABLE err:1 text:xxx';
} }
log.verbose(logPrefix + 'Sending DLR message: "' + shortMessage + '"'); exports.log.verbose(logPrefix + 'Sending DLR message: "' + shortMessage + '"');
dlrPduObj.cmdName = 'deliver_sm'; dlrPduObj.cmdName = 'deliver_sm';
dlrPduObj.params = { dlrPduObj.params = {
@@ -733,3 +734,4 @@ exports.smppDate = smppDate;
exports.bitCount = bitCount; exports.bitCount = bitCount;
exports.splitMsg = splitMsg; exports.splitMsg = splitMsg;
exports.smsDlr = smsDlr; exports.smsDlr = smsDlr;
exports.log = new lUtils.Log();
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "larvitsmpp", "name": "larvitsmpp",
"version": "0.3.4", "version": "0.4.0",
"author": { "author": {
"name": "Mikael 'Lilleman' Göransson", "name": "Mikael 'Lilleman' Göransson",
"email": "lilleman@larvit.se", "email": "lilleman@larvit.se",
@@ -11,10 +11,10 @@
"dependencies": { "dependencies": {
"async": "^2.4.1", "async": "^2.4.1",
"iconv-lite": "^0.4.18", "iconv-lite": "^0.4.18",
"larvitutils": "^2.1.0",
"moment": "^2.18.1", "moment": "^2.18.1",
"utils-merge": "^1.0.0", "utils-merge": "^1.0.0",
"uuid": "^3.2.1", "uuid": "^3.2.1"
"winston": "^3.0.0"
}, },
"description": "Simplified SMPP implementation", "description": "Simplified SMPP implementation",
"devDependencies": { "devDependencies": {
-6
View File
@@ -1,6 +0,0 @@
'use strict';
const log = require('winston');
// Remove log output to the console
log.remove(log.transports.Console);