crashes when trying to forward UDH
For testing purposes, I created a transparent smpp proxy. socket A <-> (PDU) <-> socket B. Here is part of simplest code:
a.on("pdu", pdu => {
console.log("->", pdu);
// Inverse message_id to prevent message_id dublicates
if (pdu.message_id) pdu.message_id = inverse(pdu.message_id);
// Forward PDU
console.log("<-", pdu);
b.send(pdu);
});
Everything works fine, but sometimes these death messages happen: console.log output:
-> PDU {
command_length: 83,
command_id: 4,
command_status: 0,
sequence_number: 16704908,
command: 'submit_sm',
service_type: '',
source_addr_ton: 5,
source_addr_npi: 0,
source_addr: 'aaaa',
dest_addr_ton: 1,
dest_addr_npi: 1,
destination_addr: '0000',
esm_class: 64,
protocol_id: 0,
priority_flag: 0,
schedule_delivery_time: '',
validity_period: 2021-01-16T15:32:33.000Z,
registered_delivery: 1,
replace_if_present_flag: 0,
data_coding: 8,
sm_default_msg_id: 0,
short_message: { udh: [ <Buffer 00 03 26 02 02> ], message: 'nutes.' }
}
<- PDU {
command_length: 83,
command_id: 4,
command_status: 0,
sequence_number: 16704908,
command: 'submit_sm',
service_type: '',
source_addr_ton: 5,
source_addr_npi: 0,
source_addr: 'aaaa',
dest_addr_ton: 1,
dest_addr_npi: 1,
destination_addr: '0000',
esm_class: 64,
protocol_id: 0,
priority_flag: 0,
schedule_delivery_time: '',
validity_period: 2021-01-16T15:32:33.000Z,
registered_delivery: 1,
replace_if_present_flag: 0,
data_coding: 8,
sm_default_msg_id: 0,
short_message: { udh: [ <Buffer 00 03 26 02 02> ], message: 'nutes.' }
}
TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received an instance of Array
at Object.concat (buffer.js:574:13)
at PDU.encode (/devel/smpp-tools/node_modules/smpp/lib/defs.js:545:17)
at PDU._filter (/devel/smpp-tools/node_modules/smpp/lib/pdu.js:144:41)
at PDU.toBuffer (/devel/smpp-tools/node_modules/smpp/lib/pdu.js:177:7)
at Session.send (/devel/smpp-tools/node_modules/smpp/lib/smpp.js:119:24)
at Session.<anonymous> (/devel/smpp-tools/proxy.js:90:11)
at Session.emit (events.js:315:20)
at Session._extractPDUs (/devel/smpp-tools/node_modules/smpp/lib/smpp.js:88:8)
at Socket.emit (events.js:315:20)
at emitReadable_ (_stream_readable.js:569:12) {
code: 'ERR_INVALID_ARG_TYPE'
}
It looks like not correctly decoded-encoded message body. Here is my ugly workaround preventing proxy from crash but we lost a part of message:
a.on("pdu", pdu => {
console.log("->", pdu);
// Inverse message_id to prevent message_id dublicates
if (pdu.message_id) pdu.message_id = inverse(pdu.message_id);
// Ugly workaround
for (let key in pdu.short_message) {
if (key !== "message") delete pdu.short_message[key];
}
// Forward PDU
console.log("<-", pdu);
b.send(pdu);
});
I would like to understand the problem, but manipulations with message encoding-decoding are confusing.
I'm not sure about what kind of configuration are you testing. Are you trying to implement some type of relay server?
client > relay (server & client) > server
Also, could you enable the new debug mode for all clients / servers and post the results? They will be very helpful to try to understand the issue. Debug messages are emitted on the socket level.
Thanks for your comment, rmruano. I've made some kind of transparent proxy for SMPP PDUs. And I found the problem with incorrect encoding/decoding of the UDHs. If one socket sends us a SUBMIT_SM with a UDH, we will get a failure trying to resend this PDU as is on another socket.
@0LEG0 that is because the original full UDH header is lost and extracted as an array to be used by the developer, you should compose the UDH header again
Need help to resolve the issue. Here is the PDU I received:
PDU {
command_length: 83,
command_id: 4,
command_status: 0,
sequence_number: 16704908,
command: 'submit_sm',
service_type: '',
source_addr_ton: 5,
source_addr_npi: 0,
source_addr: 'aaaa',
dest_addr_ton: 1,
dest_addr_npi: 1,
destination_addr: '0000',
esm_class: 64,
protocol_id: 0,
priority_flag: 0,
schedule_delivery_time: '',
validity_period: 2021-01-16T15:32:33.000Z,
registered_delivery: 1,
replace_if_present_flag: 0,
data_coding: 8,
sm_default_msg_id: 0,
short_message: { udh: [ <Buffer 00 03 26 02 02> ], message: 'nutes.' }
}
Then I get following error when I try to resend this PDU (as is) to another smpp session:
TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received an instance of Array
at Object.concat (buffer.js:574:13)
at PDU.encode (/devel/smpp-tools/node_modules/smpp/lib/defs.js:545:17)
at PDU._filter (/devel/smpp-tools/node_modules/smpp/lib/pdu.js:144:41)
at PDU.toBuffer (/devel/smpp-tools/node_modules/smpp/lib/pdu.js:177:7)
at Session.send (/devel/smpp-tools/node_modules/smpp/lib/smpp.js:119:24)
at Session.<anonymous> (/devel/smpp-tools/proxy.js:90:11)
at Session.emit (events.js:315:20)
at Session._extractPDUs (/devel/smpp-tools/node_modules/smpp/lib/smpp.js:88:8)
at Socket.emit (events.js:315:20)
at emitReadable_ (_stream_readable.js:569:12) {
code: 'ERR_INVALID_ARG_TYPE'
}
Here's a possible problem spot in lib/defs.js:
filters.message = {
encode: function(value) {
if (Buffer.isBuffer(value)) {
return value;
}
var message = typeof value === 'string' ? value : value.message;
if (typeof message === 'string' && message) {
var encoded = false;
if (value.udh) {
var udhList = udhCoder.getUdh(value.udh);
for (var i = 0; i < udhList.length; i++) {
var udh = udhList[i];
if (udh[0] === 0x24 || udh[0] === 0x25) {
this.data_coding = consts.ENCODING.ASCII;
message = gsmCoder.encode(message, udh[2]);
encoded = true;
break;
}
}
}
if (!encoded) {
var encoding = encodings.default;
if (this.data_coding === null) {
encoding = encodings.detect(message);
this.data_coding = consts.ENCODING[encoding];
} else if (this.data_coding !== consts.ENCODING.SMSC_DEFAULT) {
for (var key in consts.ENCODING) {
if (consts.ENCODING[key] === this.data_coding) {
encoding = key;
break;
}
}
}
message = encodings[encoding].encode(message);
}
}
if (!value.udh || !value.udh.length) {
return message;
}
if ('esm_class' in this) {
this.esm_class = this.esm_class | consts.ESM_CLASS.UDH_INDICATOR;
}
return Buffer.concat([value.udh, message]);
// ^
// |
// Error: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received an instance of Array
}
Unfortunately I can't reproduce this issue in my sandbox because I don't have enough experience with UDH. Any help is appreciated.
https://github.com/farhadi/node-smpp/issues/107 https://github.com/farhadi/node-smpp/issues/69
Greetings @juliangut! What do you mean when said "the original full UDH header is lost" ? I looked old issues about UDH and found https://github.com/farhadi/node-smpp/issues/139 somebody got the same message:
short_message: {
udh: [ <Buffer 00 03 01 02 02> ],
message: 'y complaint or enquiry, please call 8980'
}
Considering this https://en.wikipedia.org/wiki/User_Data_Header#UDH_Information_Elements and this https://en.m.wikipedia.org/wiki/Concatenated_SMS I assume this is a multiparted message: 00 - Concatenated short message 03 - Length of the header, excluding the first two fields; equal to 03 01 - CSMS reference number, must be same for all the SMS parts in the CSMS 02 - total number of parts 02 - part's number in the sequence Did I understand everything correctly? Thanks
For forwarding UDH, working well for me.
this.reCalculateUDH = (short_message)=>{
if(short_message.udh){
let udhString = JSON.stringify(short_message.udh[0])
let udhJSON = JSON.parse(udhString)
let udhData = udhJSON.data
let sms_count=udhData[3]
let part_id=udhData[4]
//This is a unique id present in each message part
let concat_ref = this.concat_ref++;
let udh = new Buffer.alloc(6);
udh.write(String.fromCharCode(0x5), 0); //Length of UDF
udh.write(String.fromCharCode(0x0), 1); //Indicator for concatenated message
udh.write(String.fromCharCode(0x3), 2); // Subheader Length ( 3 bytes)
udh.write(String.fromCharCode(concat_ref), 3); //Same reference for all concatenated messages
udh.write(String.fromCharCode(sms_count), 4); //Number of total messages in the concatenation
udh.write(String.fromCharCode(part_id), 5); //Sequence number ( used by the mobile to concatenate the split messages)
return udh
}else{
return null
}
}