Project

General

Profile

root / tags / version_1_4_4 / gw / smsc / smsc_http.c

1 3938 stolj
/* ====================================================================
2
 * The Kannel Software License, Version 1.0
3
 *
4 5097 stolj
 * Copyright (c) 2001-2014 Kannel Group
5 3938 stolj
 * 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 3021 harrie
/*
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 4992 amalysh
 *
99 3021 harrie
 *  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 4992 amalysh
 *
108 3021 harrie
 * Kalle Marjola for Project Kannel 2001
109 4451 stolj
 * Stipe Tolj <st@tolj.org>
110 4172 stolj
 * Alexander Malysh <amalysh at kannel.org>
111 4169 stolj
 * Tobias Weber <weber@wapme.de>
112 3021 harrie
 */
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 3576 stolj
#include "sms.h"
127 3698 davi
#include "dlr.h"
128 4451 stolj
#include "urltrans.h"
129 4941 afink
#include "meta_data.h"
130 3021 harrie
131 4883 stolj
#define DEFAULT_CHARSET "UTF-8"
132 4616 stolj
133 4992 amalysh
/* 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 4754 aguerrieri
142 3021 harrie
typedef struct conndata {
143 3519 stolj
    HTTPCaller *http_ref;
144
    long receive_thread;
145
    long send_cb_thread;
146 4894 amalysh
    long sender_thread;
147 4992 amalysh
    volatile int shutdown;
148
    long port;   /* port for receiving SMS'es */
149 3519 stolj
    Octstr *allow_ip;
150
    Octstr *send_url;
151 4894 amalysh
    Octstr *dlr_url;
152
    Counter *open_sends;
153
    Semaphore *max_pending_sends;
154 3519 stolj
    Octstr *username;   /* if needed */
155
    Octstr *password;   /* as said */
156 4382 amalysh
    Octstr *system_id;        /* api id for clickatell */
157 3519 stolj
    int no_sender;      /* ditto */
158
    int no_coding;      /* this, too */
159
    int no_sep;         /* not to mention this */
160 4161 stolj
    Octstr *proxy;      /* proxy a constant string */
161 4616 stolj
    Octstr *alt_charset;    /* alternative charset use */
162 4894 amalysh
    List *msg_to_send; /* our send queue */
163 3021 harrie
164 4451 stolj
165 4767 amalysh
166 3021 harrie
    /* callback functions set by HTTP-SMSC type */
167 4992 amalysh
    struct smsc_http_fn_callbacks *callbacks;
168
169
    /* submodule specific data */
170
    void *data;
171 3021 harrie
} ConnData;
172
173
174
static void conndata_destroy(ConnData *conndata)
175
{
176
    if (conndata == NULL)
177 3519 stolj
        return;
178 3021 harrie
    if (conndata->http_ref)
179 3519 stolj
        http_caller_destroy(conndata->http_ref);
180 3021 harrie
    octstr_destroy(conndata->allow_ip);
181
    octstr_destroy(conndata->send_url);
182 4495 stolj
    octstr_destroy(conndata->dlr_url);
183 3021 harrie
    octstr_destroy(conndata->username);
184
    octstr_destroy(conndata->password);
185 4161 stolj
    octstr_destroy(conndata->proxy);
186 4382 amalysh
    octstr_destroy(conndata->system_id);
187 4616 stolj
    octstr_destroy(conndata->alt_charset);
188 4894 amalysh
    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 3021 harrie
193
    gw_free(conndata);
194
}
195
196
197
/*
198 3519 stolj
 * Thread to listen to HTTP requests from SMSC entity
199 3021 harrie
 */
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 3642 stolj
208 3412 stolj
    /* Make sure we log into our own log-file if defined */
209
    log_thread_to(conn->log_idx);
210 4894 amalysh
211 3519 stolj
    while (conndata->shutdown == 0) {
212 4992 amalysh
        /* reset */
213
        ip = url = body = NULL;
214
        headers = cgivars = NULL;
215 3021 harrie
216 3519 stolj
        /* XXX if conn->is_stopped, do not receive new messages.. */
217 4894 amalysh
218 3519 stolj
        client = http_accept_request(conndata->port, &ip, &url,
219
                                     &headers, &body, &cgivars);
220
        if (client == NULL)
221
            break;
222 3021 harrie
223 4962 amalysh
        if (cgivars != NULL) {
224
                octstr_append_char(url, '?');
225
                http_cgivar_dump_into(cgivars, url);
226
        }
227
228 4894 amalysh
        debug("smsc.http", 0, "HTTP[%s]: Got request `%s'",
229 3541 stolj
              octstr_get_cstr(conn->id), octstr_get_cstr(url));
230 3021 harrie
231 3519 stolj
        if (connect_denied(conndata->allow_ip, ip)) {
232 3541 stolj
            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 3519 stolj
            http_close_client(client);
236
        } else
237 4992 amalysh
            conndata->callbacks->receive_sms(conn, client, headers, body, cgivars);
238 3021 harrie
239 3541 stolj
        debug("smsc.http", 0, "HTTP[%s]: Destroying client information",
240
              octstr_get_cstr(conn->id));
241 3519 stolj
        octstr_destroy(url);
242
        octstr_destroy(ip);
243
        octstr_destroy(body);
244
        http_destroy_headers(headers);
245
        http_destroy_cgiargs(cgivars);
246 3021 harrie
    }
247 3541 stolj
    debug("smsc.http", 0, "HTTP[%s]: httpsmsc_receiver dying",
248
          octstr_get_cstr(conn->id));
249 3021 harrie
250
    conndata->shutdown = 1;
251
    http_close_port(conndata->port);
252 4894 amalysh
253 3519 stolj
    /* unblock http_receive_result() if there are no open sends */
254 4894 amalysh
    if (counter_value(conndata->open_sends) == 0)
255 3519 stolj
        http_caller_signal_shutdown(conndata->http_ref);
256 4894 amalysh
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 4992 amalysh
    if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
271
        conndata->callbacks->destroy(conn);
272
    conn->data = NULL;
273 4894 amalysh
    conndata_destroy(conndata);
274
    bb_smscconn_killed();
275 3021 harrie
}
276
277
278
/*
279 4894 amalysh
 * Thread to send queued messages
280
 */
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 4992 amalysh
        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 4894 amalysh
    }
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 4992 amalysh
        if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
341
            conndata->callbacks->destroy(conn);
342
        conn->data = NULL;
343 4894 amalysh
        conndata_destroy(conndata);
344
        bb_smscconn_killed();
345
    }
346
}
347
348
/*
349 3519 stolj
 * Thread to handle finished sendings
350 3021 harrie
 */
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 3412 stolj
    /* Make sure we log into our own log-file if defined */
361
    log_thread_to(conn->log_idx);
362
363 4894 amalysh
    while(conndata->shutdown == 0 || counter_value(conndata->open_sends)) {
364 3021 harrie
365 3519 stolj
        msg = http_receive_result(conndata->http_ref, &status,
366
                                  &final_url, &headers, &body);
367 3021 harrie
368 3519 stolj
        if (msg == NULL)
369
            break;  /* they told us to die, by unlocking */
370 3021 harrie
371 4894 amalysh
        counter_decrease(conndata->open_sends);
372
        if (conndata->max_pending_sends)
373
            semaphore_up(conndata->max_pending_sends);
374
375 3519 stolj
        /* Handle various states here. */
376 3021 harrie
377 3519 stolj
        /* request failed and we are not in shutdown mode */
378 4894 amalysh
        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 3519 stolj
        else if (status == -1 && conndata->shutdown == 1) {
406 4894 amalysh
            bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
407 3519 stolj
        }
408 4894 amalysh
        /* request succeeded */
409 3519 stolj
        else {
410
            /* we received a response, so this link is considered online again */
411 4894 amalysh
            if (conn->status != SMSCCONN_ACTIVE) {
412
                mutex_lock(conn->flow_mutex);
413 3519 stolj
                conn->status = SMSCCONN_ACTIVE;
414 4399 amalysh
                time(&conn->connect_time);
415 4894 amalysh
                mutex_unlock(conn->flow_mutex);
416
                /* tell bearerbox core that we are connected again */
417
                bb_smscconn_connected(conn);
418 3519 stolj
            }
419 4992 amalysh
            conndata->callbacks->parse_reply(conn, msg, status, headers, body);
420 3519 stolj
        }
421
422
        http_destroy_headers(headers);
423
        octstr_destroy(final_url);
424
        octstr_destroy(body);
425 3021 harrie
    }
426 3541 stolj
    debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying",
427
          octstr_get_cstr(conn->id));
428 3021 harrie
    conndata->shutdown = 1;
429
430 4894 amalysh
    if (counter_value(conndata->open_sends)) {
431 3520 stolj
        warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.",
432 4894 amalysh
                octstr_get_cstr(conn->id), counter_value(conndata->open_sends));
433 3519 stolj
    }
434 3021 harrie
}
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 3519 stolj
/*----------------------------------------------------------------
452 3021 harrie
 * Kannel
453 4495 stolj
 *
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 3021 harrie
 */
491
492 3951 stolj
enum { HEX_NOT_UPPERCASE = 0 };
493 3021 harrie
494 3951 stolj
495 4992 amalysh
static int kannel_send_sms(SMSCConn *conn, Msg *sms)
496 3021 harrie
{
497
    ConnData *conndata = conn->data;
498
    Octstr *url;
499
    List *headers;
500
501
    if (!conndata->no_sep) {
502
        url = octstr_format("%S?"
503 3307 stolj
                            "username=%E&password=%E&to=%E&text=%E",
504 3021 harrie
                             conndata->send_url,
505
                             conndata->username, conndata->password,
506
                             sms->sms.receiver, sms->sms.msgdata);
507
    } else {
508 4925 stolj
        Octstr *msgdata = octstr_duplicate(sms->sms.msgdata);
509
510
        octstr_binary_to_hex(msgdata, HEX_NOT_UPPERCASE);
511 3021 harrie
        url = octstr_format("%S?"
512 3307 stolj
                            "username=%E&password=%E&to=%E&text=%S",
513 3021 harrie
                             conndata->send_url,
514
                             conndata->username, conndata->password,
515 4925 stolj
                             sms->sms.receiver, msgdata);
516
        octstr_destroy(msgdata);
517 3021 harrie
    }
518
519
    if (octstr_len(sms->sms.udhdata)) {
520
        if (!conndata->no_sep) {
521 4925 stolj
            octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
522 3021 harrie
        } else {
523 4925 stolj
            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 3021 harrie
    }
530
531
    if (!conndata->no_sender)
532
        octstr_format_append(url, "&from=%E", sms->sms.sender);
533 3698 davi
    if (sms->sms.mclass != MC_UNDEF)
534 4524 stolj
        octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
535 3698 davi
    if (!conndata->no_coding && sms->sms.coding != DC_UNDEF)
536 4524 stolj
        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 3698 davi
    if (sms->sms.mwi != MWI_UNDEF)
551 4524 stolj
        octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
552 3021 harrie
    if (sms->sms.account) /* prepend account with local username */
553 4524 stolj
        octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
554 3899 stolj
    if (sms->sms.binfo) /* prepend billing info */
555 4524 stolj
        octstr_format_append(url, "&binfo=%S", sms->sms.binfo);
556 3307 stolj
    if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */
557 4524 stolj
        octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id);
558 4963 amalysh
        if (conndata->dlr_url) {
559
                char id[UUID_STR_LEN + 1];
560
                Octstr *mid;
561 4495 stolj
562 4963 amalysh
                /* create Octstr from UUID */
563
                uuid_unparse(sms->sms.id, id);
564
                mid = octstr_create(id);
565 4495 stolj
566 4963 amalysh
                octstr_format_append(url, "&dlr-url=%E", conndata->dlr_url);
567 4495 stolj
568 4963 amalysh
                /* 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 3769 syvanen
    if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING)
579 4104 stolj
        octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask);
580 3021 harrie
581 5019 amalysh
    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 4216 amalysh
    headers = gwlist_create();
587 3541 stolj
    debug("smsc.http.kannel", 0, "HTTP[%s]: Start request",
588
          octstr_get_cstr(conn->id));
589 3068 stolj
    http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers,
590
                       NULL, 0, sms, NULL);
591 3021 harrie
592
    octstr_destroy(url);
593
    http_destroy_headers(headers);
594 4992 amalysh
595
    return 0;
596 3021 harrie
}
597
598
static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status,
599
                               List *headers, Octstr *body)
600
{
601 3541 stolj
    /* 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 4136 stolj
     * 3. an smsbox reply of partly successful sendings */
605 3706 amalysh
    if ((status == HTTP_OK || status == HTTP_ACCEPTED)
606 4495 stolj
        && (octstr_case_compare(body, octstr_imm("0: Accepted for delivery")) == 0 ||
607
            octstr_case_compare(body, octstr_imm("Sent.")) == 0 ||
608 3706 amalysh
            octstr_case_compare(body, octstr_imm("Ok.")) == 0 ||
609 3541 stolj
            octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)) {
610 4495 stolj
        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 5083 stolj
            dlr_add(conn->id, mid, msg, 0);
620 4495 stolj
621
        octstr_destroy(mid);
622
623 3706 amalysh
        bb_smscconn_sent(conn, msg, NULL);
624 3541 stolj
    } else {
625 3706 amalysh
        bb_smscconn_send_failed(conn, msg,
626
                    SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
627 3541 stolj
    }
628 3021 harrie
}
629
630 4524 stolj
631 3021 harrie
static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client,
632 4495 stolj
                               List *headers, Octstr *body, List *cgivars)
633 3021 harrie
{
634
    ConnData *conndata = conn->data;
635 4495 stolj
    Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo;
636 5066 stolj
    Octstr *dlrmid, *dlrerr;
637 4495 stolj
    Octstr *tmp_string, *retmsg;
638
    int        mclass, mwi, coding, validity, deferred, dlrmask;
639 3021 harrie
    List *reply_headers;
640
    int ret;
641 4941 afink
642 4495 stolj
    mclass = mwi = coding = validity =
643
        deferred = dlrmask = SMS_PARAM_UNDEFINED;
644 3021 harrie
645 3541 stolj
    user = http_cgi_variable(cgivars, "username");
646
    pass = http_cgi_variable(cgivars, "password");
647 3021 harrie
    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 3899 stolj
    binfo = http_cgi_variable(cgivars, "binfo");
653 4495 stolj
    dlrmid = http_cgi_variable(cgivars, "dlr-mid");
654 3021 harrie
    tmp_string = http_cgi_variable(cgivars, "flash");
655 4495 stolj
    if (tmp_string) {
656
        sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
657 3021 harrie
    }
658
    tmp_string = http_cgi_variable(cgivars, "mclass");
659 4495 stolj
    if (tmp_string) {
660
        sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
661 3021 harrie
    }
662
    tmp_string = http_cgi_variable(cgivars, "mwi");
663 4495 stolj
    if (tmp_string) {
664
        sscanf(octstr_get_cstr(tmp_string),"%d", &mwi);
665 3021 harrie
    }
666
    tmp_string = http_cgi_variable(cgivars, "coding");
667 4495 stolj
    if (tmp_string) {
668
        sscanf(octstr_get_cstr(tmp_string),"%d", &coding);
669 3021 harrie
    }
670
    tmp_string = http_cgi_variable(cgivars, "validity");
671 4495 stolj
    if (tmp_string) {
672
        sscanf(octstr_get_cstr(tmp_string),"%d", &validity);
673 3021 harrie
    }
674
    tmp_string = http_cgi_variable(cgivars, "deferred");
675 4495 stolj
    if (tmp_string) {
676
        sscanf(octstr_get_cstr(tmp_string),"%d", &deferred);
677 3021 harrie
    }
678 4495 stolj
    tmp_string = http_cgi_variable(cgivars, "dlr-mask");
679
    if (tmp_string) {
680
        sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask);
681
    }
682 4964 amalysh
    dlrerr = http_cgi_variable(cgivars, "dlr-err");
683
684 3541 stolj
    debug("smsc.http.kannel", 0, "HTTP[%s]: Received an HTTP request",
685
          octstr_get_cstr(conn->id));
686 3021 harrie
687 3519 stolj
    if (user == NULL || pass == NULL ||
688
            octstr_compare(user, conndata->username) != 0 ||
689
            octstr_compare(pass, conndata->password) != 0) {
690 3021 harrie
691 3541 stolj
        error(0, "HTTP[%s]: Authorization failure",
692
              octstr_get_cstr(conn->id));
693
        retmsg = octstr_create("Authorization failed for sendsms");
694 4964 amalysh
    } else if (dlrmask != 0 && dlrmid != NULL) {
695 4495 stolj
        /* 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 4834 amalysh
            dlrmask, 0);
702 4495 stolj
703
        if (dlrmsg != NULL) {
704
            dlrmsg->sms.sms_type = report_mo;
705 4953 stolj
            dlrmsg->sms.msgdata = octstr_duplicate(text);
706
            dlrmsg->sms.account = octstr_duplicate(conndata->username);
707 4495 stolj
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 4941 afink
711 4964 amalysh
            if (dlrerr != NULL) {
712
                /* pass errorcode as is */
713
                    if (dlrmsg->sms.meta_data == NULL)
714
                            dlrmsg->sms.meta_data = octstr_create("");
715 4944 afink
716 4964 amalysh
                meta_data_set_value(dlrmsg->sms.meta_data, METADATA_DLR_GROUP,
717
                                    octstr_imm(METADATA_DLR_GROUP_ERRORCODE), dlrerr, 1);
718 4941 afink
            }
719 4948 stolj
720 4495 stolj
            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 3021 harrie
    else if (from == NULL || to == NULL || text == NULL) {
734
735 3541 stolj
        error(0, "HTTP[%s]: Insufficient args",
736
              octstr_get_cstr(conn->id));
737
        retmsg = octstr_create("Insufficient args, rejected");
738 3021 harrie
    }
739 3951 stolj
    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 3021 harrie
    else {
750 4495 stolj
        /* we got a normal MO SMS */
751
        Msg *msg;
752
        msg = msg_create(sms);
753 3951 stolj
754 4495 stolj
        debug("smsc.http.kannel", 0, "HTTP[%s]: Constructing new SMS",
755
              octstr_get_cstr(conn->id));
756 3021 harrie
757 4495 stolj
        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 3021 harrie
763 4495 stolj
        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 5020 amalysh
        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 4495 stolj
        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 3021 harrie
    }
778 4495 stolj
779 4216 amalysh
    reply_headers = gwlist_create();
780 3021 harrie
    http_header_add(reply_headers, "Content-Type", "text/plain");
781 3541 stolj
    debug("smsc.http.kannel", 0, "HTTP[%s]: Sending reply",
782
          octstr_get_cstr(conn->id));
783 3951 stolj
    http_send_reply(client, HTTP_ACCEPTED, reply_headers, retmsg);
784 3021 harrie
785
    octstr_destroy(retmsg);
786
    http_destroy_headers(reply_headers);
787
}
788
789 4993 amalysh
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 3021 harrie
795
/*-----------------------------------------------------------------
796
 * functions to implement various smscconn operations
797
 */
798
799
static int httpsmsc_send(SMSCConn *conn, Msg *msg)
800
{
801
    ConnData *conndata = conn->data;
802 4894 amalysh
    Msg *sms;
803 3021 harrie
804 3638 stolj
805 4894 amalysh
    /* don't crash if no send_sms handle defined */
806 4992 amalysh
    if (!conndata || !conndata->callbacks->send_sms)
807 4894 amalysh
        return -1;
808
809
    sms = msg_duplicate(msg);
810 4616 stolj
    /* convert character encoding if required */
811 4887 amalysh
    if (msg->sms.coding == DC_7BIT && conndata->alt_charset &&
812 4883 stolj
        charset_convert(sms->sms.msgdata, DEFAULT_CHARSET,
813 4894 amalysh
                        octstr_get_cstr(conndata->alt_charset)) != 0) {
814 4883 stolj
        error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.",
815 4894 amalysh
              DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset));
816
    }
817 4616 stolj
818 4894 amalysh
    gwlist_produce(conndata->msg_to_send, sms);
819 3021 harrie
820
    return 0;
821
}
822
823
824
static long httpsmsc_queued(SMSCConn *conn)
825
{
826
    ConnData *conndata = conn->data;
827 3519 stolj
828
    return (conndata ? (conn->status != SMSCCONN_DEAD ?
829 4894 amalysh
            counter_value(conndata->open_sends) : 0) : 0);
830 3021 harrie
}
831
832
833
static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
834
{
835
    ConnData *conndata = conn->data;
836
837 4894 amalysh
    if (conndata == NULL)
838
        return 0;
839
840 3541 stolj
    debug("httpsmsc_shutdown", 0, "HTTP[%s]: Shutting down",
841
          octstr_get_cstr(conn->id));
842 4894 amalysh
843
    mutex_lock(conn->flow_mutex);
844 3021 harrie
    conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
845 4894 amalysh
846 3021 harrie
    conndata->shutdown = 1;
847
848 4894 amalysh
    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 3021 harrie
    return 0;
858
}
859
860
861 4992 amalysh
#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
868 3021 harrie
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 4992 amalysh
    long max_ps;
874 3021 harrie
875 4992 amalysh
    if ((type = cfg_get(cfg, octstr_imm("system-type"))) == NULL) {
876
        error(0, "HTTP[%s]: 'system-type' missing in smsc 'http' record.",
877 3541 stolj
              octstr_get_cstr(conn->id));
878 3519 stolj
        octstr_destroy(type);
879
        return -1;
880 3021 harrie
    }
881 4992 amalysh
882 3021 harrie
    conndata = gw_malloc(sizeof(ConnData));
883 4992 amalysh
    /* reset conndata */
884
    memset(conndata, 0, sizeof(ConnData));
885
886
    conn->data = conndata;
887 3021 harrie
    conndata->http_ref = NULL;
888 4992 amalysh
    conndata->data = NULL;
889 3021 harrie
890 4992 amalysh
    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 3021 harrie
    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 4382 amalysh
    conndata->system_id = cfg_get(cfg, octstr_imm("system-id"));
901 3021 harrie
    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 4161 stolj
    conndata->proxy = cfg_get(cfg, octstr_imm("system-id"));
905 4992 amalysh
    cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl"));
906
    conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url"));
907 4616 stolj
    conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset"));
908 3021 harrie
909 4894 amalysh
    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 3021 harrie
    if (conndata->send_url == NULL)
919 3541 stolj
        panic(0, "HTTP[%s]: Sending not allowed. No 'send-url' specified.",
920
              octstr_get_cstr(conn->id));
921 3021 harrie
922 3519 stolj
    if (octstr_case_compare(type, octstr_imm("kannel")) == 0) {
923
        if (conndata->username == NULL || conndata->password == NULL) {
924 3541 stolj
            error(0, "HTTP[%s]: 'username' and 'password' required for Kannel http smsc",
925
                  octstr_get_cstr(conn->id));
926 3519 stolj
            goto error;
927
        }
928 4992 amalysh
        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 3021 harrie
    }
940
    /*
941
     * ADD NEW HTTP SMSC TYPES HERE
942
     */
943
    else {
944 4894 amalysh
        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 4992 amalysh
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 4894 amalysh
    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 3021 harrie
959 4894 amalysh
    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 3021 harrie
    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 4894 amalysh
    /* 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 3021 harrie
985 4894 amalysh
    /* 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 3541 stolj
    info(0, "HTTP[%s]: Initiated and ready", octstr_get_cstr(conn->id));
999 4894 amalysh
1000 3021 harrie
    octstr_destroy(type);
1001
    return 0;
1002
1003
error:
1004 4894 amalysh
    error(0, "HTTP[%s]: Failed to create HTTP SMSC connection",
1005 3541 stolj
          octstr_get_cstr(conn->id));
1006 3021 harrie
1007 4992 amalysh
    if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL)
1008
        conndata->callbacks->destroy(conn);
1009 3021 harrie
    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
}