Fixed problem with UCS2 encoded long messages

This commit is contained in:
2015-06-13 17:56:08 +02:00
parent 7c1f7ef485
commit c5a4b93aee
4 changed files with 115 additions and 19 deletions
+8 -1
View File
@@ -2,7 +2,8 @@
// More or less copied from https://github.com/farhadi/node-smpp
var iconv = require('iconv-lite'),
var log = require('winston'),
iconv = require('iconv-lite'),
encodings = {},
filters = {},
tlvsById = {},
@@ -135,7 +136,13 @@ types = {
},
write: function(value, buffer, offset) {
value = value || 0;
try {
buffer.writeUInt8(value, offset);
} catch (err) {
log.error('larvitsmpp: lib/defs.js - Could not write integer value "' + value + '" on offset "' + offset + '" when buffer length is "' + buffer.length + '"');
throw err;
}
},
size: function() {
return 1;
+2
View File
@@ -357,6 +357,8 @@ function sendSms(smsOptions, callback) {
// Check if we must split this message into multiple
if (utils.bitCount(smsOptions.message) > 1120) {
log.debug('larvitsmpp: lib/session.js: sendSms() - Message larger than 1120 bits, send it as long message!');
this.sendLongSms(smsOptions, callback);
return;
+33 -12
View File
@@ -1,7 +1,8 @@
'use strict';
var log = require('winston'),
defs = require('./defs');
defs = require('./defs'),
bundleMsgId = 0;
/**
* Calcualte cmdLength from object
@@ -115,15 +116,19 @@ function writeBuffer(obj, cmdLength, callback) {
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);
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 {
if (param === 'sm_length') {
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - sm_length is calculated by short_message: "' + obj.params.short_message.toString('hex') + '"');
}
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param] + '"');
}
// Write parameter value to buffer using the types method write()
paramType.write(obj.params[param], buff, offset);
// Increase the offset for the next param
offset += paramSize;
}
@@ -424,9 +429,7 @@ function objToPdu(obj, callback) {
return;
}
writeBuffer(obj, cmdLength, function(err, buff) {
callback(err, buff);
});
writeBuffer(obj, cmdLength, callback);
});
}
@@ -582,7 +585,11 @@ function smppDate(jsDateObj) {
* @return integer
*/
function bitCount(msg, encoding) {
if (encoding === 'ASCII' || defs.encodings.ASCII.match(msg)) {
if (defs.encodings[encoding] === undefined) {
encoding = defs.encodings.detect(msg);
}
if (encoding === 'ASCII') {
return defs.encodings.ASCII.encode(msg).length * 7; // * 7 since each character takes up 7 bits
} else {
return defs.encodings.UCS2.encode(msg).length * 8; // * 8 since its encoded as 16-bits.
@@ -598,24 +605,38 @@ function bitCount(msg, encoding) {
function splitMsg(msg) {
var msgPart = '',
msgs = [],
msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle"
encoding = defs.encodings.detect(msg),
totBitCount = bitCount(msg, encoding),
partBitCount,
udh,
i;
// A single message could contain up to 1120 bits
// Return directly if the message fits into that
if (bitCount(msg) < 1121) {
if (totBitCount < 1121) {
log.silly('larvitsmpp: lib/utils.js: splitMsg() - bitCount below 1121 (' + totBitCount + ') return only one part');
return [defs.encodings[encoding].encode(msg)];
}
bundleMsgId ++; // This will identify this message "bundle"
if (bundleMsgId === 256) {
bundleMsgId = 1;
}
log.silly('larvitsmpp: lib/utils.js: splitMsg() - bundleMsgId set to ' + bundleMsgId);
i = 0;
while (msg[i] !== undefined) {
msgPart += msg[i];
if (bitCount(msgPart, encoding) > 1072) {
partBitCount = bitCount(msgPart, encoding);
if (partBitCount > 1072) {
// We've reached the message limit
log.debug('larvitsmpp: lib/utils.js: splitMsg() - Msg part defined. partBitCount: ' + partBitCount + ' msgPart: "' + msgPart + '"');
// Add this msgPart minus the last character to the msgs array as an encoded buffer
msgs.push(defs.encodings[encoding].encode(msgPart.slice(0, - 1)));
@@ -641,7 +662,7 @@ function splitMsg(msg) {
0x05, // Length of User Data Header, in this case 05.
0x00, // Information Element Identifier, equal to 00 (Concatenated short messages, 8-bit reference number)
0x03, // Length of the header, excluding the first two fields; equal to 03
msgId, // CSMS reference number, must be same for all the SMS parts in the CSMS
bundleMsgId, // CSMS reference number, must be same for all the SMS parts in the CSMS
msgs.length, // Total number of parts. The value shall remain constant for every short message which makes up the concatenated short message. If the value is zero then the receiving entity shall ignore the whole information element
i + 1 // This part's number in the sequence. The value shall start at 1 and increment for every short message which makes up the concatenated short message.
]);
+66
View File
@@ -225,6 +225,72 @@ describe('Sessions', function() {
});
});
it('should try sending a weirder long sms', function(done) {
portfinder.getPort(function(err, freePort) {
assert( ! err, 'Error should not be negative');
larvitsmpp.server({
'port': freePort
}, function(err, serverSession) {
assert( ! err, 'Error should not be negative');
serverSession.on('sms', function(sms) {
sms.smsId = 2344;
assert(sms.from === 'foo', 'SMS from should be "foo"');
assert(sms.to === '46709771337', 'SMS to should be "46709771337"');
assert(sms.message === 'K sKM8NYUuoVbORtCn€swWsvTZjbtYM1TceGJJouolLk4cOtlk7j dxWMI56Domdx2W!dHKjGBR5UsynmUnbp1ysRDCktBri WW2pxIWHv0P7H OVRZNw 6 DBzAqpnd7ZPslwNyi»x OuiNH0R!WM2DTo8ItysNDNe1eNnpLvahhRgv»TC y lvgFrmv4OiUTOP', 'SMS message should be correct');
assert(sms.dlr === false, 'DLR should be boolean false');
assert(sms.pduObjs[0].pduObj.cmdId === 4, 'SMS pduObj cmdId should be 4');
sms.sendResp(function(err, retPdus) {
assert( ! err, 'Error should not be negative');
assert(retPdus[0].toString('hex') === '00000017800000040000000000000002323334342d3100', 'Return PDU 0 is wrong');
assert(retPdus[1].toString('hex') === '00000017800000040000000000000003323334342d3200', 'Return PDU 1 is wrong');
assert(retPdus[2].toString('hex') === '00000017800000040000000000000004323334342d3300', 'Return PDU 2 is wrong');
});
});
serverSession.on('close', function() {
// Manually destroy the server socket
serverSession.sock.destroy();
});
});
larvitsmpp.client({
'port': freePort
}, function(err, clientSession) {
assert( ! err, 'Error should not be negative');
clientSession.sendSms({
'from': 'foo',
'to': '46709771337',
'message': 'K sKM8NYUuoVbORtCn€swWsvTZjbtYM1TceGJJouolLk4cOtlk7j dxWMI56Domdx2W!dHKjGBR5UsynmUnbp1ysRDCktBri WW2pxIWHv0P7H OVRZNw 6 DBzAqpnd7ZPslwNyi»x OuiNH0R!WM2DTo8ItysNDNe1eNnpLvahhRgv»TC y lvgFrmv4OiUTOP'
}, function(err, smsIds, retPduObjs) {
assert( ! err, 'Error should not be negative');
assert(smsIds instanceof Array, 'smsIds should be an Array');
assert(smsIds[0] === '2344-1', 'First smsId should be "2344-1"');
assert(smsIds[1] === '2344-2', 'Second smsId should be "2344-2"');
assert(smsIds[2] === '2344-3', 'Third smsId should be "2344-3"');
assert(smsIds[3] === undefined, 'Fourth smsId should be undefined');
assert(retPduObjs[0].cmdStatus === 'ESME_ROK', 'Command status should be "ESME_ROK"');
assert(retPduObjs[0].cmdName === 'submit_sm_resp', 'Command name should be "submit_sm_resp"');
assert(retPduObjs[1].cmdStatus === 'ESME_ROK', 'Command status should be "ESME_ROK"');
assert(retPduObjs[1].cmdName === 'submit_sm_resp', 'Command name should be "submit_sm_resp"');
assert(retPduObjs[2].cmdStatus === 'ESME_ROK', 'Command status should be "ESME_ROK"');
assert(retPduObjs[2].cmdName === 'submit_sm_resp', 'Command name should be "submit_sm_resp"');
// Gracefully close connection
clientSession.unbind();
done();
});
});
});
});
it('should send a long sms and receive dlrs for it', function(done) {
portfinder.getPort(function(err, freePort) {
assert( ! err, 'Error should not be negative');