Added support for sending long messages via splitted short_message parameter

This commit is contained in:
2015-05-10 15:35:12 +02:00
parent 931dac203d
commit 0d5ba73e8a
4 changed files with 122 additions and 36 deletions
+1
View File
@@ -3,3 +3,4 @@
exports.server = require('./lib/server');
exports.client = require('./lib/client');
exports.utils = require('./lib/utils');
exports.defs = require('./lib/defs');
+69 -19
View File
@@ -1,9 +1,9 @@
'use strict';
var log = require('winston'),
events = require('events'),
smppUtils = require('./utils'),
defs = require('./defs');
var log = require('winston'),
events = require('events'),
utils = require('./utils'),
defs = require('./defs');
/**
* Generic session function
@@ -57,7 +57,7 @@ function session(sock) {
*/
returnObj.sockWrite = function(pdu, closeAfterSend) {
if ( ! Buffer.isBuffer(pdu)) {
smppUtils.objToPdu(pdu, function(err, buffer) {
utils.objToPdu(pdu, function(err, buffer) {
if (err) {
log.warn('larvitsmpp: lib/session.js: session() - sockWrite() - Could not convert PDU to buffer');
returnObj.closeSocket();
@@ -96,7 +96,7 @@ function session(sock) {
// Make sure the pdu is an object
if (Buffer.isBuffer(pdu)) {
smppUtils.pduToObj(pdu, function(err, pduObj) {
utils.pduToObj(pdu, function(err, pduObj) {
if (err) {
callback(err);
return;
@@ -180,7 +180,7 @@ function session(sock) {
closeAfterSend = undefined;
}
smppUtils.pduReturn(pdu, status, params, function(err, retPdu) {
utils.pduReturn(pdu, status, params, function(err, retPdu) {
if (err) {
log.error('larvitsmpp: lib/session.js: session() - returnObj.sendReturn() - Could not create return PDU: ' + err.message);
returnObj.closeSocket();
@@ -200,6 +200,53 @@ function session(sock) {
});
};
/**
* Send a longer SMS than 1120 bits
*
* @param obj smsOptions
* from - alphanum or international format
* to - international format
* message - string
* dlr - boolean defaults to false
* @param func callback(err, smsId, retPduObj)
*/
returnObj.sendLongSms = function(smsOptions, callback) {
var msgs = utils.splitMsg(smsOptions.message),
encoding = defs.encodings.detect(smsOptions.message); // Set encoding once for all message parts
function sendPart(i) {
var pduObj = {
'cmdName': 'submit_sm',
'params': {
'source_addr_ton': 1, // Default to international format
'esm_class': 0x40, // This indicates that there is a UDH in the short_message
'source_addr': smsOptions.from,
'destination_addr': smsOptions.to,
'data_coding': defs.consts.ENCODING[encoding],
'short_message': msgs[i],
'sm_length': msgs[i].length
}
};
// Request DLRs!
if (smsOptions.dlr) {
pduObj.params.registered_delivery = 0x01;
}
log.debug('larvitsmpp: lib/session.js: returnObj.sendLongSms() - pduObj: ' + JSON.stringify(pduObj));
returnObj.send(pduObj, function(err, retPduObj) {
if (typeof callback === 'function' && msgs[i + 1] === undefined) {
callback(err, retPduObj.params.message_id, retPduObj);
} else if (msgs[i + 1] !== undefined) {
sendPart(i + 1);
}
});
}
sendPart(0);
};
/**
* Send an SMS
*
@@ -215,6 +262,7 @@ function session(sock) {
pduObj.cmdName = 'submit_sm';
pduObj.params = {
'source_addr_ton': 1, // Default to international format
'source_addr': smsOptions.from,
'destination_addr': smsOptions.to,
'short_message': smsOptions.message
@@ -225,6 +273,13 @@ function session(sock) {
pduObj.params.registered_delivery = 0x01;
}
// Check if we must split this message into multiple
if (utils.bitCount(smsOptions.message) > 1120) {
returnObj.sendLongSms(smsOptions, callback);
return;
}
log.debug('larvitsmpp: lib/session.js: returnObj.sendSms() - pduObj: ' + JSON.stringify(pduObj));
returnObj.send(pduObj, function(err, retPduObj) {
@@ -243,7 +298,6 @@ function session(sock) {
*/
returnObj.sendDlr = function(sms, status, callback) {
var shortMessage = 'id:' + sms.smsId + ' sub:001 ',
err,
dlrPduObj;
if (typeof status === 'function') {
@@ -261,8 +315,8 @@ function session(sock) {
shortMessage += 'dlvrd:0 ';
}
shortMessage += 'submit date:' + smppUtils.smppDate(sms.submitTime);
shortMessage += ' done date:' + smppUtils.smppDate(new Date());
shortMessage += 'submit date:' + utils.smppDate(sms.submitTime);
shortMessage += ' done date:' + utils.smppDate(new Date());
if (status) {
shortMessage += ' stat:DELIVRD err:0 text:xxx';
@@ -298,15 +352,12 @@ function session(sock) {
dlrPduObj.seqNr = 323;
console.log('before:');
console.log(dlrPduObj);
smppUtils.objToPdu(dlrPduObj, function(err, pdu) {
utils.objToPdu(dlrPduObj, function(err, pdu) {
if (err) {
throw err;
}
smppUtils.pduToObj(pdu, function(err, newObj) {
utils.pduToObj(pdu, function(err, newObj) {
if (err) {
throw err;
}
@@ -316,14 +367,13 @@ function session(sock) {
});
});
return;
returnObj.send(dlrPduObj, function(err, retPduObj) {
console.log('WHATTA WHATTA');
console.log(retPduObj);
/*if (typeof callback === 'function') {
if (typeof callback === 'function') {
callback(err, retPduObj.params.message_id, retPduObj);
}*/
}
});
};
@@ -423,7 +473,7 @@ function session(sock) {
log.silly('larvitsmpp: lib/session.js: session() - sock.on(data) - Incoming PDU: ' + pduBuf.toString('hex'));
smppUtils.pduToObj(pduBuf, function(err, pduObj) {
utils.pduToObj(pduBuf, function(err, pduObj) {
if (err) {
log.warn('larvitsmpp: lib/session.js: session() - Invalid PDU. ' + err.message);
+19 -16
View File
@@ -73,6 +73,7 @@ function writeBuffer(obj, cmdLength, callback) {
buff,
param,
paramType,
paramSize,
tlvId,
tlvName,
tlvValue,
@@ -112,14 +113,19 @@ function writeBuffer(obj, cmdLength, callback) {
// Cycle through the defs list to make sure the params are in the right order
for (param in defs.cmds[obj.cmdName].params) {
paramType = defs.cmds[obj.cmdName].params[param].type;
paramSize = paramType.size(obj.params[param]);
// Write parameter value to buffer using the types method write()
paramType.write(obj.params[param], buff, offset);
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param] + '"');
if (Buffer.isBuffer(obj.params[param])) {
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param].toString('hex') + '" and size "' + paramSize + '"');
} else {
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param] + '"');
}
// Increase the offset for the next param
offset += paramType.size(obj.params[param]);
offset += paramSize;
}
// Cycle through the tlvs
@@ -143,6 +149,8 @@ function writeBuffer(obj, cmdLength, callback) {
offset += tlvDef.type.size(tlvValue) + 4;
}
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Complete PDU: "' + buff.toString('hex') + '"');
callback(null, buff);
}
@@ -255,7 +263,6 @@ function pduToObj(pdu, stupidNullByte, callback) {
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
// in some implementations, so we need to account for that.
if (stupidNullByte === true) {
log.silly('larvitsmpp: lib/utils.js: pduToObj() - stupidNullByte is set, so short_message is followed by a NULL octet, increase paramSize one extra to account for that');
paramSize ++;
@@ -326,8 +333,10 @@ function pduToObj(pdu, stupidNullByte, callback) {
log.warn('larvitsmpp: lib/utils.js: pduToObj() - Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr);
}
// Decode the short message if it is set
if (retObj.params.short_message !== undefined) {
// Decode the short message if it is set and esm_class is 0
// The esm_class 0x40 (64 int) means the short_message have a UDH
// Thats why we return the short_message as a buffer
if (retObj.params.short_message !== undefined && retObj.params.esm_class !== 0x40) {
retObj.params.short_message = decodeMsg(retObj.params.short_message, retObj.params.data_coding);
}
@@ -395,6 +404,7 @@ function objToPdu(obj, callback) {
// Acutally encode the string
shortMsg = obj.params.short_message;
obj.params.short_message = encodeMsg(obj.params.short_message);
obj.params.sm_length = obj.params.short_message.length;
log.silly('larvitsmpp: lib/utils.js: objToPdu() - encoding message "' + shortMsg + '" to "' + obj.params.short_message.toString('hex') + '"');
}
@@ -571,20 +581,13 @@ function bitCount(msg, encoding) {
* @return array of buffers
*/
function splitMsg(msg) {
var msgPart = '',
msgs = [],
msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle"
encoding,
var msgPart = '',
msgs = [],
msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle"
encoding = defs.encodings.detect(msg),
udh,
i;
// Build a buffer from the correct encoding
if (defs.encodings.ASCII.match(msg)) {
encoding = 'ASCII';
} else {
encoding = 'UCS2';
}
// A single message could contain up to 1120 bits
// Return directly if the message fits into that
if (bitCount(msg) < 1121) {
+32
View File
@@ -142,6 +142,38 @@ describe('PDU convertion', function() {
});
});
it('should create a submit_sm PDU with esm_class 0x40 and a short_message with UDH in it', function(done) {
var msg = 'hej världen',
msgBuf = Buffer.concat([new Buffer('050003010101', 'hex'), new Buffer(msg)]),
encoding = larvitsmpp.defs.encodings.detect(msg);
larvitsmpp.utils.objToPdu({
'cmdName': 'submit_sm',
'cmdStatus': 'ESME_ROK',
'seqNr': 12,
'params': {
'esm_class': 0x40,
'source_addr': '46701113311',
'destination_addr': '46709771337',
'sm_length': msgBuf.length,
'data_coding': larvitsmpp.defs.consts.ENCODING[encoding],
'short_message': msgBuf
}
}, function(err, pdu) {
assert( ! err, 'Error should be negative');
larvitsmpp.utils.pduToObj(pdu, function(err, retObj) {
assert( ! err, 'Error should be negative');
assert(retObj.params.short_message.toString('hex') === '05000301010168656a2076c3a4726c64656e', 'short_message should be correct');
done();
});
});
});
it('should encode and decode integer cstring params correctly', function(done) {
var pduObj = {
'cmdName': 'submit_sm_resp',