00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include <sys/types.h>
00067 #include <sys/socket.h>
00068 #include <unistd.h>
00069 #include <errno.h>
00070 #include <time.h>
00071 #include <limits.h>
00072
00073 #include "gwlib/gwlib.h"
00074 #include "smscconn.h"
00075 #include "smscconn_p.h"
00076 #include "bb_smscconn_cb.h"
00077 #include "msg.h"
00078 #include "sms.h"
00079 #include "dlr.h"
00080
00081 typedef struct privdata {
00082 List *outgoing_queue;
00083 long connection_thread;
00084 int shutdown;
00085 int listening_socket;
00086 int port;
00087 Octstr *allow_ip, *deny_ip;
00088 } PrivData;
00089
00090
00091 static int fake_open_connection(SMSCConn *conn, PrivData *privdata)
00092 {
00093 int s;
00094
00095 if ((s = make_server_socket(privdata->port, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) {
00096 error(0, "smsc_fake: could not create listening socket in port %d",
00097 privdata->port);
00098 return -1;
00099 }
00100 if (socket_set_blocking(s, 0) == -1) {
00101 error(0, "smsc_fake: couldn't make listening socket port %d non-blocking",
00102 privdata->port);
00103 return -1;
00104 }
00105 privdata->listening_socket = s;
00106 return 0;
00107 }
00108
00109
00110 static int sms_to_client(Connection *client, Msg *msg)
00111 {
00112 Octstr *line;
00113 Octstr *msgdata = NULL;
00114 char *contents;
00115 int len;
00116
00117 debug("bb.sms", 0, "smsc_fake: sending message to client");
00118
00119
00120 line = octstr_duplicate(msg->sms.sender);
00121 octstr_append_char(line, ' ');
00122 octstr_append(line, msg->sms.receiver);
00123 if (octstr_len(msg->sms.udhdata)) {
00124 octstr_append(line, octstr_imm(" udh "));
00125 msgdata = octstr_duplicate(msg->sms.udhdata);
00126 octstr_url_encode(msgdata);
00127 octstr_append(line, msgdata);
00128 octstr_destroy(msgdata);
00129 octstr_append_char(line, ' ');
00130 msgdata = octstr_duplicate(msg->sms.msgdata);
00131 octstr_url_encode(msgdata);
00132 octstr_append(line, msgdata);
00133 } else {
00134 contents = octstr_get_cstr(msg->sms.msgdata);
00135 len = octstr_len(msg->sms.msgdata);
00136 while (len > 0) {
00137 len--;
00138 if (contents[len] < 32 || contents[len] > 126) {
00139 octstr_append(line, octstr_imm(" data "));
00140 msgdata = octstr_duplicate(msg->sms.msgdata);
00141 octstr_url_encode(msgdata);
00142 octstr_append(line, msgdata);
00143 goto notelse;
00144 }
00145 }
00146 octstr_append(line, octstr_imm(" text "));
00147 octstr_append(line, msg->sms.msgdata);
00148 }
00149
00150 notelse:
00151 octstr_append_char(line, 10);
00152
00153 if (conn_write(client, line) == -1) {
00154 octstr_destroy(msgdata);
00155 octstr_destroy(line);
00156 return -1;
00157 }
00158 octstr_destroy(msgdata);
00159 octstr_destroy(line);
00160 return 1;
00161 }
00162
00163
00164 static void msg_to_bb(SMSCConn *conn, Octstr *line)
00165 {
00166 long p, p2;
00167 Msg *msg;
00168 Octstr *type = NULL;
00169
00170 msg = msg_create(sms);
00171 p = octstr_search_char(line, ' ', 0);
00172 if (p == -1)
00173 goto error;
00174 msg->sms.sender = octstr_copy(line, 0, p);
00175 p2 = octstr_search_char(line, ' ', p + 1);
00176 if (p2 == -1)
00177 goto error;
00178 msg->sms.receiver = octstr_copy(line, p + 1, p2 - p - 1);
00179 p = octstr_search_char(line, ' ', p2 + 1);
00180 if (p == -1)
00181 goto error;
00182 type = octstr_copy(line, p2 + 1, p - p2 - 1);
00183 if (!octstr_compare(type, octstr_imm("text")))
00184 msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX);
00185 else if (!octstr_compare(type, octstr_imm("data"))) {
00186 msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX);
00187 if (octstr_url_decode(msg->sms.msgdata) == -1)
00188 warning(0, "smsc_fake: urlcoded data from client looks malformed");
00189 }
00190 else if (!octstr_compare(type, octstr_imm("route"))) {
00191 p2 = octstr_search_char(line, ' ', p + 1);
00192 if (p2 == -1)
00193 goto error;
00194 msg->sms.boxc_id = octstr_copy(line, p + 1, p2 - p - 1);
00195 msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX);
00196 }
00197 else if (!octstr_compare(type, octstr_imm("udh"))) {
00198 p2 = octstr_search_char(line, ' ', p + 1);
00199 if (p2 == -1)
00200 goto error;
00201 msg->sms.udhdata = octstr_copy(line, p + 1, p2 - p - 1);
00202 msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX);
00203 if (msg->sms.coding == DC_UNDEF)
00204 msg->sms.coding = DC_8BIT;;
00205 if (octstr_url_decode(msg->sms.msgdata) == -1 ||
00206 octstr_url_decode(msg->sms.udhdata) == -1)
00207 warning(0, "smsc_fake: urlcoded data from client looks malformed");
00208 }
00209 else if (!octstr_compare(type, octstr_imm("dlr-mask"))) {
00210 Octstr *tmp;
00211 p2 = octstr_search_char(line, ' ', p + 1);
00212 if (p2 == -1)
00213 goto error;
00214 tmp = octstr_copy(line, p + 1, p2 - p - 1);
00215 msg->sms.dlr_mask = atoi(octstr_get_cstr(tmp));
00216 octstr_destroy(tmp);
00217 msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX);
00218 }
00219 else
00220 goto error;
00221 octstr_destroy(line);
00222 octstr_destroy(type);
00223 time(&msg->sms.time);
00224 msg->sms.smsc_id = octstr_duplicate(conn->id);
00225
00226 debug("bb.sms", 0, "smsc_fake: new message received");
00227
00228 bb_smscconn_receive(conn, msg);
00229 return;
00230 error:
00231 warning(0, "smsc_fake: invalid message syntax from client, ignored");
00232 msg_destroy(msg);
00233 octstr_destroy(line);
00234 octstr_destroy(type);
00235 return;
00236 }
00237
00238
00239 static void main_connection_loop(SMSCConn *conn, Connection *client)
00240 {
00241 PrivData *privdata = conn->data;
00242 Octstr *line;
00243 Msg *msg;
00244 double delay = 0;
00245
00246 if (conn->throughput > 0) {
00247 delay = 1.0 / conn->throughput;
00248 }
00249
00250 while (1) {
00251 while (!conn->is_stopped && !privdata->shutdown &&
00252 (line = conn_read_line(client)))
00253 msg_to_bb(conn, line);
00254 if (conn_error(client))
00255 goto error;
00256 if (conn_eof(client))
00257 goto eof;
00258
00259
00260
00261
00262
00263
00264
00265
00266 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00267
00268
00269 if (sms_to_client(client, msg) == 1) {
00270 Msg *copy = msg_duplicate(msg);
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 bb_smscconn_sent(conn, msg, NULL);
00281
00282
00283 if (DLR_IS_SUCCESS_OR_FAIL(copy->sms.dlr_mask)) {
00284 Msg *dlrmsg;
00285 Octstr *tmp;
00286 int dlrstat = DLR_SUCCESS;
00287 char id[UUID_STR_LEN + 1];
00288
00289 uuid_unparse(copy->sms.id, id);
00290 tmp = octstr_create(id);
00291 dlrmsg = dlr_find(conn->id,
00292 tmp,
00293 copy->sms.receiver,
00294 dlrstat);
00295 if (dlrmsg != NULL) {
00296
00297 bb_smscconn_receive(conn, dlrmsg);
00298 } else {
00299 error(0,"smsc_fale: got DLR but could not find message or was not interested in it");
00300 }
00301 octstr_destroy(tmp);
00302 }
00303 msg_destroy(copy);
00304
00305 } else {
00306 bb_smscconn_send_failed(conn, msg,
00307 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
00308 goto error;
00309 }
00310
00311
00312 if (conn->throughput > 0) {
00313 gwthread_sleep(delay);
00314 }
00315 }
00316 if (privdata->shutdown) {
00317 debug("bb.sms", 0, "smsc_fake shutting down, closing client socket");
00318 conn_destroy(client);
00319 return;
00320 }
00321 conn_wait(client, -1);
00322 if (conn_error(client))
00323 goto error;
00324 if (conn_eof(client))
00325 goto eof;
00326 }
00327 error:
00328 info(0, "IO error to fakesmsc client. Closing connection.");
00329 conn_destroy(client);
00330 return;
00331 eof:
00332 info(0, "EOF from fakesmsc client. Closing connection.");
00333 conn_destroy(client);
00334 return;
00335 }
00336
00337
00338 static void fake_listener(void *arg)
00339 {
00340 SMSCConn *conn = arg;
00341 PrivData *privdata = conn->data;
00342 struct sockaddr_in client_addr;
00343 socklen_t client_addr_len;
00344 Octstr *ip;
00345 Connection *client;
00346 int s, ret;
00347 Msg *msg;
00348
00349
00350 log_thread_to(conn->log_idx);
00351
00352 while (1) {
00353 client_addr_len = sizeof(client_addr);
00354 ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
00355 if (ret == -1) {
00356 if (errno == EINTR)
00357 continue;
00358 error(0, "Poll for fakesmsc connections failed, shutting down");
00359 break;
00360 }
00361 if (privdata->shutdown)
00362 break;
00363 if (ret == 0)
00364
00365
00366
00367
00368 continue;
00369 s = accept(privdata->listening_socket, (struct sockaddr *)&client_addr,
00370 &client_addr_len);
00371 if (s == -1) {
00372 warning(errno, "fake_listener: accept() failed, retrying...");
00373 continue;
00374 }
00375 ip = host_ip(client_addr);
00376 if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
00377 info(0, "Fakesmsc connection tried from denied host <%s>,"
00378 " disconnected", octstr_get_cstr(ip));
00379 octstr_destroy(ip);
00380 close(s);
00381 continue;
00382 }
00383 client = conn_wrap_fd(s, 0);
00384 if (client == NULL) {
00385 error(0, "fake_listener: conn_wrap_fd failed on accept()ed fd");
00386 octstr_destroy(ip);
00387 close(s);
00388 continue;
00389 }
00390 conn_claim(client);
00391 info(0, "Fakesmsc client connected from %s", octstr_get_cstr(ip));
00392 octstr_destroy(ip);
00393 mutex_lock(conn->flow_mutex);
00394 conn->status = SMSCCONN_ACTIVE;
00395 conn->connect_time = time(NULL);
00396 mutex_unlock(conn->flow_mutex);
00397 bb_smscconn_connected(conn);
00398
00399 main_connection_loop(conn, client);
00400
00401 if (privdata->shutdown)
00402 break;
00403 mutex_lock(conn->flow_mutex);
00404 conn->status = SMSCCONN_RECONNECTING;
00405 mutex_unlock(conn->flow_mutex);
00406 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00407 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
00408 }
00409 }
00410 if (close(privdata->listening_socket) == -1)
00411 warning(errno, "smsc_fake: couldn't close listening socket at shutdown");
00412 mutex_lock(conn->flow_mutex);
00413
00414 conn->status = SMSCCONN_DEAD;
00415
00416 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00417 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
00418 }
00419 gwlist_destroy(privdata->outgoing_queue, NULL);
00420 octstr_destroy(privdata->allow_ip);
00421 octstr_destroy(privdata->deny_ip);
00422 gw_free(privdata);
00423 conn->data = NULL;
00424
00425 mutex_unlock(conn->flow_mutex);
00426 debug("bb.sms", 0, "smsc_fake connection has completed shutdown.");
00427 bb_smscconn_killed();
00428 }
00429
00430
00431 static int add_msg_cb(SMSCConn *conn, Msg *sms)
00432 {
00433 PrivData *privdata = conn->data;
00434 Msg *copy;
00435
00436 copy = msg_duplicate(sms);
00437
00438
00439
00440
00441
00442
00443
00444 if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask)) {
00445 Octstr *tmp;
00446 char id[UUID_STR_LEN + 1];
00447 uuid_unparse(sms->sms.id, id);
00448 tmp = octstr_format("%s", id);
00449 dlr_add(conn->id, tmp, sms);
00450 octstr_destroy(tmp);
00451 }
00452 gwlist_produce(privdata->outgoing_queue, copy);
00453
00454 gwthread_wakeup(privdata->connection_thread);
00455
00456 return 0;
00457 }
00458
00459
00460 static int shutdown_cb(SMSCConn *conn, int finish_sending)
00461 {
00462 PrivData *privdata = conn->data;
00463
00464 debug("bb.sms", 0, "Shutting down SMSCConn FAKE, %s",
00465 finish_sending ? "slow" : "instant");
00466
00467
00468
00469
00470
00471 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
00472 privdata->shutdown = 1;
00473
00474
00475
00476
00477
00478 if (finish_sending == 0) {
00479 Msg *msg;
00480 while((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00481 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
00482 }
00483 }
00484
00485 gwthread_wakeup(privdata->connection_thread);
00486 return 0;
00487 }
00488
00489
00490 static void start_cb(SMSCConn *conn)
00491 {
00492 PrivData *privdata = conn->data;
00493
00494
00495 gwthread_wakeup(privdata->connection_thread);
00496 debug("bb.sms", 0, "smsc_fake: start called");
00497 }
00498
00499
00500 static long queued_cb(SMSCConn *conn)
00501 {
00502 PrivData *privdata = conn->data;
00503 long ret;
00504
00505 ret = (privdata ? gwlist_len(privdata->outgoing_queue) : 0);
00506
00507
00508
00509 conn->load = ret;
00510 return ret;
00511 }
00512
00513
00514 int smsc_fake_create(SMSCConn *conn, CfgGroup *cfg)
00515 {
00516 PrivData *privdata = NULL;
00517 Octstr *allow_ip, *deny_ip;
00518 long portno;
00519
00520 if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
00521 portno = 0;
00522 allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
00523 if (allow_ip)
00524 deny_ip = octstr_create("*.*.*.*");
00525 else
00526 deny_ip = NULL;
00527
00528 if (portno == 0) {
00529 error(0, "'port' invalid in 'fake' record.");
00530 goto error;
00531 }
00532 privdata = gw_malloc(sizeof(PrivData));
00533 privdata->listening_socket = -1;
00534
00535 privdata->port = portno;
00536 privdata->allow_ip = allow_ip;
00537 privdata->deny_ip = deny_ip;
00538
00539 if (fake_open_connection(conn, privdata) < 0) {
00540 gw_free(privdata);
00541 privdata = NULL;
00542 goto error;
00543 }
00544
00545 conn->data = privdata;
00546
00547 conn->name = octstr_format("FAKE:%d", privdata->port);
00548
00549 privdata->outgoing_queue = gwlist_create();
00550 privdata->shutdown = 0;
00551
00552 conn->status = SMSCCONN_CONNECTING;
00553 conn->connect_time = time(NULL);
00554
00555 if ((privdata->connection_thread = gwthread_create(fake_listener, conn)) == -1)
00556 goto error;
00557
00558 conn->shutdown = shutdown_cb;
00559 conn->queued = queued_cb;
00560 conn->start_conn = start_cb;
00561 conn->send_msg = add_msg_cb;
00562
00563 return 0;
00564
00565 error:
00566 error(0, "Failed to create fake smsc connection");
00567 if (privdata != NULL) {
00568 gwlist_destroy(privdata->outgoing_queue, NULL);
00569 if (close(privdata->listening_socket == -1)) {
00570 error(errno, "smsc_fake: closing listening socket port %d failed",
00571 privdata->listening_socket);
00572 }
00573 }
00574 gw_free(privdata);
00575 octstr_destroy(allow_ip);
00576 octstr_destroy(deny_ip);
00577 conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
00578 conn->status = SMSCCONN_DEAD;
00579 return -1;
00580 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.