1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 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 {
98     HTTPCaller *http_ref;
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 
httpsmsc_sender_ercisson_sdp(void * arg)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",
223                 octstr_get_cstr(conndata->username), octstr_get_cstr(conndata->password));
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 
httpsmsc_sender_gsma_oneapi(void * arg)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  */
httpsmsc_receiver(void * arg)295 static void httpsmsc_receiver(void *arg)
296 {
297     SMSCConn *conn = arg;
298     ConnData *conndata = conn->data;
299     HTTPClient *client;
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 
313         client = http_accept_request(conndata->port, &ip, &url,
314                                      &headers, &body, &cgivars);
315         if (client == NULL)
316             break;
317 
318         debug("smsc.soap", 0, "SOAP[%s]: Got HTTP request `%s'",
319               octstr_get_cstr(conn->id), octstr_get_cstr(url));
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),
324                     octstr_get_cstr(url), octstr_get_cstr(ip));
325             http_close_client(client);
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));
331         octstr_destroy(url);
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;
341     http_close_port(conndata->port);
342 
343     /* unblock http_receive_result() if there are no open sends */
344     if (conndata->open_sends == 0)
345         http_caller_signal_shutdown(conndata->http_ref);
346 }
347 
348 
349 #ifdef DEBUG
dlr_sender(void * arg)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 
iscrlf(unsigned char c)411 static int iscrlf(unsigned char c)
412 {
413     return c == '\n' || c == '\r';
414 }
415 
416 
octstr_remove_crlfs(Octstr * ostr)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 
gw_free_wrapper(void * data)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 
gbuffer_create(SMSCConn * conn,size_t size)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 
gbuffer_destroy(gBuffer * buf)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  */
mysend(struct soap * soap,const char * s,size_t n)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  */
myrecv(struct soap * soap,char * s,size_t n)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  */
myheader(struct soap * soap,const char * key,const char * value)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 
soap_send_sms(struct soap * soap,SMSCConn * conn,Msg * sms)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         }
573         gwlist_destroy(l, octstr_destroy_item);
574         octstr_destroy(delim);
575         gwlist_destroy(l, octstr_destroy_item);
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          */
611         bb_smscconn_send_failed(conn, sms, SMSCCONN_FAILED_MALFORMED,
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);
678     octstr_destroy(receiver);
679 }
680 
681 
soap_parse_reply(SMSCConn * conn,Msg * msg,int status,List * headers,Octstr * body)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 {
702         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED,
703                 octstr_duplicate(body));
704     }
705 }
706 
707 
soap_receive_sms(SMSCConn * conn,HTTPClient * client,List * headers,Octstr * body,List * cgivars)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 
763     octstr_destroy(response);
764     http_destroy_headers(reply_headers);
765 }
766 
767 
soap_send_sms_cb(SMSCConn * conn,Msg * sms)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
soap_send_dlr(struct soap * soap,SMSCConn * conn,Msg * sms)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 
830     octstr_destroy(receiver);
831     octstr_destroy(mid);
832 }
833 #endif
834 
835 
836 /********************************************************************
837  * Internal smscconn operations
838  */
839 
conndata_destroy(ConnData * conndata)840 static void conndata_destroy(ConnData *conndata)
841 {
842     if (conndata == NULL)
843         return;
844 
845     if (conndata->http_ref)
846         http_caller_destroy(conndata->http_ref);
847 
848     gwlist_destroy(conndata->sender_threads, (void(*)(void *)) gw_free_wrapper);
849     gw_prioqueue_destroy(conndata->msgs_to_send, msg_destroy_item);
850 #ifdef DEBUG
851     gwlist_destroy(conndata->dlr_queue, msg_destroy_item);
852 #endif
853 
854     octstr_destroy(conndata->allow_ip);
855     octstr_destroy(conndata->send_url);
856     octstr_destroy(conndata->dlr_url);
857     octstr_destroy(conndata->username);
858     octstr_destroy(conndata->password);
859     octstr_destroy(conndata->alt_charset);
860 
861     gw_free(conndata);
862 }
863 
864 
httpsmsc_send(SMSCConn * conn,Msg * msg)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,
878                         octstr_get_cstr(conndata->alt_charset)) != 0)
879         error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.",
880                  DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset));
881 
882     conndata->open_sends++;
883     conndata->send_sms(conn, sms);
884 
885     /* obey throughput speed limit, if any */
886     if (conn->throughput > 0)
887         gwthread_sleep(delay);
888 
889     return 0;
890 }
891 
892 
httpsmsc_queued(SMSCConn * conn)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 
httpsmsc_shutdown(SMSCConn * conn,int finish_sending)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));
909     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
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 */
919     http_close_port(conndata->port);
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;
929     conndata_destroy(conndata);
930 
931     conn->status = SMSCCONN_DEAD;
932     bb_smscconn_killed();
933 
934     return 0;
935 }
936 
937 
smsc_soap_parlayx_create(SMSCConn * conn,CfgGroup * cfg)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));
955         octstr_destroy(type);
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.",
998               octstr_get_cstr(conn->id), octstr_get_cstr(type));
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 */
1008     conndata->msgs_to_send = gw_prioqueue_create(sms_priority_compare);
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;
1016     conndata->http_ref = http_caller_create();
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 */
1034     if ((conndata->receive_thread = gwthread_create(httpsmsc_receiver, conn)) == -1)
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 
1064     octstr_destroy(type);
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;
1072     conndata_destroy(conndata);
1073     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
1074     conn->status = SMSCCONN_DEAD;
1075 
1076     octstr_destroy(type);
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  */
__px1__sendSms(struct soap * soap,struct pxSmsSend__sendSms * req,struct pxSmsSend__sendSmsResponse * resp)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 
__px2__notifySmsDeliveryReceipt(struct soap * soap,struct pxSmsNotification__notifySmsDeliveryReceipt * req,struct pxSmsNotification__notifySmsDeliveryReceiptResponse * resp)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 
__px2__notifySmsReception(struct soap * soap,struct pxSmsNotification__notifySmsReception * req,struct pxSmsNotification__notifySmsReceptionResponse * resp)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 
__px1__sendSmsLogo(struct soap * soap,struct pxSmsSend__sendSmsLogo * pxSmsSend__sendSmsLogo,struct pxSmsSend__sendSmsLogoResponse * pxSmsSend__sendSmsLogoResponse)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 
__px1__sendSmsRingtone(struct soap * soap,struct pxSmsSend__sendSmsRingtone * pxSmsSend__sendSmsRingtone,struct pxSmsSend__sendSmsRingtoneResponse * pxSmsSend__sendSmsRingtoneResponse)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 
__px1__getSmsDeliveryStatus(struct soap * soap,struct pxSmsSend__getSmsDeliveryStatus * pxSmsSend__getSmsDeliveryStatus,struct pxSmsSend__getSmsDeliveryStatusResponse * pxSmsSend__getSmsDeliveryStatusResponse)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 
__px3__getReceivedSms(struct soap * soap,struct pxSmsReceive__getReceivedSms * pxSmsReceive__getReceivedSms,struct pxSmsReceive__getReceivedSmsResponse * pxSmsReceive__getReceivedSmsResponse)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 */
1263