smpp_pdu.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:7k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * smpp_pdu.c - parse and generate SMPP PDUs
  3.  *
  4.  * Lars Wirzenius
  5.  */
  6. #include <string.h>
  7. #include "smpp_pdu.h"
  8. #define MIN_SMPP_PDU_LEN    (4*4)
  9. #define MAX_SMPP_PDU_LEN    (1024)
  10. static unsigned long decode_integer(Octstr *os, long pos, int octets)
  11. {
  12.     unsigned long u;
  13.     int i;
  14.     
  15.     gw_assert(octstr_len(os) >= pos + octets);
  16.     u = 0;
  17.     for (i = 0; i < octets; ++i)
  18.      u = (u << 8) | octstr_get_char(os, pos + i);
  19.     return u;
  20. }
  21. static void append_encoded_integer(Octstr *os, unsigned long u, long octets)
  22. {
  23.     long i;
  24.     for (i = 0; i < octets; ++i)
  25.      octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF);
  26. }
  27. static Octstr *copy_until_nul(Octstr *os, long *pos, long max_octets)
  28. {
  29.     long nul;
  30.     Octstr *data;
  31.     nul = octstr_search_char(os, '', *pos);
  32.     if (nul == -1) {
  33. warning(0, "SMPP: PDU NUL terminated string has no NUL.");
  34.      return NULL;
  35.     }
  36.     if (*pos + max_octets < nul) {
  37. error(0, "SMPP: PDU NUL terminated string longer than allowed.");
  38.      return NULL;
  39.     }
  40.     data = (nul - *pos > 0) ? octstr_copy(os, *pos, nul - *pos) : NULL;
  41.     *pos = nul + 1;
  42.     return data;
  43. }
  44. SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no)
  45. {
  46.     SMPP_PDU *pdu;
  47.     
  48.     pdu = gw_malloc(sizeof(*pdu));
  49.     pdu->type = type;
  50.     
  51.     switch (type) {
  52.     #define INTEGER(name, octets) 
  53.     if (strcmp(#name, "command_id") == 0) p->name = type; 
  54.      else if (strcmp(#name, "sequence_number") == 0) p->name = seq_no; 
  55.      else p->name = 0;
  56.     #define NULTERMINATED(name, max_octets) p->name = NULL;
  57.     #define OCTETS(name, field_giving_octetst) p->name = NULL;
  58.     #define PDU(name, id, fields) 
  59.      case id: { 
  60.     struct name *p = &pdu->u.name; 
  61.     pdu->type_name = #name; 
  62.     fields 
  63. } break;
  64.     #include "smpp_pdu.def"
  65.     default:
  66.      error(0, "Unknown SMPP_PDU type, internal error.");
  67.      gw_free(pdu);
  68. return NULL;
  69.     }
  70.     
  71.     return pdu;
  72. }
  73. void smpp_pdu_destroy(SMPP_PDU *pdu)
  74. {
  75.     if (pdu == NULL)
  76.      return;
  77.     switch (pdu->type) {
  78.     #define INTEGER(name, octets) p->name = 0; /* Make sure "p" is used */
  79.     #define NULTERMINATED(name, max_octets) octstr_destroy(p->name);
  80.     #define OCTETS(name, field_giving_octets) octstr_destroy(p->name);
  81.     #define PDU(name, id, fields) 
  82.      case id: { struct name *p = &pdu->u.name; fields } break;
  83.     #include "smpp_pdu.def"
  84.     default:
  85.      error(0, "Unknown SMPP_PDU type, internal error while destroying.");
  86.     }
  87.     gw_free(pdu);
  88. }
  89. Octstr *smpp_pdu_pack(SMPP_PDU *pdu)
  90. {
  91.     Octstr *os;
  92.     Octstr *temp;
  93.     
  94.     os = octstr_create("");
  95.     /*
  96.      * Fix lengths of octet string fields.
  97.      */
  98.     switch (pdu->type) {
  99.     #define INTEGER(name, octets) p = *(&p);
  100.     #define NULTERMINATED(name, max_octets) p = *(&p);
  101.     #define OCTETS(name, field_giving_octets) 
  102.      p->field_giving_octets = octstr_len(p->name);
  103.     #define PDU(name, id, fields) 
  104.      case id: { struct name *p = &pdu->u.name; fields } break;
  105.     #include "smpp_pdu.def"
  106.     default:
  107.      error(0, "Unknown SMPP_PDU type, internal error while packing.");
  108.     }
  109.     switch (pdu->type) {
  110.     #define INTEGER(name, octets) 
  111.      append_encoded_integer(os, p->name, octets);
  112.     #define NULTERMINATED(name, max_octets) 
  113.         if (p->name != NULL) { 
  114.             if (octstr_len(p->name) >= max_octets) { 
  115.                 warning(0, "SMPP: PDU element <%s> to long " 
  116.                         "(length is %ld, should be %d)", 
  117.                         #name, octstr_len(p->name), max_octets); 
  118.                 temp = octstr_copy(p->name, 0, max_octets-1); 
  119.             } else 
  120.                 temp = octstr_duplicate(p->name); 
  121.             octstr_append(os, temp); 
  122.             octstr_destroy(temp); 
  123.         } 
  124.         octstr_append_char(os, '');
  125.     #define OCTETS(name, field_giving_octets) 
  126.      octstr_append(os, p->name);
  127.     #define PDU(name, id, fields) 
  128.      case id: { struct name *p = &pdu->u.name; fields } break;
  129.     #include "smpp_pdu.def"
  130.     default:
  131.      error(0, "Unknown SMPP_PDU type, internal error while packing.");
  132.     }
  133.     temp = octstr_create("");
  134.     append_encoded_integer(temp, octstr_len(os) + 4, 4);
  135.     octstr_insert(os, temp, 0);
  136.     octstr_destroy(temp);
  137.     return os;
  138. }
  139. SMPP_PDU *smpp_pdu_unpack(Octstr *data_without_len)
  140. {
  141.     SMPP_PDU *pdu;
  142.     unsigned long type;
  143.     long pos;
  144.     
  145.     if (octstr_len(data_without_len) < 4) {
  146. error(0, "SMPP: PDU was too short (%ld bytes).", 
  147.       octstr_len(data_without_len));
  148. return NULL;
  149.     }
  150.     type = decode_integer(data_without_len, 0, 4);
  151.     pdu = smpp_pdu_create(type, 0);
  152.     if (pdu == NULL)
  153.      return NULL;
  154.     
  155.     pos = 0;
  156.     switch (type) {
  157.     #define INTEGER(name, octets) 
  158.      p->name = decode_integer(data_without_len, pos, octets); 
  159. pos += octets;
  160.     #define NULTERMINATED(name, max_octets) 
  161.      p->name = copy_until_nul(data_without_len, &pos, max_octets);
  162.     #define OCTETS(name, field_giving_octets) 
  163.      p->name = octstr_copy(data_without_len, pos, 
  164.                 p->field_giving_octets); 
  165.      gw_assert(p->field_giving_octets == 
  166.        (unsigned long) octstr_len(p->name)); 
  167. pos += p->field_giving_octets;
  168.     #define PDU(name, id, fields) 
  169.      case id: { struct name *p = &pdu->u.name; fields } break;
  170.     #include "smpp_pdu.def"
  171.     default:
  172.      error(0, "Unknown SMPP_PDU type, internal error while unpacking.");
  173.     }
  174.     return pdu;
  175. }
  176. void smpp_pdu_dump(SMPP_PDU *pdu)
  177. {
  178.     debug("sms.smpp", 0, "SMPP PDU %p dump:", (void *) pdu);
  179.     debug("sms.smpp", 0, "  type_name: %s", pdu->type_name);
  180.     switch (pdu->type) {
  181.     #define INTEGER(name, octets) 
  182.      debug("sms.smpp", 0, "  %s: %lu = 0x%08lx", #name, p->name, p->name);
  183.     #define NULTERMINATED(name, max_octets) 
  184. octstr_dump_short(p->name, 2, #name);
  185.     #define OCTETS(name, field_giving_octets) 
  186.         octstr_dump_short(p->name, 2, #name);
  187.     #define PDU(name, id, fields) 
  188.      case id: { struct name *p = &pdu->u.name; fields } break;
  189.     #include "smpp_pdu.def"
  190.     default:
  191.      error(0, "Unknown SMPP_PDU type, internal error.");
  192. break;
  193.     }
  194.     debug("sms.smpp", 0, "SMPP PDU dump ends.");
  195. }
  196. long smpp_pdu_read_len(Connection *conn)
  197. {
  198.     Octstr *os;
  199.     char buf[4];    /* The length is 4 octets. */
  200.     long len;
  201.     
  202.     os = conn_read_fixed(conn, sizeof(buf));
  203.     if (os == NULL)
  204.      return 0;
  205.     octstr_get_many_chars(buf, os, 0, sizeof(buf));
  206.     octstr_destroy(os);
  207.     len = decode_network_long(buf);
  208.     if (len < MIN_SMPP_PDU_LEN) {
  209. error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).",
  210.       len, (long) MIN_SMPP_PDU_LEN);
  211.      return -1;
  212.     }
  213.     if (len > MAX_SMPP_PDU_LEN) {
  214. error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).",
  215.       len, (long) MIN_SMPP_PDU_LEN);
  216.      return -1;
  217.     }
  218.     return len;
  219. }
  220. Octstr *smpp_pdu_read_data(Connection *conn, long len)
  221. {
  222.     Octstr *os;
  223.     
  224.     os = conn_read_fixed(conn, len - 4);    /* `len' includes itself. */
  225.     return os;
  226. }