Kannel: Open Source WAP and SMS gateway  svn-r5335
smsc_soap_parlayx.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  * smsc_soap_parlayx.c - Kannel SMSC module for ParlayX 2.1
59  *
60  * Stipe Tolj <stolj at kannel.org>
61  */
62 
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <unistd.h>
66 #include <errno.h>
67 #include <time.h>
68 #include <limits.h>
69 
70 #include "gwlib/gwlib.h"
71 #include "smscconn.h"
72 #include "smscconn_p.h"
73 #include "bb_smscconn_cb.h"
74 #include "msg.h"
75 #include "sms.h"
76 #include "dlr.h"
77 #include "urltrans.h"
78 
79 #ifdef HAVE_GSOAP
80 
81 #include "soapH.h"
82 #include "SendSmsBinding.nsmap"
83 #include "wsseapi.h"
84 
85 
86 /*
87  * Define DEBUG macro to also activate the DLR sending
88  * thread, which allows us to self-inject DLRs.
89  */
90 #undef DEBUG
91 #define DEBUG 1
92 
93 /* Default character encoding */
94 #define DEFAULT_CHARSET "UTF-8"
95 
96 
97 typedef struct ConnData {
99  long receive_thread;
100  long senders; /* number of concurrent sending threads */
101  int shutdown;
102  int port; /* port for receiving SMS'es */
103  Octstr *allow_ip;
104  Octstr *send_url;
105  Octstr *dlr_url;
106  long open_sends;
107  Octstr *username; /* if needed */
108  Octstr *password; /* as said */
109  Octstr *alt_charset; /* alternative charset use */
110  gw_prioqueue_t *msgs_to_send;
111  List *sender_threads;
112  long dlr_thread;
113  List *dlr_queue;
114 
115  /* callback functions */
116  void (*send_sms) (SMSCConn *conn, Msg *msg);
117  void (*parse_reply) (SMSCConn *conn, Msg *msg, int status,
118  List *headers, Octstr *body);
119  void (*receive_sms) (SMSCConn *conn, HTTPClient *client,
120  List *headers, Octstr *body, List *cgivars);
121  void (*httpsmsc_sender) (void *arg);
122 } ConnData;
123 
124 
125 static void octstr_remove_crlfs(Octstr *ostr);
126 static void soap_send_sms(struct soap *soap, SMSCConn *conn, Msg *sms);
127 #ifdef DEBUG
128 static void soap_send_dlr(struct soap *soap, SMSCConn *conn, Msg *sms);
129 #endif
130 
131 
132 /********************************************************************
133  * DLR state mapping
134  *
135  * See VMP spec v0.9, section 2.4.2, page 21 for the VMP specific
136  * value details.
137  */
138 
139 static struct StateTable {
140  unsigned int dlr_mask;
141  enum pxSms__DeliveryStatus state;
142 } state_table[] = {
143  #define ENTRY(mask, state) { mask, state },
144  ENTRY(DLR_SUCCESS, pxSms__DeliveryStatus__DeliveredToTerminal)
145  ENTRY(DLR_FAIL, pxSms__DeliveryStatus__DeliveryImpossible)
146  ENTRY(DLR_BUFFERED, pxSms__DeliveryStatus__DeliveredToNetwork)
147  ENTRY(DLR_SMSC_FAIL, pxSms__DeliveryStatus__DeliveryNotificationNotSupported)
148  ENTRY(DLR_FAIL, pxSms__DeliveryStatus__DeliveryUncertain)
149  ENTRY(DLR_BUFFERED, pxSms__DeliveryStatus__MessageWaiting)
150  #undef ENTRY
151 };
152 
153 static int state_table_entries = sizeof(state_table) / sizeof(state_table[0]);
154 
155 
156 /********************************************************************
157  * Internal threads
158  */
159 
160 /*
161  * Each sender thread has it's own gSOAP IO context that is passed along
162  * to the sending function in the consume loop. This ensures we maintain
163  * the TCP connection, along with the HTTP/1.1 keep-alive state for the
164  * HTTP transport layer.
165  */
166 
167 /*
168  * The various ParlayX variants use separate thread logic that are
169  * addressed via the corresponding function pointer callback in
170  * conndata.
171  *
172  * The variants 'ericsson-sdp' and 'oneapi-v1' have the same ParlayX
173  * SOAP XML PDUs, but differ in the authentication scheme they use, where
174  * 'ericsson-sdp' uses WS-Security via wsse and 'oneapi-v1' uses plain
175  * HTTP basic authentication.
176  */
177 
178 static void httpsmsc_sender_ercisson_sdp(void *arg)
179 {
180  SMSCConn *conn = arg;
181  ConnData *conndata = conn->data;
182  Msg *msg;
183  struct soap *soap;
184 
185  /* Make sure we log into our own log-file if defined */
186  log_thread_to(conn->log_idx);
187 
188  /* establish soap context */
189  soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE);
190 
191  /* register wsse plugin */
192  soap_register_plugin(soap, soap_wsse);
193 
194 #ifdef WITH_OPENSSL
195  /* setup the SSL context */
196  if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION,
197  NULL, NULL, NULL, NULL, NULL)) {
198  char buf[1024];
199  Octstr *os;
200 
201  soap_sprint_fault(soap, buf, 1024);
202  os = octstr_create(buf);
203  octstr_remove_crlfs(os);
204 
205  error(0, "SOAP[%s]: Could not assign gSOAP SSL context:",
206  octstr_get_cstr(conn->id));
207  error(0, "SOAP[%s]: %s",
208  octstr_get_cstr(conn->id), octstr_get_cstr(os));
209 
210  octstr_destroy(os);
211  goto done;
212  }
213 #endif
214 
215  /* main consume loop for the sender */
216  while ((msg = gw_prioqueue_consume(conndata->msgs_to_send)) != NULL) {
217 
218  /* message lifetime of 10 seconds */
219  soap_wsse_add_Timestamp(soap, "Time", 10);
220 
221  /* add user name with digest password */
222  soap_wsse_add_UsernameTokenDigest(soap, "User",
224 
225  soap_send_sms(soap, conn, msg);
226  conndata->open_sends--;
227 
228  /* clean up security header */
229  soap_wsse_delete_Security(soap);
230  }
231 
232 done:
233  /* destroy soap context */
234  soap_destroy(soap);
235  soap_end(soap);
236  soap_free(soap);
237 }
238 
239 
240 static void httpsmsc_sender_gsma_oneapi(void *arg)
241 {
242  SMSCConn *conn = arg;
243  ConnData *conndata = conn->data;
244  Msg *msg;
245  struct soap *soap;
246 
247  /* Make sure we log into our own log-file if defined */
248  log_thread_to(conn->log_idx);
249 
250  /* establish soap context */
251  soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE);
252 
253  /* assign HTTP basic authentication tokens */
254  soap->userid = octstr_get_cstr(conndata->username);
255  soap->passwd = octstr_get_cstr(conndata->password);
256 
257 #ifdef WITH_OPENSSL
258  /* setup the SSL context */
259  if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION,
260  NULL, NULL, NULL, NULL, NULL)) {
261  char buf[1024];
262  Octstr *os;
263 
264  soap_sprint_fault(soap, buf, 1024);
265  os = octstr_create(buf);
266  octstr_remove_crlfs(os);
267 
268  error(0, "SOAP[%s]: Could not assign gSOAP SSL context:",
269  octstr_get_cstr(conn->id));
270  error(0, "SOAP[%s]: %s",
271  octstr_get_cstr(conn->id), octstr_get_cstr(os));
272 
273  octstr_destroy(os);
274  goto done;
275  }
276 #endif
277 
278  /* main consume loop for the sender */
279  while ((msg = gw_prioqueue_consume(conndata->msgs_to_send)) != NULL) {
280  soap_send_sms(soap, conn, msg);
281  conndata->open_sends--;
282  }
283 
284 done:
285  /* destroy soap context */
286  soap_destroy(soap);
287  soap_end(soap);
288  soap_free(soap);
289 }
290 
291 
292 /*
293  * Thread to listen to HTTP requests from SMSC entity
294  */
295 static void httpsmsc_receiver(void *arg)
296 {
297  SMSCConn *conn = arg;
298  ConnData *conndata = conn->data;
300  Octstr *ip, *url, *body;
301  List *headers, *cgivars;
302 
303  ip = url = body = NULL;
304  headers = cgivars = NULL;
305 
306  /* Make sure we log into our own log-file if defined */
307  log_thread_to(conn->log_idx);
308 
309  while (conndata->shutdown == 0) {
310 
311  /* XXX if conn->is_stopped, do not receive new messages.. */
312 
314  &headers, &body, &cgivars);
315  if (client == NULL)
316  break;
317 
318  debug("smsc.soap", 0, "SOAP[%s]: Got HTTP request `%s'",
320 
321  if (connect_denied(conndata->allow_ip, ip)) {
322  info(0, "SOAP[%s]: Connection `%s' tried from denied "
323  "host %s, ignored", octstr_get_cstr(conn->id),
326  } else
327  conndata->receive_sms(conn, client, headers, body, cgivars);
328 
329  debug("smsc.soap", 0, "SOAP[%s]: Destroying client information",
330  octstr_get_cstr(conn->id));
332  octstr_destroy(ip);
333  octstr_destroy(body);
334  http_destroy_headers(headers);
335  http_destroy_cgiargs(cgivars);
336  }
337  debug("smsc.soap", 0, "SOAP[%s]: httpsmsc_receiver dying",
338  octstr_get_cstr(conn->id));
339 
340  conndata->shutdown = 1;
342 
343  /* unblock http_receive_result() if there are no open sends */
344  if (conndata->open_sends == 0)
346 }
347 
348 
349 #ifdef DEBUG
350 static void dlr_sender(void *arg)
351 {
352  SMSCConn *conn = arg;
353  ConnData *conndata = conn->data;
354  Msg *msg;
355  struct soap *soap;
356 
357  /* Make sure we log into our own log-file if defined */
358  log_thread_to(conn->log_idx);
359 
360  /* establish soap context */
361  soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE);
362 
363 #ifdef WITH_OPENSSL
364  /* setup the SSL context */
365  if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION,
366  NULL, NULL, NULL, NULL, NULL)) {
367  char buf[1024];
368  Octstr *os;
369 
370  soap_sprint_fault(soap, buf, 1024);
371  os = octstr_create(buf);
372  octstr_remove_crlfs(os);
373 
374  error(0, "SOAP[%s]: Could not assign gSOAP SSL context:",
375  octstr_get_cstr(conn->id));
376  error(0, "SOAP[%s]: %s",
377  octstr_get_cstr(conn->id), octstr_get_cstr(os));
378 
379  octstr_destroy(os);
380  goto done;
381  }
382 #endif
383 
384  while ((msg = gwlist_consume(conndata->dlr_queue)) != NULL) {
385  /* first we delay a bit to simulate the SMSC latency */
386  gwthread_sleep(1);
387  soap_send_dlr(soap, conn, msg);
388  msg_destroy(msg);
389  }
390 
391 done:
392  /* destroy soap context */
393  soap_destroy(soap);
394  soap_end(soap);
395  soap_free(soap);
396 }
397 #endif
398 
399 
400 /***********************************************************************
401  * Helper functions
402  */
403 
404 #define octstr_cstr(os) \
405  (os ? octstr_get_cstr(os) : NULL)
406 
407 #define octstr(os) \
408  (os ? octstr_create(os) : NULL)
409 
410 
411 static int iscrlf(unsigned char c)
412 {
413  return c == '\n' || c == '\r';
414 }
415 
416 
417 static void octstr_remove_crlfs(Octstr *ostr)
418 {
419  int i, end;
420 
421  end = octstr_len(ostr);
422 
423  for (i = 0; i < end; i++) {
424  if (iscrlf(octstr_get_char(ostr, i)))
425  octstr_set_char(ostr, i, ' ');
426  }
427 }
428 
429 
430 static void gw_free_wrapper(void *data)
431 {
432  gw_free(data);
433 }
434 
435 
436 /***********************************************************************
437  * gSOAP callbacks for internal XML transport
438  */
439 
440 typedef struct gBuffer {
441  SMSCConn *conn;
442  char *buffer;
443  size_t size;
444  size_t rlen, slen;
445 } gBuffer;
446 
447 
448 static gBuffer *gbuffer_create(SMSCConn *conn, size_t size)
449 {
450  gBuffer *buf;
451 
452  buf = gw_malloc(sizeof(gBuffer));
453  buf->conn = conn;
454  buf->buffer = gw_malloc(size);
455  buf->size = size;
456  buf->rlen = buf->slen = 0;
457 
458  return buf;
459 }
460 
461 
462 static void gbuffer_destroy(gBuffer *buf)
463 {
464  if (buf == NULL)
465  return;
466 
467  gw_free(buf->buffer);
468  gw_free(buf);
469 }
470 
471 
472 /*
473  * Callback function of gSOAP internals that sends response bytes
474  * via this callback. We use it to intercept the response to the
475  * own handled buffer.
476  */
477 static int mysend(struct soap *soap, const char *s, size_t n)
478 {
479  gBuffer *buf = (gBuffer*) soap->user;
480 
481  if (buf->slen + n > buf->size)
482  return SOAP_EOF;
483 
484  strcpy(buf->buffer + buf->slen, s);
485  buf->slen += n;
486 
487  return SOAP_OK;
488 }
489 
490 
491 /*
492  * Callback function of gSOAP internals to read the HTTP POST
493  * body contents into the gSOAP processing. We inject the input
494  * via our own mapped buffer here.
495  */
496 static size_t myrecv(struct soap *soap, char *s, size_t n)
497 {
498  gBuffer *buf = (gBuffer*) soap->user;
499 
500  strncpy(s, buf->buffer + buf->rlen, n);
501  buf->rlen += n;
502 
503  return n;
504 }
505 
506 
507 /*
508  * Callback function of gSOAP's internal HTTP response headers.
509  * We don't use them here and simply ensure that they are skipped.
510  */
511 static int myheader(struct soap *soap, const char *key, const char *value)
512 {
513  return SOAP_OK;
514 }
515 
516 
517 /********************************************************************
518  * SOAP specific operations
519  */
520 
521 static void soap_send_sms(struct soap *soap, SMSCConn *conn, Msg *sms)
522 {
523  ConnData *conndata = conn->data;
524  struct pxSmsSend__sendSmsResponse resp;
525  int ret;
526  char tid[UUID_STR_LEN + 1];
527  Octstr *mid = NULL;
528  Octstr *receiver;
529  const char *receiv[1];
530 
531  /* request parameters */
532  struct pxSmsSend__sendSms req;
533  struct pxCommon__ChargingInformation charge;
534  struct pxCommon__SimpleReference dlr;
535 
536  /* unparse our msg ID */
537  if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && !uuid_is_null(sms->sms.id)) {
538  uuid_unparse(sms->sms.id, tid);
539  mid = octstr_create(tid);
540  }
541 
542  req.__sizeaddresses = 1;
543  receiver = octstr_format("tel:%s", octstr_get_cstr(sms->sms.receiver));
544  receiv[0] = octstr_get_cstr(receiver);
545  req.addresses = (char**)receiv;
546  req.senderName = octstr_cstr(sms->sms.sender);
547  req.message = octstr_get_cstr(sms->sms.msgdata);
548  req.charging = NULL;
549  req.receiptRequest = NULL;
550 
551  /*
552  * If billing identifier is set then we will parse for the
553  * ChargingInformation fields using the following notation:
554  *
555  * binfo = <D><description><D><currency><D><amount><D><code>
556  *
557  * where <D> is the delimiter character, defined as the FIRST
558  * character of the binfo field.
559  */
560  if (sms->sms.binfo) {
561  Octstr *delim = octstr_copy(sms->sms.binfo, 0, 1);
562  List *l = octstr_split(sms->sms.binfo, delim);
563  if (gwlist_len(l) != 5) {
564  error(0, "SOAP[%s]: Billing identifier <%s> has wrong format!",
565  octstr_get_cstr(conn->id), octstr_get_cstr(sms->sms.binfo));
566  } else {
567  charge.description = octstr_get_cstr(gwlist_get(l, 1));
568  charge.currency = octstr_get_cstr(gwlist_get(l, 2));
569  charge.amount = octstr_get_cstr(gwlist_get(l, 3));
570  charge.code = octstr_get_cstr(gwlist_get(l, 3));
571  req.charging = &charge;
572  }
574  octstr_destroy(delim);
576  }
577 
578  /*
579  * Define callback for DLR notification.
580  */
581  if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && conndata->dlr_url) {
582  dlr.endpoint = octstr_get_cstr(conndata->dlr_url);
583  dlr.correlator = octstr_get_cstr(mid);
584  dlr.interfaceName = NULL;
585  req.receiptRequest = &dlr;
586  }
587 
588  /* perform the SOAP call itself */
589  ret = soap_call___px1__sendSms(
590  soap, octstr_get_cstr(conndata->send_url), "",
591  &req, &resp);
592 
593  if (ret) {
594  /* HTTP request failed, or any other SOAP fault raised. */
595  char buf[1024];
596  Octstr *os;
597 
598  soap_sprint_fault(soap, buf, 1024);
599  os = octstr_create(buf);
600  octstr_remove_crlfs(os);
601 
602  error(0, "SOAP[%s]: Sending HTTP request failed:",
603  octstr_get_cstr(conn->id));
604  error(0, "SOAP[%s]: %s",
605  octstr_get_cstr(conn->id), octstr_get_cstr(os));
606 
607  /*
608  * TODO: we may consider this also as temporary error,
609  * or even better interpret the SOAP fault detail tags.
610  */
612  octstr_duplicate(os));
613 
614  octstr_destroy(os);
615  } else {
616  /*
617  * We got a corresponding SOAP/XML PDU response,
618  * so this is considered a successful transaction.
619  */
620 
621  /*
622  * The following code parts can be used to verify
623  * for transaction time and authentication.
624  *
625  * They are NOT used in the ParlayX variants we
626  * support, but we keep them here for reference
627  * to any possible new variant.
628  */
629 
630  /*
631  if (soap_wsse_verify_Timestamp(soap)) {
632  error(0, "SOAP[%s]: Server response expired.",
633  octstr_get_cstr(conn->id));
634  goto done;
635  }
636 
637  username = soap_wsse_get_Username(soap);
638  if (!username || octstr_str_compare(conndata->username, username) ||
639  soap_wsse_verify_Password(soap, octstr_get_cstr(conndata->password))) {
640  error(0, "SOAP[%s]: Server authentication failed.",
641  octstr_get_cstr(conn->id));
642  goto done;
643  }
644  */
645 
646  /*
647  * The sendSmsResponse result is defined to be a message identifier
648  * for the transaction we did, so keep that as foreign ID.
649  */
650  if (resp.result) {
651  octstr_destroy(sms->sms.foreign_id);
652  sms->sms.foreign_id = octstr_create(resp.result);
653  }
654 
655  /* add to our own DLR storage */
656  if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && mid) {
657  dlr_add(conn->id, mid, sms, 0);
658 
659 #ifdef DEBUG
660  /*
661  * Pass duplicate into DLR re-inject queue with the
662  * msg ID that the SMSC gave us.
663  * BEWARE: This works only for internal tests where
664  * the msg ID returned is a UUID string.
665  */
666  {
667  Msg *msg = msg_duplicate(sms);
668  uuid_clear(msg->sms.id);
669  uuid_parse(octstr_get_cstr(mid), msg->sms.id);
670  gwlist_produce(conndata->dlr_queue, msg);
671  }
672 #endif
673  }
674  bb_smscconn_sent(conn, sms, NULL);
675  }
676 
677  octstr_destroy(mid);
679 }
680 
681 
682 static void soap_parse_reply(SMSCConn *conn, Msg *msg, int status,
683  List *headers, Octstr *body)
684 {
685  if (status == HTTP_OK || status == HTTP_ACCEPTED) {
686 
687  /* add to our own DLR storage */
688  if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) {
689  char id[UUID_STR_LEN + 1];
690  Octstr *mid;
691 
692  uuid_unparse(msg->sms.id, id);
693  mid = octstr_create(id);
694 
695  dlr_add(conn->id, mid, msg, 0);
696 
697  octstr_destroy(mid);
698  }
699 
700  bb_smscconn_sent(conn, msg, NULL);
701  } else {
703  octstr_duplicate(body));
704  }
705 }
706 
707 
708 static void soap_receive_sms(SMSCConn *conn, HTTPClient *client,
709  List *headers, Octstr *body, List *cgivars)
710 {
711  List *reply_headers;
712  struct soap *soap;
713  gBuffer *buf;
714  Octstr *response;
715 
716  /*
717  * We expect a SOAP/XML element as POST body. If there is no
718  * body, then return an error instantly.
719  */
720  if (octstr_len(body) == 0) {
721  http_send_reply(client, HTTP_BAD_METHOD, NULL, NULL);
722  return;
723  }
724 
725  /* dump the SOAP/XML we got */
726  octstr_dump(body, 0);
727 
728  /* move the XML into the buffer */
729  buf = gbuffer_create(conn, 32000);
730  octstr_get_many_chars(buf->buffer, body, 0, octstr_len(body));
731 
732  /* create gSOAP context and assign the buffer */
733  soap = soap_new();
734  soap->fsend = mysend;
735  soap->frecv = myrecv;
736  soap->fposthdr = myheader;
737  soap->user = buf;
738 
739  /* perform the server operation */
740  soap_serve(soap);
741 
742  /* move response XML from buffer to octstr */
743  response = octstr_create("");
744  octstr_append_data(response, buf->buffer, buf->slen);
745 
746  /* destroy buffer */
747  gbuffer_destroy(buf);
748 
749  /* destroy context */
750  soap_destroy(soap);
751  soap_end(soap);
752  soap_free(soap);
753 
754  /* send the HTTP response */
755  reply_headers = gwlist_create();
756  http_header_add(reply_headers, "SOAPAction" , "\"\"");
757  http_header_add(reply_headers, "Content-Type", "text/xml;charset=\"utf-8\"");
758  debug("smsc.soap", 0, "SOAP[%s]: Sending HTTP response",
759  octstr_get_cstr(conn->id));
760  octstr_dump(response, 0);
761  http_send_reply(client, HTTP_OK, reply_headers, response);
762 
764  http_destroy_headers(reply_headers);
765 }
766 
767 
768 static void soap_send_sms_cb(SMSCConn *conn, Msg *sms)
769 {
770  ConnData *conndata = conn->data;
771 
772  gw_prioqueue_produce(conndata->msgs_to_send, sms);
773 }
774 
775 
776 #ifdef DEBUG
777 static void soap_send_dlr(struct soap *soap, SMSCConn *conn, Msg *sms)
778 {
779  ConnData *conndata = conn->data;
780  struct pxSmsNotification__notifySmsDeliveryReceiptResponse resp;
781  int ret;
782  char tid[UUID_STR_LEN + 1];
783  Octstr *mid = NULL;
784  Octstr *receiver = octstr_format("tel:%s", sms->sms.receiver);
785 
786  /* request parameters */
787  struct pxSmsNotification__notifySmsDeliveryReceipt req;
788  struct pxSms__DeliveryInformation deliveryStatus;
789 
790  /* get the message id */
791  if (!uuid_is_null(sms->sms.id)) {
792  uuid_unparse(sms->sms.id, tid);
793  mid = octstr_create(tid);
794  }
795 
796  /* apply values from Kannel msg struct */
797  req.correlator = octstr_get_cstr(mid);
798  deliveryStatus.address = octstr_get_cstr(receiver);
799  deliveryStatus.deliveryStatus = pxSms__DeliveryStatus__DeliveredToTerminal;
800  req.deliveryStatus = &deliveryStatus;
801 
802  /* no SOAP header set */
803 
804  /* perform the SOAP call itself */
805  ret = soap_call___px2__notifySmsDeliveryReceipt(
806  soap, octstr_get_cstr(conndata->send_url), "", &req, &resp);
807 
808  if (ret) {
809  /* HTTP request failed */
810  char buf[1024];
811  Octstr *os;
812 
813  soap_sprint_fault(soap, buf, 1024);
814  os = octstr_create(buf);
815  octstr_remove_crlfs(os);
816 
817  error(0, "SOAP[%s]: Sending DLR HTTP request failed:",
818  octstr_get_cstr(conn->id));
819  error(0, "SOAP[%s]: %s",
820  octstr_get_cstr(conn->id), octstr_get_cstr(os));
821 
822  octstr_destroy(os);
823  } else {
824  /* we got a corresponding SOAP/XML response */
825 
826  debug("smsc.soap",0,"SOAP[%s] Received DLR HTTP response.",
827  octstr_get_cstr(conn->id));
828  }
829 
831  octstr_destroy(mid);
832 }
833 #endif
834 
835 
836 /********************************************************************
837  * Internal smscconn operations
838  */
839 
840 static void conndata_destroy(ConnData *conndata)
841 {
842  if (conndata == NULL)
843  return;
844 
845  if (conndata->http_ref)
847 
848  gwlist_destroy(conndata->sender_threads, (void(*)(void *)) gw_free_wrapper);
850 #ifdef DEBUG
852 #endif
853 
860 
861  gw_free(conndata);
862 }
863 
864 
865 static int httpsmsc_send(SMSCConn *conn, Msg *msg)
866 {
867  ConnData *conndata = conn->data;
868  Msg *sms = msg_duplicate(msg);
869  double delay = 0;
870 
871  if (conn->throughput > 0) {
872  delay = 1.0 / conn->throughput;
873  }
874 
875  /* convert character encoding if required */
876  if (conndata->alt_charset &&
877  charset_convert(sms->sms.msgdata, DEFAULT_CHARSET,
879  error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.",
881 
882  conndata->open_sends++;
883  conndata->send_sms(conn, sms);
884 
885  /* obey throughput speed limit, if any */
886  if (conn->throughput > 0)
888 
889  return 0;
890 }
891 
892 
893 static long httpsmsc_queued(SMSCConn *conn)
894 {
895  ConnData *conndata = conn->data;
896 
897  return (conndata ? (conn->status != SMSCCONN_DEAD ?
898  conndata->open_sends : 0) : 0);
899 }
900 
901 
902 static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
903 {
904  ConnData *conndata = conn->data;
905  long *id;
906 
907  debug("httpsmsc_shutdown", 0, "SOAP[%s]: Shutting down",
908  octstr_get_cstr(conn->id));
910  conndata->shutdown = 1;
911 
912 #ifdef DEBUG
913  /* stop DLR re-injection thread */
914  gwlist_remove_producer(conndata->dlr_queue);
915  gwthread_join(conndata->dlr_thread);
916 #endif
917 
918  /* stop receiver thread */
920 
921  /* stop all sender threads */
922  gw_prioqueue_remove_producer(conndata->msgs_to_send);
923  while ((id = gwlist_consume(conndata->sender_threads)) != NULL) {
924  gwthread_join(*id);
925  gw_free(id);
926  }
927 
928  conn->data = NULL;
930 
931  conn->status = SMSCCONN_DEAD;
933 
934  return 0;
935 }
936 
937 
938 int smsc_soap_parlayx_create(SMSCConn *conn, CfgGroup *cfg)
939 {
940  ConnData *conndata = NULL;
941  Octstr *type;
942  long portno; /* has to be long because of cfg_get_integer */
943  int ssl = 0; /* indicate if SSL-enabled server should be used */
944  int i;
945 
946  if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
947  error(0, "SOAP[%s]: 'port' invalid in 'smsc = parlayx' group.",
948  octstr_get_cstr(conn->id));
949  return -1;
950  }
951  cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl"));
952  if ((type = cfg_get(cfg, octstr_imm("system-type"))) == NULL) {
953  error(0, "SOAP[%s]: 'system-type' missing in 'smsc = parlayx' group.",
954  octstr_get_cstr(conn->id));
956  return -1;
957  }
958  conndata = gw_malloc(sizeof(ConnData));
959  conndata->http_ref = NULL;
960  conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
961  conndata->send_url = cfg_get(cfg, octstr_imm("send-url"));
962  conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url"));
963  conndata->username = cfg_get(cfg, octstr_imm("smsc-username"));
964  conndata->password = cfg_get(cfg, octstr_imm("smsc-password"));
965  conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset"));
966  if (cfg_get_integer(&(conndata->senders), cfg, octstr_imm("window")) == -1) {
967  conndata->senders = 1;
968  } else {
969  info(0, "SOAP[%s]: Using %ld sender threads.",
970  octstr_get_cstr(conn->id), conndata->senders);
971  }
972 
973  if (conndata->send_url == NULL)
974  panic(0, "SOAP[%s]: Sending not allowed. No 'send-url' specified.",
975  octstr_get_cstr(conn->id));
976 
977  if (conndata->dlr_url == NULL)
978  warning(0, "SOAP[%s]: DLR requesting not allowed. No 'dlr-url' specified.",
979  octstr_get_cstr(conn->id));
980 
981  if (conndata->username == NULL || conndata->password == NULL) {
982  error(0, "SOAP[%s]: 'username' and 'password' required for smsc",
983  octstr_get_cstr(conn->id));
984  goto error;
985  }
986 
987  if (octstr_case_compare(type, octstr_imm("ericsson-sdp")) == 0) {
988  conndata->httpsmsc_sender = httpsmsc_sender_ercisson_sdp;
989  }
990  else if (octstr_case_compare(type, octstr_imm("oneapi-v1")) == 0) {
991  conndata->httpsmsc_sender = httpsmsc_sender_gsma_oneapi;
992  }
993  /*
994  * Add new ParlayX variants here
995  */
996  else {
997  error(0, "SOAP[%s]: system-type '%s' unknown in 'smsc = parlayx' group.",
999  goto error;
1000  }
1001 
1002 #ifdef WITH_OPENSSL
1003  /* setup gSOAP SSL internals */
1004  soap_ssl_init();
1005 #endif
1006 
1007  /* setup MT queue */
1009 
1010  /* assign our SOAP operations */
1011  conndata->receive_sms = soap_receive_sms;
1012  conndata->send_sms = soap_send_sms_cb;
1013  conndata->parse_reply = soap_parse_reply;
1014 
1015  conndata->open_sends = 0;
1017 
1018  conn->data = conndata;
1019  conn->name = octstr_create("SOAP");
1020  conn->status = SMSCCONN_ACTIVE;
1021  conn->connect_time = time(NULL);
1022 
1023  conn->shutdown = httpsmsc_shutdown;
1024  conn->queued = httpsmsc_queued;
1025  conn->send_msg = httpsmsc_send;
1026 
1027  if (http_open_port_if(portno, ssl, conn->our_host) == -1)
1028  goto error;
1029 
1030  conndata->port = portno;
1031  conndata->shutdown = 0;
1032 
1033  /* receiver thread */
1035  goto error;
1036 
1037 #ifdef DEBUG
1038  /* DLR re-injection thread */
1039  conndata->dlr_queue = gwlist_create();
1040  gwlist_add_producer(conndata->dlr_queue);
1041  if ((conndata->dlr_thread = gwthread_create(dlr_sender, conn)) == -1)
1042  goto error;
1043 #else
1044  conndata->dlr_queue = NULL;
1045  conndata->dlr_thread = -1;
1046 #endif
1047 
1048  /* sender thread(s), keep record of the thread IDs in our
1049  * sender_threads list to ensure we join the right threads
1050  * at the shutdown sequence. */
1051  conndata->sender_threads = gwlist_create();
1052  gw_prioqueue_add_producer(conndata->msgs_to_send);
1053  for (i = 0; i < conndata->senders; i++) {
1054  long *id = gw_malloc(sizeof(long));
1055  if ((*id = gwthread_create(conndata->httpsmsc_sender, conn)) == -1) {
1056  gw_free(id);
1057  goto error;
1058  }
1059  gwlist_produce(conndata->sender_threads, id);
1060  }
1061 
1062  info(0, "SOAP[%s]: Initiated and ready", octstr_get_cstr(conn->id));
1063 
1065  return 0;
1066 
1067 error:
1068  error(0, "SOAP[%s]: Failed to create smsc connection",
1069  octstr_get_cstr(conn->id));
1070 
1071  conn->data = NULL;
1074  conn->status = SMSCCONN_DEAD;
1075 
1077  return -1;
1078 }
1079 
1080 
1081 /********************************************************************
1082  * SOAP specific methods
1083  */
1084 
1085 /*
1086  * This operation is handled by the server side. We just implement it
1087  * here with hard-coded values to be able to test our own gSOAP sending
1088  * routines to our own HTTP end-point.
1089  */
1090 int __px1__sendSms (
1091  /* soap structure hook */
1092  struct soap *soap,
1093  /* request struct */
1094  struct pxSmsSend__sendSms *req,
1095  /* response struct */
1096  struct pxSmsSend__sendSmsResponse *resp)
1097 {
1098  /* positive response */
1099  resp->result = "100";
1100 
1101  /* negative response */
1102  /*
1103  resp->result = "300";
1104  */
1105 
1106  return SOAP_OK;
1107 }
1108 
1109 
1110 int __px2__notifySmsDeliveryReceipt (
1111  /* soap structure hook */
1112  struct soap *soap,
1113  /* request struct */
1114  struct pxSmsNotification__notifySmsDeliveryReceipt *req,
1115  /* response struct */
1116  struct pxSmsNotification__notifySmsDeliveryReceiptResponse *resp)
1117 {
1118  gBuffer *buf = soap->user;
1119  ConnData *conndata = buf->conn->data;
1120  Msg *dlrmsg;
1121  Octstr *id, *destination;
1122  int sm_status, state, i;
1123 
1124  destination = NULL;
1125  sm_status = -1;
1126 
1127  /* get corresponding values from the SOAP/XML request */
1128  id = octstr(req->correlator);
1129  if (req->deliveryStatus) {
1130  destination = octstr(req->deliveryStatus->address);
1131 
1132  /* strip 'tel:' from address */
1133  if (destination)
1134  octstr_delete_matching(destination, octstr_imm("tel:"));
1135 
1136  sm_status = req->deliveryStatus->deliveryStatus;
1137  }
1138 
1139  /* map the DLR state */
1140  state = DLR_NOTHING;
1141  for (i = 0; sm_status != -1 && i < state_table_entries; ++i) {
1142  if (sm_status == state_table[i].state) {
1143  state = state_table[i].dlr_mask;
1144  break;
1145  }
1146  }
1147 
1148  /* resolve the DLR from the DLR temp storage */
1149  dlrmsg = dlr_find(buf->conn->id,
1150  id, /* smsc message id */
1151  destination, /* destination */
1152  state, 0);
1153 
1154  if (dlrmsg != NULL) {
1155 
1156  dlrmsg->sms.sms_type = report_mo;
1157  dlrmsg->sms.account = octstr_duplicate(conndata->username);
1158 
1159  /*
1160  * There is no response values returned.
1161  */
1162 
1163  /* passing DLR to upper layer */
1164  bb_smscconn_receive(buf->conn, dlrmsg);
1165 
1166  } else {
1167  error(0,"SOAP[%s]: got DLR but could not find message or was not interested "
1168  "in it id<%s> dst<%s>, type<%d>",
1169  octstr_get_cstr(buf->conn->id), octstr_get_cstr(id),
1170  octstr_get_cstr(destination), state);
1171  }
1172 
1173  octstr_destroy(id);
1174  octstr_destroy(destination);
1175 
1176  return SOAP_OK;
1177 }
1178 
1179 
1180 int __px2__notifySmsReception (
1181  /* soap structure hook */
1182  struct soap *soap,
1183  /* request struct */
1184  struct pxSmsNotification__notifySmsReception *req,
1185  /* response struct */
1186  struct pxSmsNotification__notifySmsReceptionResponse *resp)
1187 {
1188  gBuffer *buf = soap->user;
1189  ConnData *conndata = buf->conn->data;
1190  Msg *msg;
1191  int ret;
1192 
1193  msg = msg_create(sms);
1194  msg->sms.sms_type = mo;
1195  msg->sms.sender = octstr(req->message->senderAddress);
1196  msg->sms.receiver = octstr(req->message->smsServiceActivationNumber);
1197  msg->sms.msgdata = octstr(req->message->message);
1198  msg->sms.foreign_id = octstr(req->correlator);
1199  msg->sms.smsc_id = octstr_duplicate(buf->conn->id);
1200  msg->sms.time = time(NULL);
1201  msg->sms.account = octstr_duplicate(conndata->username);
1202 
1203  ret = bb_smscconn_receive(buf->conn, msg);
1204  if (ret == SMSCCONN_SUCCESS) {
1205  /* no response is set */
1206  } else {
1207  /* no response is set */
1208  }
1209 
1210  return SOAP_OK;
1211 }
1212 
1213 
1214 /********************************************************************
1215  * SOAP functions stubs that are not used.
1216  */
1217 
1218 int __px1__sendSmsLogo(
1219  struct soap *soap,
1220  // request parameters:
1221  struct pxSmsSend__sendSmsLogo* pxSmsSend__sendSmsLogo,
1222  // response parameters:
1223  struct pxSmsSend__sendSmsLogoResponse* pxSmsSend__sendSmsLogoResponse
1224 )
1225 {
1226  return SOAP_OK;
1227 }
1228 
1229 int __px1__sendSmsRingtone(
1230  struct soap *soap,
1231  // request parameters:
1232  struct pxSmsSend__sendSmsRingtone* pxSmsSend__sendSmsRingtone,
1233  // response parameters:
1234  struct pxSmsSend__sendSmsRingtoneResponse* pxSmsSend__sendSmsRingtoneResponse
1235 )
1236 {
1237  return SOAP_OK;
1238 }
1239 
1240 int __px1__getSmsDeliveryStatus(
1241  struct soap *soap,
1242  // request parameters:
1243  struct pxSmsSend__getSmsDeliveryStatus* pxSmsSend__getSmsDeliveryStatus,
1244  // response parameters:
1245  struct pxSmsSend__getSmsDeliveryStatusResponse* pxSmsSend__getSmsDeliveryStatusResponse
1246 )
1247 {
1248  return SOAP_OK;
1249 }
1250 
1251 int __px3__getReceivedSms(
1252  struct soap *soap,
1253  // request parameters:
1254  struct pxSmsReceive__getReceivedSms* pxSmsReceive__getReceivedSms,
1255  // response parameters:
1256  struct pxSmsReceive__getReceivedSmsResponse* pxSmsReceive__getReceivedSmsResponse
1257 )
1258 {
1259  return SOAP_OK;
1260 }
1261 
1262 #endif /* HAVE_GSOAP */
static Octstr * dlr_mask
Definition: test_ppg.c:106
Octstr * name
Definition: smscconn_p.h:173
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
Octstr * dlr_url
Definition: smsc_http_p.h:94
#define DEFAULT_CHARSET
Definition: smsc_http.c:133
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
int size
Definition: wsasm.c:84
static void httpsmsc_receiver(void *arg)
Definition: smsc_http.c:161
void octstr_append_data(Octstr *ostr, const char *data, long len)
Definition: octstr.c:1497
static void conndata_destroy(ConnData *conndata)
Definition: smsc_http.c:136
Octstr * alt_charset
Definition: smsc_http_p.h:103
static int iscrlf(unsigned char c)
Definition: octstr.c:1373
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
long receive_thread
Definition: smsc_http_p.h:87
int ssl
Definition: msg.h:106
void http_caller_signal_shutdown(HTTPCaller *caller)
Definition: http.c:913
void http_close_client(HTTPClient *client)
Definition: http.c:2758
void bb_smscconn_killed(void)
Definition: bb_smscconn.c:199
Definition: msg.h:109
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * id
Definition: smscconn_p.h:174
void gwthread_join(long thread)
long gwlist_len(List *list)
Definition: list.c:166
void * data
Definition: smscconn_p.h:250
static void client(int port)
Definition: test_udp.c:77
HTTPCaller * http_ref
Definition: smsc_http_p.h:86
#define DLR_NOTHING
Definition: dlr.h:71
void * gwlist_get(List *list, long pos)
Definition: list.c:292
int log_idx
Definition: smscconn_p.h:197
int type
Definition: smsc_cimd2.c:215
Octstr * allow_ip
Definition: smsc_http_p.h:92
void * gw_prioqueue_consume(gw_prioqueue_t *queue)
Definition: gw-prioqueue.c:303
#define cfg_get(grp, varname)
Definition: cfg.h:86
serverKeyXchgPDU rlen
void uuid_unparse(const uuid_t uu, char *out)
Definition: gw_uuid.c:562
#define gw_prioqueue_produce(queue, item)
Definition: gw-prioqueue.h:98
#define msg_create(type)
Definition: msg.h:136
Octstr * our_host
Definition: smscconn_p.h:192
static Cfg * cfg
Definition: opensmppbox.c:95
Msg * dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst)
Definition: dlr.c:387
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst)
Definition: dlr.c:330
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
int connect_denied(Octstr *allow_ip, Octstr *ip)
Definition: utils.c:833
void log_thread_to(int idx)
Definition: log.c:759
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
void http_destroy_headers(List *headers)
Definition: http.c:2879
#define DLR_SUCCESS
Definition: dlr.h:72
volatile int shutdown
Definition: smsc_http_p.h:90
int uuid_parse(const char *in, uuid_t uu)
Definition: gw_uuid.c:476
void http_destroy_cgiargs(List *args)
Definition: http.c:2818
long port
Definition: smsc_http_p.h:91
void msg_destroy_item(void *msg)
Definition: msg.c:147
void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body)
Definition: http.c:2695
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Counter * open_sends
Definition: smsc_http_p.h:95
Definition: http.h:142
Definition: msg.h:79
int sms_priority_compare(const void *a, const void *b)
Definition: sms.c:395
struct conndata ConnData
HTTPClient * http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars)
Definition: http.c:2571
void http_close_port(int port)
Definition: http.c:2515
void gwlist_remove_producer(List *list)
Definition: list.c:401
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
Definition: bb_smscconn.c:477
int uuid_is_null(const uuid_t uu)
Definition: gw_uuid.c:413
time_t connect_time
Definition: smscconn_p.h:155
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
double throughput
Definition: smscconn_p.h:203
void msg_destroy(Msg *msg)
Definition: msg.c:132
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:903
static double delay
Definition: mtbatch.c:99
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 gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
#define DLR_SMSC_FAIL
Definition: dlr.h:76
gw_prioqueue_t * gw_prioqueue_create(int(*cmp)(const void *, const void *))
Definition: gw-prioqueue.c:174
void gwthread_sleep(double seconds)
static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
Definition: smsc_http.c:461
#define UUID_STR_LEN
Definition: gw_uuid.h:19
int http_open_port_if(int port, int ssl, Octstr *interface)
Definition: http.c:2483
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:759
void gw_prioqueue_destroy(gw_prioqueue_t *queue, void(*item_destroy)(void *))
Definition: gw-prioqueue.c:201
Definition: octstr.c:118
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
Definition: bb_smscconn.c:281
void * gwlist_consume(List *list)
Definition: list.c:427
static long httpsmsc_queued(SMSCConn *conn)
Definition: smsc_http.c:450
int(* shutdown)(SMSCConn *conn, int finish_sending)
Definition: smscconn_p.h:230
Octstr * password
Definition: smsc_http_p.h:98
void gw_prioqueue_remove_producer(gw_prioqueue_t *queue)
Definition: gw-prioqueue.c:341
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
#define panic
Definition: log.h:87
Definition: cfg.c:73
smscconn_status_t status
Definition: smscconn_p.h:151
HTTPCaller * http_caller_create(void)
Definition: http.c:897
#define gwlist_create()
Definition: list.h:136
long(* queued)(SMSCConn *conn)
Definition: smscconn_p.h:241
int(* send_msg)(SMSCConn *conn, Msg *msg)
Definition: smscconn_p.h:236
Octstr * username
Definition: smsc_http_p.h:97
static int httpsmsc_send(SMSCConn *conn, Msg *msg)
Definition: smsc_http.c:402
#define DLR_BUFFERED
Definition: dlr.h:74
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:329
void http_caller_destroy(HTTPCaller *caller)
Definition: http.c:907
Octstr * send_url
Definition: smsc_http_p.h:93
void gwlist_add_producer(List *list)
Definition: list.c:383
static int response(List *push_headers, Octstr **username, Octstr **password)
static void httpsmsc_sender(void *arg)
Definition: smsc_http.c:242
static Octstr * url
Definition: test_xmlrpc.c:84
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
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:415
#define DLR_IS_ENABLED_DEVICE(dlr)
Definition: dlr.h:82
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1640
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define DLR_FAIL
Definition: dlr.h:73
void gw_prioqueue_add_producer(gw_prioqueue_t *queue)
Definition: gw-prioqueue.c:331
void uuid_clear(uuid_t uu)
Definition: gw_uuid.c:105
int charset_convert(Octstr *string, char *charset_from, char *charset_to)
Definition: charset.c:589
void octstr_delete_matching(Octstr *haystack, Octstr *needle)
Definition: octstr.c:2702
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.