Kannel: Open Source WAP and SMS gateway  svn-r5335
smpp_pdu.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * smpp_pdu.c - parse and generate SMPP PDUs
59  *
60  * Lars Wirzenius
61  * Alexander Malysh <amalysh@kannel.org>:
62  * Extended optional parameters implementation.
63  */
64 
65 
66 #include <string.h>
67 #include "smpp_pdu.h"
68 
69 #define MIN_SMPP_PDU_LEN (4*4)
70 /* old value was (1024). We need more because message_payload can be up to 64K octets*/
71 #define MAX_SMPP_PDU_LEN (7424)
72 /* we use ; in the middle because ; is split char in smsc-id and can't be in the smsc-id */
73 #define DEFAULT_SMSC_ID "def;ault"
74 
75 struct smpp_tlv {
77  long tag;
78  long length;
81 };
82 
83 /* Dict(smsc_id, Dict(tag, tlv)) */
84 static Dict *tlvs_by_tag;
85 /* Dict(smsc_id, Dict(tag_name, tlv)) */
88 static List *tlvs;
89 static int initialized;
90 
91 
92 static void smpp_tlv_destroy(struct smpp_tlv *tlv)
93 {
94  if (tlv == NULL)
95  return;
96  octstr_destroy(tlv->name);
98  gw_free(tlv);
99 }
100 
101 
103 {
104  Dict *constant;
105  List *keys;
106  Octstr *key;
107  struct smpp_tlv *tlv;
108 
110  if (constant == NULL)
111  return;
112 
113  keys = dict_keys(constant);
114  while ((key = gwlist_extract_first(keys)) != NULL) {
115  /* only add if not available already */
116  tlv = dict_get(constant, key);
117  if (tlv && tlv->constant) {
118  if (*tlvs) {
119  if (dict_get(*tlvs, key) == NULL)
120  dict_put(*tlvs, key, octstr_duplicate(tlv->constant));
121  } else {
123  dict_put(*tlvs, key, octstr_duplicate(tlv->constant));
124  }
125  }
126  octstr_destroy(key);
127  }
128  gwlist_destroy(keys, NULL);
129 }
130 
131 
133 {
134  struct smpp_tlv *res = NULL;
135  Dict *tmp_dict;
136 
137  if (tlvs_by_name == NULL || name == NULL)
138  return NULL;
139 
140  if (smsc_id != NULL) {
141  tmp_dict = dict_get(tlvs_by_name, smsc_id);
142  if (tmp_dict != NULL)
143  res = dict_get(tmp_dict, name);
144  }
145  if (res == NULL) {
146  /* try default smsc_id */
148  tmp_dict = dict_get(tlvs_by_name, smsc_id);
149  if (tmp_dict != NULL)
150  res = dict_get(tmp_dict, name);
151  }
152  return res;
153 }
154 
156 {
157  struct smpp_tlv *res = NULL;
158  Dict *tmp_dict;
159  Octstr *tmp;
160 
161  if (tlvs_by_tag == NULL)
162  return NULL;
163 
164  tmp = octstr_format("%ld", tag);
165 
166  if (smsc_id != NULL) {
167  tmp_dict = dict_get(tlvs_by_tag, smsc_id);
168  if (tmp_dict != NULL)
169  res = dict_get(tmp_dict, tmp);
170  }
171  if (res == NULL) {
172  /* try default smsc_id */
174  tmp_dict = dict_get(tlvs_by_tag, smsc_id);
175  if (tmp_dict != NULL)
176  res = dict_get(tmp_dict, tmp);
177  }
178 
179  octstr_destroy(tmp);
180 
181  return res;
182 }
183 
185 {
186  CfgGroup *grp;
187  List *l;
188 
189  if (initialized)
190  return 0;
191 
192  l = cfg_get_multi_group(cfg, octstr_imm("smpp-tlv"));
193  tlvs = gwlist_create();
194  tlvs_by_tag = dict_create(1024, (void(*)(void*))dict_destroy);
195  tlvs_by_name = dict_create(1024, (void(*)(void*))dict_destroy);
196  tlvs_by_const = dict_create(1024, (void(*)(void*))dict_destroy);
197  while (l != NULL && (grp = gwlist_extract_first(l)) != NULL) {
198  struct smpp_tlv *tlv;
199  Octstr *tmp, *smsc_id;
200  List *l2;
201 
202  tlv = gw_malloc(sizeof(*tlv));
203  if ((tlv->name = cfg_get(grp, octstr_imm("name"))) == NULL) {
204  error(0, "SMPP: Unable to get name for smpp-tlv.");
205  smpp_tlv_destroy(tlv);
206  goto failed;
207  }
208  tlv->constant = cfg_get(grp, octstr_imm("const"));
209  if (cfg_get_integer(&tlv->tag, grp, octstr_imm("tag")) == -1) {
210  error(0, "SMPP: Unable to get tag for smpp-tlv.");
211  smpp_tlv_destroy(tlv);
212  goto failed;
213  }
214  if (cfg_get_integer(&tlv->length, grp, octstr_imm("length")) == -1) {
215  error(0, "SMPP: Unable to get length for smpp-tlv.");
216  smpp_tlv_destroy(tlv);
217  goto failed;
218  }
219  if ((tmp = cfg_get(grp, octstr_imm("type"))) == NULL) {
220  error(0, "SMPP: Unable to get type for smpp-tlv.");
221  smpp_tlv_destroy(tlv);
222  goto failed;
223  }
224  if (octstr_str_case_compare(tmp, "octetstring") == 0)
225  tlv->type = SMPP_TLV_OCTETS;
226  else if (octstr_str_case_compare(tmp, "nulterminated") == 0)
228  else if (octstr_str_case_compare(tmp, "integer") == 0)
229  tlv->type = SMPP_TLV_INTEGER;
230  else {
231  error(0, "SMPP: Unknown type for smpp-tlv: `%s'", octstr_get_cstr(tmp));
232  octstr_destroy(tmp);
233  smpp_tlv_destroy(tlv);
234  goto failed;
235  }
236  octstr_destroy(tmp);
237 
238  /* put to all TLVs */
239  gwlist_produce(tlvs, tlv);
240 
241  smsc_id = cfg_get(grp, octstr_imm("smsc-id"));
242  if (smsc_id != NULL) {
243  l2 = octstr_split(smsc_id, octstr_imm(";"));
245  } else {
246  l2 = gwlist_create();
248  }
249  while(l2 != NULL && (smsc_id = gwlist_extract_first(l2)) != NULL) {
250  Dict *tmp_dict;
251 
252  debug("sms.smpp", 0, "adding smpp-tlv for smsc-id=%s", octstr_get_cstr(smsc_id));
253 
254  /* name */
255  tmp_dict = dict_get(tlvs_by_name, smsc_id);
256  if (tmp_dict == NULL) {
257  tmp_dict = dict_create(1024, NULL);
258  dict_put(tlvs_by_name, smsc_id, tmp_dict);
259  }
260  /* put into dict */
261  if (!dict_put_once(tmp_dict, tlv->name, tlv)) {
262  error(0, "SMPP: Double TLV name %s found.", octstr_get_cstr(tlv->name));
264  goto failed;
265  }
266 
267  /* tag */
268  tmp_dict = dict_get(tlvs_by_tag, smsc_id);
269  if (tmp_dict == NULL) {
270  tmp_dict = dict_create(1024, NULL);
271  dict_put(tlvs_by_tag, smsc_id, tmp_dict);
272  }
273  tmp = octstr_format("%ld", tlv->tag);
274  if (!dict_put_once(tmp_dict, tmp, tlv)) {
275  error(0, "SMPP: Double TLV tag %s found.", octstr_get_cstr(tmp));
277  octstr_destroy(tmp);
279  goto failed;
280  }
281 
282  /* const */
283  if (tlv->constant != NULL) {
284  tmp_dict = dict_get(tlvs_by_const, smsc_id);
285  if (tmp_dict == NULL) {
286  tmp_dict = dict_create(1024, NULL);
287  dict_put(tlvs_by_const, smsc_id, tmp_dict);
288  }
289  if (!dict_put_once(tmp_dict, tlv->name, tlv)) {
290  error(0, "SMPP: Double TLV name %s found.", octstr_get_cstr(tlv->name));
292  goto failed;
293  }
294  }
295 
296  octstr_destroy(tmp);
298  }
300  }
301  gwlist_destroy(l, NULL);
302 
303  initialized = 1;
304  return 0;
305 
306 failed:
307  gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy);
310  return -1;
311 }
312 
313 
315 {
316  if (initialized == 0)
317  return 0;
318 
319  initialized = 0;
320  gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy);
321  tlvs = NULL;
324  tlvs_by_tag = tlvs_by_name = NULL;
325 
326  return 0;
327 }
328 
329 
330 static long decode_integer(Octstr *os, long pos, int octets)
331 {
332  unsigned long u;
333  int i;
334 
335  if (octstr_len(os) < pos + octets)
336  return -1;
337 
338  u = 0;
339  for (i = 0; i < octets; ++i)
340  u = (u << 8) | octstr_get_char(os, pos + i);
341 
342  return u;
343 }
344 
345 
346 static void append_encoded_integer(Octstr *os, unsigned long u, long octets)
347 {
348  long i;
349 
350  for (i = 0; i < octets; ++i)
351  octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF);
352 }
353 
354 
355 static int copy_until_nul(const char *field_name, Octstr *os, long *pos, long max_octets, Octstr **data)
356 {
357  long nul;
358 
359  *data = NULL;
360 
361  nul = octstr_search_char(os, '\0', *pos);
362  if (nul == -1) {
363  warning(0, "SMPP: PDU NULL terminated string (%s) has no NULL.", field_name);
364  return -1;
365  }
366  if (*pos + max_octets < nul) {
367  error(0, "SMPP: PDU NULL terminated string (%s) longer than allowed.", field_name);
368  return -1;
369  }
370  *data = (nul - *pos > 0) ? octstr_copy(os, *pos, nul - *pos) : NULL;
371  *pos = nul + 1;
372  return 0;
373 }
374 
375 static int is_defined_field(long type, const char *field_name)
376 {
377  switch (type) {
378  #define OPTIONAL_BEGIN
379  #define TLV_INTEGER(name, octets) OCTETS(name, octets)
380  #define TLV_NULTERMINATED(name, max_len) OCTETS(name, max_len)
381  #define TLV_OCTETS(name, min_len, max_len) OCTETS(name, min_len)
382  #define OPTIONAL_END
383  #define INTEGER(name, octets) OCTETS(name, octets)
384  #define NULTERMINATED(name, max_octets) OCTETS(name, max_octets)
385  #define OCTETS(name, field_giving_octetst) \
386  if (strncmp(#name, field_name, sizeof(#name) - 1) == 0) \
387  return 1;
388  #define PDU(name, id, fields) \
389  case id: { \
390  fields \
391  } break;
392  #include "smpp_pdu.def"
393  default:
394  break;
395  }
396 
397  return 0;
398 }
399 
400 SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no)
401 {
402  SMPP_PDU *pdu;
403 
404  pdu = gw_malloc(sizeof(*pdu));
405  pdu->type = type;
406 
407  switch (type) {
408  #define OPTIONAL_BEGIN
409  #define TLV_INTEGER(name, octets) p->name = -1;
410  #define TLV_NULTERMINATED(name, max_len) p->name = NULL;
411  #define TLV_OCTETS(name, min_len, max_len) p->name = NULL;
412  #define OPTIONAL_END p->tlv = dict_create(1024, octstr_destroy_item);
413  #define INTEGER(name, octets) p->name = 0;
414  #define NULTERMINATED(name, max_octets) p->name = NULL;
415  #define OCTETS(name, field_giving_octetst) p->name = NULL;
416  #define PDU(name, id, fields) \
417  case id: { \
418  struct name *p = &pdu->u.name; \
419  pdu->type_name = #name; \
420  fields \
421  p->command_id = type; \
422  p->sequence_number = seq_no; \
423  } break;
424  #include "smpp_pdu.def"
425  default:
426  error(0, "Unknown SMPP_PDU type, internal error.");
427  gw_free(pdu);
428  return NULL;
429  }
430 
431  return pdu;
432 }
433 
435 {
436  if (pdu == NULL)
437  return;
438 
439  switch (pdu->type) {
440  #define OPTIONAL_BEGIN
441  #define TLV_INTEGER(name, octets) p->name = -1;
442  #define TLV_NULTERMINATED(name, max_octets) octstr_destroy(p->name);
443  #define TLV_OCTETS(name, min_len, max_len) octstr_destroy(p->name);
444  #define OPTIONAL_END dict_destroy(p->tlv);
445  #define INTEGER(name, octets) p->name = 0; /* Make sure "p" is used */
446  #define NULTERMINATED(name, max_octets) octstr_destroy(p->name);
447  #define OCTETS(name, field_giving_octets) octstr_destroy(p->name);
448  #define PDU(name, id, fields) \
449  case id: { struct name *p = &pdu->u.name; fields } break;
450  #include "smpp_pdu.def"
451  default:
452  error(0, "Unknown SMPP_PDU type, internal error while destroying.");
453  }
454  gw_free(pdu);
455 }
456 
457 
459 {
460  Octstr *os;
461  Octstr *temp;
462 
463  os = octstr_create("");
464 
465  gw_assert(pdu != NULL);
466 
467  /*
468  * Fix lengths of octet string fields.
469  */
470  switch (pdu->type) {
471  #define OPTIONAL_BEGIN
472  #define TLV_INTEGER(name, octets)
473  #define TLV_NULTERMINATED(name, max_len)
474  #define TLV_OCTETS(name, min_len, max_len)
475  #define OPTIONAL_END
476  #define INTEGER(name, octets) p = *(&p);
477  #define NULTERMINATED(name, max_octets) p = *(&p);
478  #define OCTETS(name, field_giving_octets) \
479  p->field_giving_octets = octstr_len(p->name);
480  #define PDU(name, id, fields) \
481  case id: { struct name *p = &pdu->u.name; fields } break;
482  #include "smpp_pdu.def"
483  default:
484  error(0, "Unknown SMPP_PDU type, internal error while packing.");
485  }
486 
487  switch (pdu->type) {
488  #define TL(name, octets) \
489  append_encoded_integer(os, SMPP_##name, 2); \
490  append_encoded_integer(os, octets, 2);
491  #define OPTIONAL_BEGIN
492  #define TLV_INTEGER(name, octets) \
493  if (p->name >= 0) { \
494  TL(name, octets); \
495  INTEGER(name, octets) \
496  }
497  #define TLV_NULTERMINATED(name, max_len) \
498  if (p->name != NULL) { \
499  TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name) + 1)); \
500  NULTERMINATED(name, max_len) \
501  }
502  #define TLV_OCTETS(name, min_len, max_len) \
503  if (p->name != NULL) { \
504  unsigned long len = octstr_len(p->name); \
505  if (len > max_len || len < min_len) { \
506  error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
507  #name, len, min_len, max_len);\
508  } else { \
509  TL(name, len); \
510  octstr_append(os, p->name); \
511  } \
512  }
513  #define OPTIONAL_END \
514  if (p->tlv != NULL) { \
515  Octstr *key; \
516  List *keys; \
517  struct smpp_tlv *tlv; \
518  keys = dict_keys(p->tlv); \
519  while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \
520  tlv = smpp_tlv_get_by_name(smsc_id, key); \
521  if (tlv == NULL) { \
522  if (!is_defined_field(pdu->type, octstr_get_cstr(key))) \
523  error(0, "SMPP: Unknown TLV `%s', don't send.", octstr_get_cstr(key)); \
524  octstr_destroy(key); \
525  continue; \
526  } \
527  switch(tlv->type) { \
528  case SMPP_TLV_INTEGER: { \
529  long val = atol(octstr_get_cstr(dict_get(p->tlv, key))); \
530  append_encoded_integer(os, tlv->tag, 2); \
531  append_encoded_integer(os, tlv->length, 2); \
532  append_encoded_integer(os, val, tlv->length); \
533  break; \
534  } \
535  case SMPP_TLV_OCTETS: \
536  case SMPP_TLV_NULTERMINATED: { \
537  Octstr *val = dict_get(p->tlv, key); \
538  unsigned long len = octstr_len(val); \
539  if (len > tlv->length) { \
540  error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \
541  octstr_get_cstr(key), len, tlv->length);\
542  octstr_destroy(key); \
543  continue; \
544  } \
545  append_encoded_integer(os, tlv->tag, 2); \
546  if (tlv->type == SMPP_TLV_NULTERMINATED) \
547  append_encoded_integer(os, len + 1, 2); \
548  else \
549  append_encoded_integer(os, len, 2); \
550  octstr_append(os, val); \
551  if (tlv->type == SMPP_TLV_NULTERMINATED) \
552  octstr_append_char(os, '\0'); \
553  break; \
554  } \
555  default: \
556  panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \
557  break; \
558  } \
559  octstr_destroy(key); \
560  } \
561  gwlist_destroy(keys, octstr_destroy_item); \
562  }
563  #define INTEGER(name, octets) \
564  append_encoded_integer(os, p->name, octets);
565  #define NULTERMINATED(name, max_octets) \
566  if (p->name != NULL) { \
567  if (octstr_len(p->name) >= max_octets) { \
568  warning(0, "SMPP: PDU element <%s> too long " \
569  "(length is %ld, should be %d)", \
570  #name, octstr_len(p->name), max_octets-1); \
571  temp = octstr_copy(p->name, 0, max_octets-1); \
572  } else \
573  temp = octstr_duplicate(p->name); \
574  octstr_append(os, temp); \
575  octstr_destroy(temp); \
576  } \
577  octstr_append_char(os, '\0');
578  #define OCTETS(name, field_giving_octets) \
579  if (p->name) octstr_append(os, p->name);
580  #define PDU(name, id, fields) \
581  case id: { struct name *p = &pdu->u.name; fields } break;
582  #include "smpp_pdu.def"
583  default:
584  error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while packing.", pdu->type);
585  break;
586  }
587 
588  temp = octstr_create("");
589  append_encoded_integer(temp, octstr_len(os) + 4, 4);
590  octstr_insert(os, temp, 0);
591  octstr_destroy(temp);
592 
593  return os;
594 }
595 
596 
598 {
599  SMPP_PDU *pdu;
600  unsigned long type;
601  long len, pos;
602 
603  len = octstr_len(data_without_len);
604 
605  if (len < 4) {
606  error(0, "SMPP: PDU was too short (%ld bytes).",
607  octstr_len(data_without_len));
608  return NULL;
609  }
610 
611  /* get the PDU type */
612  if ((type = decode_integer(data_without_len, 0, 4)) == -1)
613  return NULL;
614 
615  /* create a coresponding representation structure */
616  pdu = smpp_pdu_create(type, 0);
617  if (pdu == NULL)
618  return NULL;
619 
620  pos = 0;
621 
622  switch (type) {
623  #define OPTIONAL_BEGIN \
624  { /* Read optional parameters */ \
625  while (pos + 4 <= len) { \
626  struct smpp_tlv *tlv; \
627  unsigned long opt_tag, opt_len; \
628  opt_tag = decode_integer(data_without_len, pos, 2); pos += 2; \
629  debug("sms.smpp", 0, "Optional parameter tag (0x%04lx)", opt_tag); \
630  opt_len = decode_integer(data_without_len, pos, 2); pos += 2; \
631  debug("sms.smpp", 0, "Optional parameter length read as %ld", opt_len); \
632  /* check configured TLVs */ \
633  tlv = smpp_tlv_get_by_tag(smsc_id, opt_tag); \
634  if (tlv != NULL) debug("sms.smpp", 0, "Found configured optional parameter `%s'", octstr_get_cstr(tlv->name));
635  #define TLV_INTEGER(mname, octets) \
636  if (SMPP_##mname == opt_tag) { \
637  /* check length */ \
638  if (opt_len > octets) { \
639  error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \
640  pos += opt_len; \
641  continue; \
642  } \
643  INTEGER(mname, opt_len); \
644  if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_format("%ld", p->mname)); \
645  } else
646  #define TLV_NULTERMINATED(mname, max_len) \
647  if (SMPP_##mname == opt_tag) { \
648  /* check length */ \
649  if (opt_len > max_len || pos+opt_len > len) { \
650  error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \
651  pos += opt_len; \
652  continue; \
653  } \
654  if(p->mname != NULL) { \
655  warning(0, "SMPP: Optional field (%s) was sent more than once, overwriting", #mname); \
656  octstr_destroy(p->mname); \
657  p->mname = NULL; \
658  } \
659  copy_until_nul(#mname, data_without_len, &pos, opt_len, &p->mname); \
660  if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \
661  } else
662  #define TLV_OCTETS(mname, min_len, max_len) \
663  if (SMPP_##mname == opt_tag) { \
664  /* check length */ \
665  if (opt_len < min_len || opt_len > max_len || pos + opt_len > len) { \
666  error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
667  #mname, opt_len, min_len, max_len); \
668  pos += opt_len; \
669  continue; \
670  } \
671  if(p->mname != NULL) { \
672  warning(0, "SMPP: Optional field (%s) was sent more than once, overwriting", #mname); \
673  octstr_destroy(p->mname); \
674  p->mname = NULL; \
675  } \
676  p->mname = octstr_copy(data_without_len, pos, opt_len); \
677  pos += opt_len; \
678  if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \
679  } else
680  #define OPTIONAL_END \
681  { \
682  Octstr *val = NULL; \
683  if (tlv != NULL) { \
684  /* found configured tlv */ \
685  /* check length */ \
686  if (opt_len > tlv->length) { \
687  error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \
688  octstr_get_cstr(tlv->name), opt_len, tlv->length); \
689  pos += opt_len; \
690  continue; \
691  } \
692  switch (tlv->type) { \
693  case SMPP_TLV_INTEGER: { \
694  long val_i; \
695  if ((val_i = decode_integer(data_without_len, pos, opt_len)) == -1) \
696  goto err; \
697  val = octstr_format("%ld", val_i); \
698  dict_put(p->tlv, tlv->name, val); \
699  pos += opt_len; \
700  break; \
701  } \
702  case SMPP_TLV_OCTETS: { \
703  val = octstr_copy(data_without_len, pos, opt_len); \
704  dict_put(p->tlv, tlv->name, val); \
705  pos += opt_len; \
706  break; \
707  } \
708  case SMPP_TLV_NULTERMINATED: { \
709  if (copy_until_nul(octstr_get_cstr(tlv->name), data_without_len, &pos, opt_len, &val) == 0) \
710  dict_put(p->tlv, tlv->name, val); \
711  break; \
712  } \
713  default: \
714  panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \
715  break; \
716  } \
717  } else { \
718  val = octstr_copy(data_without_len, pos, opt_len); \
719  if (val) \
720  octstr_binary_to_hex(val, 0); \
721  else \
722  val = octstr_create(""); \
723  warning(0, "SMPP: Unknown TLV(0x%04lx,0x%04lx,%s) for PDU type (%s) received!", \
724  opt_tag, opt_len, octstr_get_cstr(val), pdu->type_name); \
725  octstr_destroy(val); \
726  pos += opt_len; \
727  } \
728  } \
729  } \
730  }
731  #define INTEGER(name, octets) \
732  if ((p->name = decode_integer(data_without_len, pos, octets)) == -1) \
733  goto err; \
734  pos += octets;
735  #define NULTERMINATED(name, max_octets) \
736  /* just warn about errors but not fail */ \
737  copy_until_nul(#name, data_without_len, &pos, max_octets, &p->name);
738  #define OCTETS(name, field_giving_octets) \
739  p->name = octstr_copy(data_without_len, pos, \
740  p->field_giving_octets); \
741  if (p->field_giving_octets != (unsigned long) octstr_len(p->name)) { \
742  error(0, "smpp_pdu: error while unpacking '" #name "', " \
743  "len is %ld but should have been %ld, dropping.", \
744  octstr_len(p->name), p->field_giving_octets); \
745  goto err; \
746  } else { \
747  pos += p->field_giving_octets; \
748  }
749  #define PDU(name, id, fields) \
750  case id: { struct name *p = &pdu->u.name; fields } break;
751  #include "smpp_pdu.def"
752  default:
753  error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while unpacking.", type);
754  break;
755  }
756 
757  return pdu;
758 
759 err:
760  smpp_pdu_destroy(pdu);
761  octstr_dump(data_without_len, 0);
762  return NULL;
763 }
764 
765 
767 {
768  debug("sms.smpp", 0, "SMPP PDU %p dump:", (void *) pdu);
769  debug("sms.smpp", 0, " type_name: %s", pdu->type_name);
770  switch (pdu->type) {
771  #define OPTIONAL_BEGIN
772  #define TLV_INTEGER(name, max_len) \
773  if (p->name != -1) { \
774  INTEGER(name, max_len) \
775  }
776  #define TLV_NULTERMINATED(name, max_len) \
777  if (p->name != NULL) { \
778  NULTERMINATED(name, max_len) \
779  }
780  #define TLV_OCTETS(name, min_len, max_len) \
781  if (p->name != NULL) { \
782  OCTETS(name, max_len) \
783  }
784  #define OPTIONAL_END \
785  if (p->tlv != NULL) { \
786  List *keys; \
787  Octstr *key; \
788  struct smpp_tlv *tlv; \
789  keys = dict_keys(p->tlv); \
790  while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \
791  tlv = smpp_tlv_get_by_name(smsc_id, key); \
792  if (tlv != NULL) { \
793  octstr_dump_short(dict_get(p->tlv, key), 2, octstr_get_cstr(key)); \
794  } \
795  octstr_destroy(key); \
796  } \
797  gwlist_destroy(keys, octstr_destroy_item); \
798  }
799  #define INTEGER(name, octets) \
800  debug("sms.smpp", 0, " %s: %lu = 0x%08lx", #name, p->name, p->name);
801  #define NULTERMINATED(name, max_octets) \
802  octstr_dump_short(p->name, 2, #name);
803  #define OCTETS(name, field_giving_octets) \
804  octstr_dump_short(p->name, 2, #name);
805  #define PDU(name, id, fields) \
806  case id: { struct name *p = &pdu->u.name; fields } break;
807  #include "smpp_pdu.def"
808  default:
809  error(0, "Unknown SMPP_PDU type, internal error.");
810  break;
811  }
812  debug("sms.smpp", 0, "SMPP PDU dump ends.");
813 }
814 
815 
817 {
818  Octstr *str = octstr_create("");
819 
820  octstr_format_append(str, "SMPP PDU %p dump: [type_name:%d:%s]", (void *) pdu, strlen(pdu->type_name), pdu->type_name);
821  switch (pdu->type) {
822  #define OPTIONAL_BEGIN
823  #define TLV_INTEGER(name, max_len) \
824  if (p->name != -1) { \
825  INTEGER(name, max_len) \
826  }
827  #define TLV_NULTERMINATED(name, max_len) \
828  if (p->name != NULL) { \
829  NULTERMINATED(name, max_len) \
830  }
831  #define TLV_OCTETS(name, min_len, max_len) \
832  if (p->name != NULL) { \
833  OCTETS(name, max_len) \
834  }
835  #define OPTIONAL_END \
836  if (p->tlv != NULL) { \
837  List *keys; \
838  Octstr *key; \
839  struct smpp_tlv *tlv; \
840  keys = dict_keys(p->tlv); \
841  while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \
842  tlv = smpp_tlv_get_by_name(smsc_id, key); \
843  if (tlv != NULL) { \
844  Octstr *val = dict_get(p->tlv, key); \
845  octstr_format_append(str, " [%E:%d:%E]", key, octstr_len(val), val); \
846  } \
847  octstr_destroy(key); \
848  } \
849  gwlist_destroy(keys, octstr_destroy_item); \
850  }
851  #define INTEGER(name, octets) \
852  octstr_format_append(str, " [%s:0:0x%08lx]", #name, p->name);
853  #define NULTERMINATED(name, max_octets) \
854  octstr_format_append(str, " [%s:%d:%E]", #name, octstr_len(p->name), (p->name != NULL ? p->name : octstr_imm("NULL")));
855  #define OCTETS(name, field_giving_octets) \
856  octstr_format_append(str, " [%s:%d:%E]", #name, octstr_len(p->name), (p->name != NULL ? p->name : octstr_imm("NULL")));
857  #define PDU(name, id, fields) \
858  case id: { struct name *p = &pdu->u.name; fields } break;
859  #include "smpp_pdu.def"
860  default:
861  error(0, "Unknown SMPP_PDU type, internal error.");
862  break;
863  }
864  debug("sms.smpp", 0, "%s", octstr_get_cstr(str));
865  octstr_destroy(str);
866 }
867 
868 
870 {
871  Octstr *os;
872  unsigned char buf[4]; /* The length is 4 octets. */
873  long len;
874 
875  os = conn_read_fixed(conn, sizeof(buf));
876  if (os == NULL)
877  return 0;
878  octstr_get_many_chars((char*) buf, os, 0, sizeof(buf));
879  octstr_destroy(os);
880  len = decode_network_long(buf);
881  if (len < MIN_SMPP_PDU_LEN) {
882  error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).",
883  len, (long) MIN_SMPP_PDU_LEN);
884  return -1;
885  }
886  if (len > MAX_SMPP_PDU_LEN) {
887  error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).",
888  len, (long) MAX_SMPP_PDU_LEN);
889  return -1;
890  }
891  return len;
892 }
893 
894 
896 {
897  Octstr *os;
898 
899  os = conn_read_fixed(conn, len - 4); /* `len' includes itself. */
900  return os;
901 }
902 
903 
904 /*
905  * Return error string for given error code
906  * NOTE: If you add new error strings here please use
907  * error strings from SMPP spec. and please keep
908  * error codes in switch statement sorted by error
909  * code ID.
910  */
912 {
913  switch (error) {
914  case SMPP_ESME_ROK:
915  return "OK";
917  return "Message Length is invalid";
919  return "Command Length is invalid";
920  case SMPP_ESME_RINVCMDID:
921  return "Invalid Command ID";
923  return "Incorrect BIND Status for given command";
924  case SMPP_ESME_RALYBND:
925  return "ESME Already in Bound State";
927  return "Invalid Priority Flag";
929  return "Invalid Registered Delivery Flag";
930  case SMPP_ESME_RSYSERR:
931  return "System Error";
933  return "Invalid Source Address";
935  return "Invalid Destination Address";
936  case SMPP_ESME_RBINDFAIL:
937  return "Bind Failed";
938  case SMPP_ESME_RINVPASWD:
939  return "Invalid Password";
940  case SMPP_ESME_RINVSYSID:
941  return "Invalid System ID";
943  return "Cancel SM Failed";
945  return "Replace SM Failed";
946  case SMPP_ESME_RMSGQFUL:
947  return "Message Queue Full";
949  return "Invalid Service Type";
951  return "Invalid number of destinations";
953  return "Invalid Distribution List Name";
955  return "Destination flag is invalid";
957  return "Submit w/replace not supported/allowed";
959  return "Invalid esm_class field data";
960  case SMPP_ESME_RCNTSUBDL:
961  return "Cannot Submit to Distribution List";
963  return "Submit failed";
965  return "Invalid Source address TON";
967  return "Invalid Source address NPI";
969  return "Invalid Destination address TON";
971  return "Invalid Destination address NPI";
973  return "Invalid system_type field";
975  return "Invalid replace_if_present flag";
977  return "Invalid number of messages";
979  return "Throttling error";
980  case SMPP_ESME_RINVSCHED:
981  return "Invalid Scheduled Delivery Time";
983  return "Invalid message validity period";
985  return "Predefined Message ID is Invalid or specific predefined message was not found";
986  case SMPP_ESME_RX_T_APPN:
987  return "ESME Receiver Temporary App Error Code";
988  case SMPP_ESME_RX_P_APPN:
989  return "ESME Receiver Permanent App Error Code";
990  case SMPP_ESME_RX_R_APPN:
991  return "ESME Receiver Reject Message Error Code";
993  return "query_sm request failed";
995  return "Error in optional part of the PDU Body";
997  return "TLV not allowed";
999  return "Invalid Parameter Length";
1000  case SMPP_ESME_RMISSINGTLV:
1001  return "Expected TLV missing";
1002  case SMPP_ESME_RINVTLVVAL:
1003  return "Invalid TLV value";
1005  return "Transaction Delivery Failure";
1006  case SMPP_ESME_RUNKNOWNERR:
1007  return "Unknown Error";
1009  return "ESME Not authorized to use specified service_type";
1010  case SMPP_ESME_RPROHIBITED:
1011  return "ESME Prohibited from using specified operation";
1013  return "Specified service_type is unavailable";
1015  return "Specified service_type is denied";
1016  case SMPP_ESME_RINVDCS:
1017  return "Invalid Data Coding Scheme";
1019  return "Source Address Sub unit is invalid";
1021  return "Destination Address Sub unit is invalid";
1023  return "Broadcast Frequency Interval is invalid";
1025  return "Broadcast Alias Name is invalid";
1027  return "Broadcast Area Format is invalid";
1029  return "Number of Broadcast Areas is invalid";
1031  return "Broadcast Content Type is invalid";
1033  return "Broadcast Message Class is invalid";
1034  case SMPP_ESME_RBCASTFAIL:
1035  return "broadcast_sm operation failed";
1037  return "broadcast_query_sm operation failed";
1039  return "broadcast_cancel_sm operation failed";
1041  return "Number of Repeated Broadcasts is invalid";
1043  return "Broadcast Service Group is invalid";
1045  return "Broadcast Channel Indicator is invalid";
1046 
1047  default:
1048  /* tell the user that we have a vendor-specific beast here */
1049  if (error >= 0x0400 && error <= 0x04FF)
1050  return "Vendor-specific error, please refer to your SMPP provider";
1051  else
1052  return "Unknown/Reserved";
1053  }
1054 }
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
const char * smpp_error_to_string(enum SMPP_ERROR_MESSAGES error)
Definition: smpp_pdu.c:911
void smpp_pdu_destroy(SMPP_PDU *pdu)
Definition: smpp_pdu.c:434
void error(int err, const char *fmt,...)
Definition: log.c:648
Octstr * constant
Definition: smpp_pdu.c:79
int octstr_str_case_compare(const Octstr *ostr, const char *str)
Definition: octstr.c:986
static int initialized
Definition: smpp_pdu.c:89
gw_assert(wtls_machine->packet_to_send !=NULL)
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
enum smpp_tlv::@13 type
void gwlist_produce(List *list, void *item)
Definition: list.c:411
void smpp_tlv_add_constant(Octstr *smsc_id, Dict **tlvs)
Definition: smpp_pdu.c:102
const char * type_name
Definition: smpp_pdu.h:92
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1517
int type
Definition: smsc_cimd2.c:215
#define cfg_get(grp, varname)
Definition: cfg.h:86
unsigned long type
Definition: smpp_pdu.h:91
static Dict * tlvs_by_name
Definition: smpp_pdu.c:86
long smpp_pdu_read_len(Connection *conn)
Definition: smpp_pdu.c:869
static void smpp_tlv_destroy(struct smpp_tlv *tlv)
Definition: smpp_pdu.c:92
static Cfg * cfg
Definition: opensmppbox.c:95
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1012
static Dict * tlvs_by_tag
Definition: smpp_pdu.c:84
static int copy_until_nul(const char *field_name, Octstr *os, long *pos, long max_octets, Octstr **data)
Definition: smpp_pdu.c:355
int smpp_pdu_shutdown(void)
Definition: smpp_pdu.c:314
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: cfg.c:164
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1303
void * gwlist_extract_first(List *list)
Definition: list.c:305
void * dict_get(Dict *dict, Octstr *key)
Definition: dict.c:286
#define MAX_SMPP_PDU_LEN
Definition: smpp_pdu.c:71
long tag
Definition: smpp_pdu.c:77
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
static Octstr * smsc_id
Definition: mtbatch.c:98
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:645
#define DEFAULT_SMSC_ID
Definition: smpp_pdu.c:73
Octstr * smpp_pdu_pack(Octstr *smsc_id, SMPP_PDU *pdu)
Definition: smpp_pdu.c:458
SMPP_PDU * smpp_pdu_unpack(Octstr *smsc_id, Octstr *data_without_len)
Definition: smpp_pdu.c:597
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:660
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
void smpp_pdu_dump(Octstr *smsc_id, SMPP_PDU *pdu)
Definition: smpp_pdu.c:766
Octstr * smpp_pdu_read_data(Connection *conn, long len)
Definition: smpp_pdu.c:895
static struct smpp_tlv * smpp_tlv_get_by_tag(Octstr *smsc_id, long tag)
Definition: smpp_pdu.c:155
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
void dict_destroy(Dict *dict)
Definition: dict.c:215
long decode_network_long(unsigned char *data)
Definition: utils.c:935
long length
Definition: smpp_pdu.c:78
Definition: octstr.c:118
static Dict * tlvs_by_const
Definition: smpp_pdu.c:87
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static struct smpp_tlv * smpp_tlv_get_by_name(Octstr *smsc_id, Octstr *name)
Definition: smpp_pdu.c:132
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
Definition: cfg.c:73
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2507
int smpp_pdu_init(Cfg *cfg)
Definition: smpp_pdu.c:184
static void append_encoded_integer(Octstr *os, unsigned long u, long octets)
Definition: smpp_pdu.c:346
List * dict_keys(Dict *dict)
Definition: dict.c:347
#define gwlist_create()
Definition: list.h:136
Octstr * conn_read_fixed(Connection *conn, long length)
Definition: conn.c:1110
int dict_put_once(Dict *dict, Octstr *key, void *value)
Definition: dict.c:271
Octstr * name
Definition: smpp_pdu.c:76
#define MIN_SMPP_PDU_LEN
Definition: smpp_pdu.c:69
void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
Definition: octstr.c:425
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
SMPP_ERROR_MESSAGES
Definition: smpp_pdu.h:159
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1640
Definition: list.c:102
SMPP_PDU * smpp_pdu_create(unsigned long type, unsigned long seq_no)
Definition: smpp_pdu.c:400
void smpp_pdu_dump_line(Octstr *smsc_id, SMPP_PDU *pdu)
Definition: smpp_pdu.c:816
static List * tlvs
Definition: smpp_pdu.c:88
static long decode_integer(Octstr *os, long pos, int octets)
Definition: smpp_pdu.c:330
static int is_defined_field(long type, const char *field_name)
Definition: smpp_pdu.c:375
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.