From 7d0da6202c9de9687c3e99ed2ffc24d941d5fde9 Mon Sep 17 00:00:00 2001 From: Qasim Ayyaz Khan Date: Thu, 2 Jun 2016 15:18:58 -0400 Subject: [PATCH 1/3] some fixes related to variable UDH header and Multipart SMS's reference: https://github.com/larvit/larvitsmpp/issues/1 --- lib/session.js | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/session.js b/lib/session.js index a739544..9933c41 100644 --- a/lib/session.js +++ b/lib/session.js @@ -363,22 +363,39 @@ function sendLongSms(smsOptions, callback) { // Store long smses in the temporary storage function longSms(pduObj) { - var smsGroupId = pduObj.params.short_message[3], - smsParts = pduObj.params.short_message[4], - longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId; + // Fix: UDH values are stored in HEX and decoding them make it garbage. First OCTET contains + // the size of UDH data header. If UDH data header size is 0x05 then field 4 i.e. CSMS + // reference number is of one octet otherwise it consists of 2 octets. Other fields can + // be found from below reference. + // reference: https://en.wikipedia.org/wiki/Concatenated_SMS + var encodedMessage = utils.encodeMsg(pduObj.params.short_message), + udhSize = encodedMessage[0]; + var smsGroupId, smsParts, partNr; + if(udhSize === 0x05) { + smsGroupId = encodedMessage[3], + smsParts = encodedMessage[4], + partNr = encodedMessage[5]; + } else { + smsGroupId = (encodedMessage[3] * 256) + encodedMessage[4], + smsParts = encodedMessage[5], + partNr = encodedMessage[6]; + } + + var longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId; if (this.longSmses[longSmsId] === undefined) { this.longSmses[longSmsId] = { 'created': new Date(), 'partsCount': parseInt(smsParts), + 'udhSize': udhSize, // Saving udh size to remove garbage from message 'pduObjs': [{ - 'partNr': pduObj.params.short_message[5], // We save this here to easier sort the array later on + 'partNr': partNr, // We save this here to easier sort the array later on 'pduObj': pduObj }] }; } else { this.longSmses[longSmsId].pduObjs.push({ - 'partNr': pduObj.params.short_message[5], // We save this here to easier sort the array later on + 'partNr': partNr, // We save this here to easier sort the array later on 'pduObj': pduObj }); } @@ -406,6 +423,7 @@ function checkLongSmses() { var that = this, smsGroupId, smsGroup, + udhSize, // UDH Size from longSms() function smsObj, i, curPduObj; @@ -422,7 +440,7 @@ function checkLongSmses() { for (smsGroupId in this.longSmses) { smsGroup = this.longSmses[smsGroupId]; - + udhSize = smsGroup.udhSize; // All parts are accounted for! Emit sms event and clear from tmp storage if (smsGroup.partsCount === smsGroup.pduObjs.length) { log.debug('larvitsmpp: lib/session.js: checkLongSmses() - All parts accounted for in smsGroupId "' + smsGroupId + '", emitting sms event.'); @@ -451,7 +469,9 @@ function checkLongSmses() { curPduObj = smsObj.pduObjs[i].pduObj; curPduObj.session = this; - smsObj.message += utils.decodeMsg(curPduObj.params.short_message, curPduObj.params.data_coding, curPduObj.params.short_message[0] + 1); + // Fix: message in pduObj is already decoded we dont need to do it again. Also removing garbade from original message. + //smsObj.message += utils.decodeMsg(curPduObj.params.short_message, curPduObj.params.data_coding, curPduObj.params.short_message[0] + 1); + smsObj.message += curPduObj.params.short_message.substring(udhSize + 1); i ++; } @@ -557,7 +577,9 @@ function session(sock) { var smsObj = {}; // 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 + if ((pduObj.params.esm_class & 0x40) === 0x40) { log.debug('larvitsmpp: lib/session.js: session() - returnObj.handleCmd.submit_sm() - long sms detected, esm_class 0x40.'); returnObj.longSms(pduObj); return; // Long messages should not get handled here at all, so cancel execution here @@ -709,4 +731,4 @@ function session(sock) { } // Expose some functions -exports = module.exports = session; \ No newline at end of file +exports = module.exports = session; From 8f1c94724cd51154b09bb8ff72f48b9838024ea0 Mon Sep 17 00:00:00 2001 From: Qasim Ayyaz Khan Date: Thu, 2 Jun 2016 23:52:25 -0400 Subject: [PATCH 2/3] Fixed extraction of UDH header from original buffer rather than from encoded message as CSMS reference / values number greater than 0x7F were not decoded properly. --- lib/session.js | 16 ++++------------ lib/utils.js | 25 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/session.js b/lib/session.js index 9933c41..1ae34b8 100644 --- a/lib/session.js +++ b/lib/session.js @@ -368,18 +368,10 @@ function longSms(pduObj) { // reference number is of one octet otherwise it consists of 2 octets. Other fields can // be found from below reference. // reference: https://en.wikipedia.org/wiki/Concatenated_SMS - var encodedMessage = utils.encodeMsg(pduObj.params.short_message), - udhSize = encodedMessage[0]; - var smsGroupId, smsParts, partNr; - if(udhSize === 0x05) { - smsGroupId = encodedMessage[3], - smsParts = encodedMessage[4], - partNr = encodedMessage[5]; - } else { - smsGroupId = (encodedMessage[3] * 256) + encodedMessage[4], - smsParts = encodedMessage[5], - partNr = encodedMessage[6]; - } + var udhSize = pduObj.params['udhHeader'].size, + smsGroupId = pduObj.params['udhHeader'].reference, + smsParts = pduObj.params['udhHeader'].totalParts, + partNr = pduObj.params['udhHeader'].partNr; var longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId; diff --git a/lib/utils.js b/lib/utils.js index f806205..d0aebb5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -271,8 +271,29 @@ function pduToObj(pdu, stupidNullByte, callback) { paramSize = command.params[param].type.size(retObj.params[param]); log.silly('larvitsmpp: lib/utils.js: pduToObj() - 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((retObj.params['esm_class'] & 0x40) === 0x40) { + //This is a part of long sms. We should save UDH header information in params. + console.log(pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)) + var hsize = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(0, 2)); + //If hsize is >5 then CSMS Reference consist of two parts + if(hsize == 5) { + var reference = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)), + totalParts = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(8, 10)), + partNr = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(10, 12)); + } else { + var reference = (parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)) * 256) + parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(8, 10)), + totalParts = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(10, 12)), + partNr = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(12, 14)); + } + var udhHeader = { + 'size': hsize, + 'reference': reference, + 'totalParts': totalParts, + 'partNr': partNr + } + retObj.params['udhHeader'] = udhHeader; + } // 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) { @@ -782,4 +803,4 @@ exports.pduReturn = pduReturn; exports.smppDate = smppDate; exports.bitCount = bitCount; exports.splitMsg = splitMsg; -exports.smsDlr = smsDlr; \ No newline at end of file +exports.smsDlr = smsDlr; From d811dd32f23370ef7bfd84e6eef638c5f5b66224 Mon Sep 17 00:00:00 2001 From: Qasim Ayyaz Khan Date: Fri, 3 Jun 2016 00:10:05 -0400 Subject: [PATCH 3/3] Removing some debugging logs. --- lib/utils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index d0aebb5..3beadb7 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -274,7 +274,6 @@ function pduToObj(pdu, stupidNullByte, callback) { if (param === 'short_message') { if((retObj.params['esm_class'] & 0x40) === 0x40) { //This is a part of long sms. We should save UDH header information in params. - console.log(pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)) var hsize = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(0, 2)); //If hsize is >5 then CSMS Reference consist of two parts if(hsize == 5) {