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_http.c - interface to various HTTP based content/SMS gateways
59  *
60  * HTTP based "SMSC Connection" is meant for gateway connections,
61  * and has following features:
62  *
63  * o Kannel listens to certain (HTTP server) port for MO SMS messages.
64  *   The exact format of these HTTP calls are defined by type of HTTP based
65  *   connection. Kannel replies to these messages as ACK, but does not
66  *   support immediate reply. Thus, if Kannel is linked to another Kannel,
67  *   only 'max-messages = 0' services are practically supported - any
68  *   replies must be done with SMS PUSH (sendsms)
69  *
70  * o For MT messages, Kannel does HTTP GET or POST to given address, in format
71  *   defined by type of HTTP based protocol
72  *
73  * The 'type' of requests and replies are defined by 'system-type' variable.
74  * The only type of HTTP requests currently supported are basic Kannel.
75  * If new support is added, smsc_http_create is modified accordingly and new
76  * functions added.
77  *
78  *
79  * KANNEL->KANNEL linking: (UDH not supported in MO messages)
80  *
81  *****
82  * FOR CLIENT/END-POINT KANNEL:
83  *
84  *  group = smsc
85  *  smsc = http
86  *  system-type = kannel
87  *  port = NNN
88  *  smsc-username = XXX
89  *  smsc-password = YYY
90  *  send-url = "server.host:PORT"
91  *
92  *****
93  * FOR SERVER/RELAY KANNEL:
94  *
95  *  group = smsbox
96  *  sendsms-port = PORT
97  *  ...
98  *
99  *  group = sms-service
100  *  keyword = ...
101  *  url = "client.host:NNN/sms?user=XXX&pass=YYY&from=%p&to=%P&text=%a"
102  *  max-messages = 0
103  *
104  *  group = send-sms
105  *  username = XXX
106  *  password = YYY
107  *
108  * Kalle Marjola for Project Kannel 2001
109  * Stipe Tolj <st@tolj.org>
110  * Alexander Malysh <amalysh at kannel.org>
111  * Tobias Weber <weber@wapme.de>
112  */
113 
114 #include <sys/types.h>
115 #include <sys/socket.h>
116 #include <unistd.h>
117 #include <errno.h>
118 #include <time.h>
119 #include <limits.h>
120 
121 #include "gwlib/gwlib.h"
122 #include "smscconn.h"
123 #include "smscconn_p.h"
124 #include "bb_smscconn_cb.h"
125 #include "msg.h"
126 #include "sms.h"
127 #include "dlr.h"
128 #include "urltrans.h"
129 #include "meta_data.h"
130 
131 #define DEFAULT_CHARSET "UTF-8"
132 
133 /* callback functions set by HTTP-SMSC type */
134 struct smsc_http_fn_callbacks {
135     int (*init) (SMSCConn *conn, CfgGroup *cfg);
136     void (*destroy) (SMSCConn *conn);
137     int (*send_sms) (SMSCConn *conn, Msg *msg);
138     void (*parse_reply) (SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body);
139     void (*receive_sms) (SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars);
140 };
141 
142 typedef struct conndata {
143     HTTPCaller *http_ref;
144     long receive_thread;
145     long send_cb_thread;
146     long sender_thread;
147     volatile int shutdown;
148     long port;   /* port for receiving SMS'es */
149     Octstr *allow_ip;
150     Octstr *send_url;
151     Octstr *dlr_url;
152     Counter *open_sends;
153     Semaphore *max_pending_sends;
154     Octstr *username;   /* if needed */
155     Octstr *password;   /* as said */
156     Octstr *system_id;	/* api id for clickatell */
157     int no_sender;      /* ditto */
158     int no_coding;      /* this, too */
159     int no_sep;         /* not to mention this */
160     Octstr *proxy;      /* proxy a constant string */
161     Octstr *alt_charset;    /* alternative charset use */
162     List *msg_to_send; /* our send queue */
163 
164 
165 
166     /* callback functions set by HTTP-SMSC type */
167     struct smsc_http_fn_callbacks *callbacks;
168 
169     /* submodule specific data */
170     void *data;
171 } ConnData;
172 
173 
conndata_destroy(ConnData * conndata)174 static void conndata_destroy(ConnData *conndata)
175 {
176     if (conndata == NULL)
177         return;
178     if (conndata->http_ref)
179         http_caller_destroy(conndata->http_ref);
180     octstr_destroy(conndata->allow_ip);
181     octstr_destroy(conndata->send_url);
182     octstr_destroy(conndata->dlr_url);
183     octstr_destroy(conndata->username);
184     octstr_destroy(conndata->password);
185     octstr_destroy(conndata->proxy);
186     octstr_destroy(conndata->system_id);
187     octstr_destroy(conndata->alt_charset);
188     counter_destroy(conndata->open_sends);
189     gwlist_destroy(conndata->msg_to_send, NULL);
190     if (conndata->max_pending_sends)
191         semaphore_destroy(conndata->max_pending_sends);
192 
193     gw_free(conndata);
194 }
195 
196 
197 /*
198  * Thread to listen to HTTP requests from SMSC entity
199  */
httpsmsc_receiver(void * arg)200 static void httpsmsc_receiver(void *arg)
201 {
202     SMSCConn *conn = arg;
203     ConnData *conndata = conn->data;
204     HTTPClient *client;
205     Octstr *ip, *url, *body;
206     List *headers, *cgivars;
207 
208     /* Make sure we log into our own log-file if defined */
209     log_thread_to(conn->log_idx);
210 
211     while (conndata->shutdown == 0) {
212         /* reset */
213         ip = url = body = NULL;
214         headers = cgivars = NULL;
215 
216         /* XXX if conn->is_stopped, do not receive new messages.. */
217 
218         client = http_accept_request(conndata->port, &ip, &url,
219                                      &headers, &body, &cgivars);
220         if (client == NULL)
221             break;
222 
223         if (cgivars != NULL) {
224         	octstr_append_char(url, '?');
225         	http_cgivar_dump_into(cgivars, url);
226         }
227 
228         debug("smsc.http", 0, "HTTP[%s]: Got request `%s'",
229               octstr_get_cstr(conn->id), octstr_get_cstr(url));
230 
231         if (connect_denied(conndata->allow_ip, ip)) {
232             info(0, "HTTP[%s]: Connection `%s' tried from denied "
233                     "host %s, ignored", octstr_get_cstr(conn->id),
234                     octstr_get_cstr(url), octstr_get_cstr(ip));
235             http_close_client(client);
236         } else
237             conndata->callbacks->receive_sms(conn, client, headers, body, cgivars);
238 
239         debug("smsc.http", 0, "HTTP[%s]: Destroying client information",
240               octstr_get_cstr(conn->id));
241         octstr_destroy(url);
242         octstr_destroy(ip);
243         octstr_destroy(body);
244         http_destroy_headers(headers);
245         http_destroy_cgiargs(cgivars);
246     }
247     debug("smsc.http", 0, "HTTP[%s]: httpsmsc_receiver dying",
248           octstr_get_cstr(conn->id));
249 
250     conndata->shutdown = 1;
251     http_close_port(conndata->port);
252 
253     /* unblock http_receive_result() if there are no open sends */
254     if (counter_value(conndata->open_sends) == 0)
255         http_caller_signal_shutdown(conndata->http_ref);
256 
257     if (conndata->sender_thread != -1) {
258         gwthread_wakeup(conndata->sender_thread);
259         gwthread_join(conndata->sender_thread);
260     }
261     if (conndata->send_cb_thread != -1) {
262         gwthread_wakeup(conndata->send_cb_thread);
263         gwthread_join(conndata->send_cb_thread);
264     }
265 
266     mutex_lock(conn->flow_mutex);
267     conn->status = SMSCCONN_DEAD;
268     mutex_unlock(conn->flow_mutex);
269 
270     if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
271         conndata->callbacks->destroy(conn);
272     conn->data = NULL;
273     conndata_destroy(conndata);
274     bb_smscconn_killed();
275 }
276 
277 
278 /*
279  * Thread to send queued messages
280  */
httpsmsc_sender(void * arg)281 static void httpsmsc_sender(void *arg)
282 {
283     SMSCConn *conn = arg;
284     ConnData *conndata = conn->data;
285     Msg *msg;
286     double delay = 0;
287 
288     /* Make sure we log into our own log-file if defined */
289     log_thread_to(conn->log_idx);
290 
291     if (conn->throughput) {
292         delay = 1.0 / conn->throughput;
293     }
294 
295     while (conndata->shutdown == 0) {
296         /* check if we can send ; otherwise block on semaphore */
297         if (conndata->max_pending_sends)
298             semaphore_down(conndata->max_pending_sends);
299 
300         if (conndata->shutdown) {
301             if (conndata->max_pending_sends)
302                 semaphore_up(conndata->max_pending_sends);
303             break;
304         }
305 
306         msg = gwlist_consume(conndata->msg_to_send);
307         if (msg == NULL)
308             break;
309 
310         /* obey throughput speed limit, if any */
311         if (conn->throughput > 0) {
312             gwthread_sleep(delay);
313         }
314         counter_increase(conndata->open_sends);
315         if (conndata->callbacks->send_sms(conn, msg) == -1) {
316             counter_decrease(conndata->open_sends);
317             if (conndata->max_pending_sends)
318                 semaphore_up(conndata->max_pending_sends);
319         }
320     }
321 
322     /* put outstanding sends back into global queue */
323     while((msg = gwlist_extract_first(conndata->msg_to_send)))
324         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
325 
326     /* if there no receiver shutdown */
327     if (conndata->port <= 0) {
328         /* unblock http_receive_result() if there are no open sends */
329         if (counter_value(conndata->open_sends) == 0)
330             http_caller_signal_shutdown(conndata->http_ref);
331 
332         if (conndata->send_cb_thread != -1) {
333             gwthread_wakeup(conndata->send_cb_thread);
334             gwthread_join(conndata->send_cb_thread);
335         }
336         mutex_lock(conn->flow_mutex);
337         conn->status = SMSCCONN_DEAD;
338         mutex_unlock(conn->flow_mutex);
339 
340         if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
341             conndata->callbacks->destroy(conn);
342         conn->data = NULL;
343         conndata_destroy(conndata);
344         bb_smscconn_killed();
345     }
346 }
347 
348 /*
349  * Thread to handle finished sendings
350  */
httpsmsc_send_cb(void * arg)351 static void httpsmsc_send_cb(void *arg)
352 {
353     SMSCConn *conn = arg;
354     ConnData *conndata = conn->data;
355     Msg *msg;
356     int status;
357     List *headers;
358     Octstr *final_url, *body;
359 
360     /* Make sure we log into our own log-file if defined */
361     log_thread_to(conn->log_idx);
362 
363     while(conndata->shutdown == 0 || counter_value(conndata->open_sends)) {
364 
365         msg = http_receive_result(conndata->http_ref, &status,
366                                   &final_url, &headers, &body);
367 
368         if (msg == NULL)
369             break;  /* they told us to die, by unlocking */
370 
371         counter_decrease(conndata->open_sends);
372         if (conndata->max_pending_sends)
373             semaphore_up(conndata->max_pending_sends);
374 
375         /* Handle various states here. */
376 
377         /* request failed and we are not in shutdown mode */
378         if (status == -1 && conndata->shutdown == 0) {
379             error(0, "HTTP[%s]: Couldn't connect to SMS center."
380                      "(retrying in %ld seconds) %ld.",
381                      octstr_get_cstr(conn->id), conn->reconnect_delay, counter_value(conndata->open_sends));
382             mutex_lock(conn->flow_mutex);
383             conn->status = SMSCCONN_RECONNECTING;
384             mutex_unlock(conn->flow_mutex);
385             /* XXX how should we know whether it's temp. error ?? */
386             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
387             /*
388              * Just sleep reconnect delay and set conn to ACTIVE again;
389              * otherwise if no pending request are here, we leave conn in
390              * RECONNECTING state for ever and no routing (trials) take place.
391              */
392             if (counter_value(conndata->open_sends) == 0) {
393                 gwthread_sleep(conn->reconnect_delay);
394                 /* and now enable routing again */
395                 mutex_lock(conn->flow_mutex);
396                 conn->status = SMSCCONN_ACTIVE;
397                 time(&conn->connect_time);
398                 mutex_unlock(conn->flow_mutex);
399                 /* tell bearerbox core that we are connected again */
400                 bb_smscconn_connected(conn);
401             }
402             continue;
403         }
404         /* request failed and we *are* in shutdown mode, drop the message */
405         else if (status == -1 && conndata->shutdown == 1) {
406             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
407         }
408         /* request succeeded */
409         else {
410             /* we received a response, so this link is considered online again */
411             if (conn->status != SMSCCONN_ACTIVE) {
412                 mutex_lock(conn->flow_mutex);
413                 conn->status = SMSCCONN_ACTIVE;
414                 time(&conn->connect_time);
415                 mutex_unlock(conn->flow_mutex);
416                 /* tell bearerbox core that we are connected again */
417                 bb_smscconn_connected(conn);
418             }
419             conndata->callbacks->parse_reply(conn, msg, status, headers, body);
420         }
421 
422         http_destroy_headers(headers);
423         octstr_destroy(final_url);
424         octstr_destroy(body);
425     }
426     debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying",
427           octstr_get_cstr(conn->id));
428     conndata->shutdown = 1;
429 
430     if (counter_value(conndata->open_sends)) {
431         warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.",
432                 octstr_get_cstr(conn->id), counter_value(conndata->open_sends));
433     }
434 }
435 
436 
437 /*----------------------------------------------------------------
438  * SMSC-type specific functions
439  *
440  * 3 functions are needed for each:
441  *
442  *   1) send SMS
443  *   2) parse send SMS result
444  *   3) receive SMS (and send reply)
445  *
446  *   These functions do not return anything and do not destroy
447  *   arguments. They must handle everything that happens therein
448  *   and must call appropriate bb_smscconn functions
449  */
450 
451 /*----------------------------------------------------------------
452  * Kannel
453  *
454  * This type allows concatenation of Kannel instances, ie:
455  *
456  *  <smsc>--<bearerbox2><smsbox2>--HTTP--<smsc_http><bearerbox1><smsbox1>
457  *
458  * Where MT messages are injected via the sendsms HTTP interface at smsbox1,
459  * forwarded to bearerbo1 and routed via the SMSC HTTP type kannel to
460  * sendsms HTTP interface of smsbox2 and further on.
461  *
462  * This allows chaining of Kannel instances for MO and MT traffic.
463  *
464  * DLR handling:
465  * For DLR handling we have the usual effect that the "last" smsbox instance
466  * of the chain is signaling the DLR-URL, since the last instance receives
467  * the DLR from the upstream SMSC and the associated smsbox triggers the
468  * DLR-URL.
469  * For some considerations this is not what we want. If we want to transport
470  * the orginal DLR-URL to the "first" smsbox instance of the calling chain
471  * then we need to define a 'dlr-url' config directive in the smsc group.
472  * This value defines the inbound MO/DLR port of our own smsc group and
473  * maps arround the orginal DLR-URL. So the next smsbox does not signal the
474  * orginal DLR-URL, but our own smsc group instance with the DLR, and we can
475  * forward on to smsbox and possibly further on the chain to the first
476  * instance.
477  *
478  * Example: (consider the 2 chain architecture from above)
479  * A MT is put to smsbox1 with dlr-url=http://foobar/aaa as DLR-URL. The MT
480  * is forwarded to bearerbox.
481  * If no 'dlr-url' is given in the smsc HTTP for the next smsbox2, then we
482  * simply pass the same value to smsbox2. Resulting that smsbox2 will call
483  * the DLR-URL when we receive a DLR from the upstream SMSC connection of
484  * bearerbox2.
485  * If 'dlr-url = http://localhost:15015/' is given in the smsc HTTP for the
486  * next smsbox2, then we map the orginal DLR-URL into this value, resulting
487  * in a dlr-url=http://lcoalhost:15015/&dlr-url=http://foobar/aaa call to
488  * smsbox2. So smsbox2 is not signaling http://foobar/aaa directly, but our
489  * own bearerbox1's smsc HTTP port for MO/DLR receive.
490  */
491 
492 enum { HEX_NOT_UPPERCASE = 0 };
493 
494 
kannel_send_sms(SMSCConn * conn,Msg * sms)495 static int kannel_send_sms(SMSCConn *conn, Msg *sms)
496 {
497     ConnData *conndata = conn->data;
498     Octstr *url;
499     List *headers;
500 
501     if (!conndata->no_sep) {
502         url = octstr_format("%S?"
503 			    "username=%E&password=%E&to=%E&text=%E",
504 			     conndata->send_url,
505 			     conndata->username, conndata->password,
506 			     sms->sms.receiver, sms->sms.msgdata);
507     } else {
508         Octstr *msgdata = octstr_duplicate(sms->sms.msgdata);
509 
510         octstr_binary_to_hex(msgdata, HEX_NOT_UPPERCASE);
511         url = octstr_format("%S?"
512 			    "username=%E&password=%E&to=%E&text=%S",
513 			     conndata->send_url,
514 			     conndata->username, conndata->password,
515 			     sms->sms.receiver, msgdata);
516         octstr_destroy(msgdata);
517     }
518 
519     if (octstr_len(sms->sms.udhdata)) {
520         if (!conndata->no_sep) {
521             octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
522         } else {
523             Octstr *udhdata = octstr_duplicate(sms->sms.udhdata);
524 
525             octstr_binary_to_hex(udhdata, HEX_NOT_UPPERCASE);
526             octstr_format_append(url, "&udh=%S", udhdata);
527             octstr_destroy(udhdata);
528         }
529     }
530 
531     if (!conndata->no_sender)
532         octstr_format_append(url, "&from=%E", sms->sms.sender);
533     if (sms->sms.mclass != MC_UNDEF)
534         octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
535     if (!conndata->no_coding && sms->sms.coding != DC_UNDEF)
536         octstr_format_append(url, "&coding=%d", sms->sms.coding);
537 
538     /* Obey that smsbox's sendsms HTTP interface is still expecting
539      * WINDOWS-1252 as default charset, while all other internal parts
540      * use UTF-8 as internal encoding. This means, when we pass a SMS
541      * into a next Kannel instance, we need to let the smsbox know which
542      * charset we have in use.
543      * XXX TODO: change smsbox interface to use UTF-8 as default
544      * in next major release. */
545     if (sms->sms.coding == DC_7BIT)
546         octstr_append_cstr(url, "&charset=UTF-8");
547     else if (sms->sms.coding == DC_UCS2)
548         octstr_append_cstr(url, "&charset=UTF-16BE");
549 
550     if (sms->sms.mwi != MWI_UNDEF)
551         octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
552     if (sms->sms.account) /* prepend account with local username */
553         octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
554     if (sms->sms.binfo) /* prepend billing info */
555         octstr_format_append(url, "&binfo=%S", sms->sms.binfo);
556     if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */
557         octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id);
558 	if (conndata->dlr_url) {
559 		char id[UUID_STR_LEN + 1];
560 		Octstr *mid;
561 
562 		/* create Octstr from UUID */
563 		uuid_unparse(sms->sms.id, id);
564 		mid = octstr_create(id);
565 
566 		octstr_format_append(url, "&dlr-url=%E", conndata->dlr_url);
567 
568 		/* encapsulate the original DLR-URL, escape code for DLR mask
569 		 * and message id */
570 		octstr_format_append(url, "%E%E%E%E%E",
571 			octstr_imm("&dlr-url="), sms->sms.dlr_url != NULL ? sms->sms.dlr_url : octstr_imm(""),
572 			octstr_imm("&dlr-mask=%d"),
573 			octstr_imm("&dlr-mid="), mid);
574 
575 		octstr_destroy(mid);
576 	} else if (sms->sms.dlr_url != NULL)
577 		octstr_format_append(url, "&dlr-url=%E", sms->sms.dlr_url);
578     if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING)
579         octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask);
580 
581     if (sms->sms.validity != SMS_PARAM_UNDEFINED)
582     	octstr_format_append(url, "&validity=%ld", (sms->sms.validity - time(NULL)) / 60);
583     if (sms->sms.deferred != SMS_PARAM_UNDEFINED)
584     	octstr_format_append(url, "&deferred=%ld", (sms->sms.deferred - time(NULL)) / 60);
585 
586     headers = gwlist_create();
587     debug("smsc.http.kannel", 0, "HTTP[%s]: Start request",
588           octstr_get_cstr(conn->id));
589     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers,
590                        NULL, 0, sms, NULL);
591 
592     octstr_destroy(url);
593     http_destroy_headers(headers);
594 
595     return 0;
596 }
597 
kannel_parse_reply(SMSCConn * conn,Msg * msg,int status,List * headers,Octstr * body)598 static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status,
599 			       List *headers, Octstr *body)
600 {
601     /* Test on three cases:
602      * 1. an smsbox reply of an remote kannel instance
603      * 2. an smsc_http response (if used for MT to MO looping)
604      * 3. an smsbox reply of partly successful sendings */
605     if ((status == HTTP_OK || status == HTTP_ACCEPTED)
606         && (octstr_case_compare(body, octstr_imm("0: Accepted for delivery")) == 0 ||
607             octstr_case_compare(body, octstr_imm("Sent.")) == 0 ||
608             octstr_case_compare(body, octstr_imm("Ok.")) == 0 ||
609             octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)) {
610         char id[UUID_STR_LEN + 1];
611         Octstr *mid;
612 
613         /* create Octstr from UUID */
614         uuid_unparse(msg->sms.id, id);
615         mid = octstr_create(id);
616 
617         /* add to our own DLR storage */
618         if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
619             dlr_add(conn->id, mid, msg, 0);
620 
621         octstr_destroy(mid);
622 
623         bb_smscconn_sent(conn, msg, NULL);
624     } else {
625         bb_smscconn_send_failed(conn, msg,
626 	            SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
627     }
628 }
629 
630 
kannel_receive_sms(SMSCConn * conn,HTTPClient * client,List * headers,Octstr * body,List * cgivars)631 static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client,
632                                List *headers, Octstr *body, List *cgivars)
633 {
634     ConnData *conndata = conn->data;
635     Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo;
636     Octstr *dlrmid, *dlrerr;
637     Octstr *tmp_string, *retmsg;
638     int	mclass, mwi, coding, validity, deferred, dlrmask;
639     List *reply_headers;
640     int ret;
641 
642     mclass = mwi = coding = validity =
643         deferred = dlrmask = SMS_PARAM_UNDEFINED;
644 
645     user = http_cgi_variable(cgivars, "username");
646     pass = http_cgi_variable(cgivars, "password");
647     from = http_cgi_variable(cgivars, "from");
648     to = http_cgi_variable(cgivars, "to");
649     text = http_cgi_variable(cgivars, "text");
650     udh = http_cgi_variable(cgivars, "udh");
651     account = http_cgi_variable(cgivars, "account");
652     binfo = http_cgi_variable(cgivars, "binfo");
653     dlrmid = http_cgi_variable(cgivars, "dlr-mid");
654     tmp_string = http_cgi_variable(cgivars, "flash");
655     if (tmp_string) {
656         sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
657     }
658     tmp_string = http_cgi_variable(cgivars, "mclass");
659     if (tmp_string) {
660         sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
661     }
662     tmp_string = http_cgi_variable(cgivars, "mwi");
663     if (tmp_string) {
664         sscanf(octstr_get_cstr(tmp_string),"%d", &mwi);
665     }
666     tmp_string = http_cgi_variable(cgivars, "coding");
667     if (tmp_string) {
668         sscanf(octstr_get_cstr(tmp_string),"%d", &coding);
669     }
670     tmp_string = http_cgi_variable(cgivars, "validity");
671     if (tmp_string) {
672         sscanf(octstr_get_cstr(tmp_string),"%d", &validity);
673     }
674     tmp_string = http_cgi_variable(cgivars, "deferred");
675     if (tmp_string) {
676         sscanf(octstr_get_cstr(tmp_string),"%d", &deferred);
677     }
678     tmp_string = http_cgi_variable(cgivars, "dlr-mask");
679     if (tmp_string) {
680         sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask);
681     }
682     dlrerr = http_cgi_variable(cgivars, "dlr-err");
683 
684     debug("smsc.http.kannel", 0, "HTTP[%s]: Received an HTTP request",
685           octstr_get_cstr(conn->id));
686 
687     if (user == NULL || pass == NULL ||
688 	    octstr_compare(user, conndata->username) != 0 ||
689 	    octstr_compare(pass, conndata->password) != 0) {
690 
691         error(0, "HTTP[%s]: Authorization failure",
692               octstr_get_cstr(conn->id));
693         retmsg = octstr_create("Authorization failed for sendsms");
694     } else if (dlrmask != 0 && dlrmid != NULL) {
695         /* we got a DLR, and we don't require additional values */
696         Msg *dlrmsg;
697 
698         dlrmsg = dlr_find(conn->id,
699             dlrmid, /* message id */
700             to, /* destination */
701             dlrmask, 0);
702 
703         if (dlrmsg != NULL) {
704             dlrmsg->sms.sms_type = report_mo;
705             dlrmsg->sms.msgdata = octstr_duplicate(text);
706             dlrmsg->sms.account = octstr_duplicate(conndata->username);
707 
708             debug("smsc.http.kannel", 0, "HTTP[%s]: Received DLR for DLR-URL <%s>",
709                   octstr_get_cstr(conn->id), octstr_get_cstr(dlrmsg->sms.dlr_url));
710 
711             if (dlrerr != NULL) {
712                 /* pass errorcode as is */
713             	if (dlrmsg->sms.meta_data == NULL)
714             		dlrmsg->sms.meta_data = octstr_create("");
715 
716                 meta_data_set_value(dlrmsg->sms.meta_data, METADATA_DLR_GROUP,
717                                     octstr_imm(METADATA_DLR_GROUP_ERRORCODE), dlrerr, 1);
718             }
719 
720             ret = bb_smscconn_receive(conn, dlrmsg);
721             if (ret == -1)
722                 retmsg = octstr_create("Not accepted");
723             else
724                 retmsg = octstr_create("Sent.");
725         } else {
726             error(0,"HTTP[%s]: Got DLR but could not find message or was not interested "
727                   "in it id<%s> dst<%s>, type<%d>",
728                   octstr_get_cstr(conn->id), octstr_get_cstr(dlrmid),
729                   octstr_get_cstr(to), dlrmask);
730             retmsg = octstr_create("Unknown DLR, not accepted");
731         }
732     }
733     else if (from == NULL || to == NULL || text == NULL) {
734 
735         error(0, "HTTP[%s]: Insufficient args",
736               octstr_get_cstr(conn->id));
737         retmsg = octstr_create("Insufficient args, rejected");
738     }
739     else if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) {
740         error(0, "HTTP[%s]: UDH field misformed, rejected",
741               octstr_get_cstr(conn->id));
742         retmsg = octstr_create("UDH field misformed, rejected");
743     }
744     else if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) {
745         error(0, "HTTP[%s]: UDH field is too long, rejected",
746               octstr_get_cstr(conn->id));
747         retmsg = octstr_create("UDH field is too long, rejected");
748     }
749     else {
750         /* we got a normal MO SMS */
751         Msg *msg;
752         msg = msg_create(sms);
753 
754         debug("smsc.http.kannel", 0, "HTTP[%s]: Constructing new SMS",
755               octstr_get_cstr(conn->id));
756 
757         msg->sms.service = octstr_duplicate(user);
758         msg->sms.sender = octstr_duplicate(from);
759         msg->sms.receiver = octstr_duplicate(to);
760         msg->sms.msgdata = octstr_duplicate(text);
761         msg->sms.udhdata = octstr_duplicate(udh);
762 
763         msg->sms.smsc_id = octstr_duplicate(conn->id);
764         msg->sms.time = time(NULL);
765         msg->sms.mclass = mclass;
766         msg->sms.mwi = mwi;
767         msg->sms.coding = coding;
768         msg->sms.validity = (validity == SMS_PARAM_UNDEFINED ? validity : time(NULL) + validity * 60);
769         msg->sms.deferred = (deferred == SMS_PARAM_UNDEFINED ? deferred : time(NULL) + deferred * 60);
770         msg->sms.account = octstr_duplicate(account);
771         msg->sms.binfo = octstr_duplicate(binfo);
772         ret = bb_smscconn_receive(conn, msg);
773         if (ret == -1)
774             retmsg = octstr_create("Not accepted");
775         else
776             retmsg = octstr_create("Sent.");
777     }
778 
779     reply_headers = gwlist_create();
780     http_header_add(reply_headers, "Content-Type", "text/plain");
781     debug("smsc.http.kannel", 0, "HTTP[%s]: Sending reply",
782           octstr_get_cstr(conn->id));
783     http_send_reply(client, HTTP_ACCEPTED, reply_headers, retmsg);
784 
785     octstr_destroy(retmsg);
786     http_destroy_headers(reply_headers);
787 }
788 
789 struct smsc_http_fn_callbacks smsc_http_kannel_callback = {
790         .send_sms = kannel_send_sms,
791         .parse_reply = kannel_parse_reply,
792         .receive_sms = kannel_receive_sms,
793 };
794 
795 /*-----------------------------------------------------------------
796  * functions to implement various smscconn operations
797  */
798 
httpsmsc_send(SMSCConn * conn,Msg * msg)799 static int httpsmsc_send(SMSCConn *conn, Msg *msg)
800 {
801     ConnData *conndata = conn->data;
802     Msg *sms;
803 
804 
805     /* don't crash if no send_sms handle defined */
806     if (!conndata || !conndata->callbacks->send_sms)
807         return -1;
808 
809     sms = msg_duplicate(msg);
810     /* convert character encoding if required */
811     if (msg->sms.coding == DC_7BIT && conndata->alt_charset &&
812         charset_convert(sms->sms.msgdata, DEFAULT_CHARSET,
813                         octstr_get_cstr(conndata->alt_charset)) != 0) {
814         error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.",
815               DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset));
816     }
817 
818     gwlist_produce(conndata->msg_to_send, sms);
819 
820     return 0;
821 }
822 
823 
httpsmsc_queued(SMSCConn * conn)824 static long httpsmsc_queued(SMSCConn *conn)
825 {
826     ConnData *conndata = conn->data;
827 
828     return (conndata ? (conn->status != SMSCCONN_DEAD ?
829             counter_value(conndata->open_sends) : 0) : 0);
830 }
831 
832 
httpsmsc_shutdown(SMSCConn * conn,int finish_sending)833 static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
834 {
835     ConnData *conndata = conn->data;
836 
837     if (conndata == NULL)
838         return 0;
839 
840     debug("httpsmsc_shutdown", 0, "HTTP[%s]: Shutting down",
841           octstr_get_cstr(conn->id));
842 
843     mutex_lock(conn->flow_mutex);
844     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
845 
846     conndata->shutdown = 1;
847 
848     if (conndata->port > 0)
849         http_close_port(conndata->port);
850     gwlist_remove_producer(conndata->msg_to_send);
851     if (conndata->receive_thread != -1)
852         gwthread_wakeup(conndata->receive_thread);
853     if (conndata->sender_thread != -1)
854         gwthread_wakeup(conndata->sender_thread);
855     mutex_unlock(conn->flow_mutex);
856 
857     return 0;
858 }
859 
860 
861 #include "http/generic.c"
862 #include "http/brunet.c"
863 #include "http/xidris.c"
864 #include "http/clickatell.c"
865 #include "http/wapme.c"
866 
867 
smsc_http_create(SMSCConn * conn,CfgGroup * cfg)868 int smsc_http_create(SMSCConn *conn, CfgGroup *cfg)
869 {
870     ConnData *conndata = NULL;
871     Octstr *type;
872     int ssl = 0;   /* indicate if SSL-enabled server should be used */
873     long max_ps;
874 
875     if ((type = cfg_get(cfg, octstr_imm("system-type"))) == NULL) {
876         error(0, "HTTP[%s]: 'system-type' missing in smsc 'http' record.",
877               octstr_get_cstr(conn->id));
878         octstr_destroy(type);
879         return -1;
880     }
881 
882     conndata = gw_malloc(sizeof(ConnData));
883     /* reset conndata */
884     memset(conndata, 0, sizeof(ConnData));
885 
886     conn->data = conndata;
887     conndata->http_ref = NULL;
888     conndata->data = NULL;
889 
890     if (cfg_get_integer(&conndata->port, cfg, octstr_imm("port")) == -1) {
891         warning(0, "HTTP[%s]: 'port' not set in smsc 'http' group.",
892               octstr_get_cstr(conn->id));
893         conndata->port = -1;
894     }
895 
896     conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
897     conndata->send_url = cfg_get(cfg, octstr_imm("send-url"));
898     conndata->username = cfg_get(cfg, octstr_imm("smsc-username"));
899     conndata->password = cfg_get(cfg, octstr_imm("smsc-password"));
900     conndata->system_id = cfg_get(cfg, octstr_imm("system-id"));
901     cfg_get_bool(&conndata->no_sender, cfg, octstr_imm("no-sender"));
902     cfg_get_bool(&conndata->no_coding, cfg, octstr_imm("no-coding"));
903     cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep"));
904     conndata->proxy = cfg_get(cfg, octstr_imm("system-id"));
905     cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl"));
906     conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url"));
907     conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset"));
908 
909     if (cfg_get_integer(&max_ps, cfg, octstr_imm("max-pending-submits")) == -1 || max_ps < 1)
910         max_ps = 10;
911 
912     conndata->max_pending_sends = semaphore_create(max_ps);
913 
914     if (conndata->port <= 0 && conndata->send_url == NULL) {
915         error(0, "Sender and receiver disabled. Dummy SMSC not allowed.");
916         goto error;
917     }
918     if (conndata->send_url == NULL)
919         panic(0, "HTTP[%s]: Sending not allowed. No 'send-url' specified.",
920               octstr_get_cstr(conn->id));
921 
922     if (octstr_case_compare(type, octstr_imm("kannel")) == 0) {
923         if (conndata->username == NULL || conndata->password == NULL) {
924             error(0, "HTTP[%s]: 'username' and 'password' required for Kannel http smsc",
925                   octstr_get_cstr(conn->id));
926             goto error;
927         }
928         conndata->callbacks = &smsc_http_kannel_callback;
929     } else if (octstr_case_compare(type, octstr_imm("brunet")) == 0) {
930         conndata->callbacks = &smsc_http_brunet_callback;
931     } else if (octstr_case_compare(type, octstr_imm("xidris")) == 0) {
932         conndata->callbacks = &smsc_http_xidris_callback;
933     } else if (octstr_case_compare(type, octstr_imm("generic")) == 0) {
934         conndata->callbacks = &smsc_http_generic_callback;
935     } else if (octstr_case_compare(type, octstr_imm("clickatell")) == 0) {
936         conndata->callbacks = &smsc_http_clickatell_callback;
937     } else if (octstr_case_compare(type, octstr_imm("wapme")) == 0) {
938         conndata->callbacks = &smsc_http_wapme_callback;
939     }
940     /*
941      * ADD NEW HTTP SMSC TYPES HERE
942      */
943     else {
944         error(0, "HTTP[%s]: system-type '%s' unknown smsc 'http' record.",
945               octstr_get_cstr(conn->id), octstr_get_cstr(type));
946         goto error;
947     }
948 
949     if (conndata->callbacks != NULL && conndata->callbacks->init != NULL && conndata->callbacks->init(conn, cfg)) {
950         error(0, "HTTP[%s]: submodule '%s' init failed.", octstr_get_cstr(conn->id), octstr_get_cstr(type));
951         goto error;
952     }
953 
954     conndata->open_sends = counter_create();
955     conndata->msg_to_send = gwlist_create();
956     gwlist_add_producer(conndata->msg_to_send);
957     conndata->http_ref = http_caller_create();
958 
959     conn->name = octstr_format("HTTP%s:%S:%d", (ssl?"S":""), type, conndata->port);
960 
961     if (conndata->send_url != NULL) {
962         conn->status = SMSCCONN_ACTIVE;
963     } else {
964         conn->status = SMSCCONN_ACTIVE_RECV;
965     }
966 
967 
968     conn->connect_time = time(NULL);
969 
970     conn->shutdown = httpsmsc_shutdown;
971     conn->queued = httpsmsc_queued;
972     conn->send_msg = httpsmsc_send;
973 
974     conndata->shutdown = 0;
975 
976     /* start receiver thread */
977     if (conndata->port > 0) {
978         if (http_open_port(conndata->port, ssl) == -1)
979             goto error;
980         if ((conndata->receive_thread = gwthread_create(httpsmsc_receiver, conn)) == -1)
981             goto error;
982     } else
983         conndata->receive_thread = -1;
984 
985     /* start sender threads */
986     if (conndata->send_url) {
987         if ((conndata->send_cb_thread =
988 	        gwthread_create(httpsmsc_send_cb, conn)) == -1)
989 	    goto error;
990         if ((conndata->sender_thread =
991                 gwthread_create(httpsmsc_sender, conn)) == -1)
992 	    goto error;
993     }
994     else {
995         conndata->send_cb_thread = conndata->sender_thread = -1;
996     }
997 
998     info(0, "HTTP[%s]: Initiated and ready", octstr_get_cstr(conn->id));
999 
1000     octstr_destroy(type);
1001     return 0;
1002 
1003 error:
1004     error(0, "HTTP[%s]: Failed to create HTTP SMSC connection",
1005           octstr_get_cstr(conn->id));
1006 
1007     if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
1008         conndata->callbacks->destroy(conn);
1009     conn->data = NULL;
1010     conndata_destroy(conndata);
1011     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
1012     conn->status = SMSCCONN_DEAD;
1013     octstr_destroy(type);
1014     return -1;
1015 }
1016 
1017