Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

smpp_pdu.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * smpp_pdu.c - parse and generate SMPP PDUs
00059  *
00060  * Lars Wirzenius
00061  * Alexander Malysh <a.malysh@centrium.de>:
00062  *     Extended optional parameters implementation.
00063  */
00064 
00065 
00066 #include <string.h>
00067 #include "smpp_pdu.h"
00068 
00069 #define MIN_SMPP_PDU_LEN    (4*4)
00070 /* old value was (1024). We need more because message_payload can be up to 64K octets*/
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; /* Make sure "p" is used */
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      * Fix lengths of octet string fields.
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     /* get the PDU type */
00282     if ((type = decode_integer(data_without_len, 0, 4)) == -1)
00283         return NULL;
00284 
00285     /* create a coresponding representation structure */
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         {   /* Read optional parameters */  \
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                     /* check length */ \
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                     /* check length */ \
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                     /* check length */ \
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         /* just warn about errors but not fail */ \
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];    /* The length is 4 octets. */
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);    /* `len' includes itself. */
00446     return os;
00447 }
00448 
00449 
00450 /*
00451  * Return error string for given error code
00452  * NOTE: If you add new error strings here please use
00453  *       error strings from SMPP spec. and please keep
00454  *       error codes in switch statement sorted by error
00455  *       code ID.
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             /* tell the user that we have a vendor-specific beast here */
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.