static void receive_smpp_thread(void *arg) { ESME *esme; Octstr *os; long len; long sender_id; SMPP_PDU *pdu; esme = arg; sender_id = -1; len = 0; while (!quitting && conn_wait(esme->conn, -1.0) != -1) { for (;;) { if (len == 0) { len = smpp_pdu_read_len(esme->conn); if (len == -1) { error(0, "Client sent garbage, closing connection."); goto error; } else if (len == 0) { if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; break; } } gw_assert(len > 0); os = smpp_pdu_read_data(esme->conn, len); if (os != NULL) { len = 0; pdu = smpp_pdu_unpack(NULL, os); if (pdu == NULL) { error(0, "PDU unpacking failed!"); octstr_dump(os, 0); } else { handle_pdu(esme, pdu); smpp_pdu_destroy(pdu); } octstr_destroy(os); } else if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; else break; } if (!quitting && esme->receiver && sender_id == -1) sender_id = gwthread_create(send_smpp_thread, esme); } error: if (sender_id != -1) { quit(); gwthread_join(sender_id); } esme_destroy(esme); quit(); debug("test.smpp", 0, "%s terminates.", __func__); }
static void send_smpp_thread(void *arg) { ESME *esme; Octstr *os; SMPP_PDU *pdu; unsigned long id; esme = arg; id = 0; while (!quitting && counter_value(num_to_esme) < max_to_esme) { id = counter_increase(num_to_esme) + 1; while (!quitting && counter_value(num_from_esme) + 500 < id) gwthread_sleep(1.0); if (quitting) break; pdu = smpp_pdu_create(deliver_sm, counter_increase(message_id_counter)); pdu->u.deliver_sm.source_addr = octstr_create("456"); pdu->u.deliver_sm.destination_addr = octstr_create("123"); pdu->u.deliver_sm.short_message = octstr_format("%ld", id); if (esme->version > 0x33) pdu->u.deliver_sm.receipted_message_id = octstr_create("receipted_message_id\0"); os = smpp_pdu_pack(NULL, pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); if (first_to_esme == (time_t) -1) time(&first_to_esme); debug("test.smpp", 0, "Delivered SMS %ld of %ld to bearerbox via SMPP.", id, max_to_esme); if ((id % enquire_interval) == 0) { pdu = smpp_pdu_create(enquire_link, counter_increase(message_id_counter)); os = smpp_pdu_pack(NULL, pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); debug("test.smpp", 0, "Sent enquire_link to bearerbox."); } } time(&last_to_esme); if (id == max_to_esme) info(0, "All messages sent to ESME."); debug("test.smpp", 0, "%s terminates.", __func__); }
static void handle_pdu(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; Octstr *os; int i; debug("test.smpp", 0, "Handling SMPP PDU of type %s", pdu->type_name); for (i = 0; i < num_handlers; ++i) { if (handlers[i].type == pdu->type) { resp = handlers[i].handler(esme, pdu); if (resp != NULL) { os = smpp_pdu_pack(NULL, resp); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(resp); } return; } } error(0, "Unhandled SMPP PDU."); smpp_pdu_dump(octstr_imm(""), pdu); }
SMPP_PDU *smpp_pdu_unpack(Octstr *data_without_len) { SMPP_PDU *pdu; unsigned long type; long len, pos; len = octstr_len(data_without_len); if (len < 4) { error(0, "SMPP: PDU was too short (%ld bytes).", octstr_len(data_without_len)); return NULL; } /* get the PDU type */ if ((type = decode_integer(data_without_len, 0, 4)) == -1) return NULL; /* create a coresponding representation structure */ pdu = smpp_pdu_create(type, 0); if (pdu == NULL) return NULL; pos = 0; switch (type) { #define OPTIONAL_BEGIN \ { /* Read optional parameters */ \ while (pos + 4 <= len) { \ unsigned long opt_tag, opt_len; \ opt_tag = decode_integer(data_without_len, pos, 2); pos += 2; \ debug("sms.smpp", 0, "Optional parameter tag (0x%04lx)", opt_tag); \ opt_len = decode_integer(data_without_len, pos, 2); pos += 2; \ debug("sms.smpp", 0, "Optional parameter length read as %ld", opt_len); #define TLV_INTEGER(name, octets) \ if (SMPP_##name == opt_tag) { \ /* check length */ \ if (opt_len > octets) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #name, opt_len); \ pos += opt_len; \ continue; \ } \ INTEGER(name, opt_len); \ } else #define TLV_NULTERMINATED(name, max_len) \ if (SMPP_##name == opt_tag) { \ /* check length */ \ if (opt_len > max_len || pos+opt_len > len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #name, opt_len); \ pos += opt_len; \ continue; \ } \ copy_until_nul(#name, data_without_len, &pos, opt_len, &p->name); \ } else #define TLV_OCTETS(name, min_len, max_len) \ if (SMPP_##name == opt_tag) { \ /* check length */ \ if (opt_len < min_len || opt_len > max_len || pos + opt_len > len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \ #name, opt_len, min_len, max_len); \ pos += opt_len; \ continue; \ } \ p->name = octstr_copy(data_without_len, pos, opt_len); \ pos += opt_len; \ } else #define OPTIONAL_END \ { \ Octstr *val = octstr_copy(data_without_len, pos, opt_len); \ if (val) octstr_binary_to_hex(val, 0); \ else val = octstr_create(""); \ warning(0, "SMPP: Unknown TLV(0x%04lx,0x%04lx,%s) for PDU type (%s) received!", \ opt_tag, opt_len, octstr_get_cstr(val), pdu->type_name); \ pos += opt_len; \ octstr_destroy(val); \ } \ } \ } #define INTEGER(name, octets) \ if ((p->name = decode_integer(data_without_len, pos, octets)) == -1) \ goto err; \ pos += octets; #define NULTERMINATED(name, max_octets) \ /* just warn about errors but not fail */ \ copy_until_nul(#name, data_without_len, &pos, max_octets, &p->name); #define OCTETS(name, field_giving_octets) \ p->name = octstr_copy(data_without_len, pos, \ p->field_giving_octets); \ if (p->field_giving_octets != (unsigned long) octstr_len(p->name)) { \ error(0, "smpp_pdu: error while unpacking '" #name "', " \ "len is %ld but should have been %ld, dropping.", \ octstr_len(p->name), p->field_giving_octets); \ goto err; \ } else { \ pos += p->field_giving_octets; \ } #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while unpacking."); } return pdu; err: smpp_pdu_destroy(pdu); octstr_dump(data_without_len, 0); return NULL; }