Fixed mismatch in files between openbts and smqueue.

Fixed all places where + was not being sent. Plus can't be sent as a digit it has to be encoded as an international type.
Fixed error where # is displayed in reply address for +.
SMS reply not working with plus in from address.
Fixed all places in smqueue that crash on purpose when bad data is found.
Fixed several other crashes related to handling missing tags.
Added support for receiving addresses with and without +. Whether a + is received or not depends on what the sender enters.
3gpp mode is working.
Fixed error where smqueue gets into an infinite loop when restarted with bad messages in the queue.
This commit is contained in:
svangundy 2014-03-28 19:46:50 +01:00 committed by Michael Iedema
parent e69dc10abc
commit b34ac5902a
8 changed files with 100 additions and 88 deletions

View File

@ -53,13 +53,17 @@ static int encode(char c, bool *invalid)
return 0; // Not sure what to do.
}
/*
* If digit string starts with a plus strip off the plus. I suspect that this get encoded as an international type somewhere else
* The write function send digits/information and the parse function decodes and store digits/incomming information. SVG
*/
void L3BCDDigits::write(L3Frame& dest, size_t &wp) const
{
bool invalid = false;
unsigned index = 0;
unsigned numDigits = strlen(mDigits);
if (index < numDigits && mDigits[index] == '+') {
//LOG(DEBUG) << "write got +";
index++;
}
while (index < numDigits) {
@ -92,7 +96,7 @@ ostream& GSM::operator<<(ostream& os, const L3BCDDigits& digits)
void L3CalledPartyBCDNumber::writeV( L3Frame &dest, size_t &wp ) const
{
dest.writeField(wp, 0x01, 1);
LOG(DEBUG) << "writeV mType" << mType;
LOG(DEBUG) << "writeV mType " << mType << " first digit " << *digits();
dest.writeField(wp, mType, 3);
dest.writeField(wp, mPlan, 4);
mDigits.write(dest,wp);
@ -104,7 +108,7 @@ void L3CalledPartyBCDNumber::parseV( const L3Frame &src, size_t &rp, size_t expe
// ext bit must be 1
if (src.readField(rp, 1) != 1) L3_READ_ERROR;
mType = (TypeOfNumber)src.readField(rp, 3);
LOG(DEBUG) << "parseV Mtype " << mType;
//LOG(DEBUG) << "parseV mType " << mType;
mPlan = (NumberingPlan)src.readField(rp, 4);
mDigits.parse(src,rp,expectedLength-1, mType == InternationalNumber);
}
@ -129,7 +133,7 @@ void L3CallingPartyBCDNumber::writeV( L3Frame &dest, size_t &wp ) const
{
// If Octet3a is extended, then write 0 else 1.
dest.writeField(wp, (!mHaveOctet3a & 0x01), 1);
LOG(DEBUG) << "writeV mType" << mType;
LOG(DEBUG) << "writeV mType " << mType << " first digit " << *digits();
dest.writeField(wp, mType, 3);
dest.writeField(wp, mPlan, 4);
@ -155,7 +159,7 @@ void L3CallingPartyBCDNumber::parseV( const L3Frame &src, size_t &rp, size_t exp
// Read out first bit = 1.
mHaveOctet3a = !src.readField(rp, 1); // Bit is reversed 0 means you have an octet
mType = (TypeOfNumber)src.readField(rp, 3);
LOG(DEBUG) << "parseV mType" << mType;
// LOG(DEBUG) << "parseV mType " << mType;
mPlan = (NumberingPlan)src.readField(rp, 4);
remainingLength -= 1;

View File

@ -21,7 +21,7 @@
#include "GSML3Message.h"
#include <iostream>
#include <Logger.h>
namespace GSM {
@ -65,6 +65,7 @@ std::ostream& operator<<(std::ostream&, const L3BCDDigits&);
/** Calling Party BCD Number, GSM 04.08 10.5.4.9 */
// (pat) 24.018 10.5.4.9 quote: "This IE is not used in the MS to network direction."
class L3CallingPartyBCDNumber : public L3ProtocolElement {
private:
@ -89,10 +90,20 @@ public:
mHaveOctet3a(false)
{ }
L3CallingPartyBCDNumber( const char * wDigits )
:mType(NationalNumber),mPlan(E164Plan),mDigits(wDigits),
L3CallingPartyBCDNumber( const char * wDigits)
:mPlan(E164Plan), mDigits(wDigits),
mHaveOctet3a(false)
{ }
{
mType = (wDigits[0] == '+') ? InternationalNumber : NationalNumber;
LOG(DEBUG) << "L3CallingPartyBCDNumber ctor type=" << mType << " Digits " << wDigits;
}
L3CallingPartyBCDNumber(const L3CallingPartyBCDNumber &other)
:mType(other.mType),mPlan(other.mPlan),mDigits(other.mDigits),
mHaveOctet3a(other.mHaveOctet3a),
mPresentationIndicator(other.mPresentationIndicator),
mScreeningIndicator(other.mScreeningIndicator)
{}
NumberingPlan plan() const { return mPlan; }
@ -125,11 +136,23 @@ public:
{ }
L3CalledPartyBCDNumber(const char * wDigits)
:mType(NationalNumber),mPlan(E164Plan),mDigits(wDigits)
:mPlan(E164Plan), mDigits(wDigits)
{
mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber;
//LOG(DEBUG) << "L3CallingPartyBCDNumber ctor type=" << mType << " Digits " << wDigits;
}
// (pat) This auto-conversion from CallingParty to CalledParty was used in the SMS code,
// however, it was creating a disaster during unintended auto-conversions of L3Messages,
// which are unintentionally sprinkled throughout the code base due to incomplete constructors.
// The fix would be to add 'explicit' keywords everywhere.
explicit L3CalledPartyBCDNumber(const L3CallingPartyBCDNumber& other)
:mType(other.type()),mPlan(other.plan()),mDigits(other.digits())
{ }
L3CalledPartyBCDNumber(const L3CallingPartyBCDNumber& other)
:mType(other.type()),mPlan(other.plan()),mDigits(other.digits())
// (pat) We must have this constructor as a choice also.
L3CalledPartyBCDNumber(const L3CalledPartyBCDNumber& other)
:mType(other.mType),mPlan(other.mPlan),mDigits(other.mDigits)
{ }

View File

@ -91,7 +91,7 @@ RPData *SMS::hex2rpdata(const char *hexstring)
BitVector RPDUbits(strlen(hexstring)*4);
if (!RPDUbits.unhex(hexstring)) {
return false;
return NULL;
}
LOG(DEBUG) << "SMS RPDU bits: " << RPDUbits;
@ -291,6 +291,7 @@ void RPData::parseBody(const RLFrame& src, size_t &rp)
mOriginator.parseLV(src,rp);
mDestination.parseLV(src,rp);
mUserData.parseLV(src,rp);
//LOG(DEBUG) << "parseBody orig=" << mOriginator << " dest=" << mDestination;
}
@ -299,6 +300,7 @@ void RPData::writeBody(RLFrame& dest, size_t& wp) const
// GSM 04.11 7.3.1.1
// This is the downlink form.
mOriginator.writeLV(dest,wp);
//LOG(DEBUG) << "writeBody orig=" << mOriginator << " dest=" << mDestination;
mDestination.writeLV(dest,wp);
mUserData.writeLV(dest,wp);
}
@ -378,7 +380,8 @@ void TLAddress::parse(const TLFrame& src, size_t& rp)
if (src.readField(rp, 1) != 1) SMS_READ_ERROR;
mType = (TypeOfNumber)src.readField(rp, 3);
mPlan = (NumberingPlan)src.readField(rp, 4);
mDigits.parse(src,rp,length);
//LOG(DEBUG) << "parse mType " << mType;
mDigits.parse(src,rp,length, mType == InternationalNumber);
}
@ -724,6 +727,7 @@ void TLSubmit::parseBody(const TLFrame& src, size_t& rp)
parseSRR(src);
mMR = src.readField(rp,8);
mDA.parse(src,rp);
//LOG(DEBUG) << "Destination " << mDA.digits();
mPI = src.readField(rp,8);
mDCS = src.readField(rp,8);
mVP.VPF(mVPF);
@ -758,18 +762,19 @@ size_t TLDeliver::l2BodyLength() const
}
// (pat) See 3GPP 3.40 9.2.2
void TLDeliver::writeBody(TLFrame& dest, size_t& wp) const
{
writeMMS(dest);
writeRP(dest);
writeUDHI(dest, mUD.UDHI());
writeSRI(dest);
mOA.write(dest,wp);
dest.writeField(wp,mPID,8);
dest.writeField(wp,mUD.DCS(),8);
mSCTS.write(dest,wp);
writeUnused(dest);
mUD.write(dest,wp);
writeMMS(dest); // more messages to send bit.
writeRP(dest); // reply path bit.
writeUDHI(dest, mUD.UDHI()); // User-data-header-indicator bit
writeSRI(dest); // status-report-indication bit
mOA.write(dest,wp); // originating address
dest.writeField(wp,mPID,8); // protocol id
dest.writeField(wp,mUD.DCS(),8); // Data-coding-scheme
mSCTS.write(dest,wp); // service-centre-time-stamp
writeUnused(dest); // user-data-length. (pat) Why empty?
mUD.write(dest,wp); // user data.
}

View File

@ -38,7 +38,7 @@
#include <GSML3Message.h>
#include <GSML3CCElements.h>
#include <GSML3MMElements.h>
#include <Logger.h>
namespace SMS {
@ -91,13 +91,19 @@ public:
TLAddress(GSM::TypeOfNumber wType, GSM::NumberingPlan wPlan, const char* wDigits)
:TLElement(),
mType(wType),mPlan(wPlan),mDigits(wDigits)
{ }
mPlan(wPlan),mDigits(wDigits)
{
mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber;
//LOG(DEBUG) << "TLaddrress ctor type=" << mType << " Digits " << wDigits;
}
TLAddress(const char* wDigits)
:TLElement(),
mType(GSM::NationalNumber),mPlan(GSM::E164Plan),mDigits(wDigits)
{ }
mPlan(GSM::E164Plan),mDigits(wDigits)
{
mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber;
//LOG(DEBUG) << "TLaddrress ctor type=" << mType << " Digits " << wDigits;
}
const char *digits() const { return mDigits.digits(); }
GSM::TypeOfNumber type() const { return mType; }
@ -299,7 +305,7 @@ class TLMessage {
virtual void writeBody( TLFrame& frame, size_t &rp) const =0;
virtual void text(std::ostream& os) const
{ os << MTI(); }
{ os << "MTI="<<MTI(); }
// Accessors
bool MMS() const { return mMMS; }
@ -323,7 +329,7 @@ class TLMessage {
void writeSRQ(TLFrame& fm) const { fm[2]=mSRQ; }
void parseSRQ(const TLFrame& fm) { mSRQ=fm[2]; }
void writeUDHI(TLFrame& fm, bool udhi) const { fm[1]=udhi; }
bool parseUDHI(const TLFrame& fm) { return fm[1]; }
bool parseUDHI(const TLFrame& fm) { return mUDHI = fm[1]; }
void writeRP(TLFrame& fm) const { fm[0]=mRP; }
void parseRP(const TLFrame& fm) { mRP=fm[0]; }
void writeUnused(TLFrame& fm) const { fm.fill(0,3,2); } ///< Fill unused bits with 0s

2
SR

@ -1 +1 @@
Subproject commit bb2e13249e871c85441732a160e42450af5b7005
Subproject commit a0e2934e2c4311d93feaa811c73be5081fe3dced

View File

@ -335,7 +335,7 @@ shortcode_register (const char *imsi, const char *msgtext,
<< gConfig.getStr("SC.Register.Msg.AlreadyB").c_str();
}
} else {
existing = smq->my_hlr.getIMSI(phonenum);
existing = smq->my_hlr.getIMSI2(phonenum);
if (existing) {
LOG(DEBUG) << phonenum << " is already in the HLR";
answer << gConfig.getStr("SC.Register.Msg.TakenA").c_str()

View File

@ -946,7 +946,7 @@ void short_msg_pending::write_cdr(SubscriberRegistry& hlr) const
time_t now = time(NULL); // Need real time for CDR
if (gCDRFile) {
char * user = hlr.getIMSI(from); // I am not a fan of this hlr call here. Probably a decent performance hit...
char * user = hlr.getIMSI2(from); // I am not a fan of this hlr call here. Probably a decent performance hit...
// source, sourceIMSI, dest, date
fprintf(gCDRFile,"%s,%s,%s,%s", from, user, dest, ctime(&now));
fflush(gCDRFile);
@ -1864,58 +1864,27 @@ bool SMq::handle_short_code(const short_code_map_t &short_code_map,
} // SMq::handle_short_code
/* Change the From address to a valid phone number in + countrycode phonenum
format. Also add a Via: line about us. */
/* Change the From address imsi to a valid phone number in + countrycode phonenum
format. Also add a Via: line about us.
From address can contain imsi or phone number ????
fromusername contains imsi
*/
enum sm_state
SMq::lookup_from_address (short_msg_pending *qmsg)
{
char *host = qmsg->parsed->from->url->host;
bool got_phone = false;
bool got_phone = false; // Never updated
char *scheme = qmsg->parsed->from->url->scheme;
if (!scheme) { LOG(ERR) << "no scheme"; return NO_STATE; }
if (0 != strcmp("sip", scheme)) { LOG(ERR) << "scheme != sip"; return NO_STATE; }
char *username = qmsg->parsed->from->url->username;
if (!username) { LOG(ERR) << "no username"; return NO_STATE; }
// Get from user name
char *fromusername = qmsg->parsed->from->url->username;
if (!fromusername) { LOG(ERR) << "No from user name"; return NO_STATE; }
if (!host) { LOG(ERR) << "no hostname"; return NO_STATE; }
/* disabled by Kurtis, as the sender's hostname is no way to
determine if it's a phone number or not */
/*
if (0 != strcmp("127.0.0.1", host)
&& 0 != strcmp("localhost", host)
&& 0 != strcmp(my_ipaddress.c_str(), host)
&& 0 != strcmp(my_2nd_ipaddress.c_str(), host)) {
// This isn't a phone number.
//
// There's a bizarre convention to move the email address
// into the message text, followed by a space... GSM 03.40 sec 3.8
ostringstream newtext;
osip_body_t *bod1;
if (qmsg->parsed->bodies.nb_elt == 1) {
bod1 = (osip_body_t *)qmsg->parsed->bodies.node->element;
} else {
LOG(ERR) << "Message has no text!";
return NO_STATE; // Punt on msg w/no text
}
newtext << qmsg->parsed->from->url->username << "@"
<< host << " " << qmsg->get_text();
osip_free(bod1->body);
bod1->body = osip_strdup(newtext.str().c_str());
bod1->length = strlen(bod1->body);
// Change From address to a local shortcode
osip_free(qmsg->parsed->from->url->username);
osip_free(qmsg->parsed->from->url->host);
qmsg->parsed->from->url->username = osip_strdup ("211");
qmsg->parsed->from->url->host = osip_strdup (my_ipaddress.c_str());
got_phone = true;
}
*/
// Insert a Via: line describing us, this makes us easier to trace,
// and also allows a remote SIP agent to reply to us. (Maybe?)
osip_via_t *via;
@ -1931,9 +1900,10 @@ SMq::lookup_from_address (short_msg_pending *qmsg)
via_set_port(via, osip_strdup(my_udp_port.c_str()));
/* Username can be in various formats. Check for formats that
we know about. Anything else we punt. */
we know about. Anything else we punt.
This can be phone number or IMSI */
/* TODO: Check for tel BM2011 */
if (got_phone || username[0] == '+' || isdigit(username[0])) {
if (got_phone || fromusername[0] == '+' || isdigit(fromusername[0])) {
/* We have a phone number. This is what we want.
So we're done, and can move on to the next part
of processing the short_msg. */
@ -1941,15 +1911,16 @@ SMq::lookup_from_address (short_msg_pending *qmsg)
}
/* If we have "imsi" on the front, strip it. */
char *tryuser = username;
if ((username[0] == 'i'||username[0]=='I')
&& (username[1] == 'm'||username[1]=='M')
&& (username[2] == 's'||username[2]=='S')
&& (username[3] == 'i'||username[3]=='I')) {
char *tryuser = fromusername;
if ((fromusername[0] == 'i'||fromusername[0]=='I')
&& (fromusername[1] == 'm'||fromusername[1]=='M')
&& (fromusername[2] == 's'||fromusername[2]=='S')
&& (fromusername[3] == 'i'||fromusername[3]=='I')) {
tryuser += 4;
}
/* http://en.wikipedia.org/wiki/International_Mobile_Subscriber_Identity */
/* IMSI length check */
size_t len = strlen (tryuser);
if (len != 15 && len != 14) {
LOG(ERR) << "Message does not have a valid IMSI!";
@ -1960,13 +1931,13 @@ SMq::lookup_from_address (short_msg_pending *qmsg)
/* Look up the IMSI in the Home Location Register. */
char *newfrom;
newfrom = my_hlr.getCLIDLocal(username);
newfrom = my_hlr.getCLIDLocal(fromusername);
if (!newfrom) {
/* ==================FIXME KLUDGE====================
* Here is our fake table of IMSIs and phone numbers
* ==================FIXME KLUDGE==================== */
for (int i = 0; imsi_phone[i].imsi[0]; i++) {
if (0 == strcmp(imsi_phone[i].imsi, username)) {
if (0 == strcmp(imsi_phone[i].imsi, fromusername)) {
newfrom = strdup(imsi_phone[i].phone);
break;
}
@ -1974,7 +1945,7 @@ SMq::lookup_from_address (short_msg_pending *qmsg)
}
if (!newfrom) {
LOG(NOTICE) << "Lookup IMSI <" << username
LOG(NOTICE) << "Lookup IMSI <" << fromusername
<< "> to phonenum failed.";
LOG(DEBUG) << qmsg->text;
//return bounce_message (qmsg,
@ -2011,7 +1982,7 @@ bool SMq::to_is_deliverable(const char *to)
isDeliverable = (short_code_map.find(to) != short_code_map.end());
if (!isDeliverable) {
char *newdest = my_hlr.getIMSI(to);
char *newdest = my_hlr.getIMSI2(to);
if (newdest
&& 0 != strncmp("imsi", newdest, 4)
@ -2058,7 +2029,10 @@ SMq::convert_content_type(short_msg_pending *message, short_msg::ContentType to_
return true;
}
/* Change the Request-URI's address to a valid IMSI. */
/*
* Change the Request-URI's/phone number to a valid IMSI.
*
*/
enum sm_state
SMq::lookup_uri_imsi (short_msg_pending *qmsg)
{
@ -2089,7 +2063,7 @@ SMq::lookup_uri_imsi (short_msg_pending *qmsg)
&& 0 != strncmp("IMSI", username, 4))) {
// We have a phone number. It needs translation.
char *newdest = my_hlr.getIMSI(username);
char *newdest = my_hlr.getIMSI2(username); // Get IMSI from phone number
if (!newdest) {
/* ==================FIXME KLUDGE====================
` * Here is our fake table of IMSIs and phone numbers

View File

@ -304,7 +304,7 @@ short_code_action submitSMS(const char *imsi, const TLSubmit& submit,
}
//#endif
char* destinationNumber = scp->scp_smq->my_hlr.getIMSI(address.digits());
char* destinationNumber = scp->scp_smq->my_hlr.getIMSI2(address.digits());
// Send to smqueue or HTTP gateway, depending on what's defined in the config.
// And whether of not we can resolve the destination, and a global relay does not exist,