Fixed zero length sms message in both text and 3gpp mode. Fixed many crahses along the way. Changes were made in openbts and smqueue. Fixed issue with loading smqueue from back up file. All cases of plain text and 3gpp are working now. Improved logging in smqueue. Fixed error where data was be sent in 3gpp mode when text was selected.

This commit is contained in:
svangundy 2014-03-31 12:54:03 +02:00 committed by Michael Iedema
parent 871679385c
commit 274df56751
5 changed files with 100 additions and 81 deletions

View File

@ -90,7 +90,8 @@ RPData *SMS::hex2rpdata(const char *hexstring)
RPData *rp_data = NULL;
BitVector RPDUbits(strlen(hexstring)*4);
if (!RPDUbits.unhex(hexstring)) {
if ((strlen(hexstring) == 0) || !RPDUbits.unhex(hexstring)) {
LOG(DEBUG) << "SMS RPDU string is empty";
return NULL;
}
LOG(DEBUG) << "SMS RPDU bits: " << RPDUbits;
@ -291,16 +292,16 @@ 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;
//LOG(DEBUG) << "parseBody orig=" << mOriginator << " dest=" << mDestination << " mUserData=" << mUserData;
}
void RPData::writeBody(RLFrame& dest, size_t& wp) const
{
// GSM 04.11 7.3.1.1
// This is the downlink form.
// This is the downlink form
//LOG(DEBUG) << "writeBody orig=" << mOriginator << " dest=" << mDestination << " mUserData=" << mUserData;
mOriginator.writeLV(dest,wp);
//LOG(DEBUG) << "writeBody orig=" << mOriginator << " dest=" << mDestination;
mDestination.writeLV(dest,wp);
mUserData.writeLV(dest,wp);
}

View File

@ -30,6 +30,7 @@
#include <ostream>
#include <BitVector.h>
#include <GSMTransfer.h>
#include <Logger.h>
namespace SMS {

View File

@ -177,7 +177,7 @@ string SMqueue::sm_state_strings[STATE_MAX_PLUS_ONE] = {
string sm_state_string(enum sm_state astate)
string SMqueue::sm_state_string(enum sm_state astate)
{
if (astate < STATE_MAX_PLUS_ONE)
return sm_state_strings[astate];
@ -550,6 +550,7 @@ short_msg_pending::validate_short_msg(SMq *manager, bool should_early_check)
return 400;
}
clen = 0;
// Leave this test in for responses
if (p->content_length && p->content_length->value) {
errno = 0;
clen = strtol(p->content_length->value, &endptr, 10);
@ -557,6 +558,8 @@ short_msg_pending::validate_short_msg(SMq *manager, bool should_early_check)
LOG(DEBUG) << "Invalid Content Length";
return 400;
}
} else {
LOG(DEBUG) << "Content Length zero";
}
if (clen != 0) {
LOG(DEBUG) << "ACK has a content length";
@ -606,13 +609,22 @@ short_msg_pending::validate_short_msg(SMq *manager, bool should_early_check)
LOG(DEBUG) << "Content type not supported";
return 415;
}
if (p->bodies.nb_elt != 1 || !p->bodies.node
|| 0 != p->bodies.node->next
|| !p->bodies.node->element
|| false) { // .
LOG(DEBUG) << "Message entity-body too large";
return 413; // "Request entity-body too large"
int len;
if (p->content_length && p->content_length->value && ((len=strtol(p->content_length->value, NULL, 10)) > 0) ) {
//If length is greater than zero check this
// Bad if any of these are true nb_elt!=1, node=0, node->next!=0, node->element=0
if (p->bodies.nb_elt != 1 // p->bodies.nb_elt should always be one
|| 0 == p->bodies.node
|| 0 != p->bodies.node->next
|| 0 == p->bodies.node->element) {
LOG(DEBUG) << "Message entity-body too large";
return 413; // Request entity-body too large
}
} else {
LOG(DEBUG) << "Content length is zero";
}
if (!p->cseq || !p->cseq->method
|| 0 != strcmp("MESSAGE", p->cseq->method)
|| !p->cseq->number) { // FIXME, validate number??
@ -620,12 +632,6 @@ short_msg_pending::validate_short_msg(SMq *manager, bool should_early_check)
return 400;
}
// contacts -- cannot occur in SIP MESSAGE's
// or most response acks.
// DCK: As a stop gap, we are going to allow them.
/*if (p->contacts.nb_elt)
return 400;*/
} else if (0 == strcmp("REGISTER", p->sip_method)) {
// Null username is OK in register message.
// Null content-type is OK.
@ -654,23 +660,9 @@ short_msg_pending::validate_short_msg(SMq *manager, bool should_early_check)
LOG(DEBUG) << "No call-id";
return 400;
}
// call_infos - no restrictions
// content-encodings - FIXME - no restrictions?
clen = 0;
if (p->content_length && p->content_length->value) {
errno = 0;
clen = strtol(p->content_length->value, &endptr, 10);
if (*endptr != '\0' || errno != 0) { // Errs or trailing crud?
LOG(DEBUG) << "Invalid data in message";
return 413;
}
}
// clen is now the numeric content_length.
// FIXME where is the message body??
// FIXME check the content_length for < 140 chars too */
// But we may have to do that AFTER the encoding, etc is decoded
// error_infos - no restrictions
// Remove content length check
// According to rfc3261 length can be 0 or greater svg 03/20/2014
// From address needs to exist but a tag in the from address is optional
if (!p->from || !p->from->url
@ -800,7 +792,7 @@ short_msg_pending::set_qtag()
char *fromtag;
int error;
LOG(DEBUG) << "Enter parse"; //SVGDBG
//LOG(DEBUG) << "Enter parse";
if (!parsed_is_valid) {
if (!parse()) {
LOG(DEBUG) << "Parse failed in setqtag";
@ -2204,7 +2196,7 @@ SMq::respond_sip_ack(int errcode, SMqueue::short_msg_pending *smp,
return; // Don't ack invalid SIP messages
}
LOG(DEBUG) << "Short message parse returned success"; // SVGDBG
LOG(DEBUG) << "Short message parse returned success";
if (MSG_IS_RESPONSE(smp->parsed)) {
LOG(DEBUG) << "Ignore response message";
return; // Don't ack a response message, or we loop!
@ -2470,8 +2462,7 @@ void SMq::main_loop(int msTMO)
<< smp->qtag << "' from "
<< smp->parsed->from->url->username
<< " for "
<< (smp->parsed->req_uri ? smp->parsed->req_uri->username : "") // just shows smsc
<< ".";
<< (smp->parsed->req_uri ? smp->parsed->req_uri->username : ""); // just shows smsc
} else {
LOG(INFO) << "Got SMS "
<< smp->parsed->status_code
@ -2496,7 +2487,7 @@ void SMq::main_loop(int msTMO)
// We won't leak memory if we didn't queue it up, since
// the delete of smpl will delete anything still
// in ITS list.
// in its list.
delete smpl; // List entry that got added
} // got datagram
@ -2512,7 +2503,7 @@ void SMq::debug_dump() {
short_msg_p_list::iterator x = time_sorted_list.begin();
for (; x != time_sorted_list.end(); ++x) {
x->make_text_valid();
LOG(DEBUG) << "== State: " << sm_state_string (x->state) << "\t"
LOG(DEBUG) << "=== State: " << sm_state_string(x->state) << "\t"
<< (x->next_action_time - now) << endl << "MSG = "
<< x->text;
}
@ -2538,16 +2529,23 @@ SMq::save_queue_to_file(std::string qfile)
return false;
lockSortedList(); // Lock file during the write. Check the time on this.
// Example of what should be in the file
// === 10 -506057005 127.0.0.1:5062 640 0 0
// === state next_action_time network_address length ms_to_sc need_repack message_text
short_msg_p_list::reverse_iterator x = time_sorted_list.rbegin();
for (; x != time_sorted_list.rend(); ++x) {
x->make_text_valid();
ofile << "=== " << (int) x->state << " "
ofile << "=== "
<< (int) x->state << " "
<< x->next_action_time << " "
<< my_network.string_addr((struct sockaddr *)x->srcaddr, x->srcaddrlen, true) << " "
<< strlen(x->text)
<< x->ms_to_sc << x->need_repack << endl
<< strlen(x->text) << " "
<< x->ms_to_sc << " "
<< x->need_repack << endl
<< x->text << endl << endl;
howmany++;
LOG(DEBUG) << "Write entry:" << howmany << " Len:" << strlen(x->text) << " MSG:" << x->text;
}
unlockSortedList();
@ -2584,25 +2582,32 @@ SMq::read_queue_from_file(std::string qfile)
int errcode;
LOG(DEBUG) << "read_queue_from_file:" << qfile;
ifile.open (qfile.c_str(), ios::in | ios::binary);
ifile.open(qfile.c_str(), ios::in | ios::binary);
if (!ifile.is_open())
return false;
// === state next_action_time network_address length ms_to_sc need_repack message_text // === state next_action_time network_address length message_text ms_to_sc need_repack
while (!ifile.eof()) {
ifile >> equals >> astate >> atime;
if ((equals != "===") || (ifile.eof())) { // === is the beginning of a record
LOG(DEBUG) << "End of smqueue file";
break; // End of file
}
// LOG(DEBUG) << "Get next entry";
ifile >> netaddrstr;
ifile >> alength;
ifile >> ms_to_sc;
ifile >> need_repack;
//LOG(DEBUG) << "netaddrstr=" << netaddrstr << " length=" << alength << " ms_to_sc="
// << ms_to_sc << " need_repack=" << need_repack;
while (ifile.peek() == '\n')
ignoreme = ifile.get();
ignoreme = ifile.get(); // Skip over blank lines
msgtext = new char[alength+2];
// Get alength chars (or until null char, hope there are none)
ifile.get(msgtext, alength+1, '\0');
ifile.get(msgtext, alength+1, '\0'); // read the next record
while (ifile.peek() == '\n')
ignoreme = ifile.get();
ignoreme = ifile.get(); // Skip blanks
howmany++;
mystate = (SMqueue::sm_state)astate;
mytime = atime;

View File

@ -54,9 +54,6 @@ namespace SMqueue {
/* Maximum text size of an SMS message. */
#define SMS_MESSAGE_MAX_LENGTH 160
/* std::abort isn't always there. Neither is the C library version.
Idiots? You tell me. */
void abfuckingort(); // Where is the real one?
/* strdup uses malloc, which doesn't play well with new/delete.
The idiots who defined C++ don't provide one, so we will. */
@ -75,7 +72,7 @@ char *new_strdup(const char *orig);
enum sm_state { // timeout, next-state-if-timeout
NO_STATE,
INITIAL_STATE,
INITIAL_STATE, // 1
REQUEST_FROM_ADDRESS_LOOKUP,
ASKED_FOR_FROM_ADDRESS_LOOKUP, //3
@ -104,7 +101,7 @@ enum sm_state { // timeout, next-state-if-timeout
// How to print a state
extern std::string sm_state_strings[STATE_MAX_PLUS_ONE];
std::string sm_state_name(enum sm_state astate);
extern string sm_state_string(enum sm_state astate);
/* Set this once we've called the initializer for the OSIP parser library. */
extern bool osip_initialized;
@ -286,7 +283,7 @@ class short_msg {
return true;
if (!osip_initialized) {
LOG(DEBUG) << "Calling osip_init"; // SVGDBG
//LOG(DEBUG) << "Calling osip_init";
i = osip_init(&osipptr);
if (i != 0) {
LOG(DEBUG) << "osip_init failed error " << i;
@ -298,14 +295,14 @@ class short_msg {
unparse(); // Free any previous one.
// Parse SIP message
LOG(DEBUG) << "Calling osip_message_init"; // SVGDBG
//LOG(DEBUG) << "Calling osip_message_init";
i = osip_message_init(&sip);
if (i != 0) {
LOG(DEBUG) << "osip_message_init failed error " << i;
return false;
}
LOG(DEBUG) << "Calling osip_message_parse"; // SVGDBG
//LOG(DEBUG) << "Calling osip_message_parse";
i = osip_message_parse(sip, text, text_length);
if (i != 0) {
LOG(DEBUG) << "osip_message_parse failed error " << i;
@ -322,34 +319,34 @@ class short_msg {
LOG(DEBUG) << "SMS content not set continue anyway??";
// Most likely this is SIP response.
content_type = UNSUPPORTED_CONTENT;
// SVGDBG Consider not continuing
// SVG Consider not continuing
} else if ( strcmp(parsed->content_type->type, "text") == 0
&& strcmp(parsed->content_type->subtype, "plain") == 0)
{
// If Content-Type is text/plain, then no decoding is needed.
content_type = TEXT_PLAIN;
LOG(DEBUG) << "SMS message encoded text"; //SVGDBG
//LOG(DEBUG) << "SMS message encoded text";
} else if ( strcmp(parsed->content_type->type, "application") == 0
&& strcmp(parsed->content_type->subtype, "vnd.3gpp.sms") == 0)
{
// This is an encoded SMS' TPDU.
LOG(DEBUG) << "SMS message encoded 3GPP"; //SVGDBG
LOG(DEBUG) << "SMS message encoded 3GPP";
content_type = VND_3GPP_SMS;
// Decode it RP-DATA
osip_body_t *bod1 = (osip_body_t *)parsed->bodies.node->element;
const char *bods = bod1->body;
LOG(DEBUG) << "Calling hex2rpdata"; // SVGDBG
//LOG(DEBUG) << "Calling hex2rpdata";
rp_data = hex2rpdata(bods);
if (rp_data == NULL) {
LOG(INFO) << "RP-DATA unpacking failed";
return false;
LOG(INFO) << "RP-DATA length is zero"; // This is okay
return true;
}
// Decode RPDU
tl_message = parseTPDU(rp_data->TPDU());
if (rp_data == NULL) {
LOG(INFO) << "RPDU parsing failed";
if (tl_message == NULL) {
LOG(INFO) << "TPDU parsing failed";
return false;
}
}
@ -364,7 +361,7 @@ class short_msg {
so we have to invalidate both of them. */
void
parsed_was_changed() {
LOG(DEBUG) << "Calling osip_message_force_update"; // SVGDBG
//LOG(DEBUG) << "Calling osip_message_force_update";
parsed_is_better = true;
osip_message_force_update(parsed); // Tell osip library too
}
@ -384,7 +381,7 @@ class short_msg {
return;
}
LOG(DEBUG) << "Calling osip_message_to_str"; //SVGDBG
//LOG(DEBUG) << "Calling osip_message_to_str";
int i = osip_message_to_str(parsed, &dest, &length);
if (i != 0) {
LOG(DEBUG) << "osip_message_to_str failed"; // Is this fatal
@ -426,12 +423,18 @@ class short_msg {
parsed_is_better = false;
} //unparse
// Get text for short message
std::string get_text() const
{
switch (content_type) {
case TEXT_PLAIN: {
osip_body_t *bod1 = (osip_body_t *)parsed->bodies.node->element;
return bod1->body;
if (parsed->bodies.node != 0) {
osip_body_t *bod1 = (osip_body_t *)parsed->bodies.node->element;
return bod1->body;
} else {
return "";
}
}
break;
@ -677,7 +680,7 @@ class short_msg_pending: public short_msg {
void set_state(enum sm_state newstate) {
next_action_time = msgettime() +
(*SMqueue::timeouts[state])[newstate];
LOG(DEBUG) << "Set state orig " << state << " Newstate " << newstate
LOG(DEBUG) << "Set state Current: " << sm_state_string(state) << " Newstate: " << sm_state_string(newstate)
<< " Timeout value " << *SMqueue::timeouts[state][newstate];
state = newstate;
/* If we're in a queue, some code in another class is now going

View File

@ -189,13 +189,20 @@ void pack_tpdu(short_msg_p_list::iterator &smsg)
osip_message_t *omsg = smsg->parsed;
// Message body
osip_body_t *bod1 = (osip_body_t *)omsg->bodies.node->element;
osip_free(bod1->body);
ostringstream body_stream;
RPDU_new.hex(body_stream);
bod1->length = body_stream.str().length();
bod1->body = (char *)osip_malloc (bod1->length+1);
strcpy(bod1->body, body_stream.str().data());
LOG(DEBUG) << "omsg->bodies.node " << omsg->bodies.node
<< " omsg->bodies.node->element " << omsg->bodies.node->element;
if (omsg->bodies.node != 0 && omsg->bodies.node->element != 0) {
osip_body_t *bod1 = (osip_body_t *)omsg->bodies.node->element;
osip_free(bod1->body);
ostringstream body_stream;
RPDU_new.hex(body_stream);
bod1->length = body_stream.str().length();
bod1->body = (char *)osip_malloc (bod1->length+1);
strcpy(bod1->body, body_stream.str().data());
} else {
LOG(DEBUG) << "String length zero";
}
// Let them know that parsed part has been changed.
smsg->parsed_was_changed();
@ -430,6 +437,7 @@ bool pack_text_to_tpdu(const std::string &body,
return true;
}
bool pack_plain_text(const std::string &body,
short_msg_p_list::iterator &smsg)
{
@ -437,12 +445,13 @@ bool pack_plain_text(const std::string &body,
osip_message_t *omsg = smsg->parsed;
// Message body
osip_body_t *bod1 = (osip_body_t *)omsg->bodies.node->element;
osip_free(bod1->body);
bod1->length = body.length();
bod1->body = (char *)osip_malloc (bod1->length+1);
strcpy(bod1->body, body.data());
if (omsg->bodies.node != 0 && omsg->bodies.node->element != 0) {
osip_body_t *bod1 = (osip_body_t *)omsg->bodies.node->element;
osip_free(bod1->body);
bod1->length = body.length();
bod1->body = (char *)osip_malloc (bod1->length+1);
strcpy(bod1->body, body.data());
}
// Let them know that parsed part has been changed.
smsg->parsed_was_changed();
@ -537,7 +546,7 @@ bool pack_sms_for_delivery(short_msg_p_list::iterator &smsg)
} else {
switch (content_type) {
case short_msg::TEXT_PLAIN:
return_action = pack_text_to_tpdu(msgtext, smsg);
return_action = pack_plain_text(msgtext, smsg);
break;
case short_msg::VND_3GPP_SMS: