00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include <string.h>
00067 #include "smpp_pdu.h"
00068
00069 #define MIN_SMPP_PDU_LEN (4*4)
00070
00071 #define MAX_SMPP_PDU_LEN (7424)
00072
00073
00074 static long decode_integer(Octstr *os, long pos, int octets)
00075 {
00076 unsigned long u;
00077 int i;
00078
00079 if (octstr_len(os) < pos + octets)
00080 return -1;
00081
00082 u = 0;
00083 for (i = 0; i < octets; ++i)
00084 u = (u << 8) | octstr_get_char(os, pos + i);
00085
00086 return u;
00087 }
00088
00089
00090 static void append_encoded_integer(Octstr *os, unsigned long u, long octets)
00091 {
00092 long i;
00093
00094 for (i = 0; i < octets; ++i)
00095 octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF);
00096 }
00097
00098
00099 static int copy_until_nul(const char *field_name, Octstr *os, long *pos, long max_octets, Octstr **data)
00100 {
00101 long nul;
00102
00103 *data = NULL;
00104
00105 nul = octstr_search_char(os, '\0', *pos);
00106 if (nul == -1) {
00107 warning(0, "SMPP: PDU NULL terminated string (%s) has no NULL.", field_name);
00108 return -1;
00109 }
00110 if (*pos + max_octets < nul) {
00111 error(0, "SMPP: PDU NULL terminated string (%s) longer than allowed.", field_name);
00112 return -1;
00113 }
00114 *data = (nul - *pos > 0) ? octstr_copy(os, *pos, nul - *pos) : NULL;
00115 *pos = nul + 1;
00116 return 0;
00117 }
00118
00119
00120 SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no)
00121 {
00122 SMPP_PDU *pdu;
00123
00124 pdu = gw_malloc(sizeof(*pdu));
00125 pdu->type = type;
00126
00127 switch (type) {
00128 #define OPTIONAL_BEGIN
00129 #define TLV_INTEGER(name, octets) p->name = -1;
00130 #define TLV_NULTERMINATED(name, max_len) p->name = NULL;
00131 #define TLV_OCTETS(name, min_len, max_len) p->name = NULL;
00132 #define OPTIONAL_END
00133 #define INTEGER(name, octets) p->name = 0;
00134 #define NULTERMINATED(name, max_octets) p->name = NULL;
00135 #define OCTETS(name, field_giving_octetst) p->name = NULL;
00136 #define PDU(name, id, fields) \
00137 case id: { \
00138 struct name *p = &pdu->u.name; \
00139 pdu->type_name = #name; \
00140 fields \
00141 p->command_id = type; \
00142 p->sequence_number = seq_no; \
00143 } break;
00144 #include "smpp_pdu.def"
00145 default:
00146 error(0, "Unknown SMPP_PDU type, internal error.");
00147 gw_free(pdu);
00148 return NULL;
00149 }
00150
00151 return pdu;
00152 }
00153
00154 void smpp_pdu_destroy(SMPP_PDU *pdu)
00155 {
00156 if (pdu == NULL)
00157 return;
00158
00159 switch (pdu->type) {
00160 #define OPTIONAL_BEGIN
00161 #define TLV_INTEGER(name, octets) p->name = -1;
00162 #define TLV_NULTERMINATED(name, max_octets) octstr_destroy(p->name);
00163 #define TLV_OCTETS(name, min_len, max_len) octstr_destroy(p->name);
00164 #define OPTIONAL_END
00165 #define INTEGER(name, octets) p->name = 0;
00166 #define NULTERMINATED(name, max_octets) octstr_destroy(p->name);
00167 #define OCTETS(name, field_giving_octets) octstr_destroy(p->name);
00168 #define PDU(name, id, fields) \
00169 case id: { struct name *p = &pdu->u.name; fields } break;
00170 #include "smpp_pdu.def"
00171 default:
00172 error(0, "Unknown SMPP_PDU type, internal error while destroying.");
00173 }
00174 gw_free(pdu);
00175 }
00176
00177
00178 Octstr *smpp_pdu_pack(SMPP_PDU *pdu)
00179 {
00180 Octstr *os;
00181 Octstr *temp;
00182
00183 os = octstr_create("");
00184
00185 gw_assert(pdu != NULL);
00186
00187
00188
00189
00190 switch (pdu->type) {
00191 #define OPTIONAL_BEGIN
00192 #define TLV_INTEGER(name, octets)
00193 #define TLV_NULTERMINATED(name, max_len)
00194 #define TLV_OCTETS(name, min_len, max_len)
00195 #define OPTIONAL_END
00196 #define INTEGER(name, octets) p = *(&p);
00197 #define NULTERMINATED(name, max_octets) p = *(&p);
00198 #define OCTETS(name, field_giving_octets) \
00199 p->field_giving_octets = octstr_len(p->name);
00200 #define PDU(name, id, fields) \
00201 case id: { struct name *p = &pdu->u.name; fields } break;
00202 #include "smpp_pdu.def"
00203 default:
00204 error(0, "Unknown SMPP_PDU type, internal error while packing.");
00205 }
00206
00207 switch (pdu->type) {
00208 #define TL(name, octets) \
00209 append_encoded_integer(os, SMPP_##name, 2); \
00210 append_encoded_integer(os, octets, 2);
00211 #define OPTIONAL_BEGIN
00212 #define TLV_INTEGER(name, octets) \
00213 if (p->name != -1) { \
00214 TL(name, octets); \
00215 INTEGER(name, octets) \
00216 }
00217 #define TLV_NULTERMINATED(name, max_len) \
00218 if (p->name != NULL) { \
00219 TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name) + 1)); \
00220 NULTERMINATED(name, max_len) \
00221 }
00222 #define TLV_OCTETS(name, min_len, max_len) \
00223 if (p->name != NULL) { \
00224 unsigned long len = octstr_len(p->name); \
00225 if (len > max_len || len < min_len) { \
00226 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
00227 #name, len, min_len, max_len);\
00228 } else { \
00229 TL(name, len); \
00230 octstr_append(os, p->name); \
00231 } \
00232 }
00233 #define OPTIONAL_END
00234 #define INTEGER(name, octets) \
00235 append_encoded_integer(os, p->name, octets);
00236 #define NULTERMINATED(name, max_octets) \
00237 if (p->name != NULL) { \
00238 if (octstr_len(p->name) >= max_octets) { \
00239 warning(0, "SMPP: PDU element <%s> too long " \
00240 "(length is %ld, should be %d)", \
00241 #name, octstr_len(p->name), max_octets-1); \
00242 temp = octstr_copy(p->name, 0, max_octets-1); \
00243 } else \
00244 temp = octstr_duplicate(p->name); \
00245 octstr_append(os, temp); \
00246 octstr_destroy(temp); \
00247 } \
00248 octstr_append_char(os, '\0');
00249 #define OCTETS(name, field_giving_octets) \
00250 if (p->name) octstr_append(os, p->name);
00251 #define PDU(name, id, fields) \
00252 case id: { struct name *p = &pdu->u.name; fields } break;
00253 #include "smpp_pdu.def"
00254 default:
00255 error(0, "Unknown SMPP_PDU type, internal error while packing.");
00256 }
00257
00258 temp = octstr_create("");
00259 append_encoded_integer(temp, octstr_len(os) + 4, 4);
00260 octstr_insert(os, temp, 0);
00261 octstr_destroy(temp);
00262
00263 return os;
00264 }
00265
00266
00267 SMPP_PDU *smpp_pdu_unpack(Octstr *data_without_len)
00268 {
00269 SMPP_PDU *pdu;
00270 unsigned long type;
00271 long len, pos;
00272
00273 len = octstr_len(data_without_len);
00274
00275 if (len < 4) {
00276 error(0, "SMPP: PDU was too short (%ld bytes).",
00277 octstr_len(data_without_len));
00278 return NULL;
00279 }
00280
00281
00282 if ((type = decode_integer(data_without_len, 0, 4)) == -1)
00283 return NULL;
00284
00285
00286 pdu = smpp_pdu_create(type, 0);
00287 if (pdu == NULL)
00288 return NULL;
00289
00290 pos = 0;
00291
00292 switch (type) {
00293 #define OPTIONAL_BEGIN \
00294 { \
00295 while (pos + 4 <= len) { \
00296 unsigned long opt_tag, opt_len; \
00297 opt_tag = decode_integer(data_without_len, pos, 2); pos += 2; \
00298 debug("sms.smpp", 0, "Optional parameter tag (0x%04lx)", opt_tag); \
00299 opt_len = decode_integer(data_without_len, pos, 2); pos += 2; \
00300 debug("sms.smpp", 0, "Optional parameter length read as %ld", opt_len);
00301 #define TLV_INTEGER(name, octets) \
00302 if (SMPP_##name == opt_tag) { \
00303 \
00304 if (opt_len > octets) { \
00305 error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #name, opt_len); \
00306 pos += opt_len; \
00307 continue; \
00308 } \
00309 INTEGER(name, opt_len); \
00310 } else
00311 #define TLV_NULTERMINATED(name, max_len) \
00312 if (SMPP_##name == opt_tag) { \
00313 \
00314 if (opt_len > max_len || pos+opt_len > len) { \
00315 error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #name, opt_len); \
00316 pos += opt_len; \
00317 continue; \
00318 } \
00319 copy_until_nul(#name, data_without_len, &pos, opt_len, &p->name); \
00320 } else
00321 #define TLV_OCTETS(name, min_len, max_len) \
00322 if (SMPP_##name == opt_tag) { \
00323 \
00324 if (opt_len < min_len || opt_len > max_len || pos + opt_len > len) { \
00325 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
00326 #name, opt_len, min_len, max_len); \
00327 pos += opt_len; \
00328 continue; \
00329 } \
00330 p->name = octstr_copy(data_without_len, pos, opt_len); \
00331 pos += opt_len; \
00332 } else
00333 #define OPTIONAL_END \
00334 { \
00335 Octstr *val = octstr_copy(data_without_len, pos, opt_len); \
00336 if (val) octstr_binary_to_hex(val, 0); \
00337 else val = octstr_create(""); \
00338 warning(0, "SMPP: Unknown TLV(0x%04lx,0x%04lx,%s) for PDU type (%s) received!", \
00339 opt_tag, opt_len, octstr_get_cstr(val), pdu->type_name); \
00340 pos += opt_len; \
00341 octstr_destroy(val); \
00342 } \
00343 } \
00344 }
00345 #define INTEGER(name, octets) \
00346 if ((p->name = decode_integer(data_without_len, pos, octets)) == -1) \
00347 goto err; \
00348 pos += octets;
00349 #define NULTERMINATED(name, max_octets) \
00350 \
00351 copy_until_nul(#name, data_without_len, &pos, max_octets, &p->name);
00352 #define OCTETS(name, field_giving_octets) \
00353 p->name = octstr_copy(data_without_len, pos, \
00354 p->field_giving_octets); \
00355 if (p->field_giving_octets != (unsigned long) octstr_len(p->name)) { \
00356 error(0, "smpp_pdu: error while unpacking '" #name "', " \
00357 "len is %ld but should have been %ld, dropping.", \
00358 octstr_len(p->name), p->field_giving_octets); \
00359 goto err; \
00360 } else { \
00361 pos += p->field_giving_octets; \
00362 }
00363 #define PDU(name, id, fields) \
00364 case id: { struct name *p = &pdu->u.name; fields } break;
00365 #include "smpp_pdu.def"
00366 default:
00367 error(0, "Unknown SMPP_PDU type, internal error while unpacking.");
00368 }
00369
00370 return pdu;
00371
00372 err:
00373 smpp_pdu_destroy(pdu);
00374 octstr_dump(data_without_len, 0);
00375 return NULL;
00376 }
00377
00378
00379 void smpp_pdu_dump(SMPP_PDU *pdu)
00380 {
00381 debug("sms.smpp", 0, "SMPP PDU %p dump:", (void *) pdu);
00382 debug("sms.smpp", 0, " type_name: %s", pdu->type_name);
00383 switch (pdu->type) {
00384 #define OPTIONAL_BEGIN
00385 #define TLV_INTEGER(name, max_len) \
00386 if (p->name != -1) { \
00387 INTEGER(name, max_len) \
00388 }
00389 #define TLV_NULTERMINATED(name, max_len) \
00390 if (p->name != NULL) { \
00391 NULTERMINATED(name, max_len) \
00392 }
00393 #define TLV_OCTETS(name, min_len, max_len) \
00394 if (p->name != NULL) { \
00395 OCTETS(name, max_len) \
00396 }
00397 #define OPTIONAL_END
00398 #define INTEGER(name, octets) \
00399 debug("sms.smpp", 0, " %s: %lu = 0x%08lx", #name, p->name, p->name);
00400 #define NULTERMINATED(name, max_octets) \
00401 octstr_dump_short(p->name, 2, #name);
00402 #define OCTETS(name, field_giving_octets) \
00403 octstr_dump_short(p->name, 2, #name);
00404 #define PDU(name, id, fields) \
00405 case id: { struct name *p = &pdu->u.name; fields } break;
00406 #include "smpp_pdu.def"
00407 default:
00408 error(0, "Unknown SMPP_PDU type, internal error.");
00409 break;
00410 }
00411 debug("sms.smpp", 0, "SMPP PDU dump ends.");
00412 }
00413
00414
00415 long smpp_pdu_read_len(Connection *conn)
00416 {
00417 Octstr *os;
00418 unsigned char buf[4];
00419 long len;
00420
00421 os = conn_read_fixed(conn, sizeof(buf));
00422 if (os == NULL)
00423 return 0;
00424 octstr_get_many_chars((char*) buf, os, 0, sizeof(buf));
00425 octstr_destroy(os);
00426 len = decode_network_long(buf);
00427 if (len < MIN_SMPP_PDU_LEN) {
00428 error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).",
00429 len, (long) MIN_SMPP_PDU_LEN);
00430 return -1;
00431 }
00432 if (len > MAX_SMPP_PDU_LEN) {
00433 error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).",
00434 len, (long) MAX_SMPP_PDU_LEN);
00435 return -1;
00436 }
00437 return len;
00438 }
00439
00440
00441 Octstr *smpp_pdu_read_data(Connection *conn, long len)
00442 {
00443 Octstr *os;
00444
00445 os = conn_read_fixed(conn, len - 4);
00446 return os;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 const char *smpp_error_to_string(enum SMPP_ERROR_MESSAGES error)
00458 {
00459 switch (error) {
00460 case SMPP_ESME_ROK:
00461 return "OK";
00462 case SMPP_ESME_RINVMSGLEN:
00463 return "Message Length is invalid";
00464 case SMPP_ESME_RINVCMDLEN:
00465 return "Command Length is invalid";
00466 case SMPP_ESME_RINVCMDID:
00467 return "Invalid Command ID";
00468 case SMPP_ESME_RINVBNDSTS:
00469 return "Incorrect BIND Status for given command";
00470 case SMPP_ESME_RALYNBD:
00471 return "ESME Already in Bound State";
00472 case SMPP_ESME_RINVPRTFLG:
00473 return "Invalid Priority Flag";
00474 case SMPP_ESME_RINVREGDLVFLG:
00475 return "Invalid Registered Delivery Flag";
00476 case SMPP_ESME_RSYSERR:
00477 return "System Error";
00478 case SMPP_ESME_RINVSRCADR:
00479 return "Invalid Source Address";
00480 case SMPP_ESME_RINVDSTADR:
00481 return "Invalid Destination Address";
00482 case SMPP_ESME_RBINDFAIL:
00483 return "Bind Failed";
00484 case SMPP_ESME_RINVPASWD:
00485 return "Invalid Password";
00486 case SMPP_ESME_RINVSYSID:
00487 return "Invalid System ID";
00488 case SMPP_ESME_RCANCELFAIL:
00489 return "Cancel SM Failed";
00490 case SMPP_ESME_RREPLACEFAIL:
00491 return "Replace SM Failed";
00492 case SMPP_ESME_RMSGQFUL:
00493 return "Message Queue Full";
00494 case SMPP_ESME_RINVSERTYP:
00495 return "Invalid Service Type";
00496 case SMPP_ESME_RINVNUMDESTS:
00497 return "Invalid number of destinations";
00498 case SMPP_ESME_RINVDLNAME:
00499 return "Invalid Distribution List Name";
00500 case SMPP_ESME_RINVDESTFLAG:
00501 return "Destination flag is invalid";
00502 case SMPP_ESME_RINVSUBREP:
00503 return "Submit w/replace not supported/allowed";
00504 case SMPP_ESME_RINVESMCLASS:
00505 return "Invalid esm_class field data";
00506 case SMPP_ESME_RCNTSUBDL:
00507 return "Cannot Submit to Distribution List";
00508 case SMPP_ESME_RSUBMITFAIL:
00509 return "Submit failed";
00510 case SMPP_ESME_RINVSRCTON:
00511 return "Invalid Source address TON";
00512 case SMPP_ESME_RINVSRCNPI:
00513 return "Invalid Source address NPI";
00514 case SMPP_ESME_RINVDSTTON:
00515 return "Invalid Destination address TON";
00516 case SMPP_ESME_RINVDSTNPI:
00517 return "Invalid Destination address NPI";
00518 case SMPP_ESME_RINVSYSTYP:
00519 return "Invalid system_type field";
00520 case SMPP_ESME_RINVREPFLAG:
00521 return "Invalid replace_if_present flag";
00522 case SMPP_ESME_RINVNUMMSGS:
00523 return "Invalid number of messages";
00524 case SMPP_ESME_RTHROTTLED:
00525 return "Throttling error";
00526 case SMPP_ESME_RINVSCHED:
00527 return "Invalid Scheduled Delivery Time";
00528 case SMPP_ESME_RINVEXPIRY:
00529 return "Invalid message validity period";
00530 case SMPP_ESME_RINVDFTMSGID:
00531 return "Predefined Message ID is Invalid or specific predefined message was not found";
00532 case SMPP_ESME_RX_T_APPN:
00533 return "ESME Receiver Temporary App Error Code";
00534 case SMPP_ESME_RX_P_APPN:
00535 return "ESME Receiver Permanent App Error Code";
00536 case SMPP_ESME_RX_R_APPN:
00537 return "ESME Receiver Reject Message Error Code";
00538 case SMPP_ESME_RQUERYFAIL:
00539 return "query_sm request failed";
00540 case SMPP_ESME_RINVTLVSTREAM:
00541 return "Error in optional part of the PDU Body";
00542 case SMPP_ESME_RTLVNOTALLWD:
00543 return "TLV not allowed";
00544 case SMPP_ESME_RINVTLVLEN:
00545 return "Invalid Parameter Length";
00546 case SMPP_ESME_RMISSINGTLV:
00547 return "Expected TLV missing";
00548 case SMPP_ESME_RINVTLVVAL:
00549 return "Invalid TLV value";
00550 case SMPP_ESME_RDELIVERYFAILURE:
00551 return "Transaction Delivery Failure";
00552 case SMPP_ESME_RUNKNOWNERR:
00553 return "Unknown Error";
00554 case SMPP_ESME_RSERTYPUNAUTH:
00555 return "ESME Not authorized to use specified service_type";
00556 case SMPP_ESME_RPROHIBITED:
00557 return "ESME Prohibited from using specified operation";
00558 case SMPP_ESME_RSERTYPUNAVAIL:
00559 return "Specified service_type is unavailable";
00560 case SMPP_ESME_RSERTYPDENIED:
00561 return "Specified service_type is denied";
00562 case SMPP_ESME_RINVDCS:
00563 return "Invalid Data Coding Scheme";
00564 case SMPP_ESME_RINVSRCADDRSUBUNIT:
00565 return "Source Address Sub unit is invalid";
00566 case SMPP_ESME_RINVDSTADDRSUBUNIT:
00567 return "Destination Address Sub unit is invalid";
00568 case SMPP_ESME_RINVBCASTFREQINT:
00569 return "Broadcast Frequency Interval is invalid";
00570 case SMPP_ESME_RINVBCASTALIAS_NAME:
00571 return "Broadcast Alias Name is invalid";
00572 case SMPP_ESME_RINVBCASTAREAFMT:
00573 return "Broadcast Area Format is invalid";
00574 case SMPP_ESME_RINVNUMBCAST_AREAS:
00575 return "Number of Broadcast Areas is invalid";
00576 case SMPP_ESME_RINVBCASTCNTTYPE:
00577 return "Broadcast Content Type is invalid";
00578 case SMPP_ESME_RINVBCASTMSGCLASS:
00579 return "Broadcast Message Class is invalid";
00580 case SMPP_ESME_RBCASTFAIL:
00581 return "broadcast_sm operation failed";
00582 case SMPP_ESME_RBCASTQUERYFAIL:
00583 return "broadcast_query_sm operation failed";
00584 case SMPP_ESME_RBCASTCANCELFAIL:
00585 return "broadcast_cancel_sm operation failed";
00586 case SMPP_ESME_RINVBCAST_REP:
00587 return "Number of Repeated Broadcasts is invalid";
00588 case SMPP_ESME_RINVBCASTSRVGRP:
00589 return "Broadcast Service Group is invalid";
00590 case SMPP_ESME_RINVBCASTCHANIND:
00591 return "Broadcast Channel Indicator is invalid";
00592
00593 default:
00594
00595 if (error >= 0x0400 && error <= 0x04FF)
00596 return "Vendor-specific error, please refer to your SMPP provider";
00597 else
00598 return "Unknown/Reserved";
00599 }
00600 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.