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