#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <errno.h>#include <time.h>#include <limits.h>#include "gwlib/gwlib.h"#include "smscconn.h"#include "smscconn_p.h"#include "bb_smscconn_cb.h"#include "msg.h"#include "sms.h"#include "dlr.h"Include dependency graph for smsc_cgw.c:

Go to the source code of this file.
|
|
Definition at line 123 of file smsc_cgw.c. Referenced by smsc_cgw_create(). |
|
|
Definition at line 124 of file smsc_cgw.c. Referenced by cgw_encode_msg(), and cgwop_tostr(). |
|
|
Definition at line 135 of file smsc_cgw.c. Referenced by cgw_handle_op(). |
|
|
Definition at line 134 of file smsc_cgw.c. Referenced by cgw_handle_op(). |
|
|
Definition at line 136 of file smsc_cgw.c. Referenced by cgw_handle_op(). |
|
|
Definition at line 132 of file smsc_cgw.c. Referenced by cgw_handle_op(), and msg_to_cgwop(). |
|
|
Definition at line 131 of file smsc_cgw.c. |
|
|
Definition at line 133 of file smsc_cgw.c. Referenced by cgw_handle_op(). |
|
|
Definition at line 137 of file smsc_cgw.c. Referenced by cgw_handle_op(). |
|
|
Definition at line 125 of file smsc_cgw.c. |
|
|
Definition at line 127 of file smsc_cgw.c. Referenced by cgwop_create(). |
|
|
||||||||||||
|
Definition at line 549 of file smsc_cgw.c. References smscconn::data, gwlist_produce(), gwthread_wakeup(), msg_duplicate(), privdata::outgoing_queue, PrivData, privdata::sender_thread, sms, and SMSCConn. 00550 {
00551 PrivData *privdata = conn->data;
00552 Msg *copy;
00553
00554 copy = msg_duplicate(sms);
00555 gwlist_produce(privdata->outgoing_queue, copy);
00556 gwthread_wakeup(privdata->sender_thread);
00557
00558 return 0;
00559 }
|
Here is the call graph for this function:

|
|
Definition at line 787 of file smsc_cgw.c. References privdata::check_time, gwlist_produce(), privdata::outgoing_queue, PrivData, privdata::sendmsg, privdata::sendtime, privdata::unacked, privdata::waitack, and warning(). Referenced by cgw_sender(). 00788 {
00789 time_t current_time;
00790 int i;
00791
00792 current_time = time(NULL);
00793 if (privdata->unacked && (current_time > privdata->check_time + 30)) {
00794 privdata->check_time = current_time;
00795 for (i = 0; i < CGW_TRN_MAX; i++)
00796 if (privdata->sendtime[i] && privdata->sendtime[i] < (current_time - privdata->waitack)) {
00797 privdata->sendtime[i] = 0;
00798 privdata->unacked--;
00799 warning(0, "smsc_cgw: received neither OK nor ERR for message %d "
00800 "in %d seconds, resending message", i, privdata->waitack);
00801 gwlist_produce(privdata->outgoing_queue, privdata->sendmsg[i]);
00802 }
00803 }
00804 }
|
Here is the call graph for this function:

|
|
Definition at line 354 of file smsc_cgw.c. References octstr_delete(), octstr_imm(), octstr_insert(), and octstr_search(). Referenced by cgw_handle_op(). 00355 {
00356 int i;
00357
00358 /* make \n -> linefeed */
00359 while ((i = octstr_search(str, octstr_imm("\\n"), 0)) != -1) {
00360 octstr_delete(str, i, 2); /* delete "\n" str */
00361 octstr_insert(str, octstr_imm("\n"), i);
00362 }
00363 /* make \r -> carriage return */
00364 while ((i = octstr_search(str, octstr_imm("\\r"), 0)) != -1) {
00365 octstr_delete(str, i, 2); /* delete EOL char */
00366 octstr_insert(str, octstr_imm("\r"), i);
00367 }
00368 /* remove double backslashes */
00369 while ((i = octstr_search(str, octstr_imm("\\\\"), 0)) != -1) {
00370 octstr_delete(str, i, 1);
00371 }
00372
00373 return str;
00374 }
|
Here is the call graph for this function:

|
|
Definition at line 312 of file smsc_cgw.c. References CGW_EOL, octstr_delete(), octstr_imm(), octstr_insert(), octstr_insert_data(), octstr_len(), and octstr_search_char(). Referenced by msg_to_cgwop(). 00313 {
00314 int i;
00315 char esc = 27;
00316 char e = 'e';
00317
00318 /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message
00319 length is under 160 chars (the checking could probably be done better) */
00320
00321 while ((i = octstr_search_char(str, 0x80, 0)) != -1) {
00322 octstr_delete(str, i, 1); /* delete Euro char */
00323 if (octstr_len(str) < 160) {
00324 octstr_insert_data(str, i, &esc, 1); /* replace with ESC + e */
00325 octstr_insert_data(str, i+1, &e, 1);
00326 } else {
00327 octstr_insert_data(str, i, &e, 1); /* no room for ESC + e, just replace with an e */
00328 }
00329 }
00330
00331
00332 /* Escape backslash characters */
00333 while ((i = octstr_search_char(str, '\\', 0)) != -1) {
00334 octstr_insert(str, octstr_imm("\\"), i);
00335 }
00336 /* Remove Line Feed characters */
00337 while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) {
00338 octstr_delete(str, i, 1); /* delete EOL char */
00339 octstr_insert(str, octstr_imm("\\n"), i);
00340 }
00341 /* Remove Carriage return characters */
00342 while ((i = octstr_search_char(str, 13, 0)) != -1) {
00343 octstr_delete(str, i, 1); /* delete EOL char */
00344 octstr_insert(str, octstr_imm("\\r"), i);
00345 }
00346
00347 return str;
00348 }
|
Here is the call graph for this function:

|
||||||||||||||||
|
Definition at line 1067 of file smsc_cgw.c. References bb_smscconn_receive(), bb_smscconn_send_failed(), bb_smscconn_sent(), cgw_decode_msg(), CGW_OP_DELIVERY, CGW_OP_ERR, CGW_OP_HELLO, CGW_OP_MSG, CGW_OP_OK, CGW_OP_STATUS, cgwop_add(), cgwop_create(), cgwop_destroy(), cgwop_get(), cgwop_send(), smscconn::data, privdata::dlr, dlr_add(), DLR_BUFFERED, DLR_FAIL, dlr_find(), DLR_IS_ENABLED_DEVICE, DLR_SUCCESS, smscconn::id, info(), msg_create, octstr_append(), octstr_append_char(), octstr_append_decimal(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_parse_long(), cgwop::op, PrivData, privdata::sendmsg, privdata::sendtime, sms, SMSCConn, SMSCCONN_FAILED_REJECTED, and privdata::unacked. Referenced by cgw_receiver(), and cgw_wait_command(). 01068 {
01069 PrivData *privdata = conn->data;
01070 Msg *msg = NULL;
01071 Octstr *from, *app, *sid, *to, *msgtype, *msgdata; /* for messages */
01072 Octstr *msid, *status, *txt; /* delivery reports */
01073 Octstr *clid; /* for acks */
01074 struct cgwop *reply = NULL;
01075 long trn, stat; /* transaction number for ack */
01076 Msg *dlrmsg = NULL, *origmsg = NULL;
01077 Octstr *ts;
01078
01079 if (cgwop == NULL) return 0;
01080
01081 from = cgwop_get(cgwop, octstr_imm("from"));
01082 app = cgwop_get(cgwop, octstr_imm("app"));
01083 sid = cgwop_get(cgwop, octstr_imm("session-id"));
01084 to = cgwop_get(cgwop, octstr_imm("to"));
01085 msgtype = cgwop_get(cgwop, octstr_imm("type"));
01086 msgdata = cgwop_get(cgwop, octstr_imm("msg"));
01087 txt = cgwop_get(cgwop, octstr_imm("txt"));
01088
01089 msid = cgwop_get(cgwop, octstr_imm("msid"));
01090 status = cgwop_get(cgwop, octstr_imm("status"));
01091 clid = cgwop_get(cgwop, octstr_imm("client-id"));
01092
01093 if (clid != NULL)
01094 {
01095 octstr_parse_long(&trn, clid, 0, 10);
01096 if ((trn < 0) || (trn >= CGW_TRN_MAX)) { /* invalid transaction number */
01097 info(0, "cgw: Invalid transaction number: %d", (int) trn);
01098 trn = -1;
01099 return 0;
01100 }
01101 }
01102
01103 switch (cgwop->op)
01104 {
01105 case CGW_OP_MSG:
01106 msg = msg_create(sms);
01107 time(&msg->sms.time);
01108 msg->sms.msgdata = cgw_decode_msg(octstr_duplicate(msgdata));
01109 msg->sms.sender = octstr_duplicate(from);
01110 msg->sms.receiver = octstr_duplicate(to);
01111 msg->sms.smsc_id = octstr_duplicate(conn->id);
01112 bb_smscconn_receive(conn, msg);
01113
01114 reply = cgwop_create(CGW_OP_OK, -1);
01115 cgwop_add(reply, octstr_imm("session-id"), sid);
01116 cgwop_send(server, reply); /* send reply */
01117
01118 cgwop_destroy(reply);
01119
01120 break;
01121
01122 case CGW_OP_DELIVERY:
01123 if (privdata->dlr[trn]) {
01124
01125 octstr_parse_long(&stat, status, 0, 10);
01126 origmsg = privdata->sendmsg[trn];
01127
01128 if (origmsg == NULL) break;
01129
01130 ts = octstr_create("");
01131 octstr_append(ts, conn->id);
01132 octstr_append_char(ts, '-');
01133 octstr_append_decimal(ts, trn);
01134
01135 switch (stat) {
01136 case 0: /* delivered */
01137 dlrmsg = dlr_find(conn->id,
01138 ts, /* timestamp */
01139 msid, /* destination */
01140 DLR_SUCCESS);
01141 break;
01142 case 1: /* buffered */
01143 dlrmsg = dlr_find(conn->id,
01144 ts, /* timestamp */
01145 msid, /* destination */
01146 DLR_BUFFERED);
01147 break;
01148 case 2: /* not delivered */
01149 dlrmsg = dlr_find(conn->id,
01150 ts, /* timestamp */
01151 msid, /* destination */
01152 DLR_FAIL);
01153 break;
01154 }
01155
01156 octstr_destroy(ts);
01157 if (dlrmsg != NULL) {
01158 dlrmsg->sms.msgdata = octstr_duplicate(txt);
01159 bb_smscconn_receive(conn, dlrmsg);
01160 }
01161 }
01162
01163 break;
01164
01165 case CGW_OP_OK:
01166 if (trn == -1) break; /* invalid transaction number */
01167 /* info(0, "cgw: Got ACK: %s", octstr_get_cstr(clid)); */
01168
01169 privdata->sendtime[trn] = 0;
01170 privdata->unacked--;
01171
01172 /* add delivery notification request if wanted */
01173
01174 msg = privdata->sendmsg[trn];
01175
01176 if (msg && msg->sms.dlr_url && DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) {
01177 Octstr *ts;
01178
01179 ts = octstr_create("");
01180 octstr_append(ts, conn->id);
01181 octstr_append_char(ts, '-');
01182 octstr_append_decimal(ts, trn);
01183
01184 dlr_add(conn->id, ts, msg);
01185
01186 octstr_destroy(ts);
01187 privdata->dlr[trn] = 1;
01188 } else {
01189 privdata->dlr[trn] = 0;
01190 }
01191
01192 /* mark as successfully sent */
01193 bb_smscconn_sent(conn, msg, NULL);
01194
01195 break;
01196
01197 case CGW_OP_STATUS:
01198 info(0, "CGW: Warning: Got session status");
01199 /* op:status messages are sent by ProviderServer to tell if there are problems with
01200 the session status. These are not wanted, and should never occur, as the delivery is
01201 cancelled, and no end-user billing is done. */
01202
01203 break;
01204
01205
01206 case CGW_OP_HELLO:
01207 info(0, "CGW: Server said: %s", octstr_get_cstr(cgwop_get(cgwop, octstr_imm("hello"))));
01208 break;
01209
01210 case CGW_OP_ERR:
01211 if (trn == -1) break; /* invalid transaction number */
01212
01213 info(0, "CGW: Received error: %s", octstr_get_cstr(txt));
01214
01215 privdata->sendtime[trn] = 0;
01216 privdata->unacked--;
01217
01218 bb_smscconn_send_failed(conn, privdata->sendmsg[trn],
01219 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01220
01221 break;
01222
01223 default:
01224 info(0, "cgw: Unknown operation: %d", cgwop->op);
01225 return 0;
01226 }
01227
01228 return 1;
01229 }
|
Here is the call graph for this function:

|
|
Definition at line 967 of file smsc_cgw.c. References privdata::allow_ip, cgw_receiver(), conn_claim(), conn_destroy(), conn_wrap_fd(), smscconn::data, privdata::deny_ip, error(), gwthread_pollfd(), gwthread_wakeup(), host_ip(), info(), is_allowed_ip(), privdata::listening_socket, smscconn::log_idx, log_thread_to(), octstr_destroy(), octstr_get_cstr, POLLIN, PrivData, privdata::sender_thread, privdata::shutdown, SMSCConn, and warning(). Referenced by smsc_cgw_create(). 00968 {
00969 SMSCConn *conn = arg;
00970 PrivData *privdata = conn->data;
00971 struct sockaddr_in server_addr;
00972 socklen_t server_addr_len;
00973 Octstr *ip;
00974 Connection *server;
00975 int s, ret;
00976
00977 /* Make sure we log into our own log-file if defined */
00978 log_thread_to(conn->log_idx);
00979
00980 while (!privdata->shutdown) {
00981 server_addr_len = sizeof(server_addr);
00982
00983 ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
00984 if (ret == -1) {
00985 if (errno == EINTR)
00986 continue;
00987 error(0, "Poll for cgw smsc connections failed, shutting down");
00988 break;
00989 }
00990
00991 if (privdata->shutdown)
00992 break;
00993 if (ret == 0) /* This thread was woken up from elsewhere, but
00994 * if we're not shutting down nothing to do here. */
00995 continue;
00996 s = accept(privdata->listening_socket, (struct sockaddr *) & server_addr,
00997 &server_addr_len);
00998 if (s == -1) {
00999 warning(errno, "cgw_listener: accept() failed, retrying...");
01000 continue;
01001 }
01002
01003 ip = host_ip(server_addr);
01004 if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
01005 info(0, "CGW smsc connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip));
01006 octstr_destroy(ip);
01007 close(s);
01008 continue;
01009 }
01010 server = conn_wrap_fd(s, 0);
01011 if (server == NULL) {
01012 error(0, "cgw_listener: conn_wrap_fd failed on accept()ed fd");
01013 octstr_destroy(ip);
01014 close(s);
01015 continue;
01016 }
01017 conn_claim(server);
01018 info(0, "cgw: smsc connected from %s", octstr_get_cstr(ip));
01019 octstr_destroy(ip);
01020
01021 cgw_receiver(conn, server);
01022 conn_destroy(server);
01023 }
01024 if (close(privdata->listening_socket) == -1)
01025 warning(errno, "smsc_cgw: couldn't close listening socket at shutdown");
01026 gwthread_wakeup(privdata->sender_thread);
01027 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 945 of file smsc_cgw.c. References error(), octstr_get_cstr, PrivData, and SMSCConn. Referenced by smsc_cgw_create(). 00946 {
00947 int s;
00948
00949 if ((s = make_server_socket(privdata->rport, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) {
00950 error(0, "smsc_cgw: could not create listening socket in port %d", privdata->rport);
00951 return -1;
00952 }
00953 if (socket_set_blocking(s, 0) == -1) {
00954 error(0, "smsc_cgw: couldn't make listening socket port %d non-blocking", privdata->rport);
00955 close(s);
00956 return -1;
00957 }
00958 privdata->listening_socket = s;
00959 return 0;
00960 }
|
Here is the call graph for this function:

|
|
Definition at line 681 of file smsc_cgw.c. References bb_smscconn_connected(), bb_smscconn_send_failed(), conn_destroy(), conn_open_tcp_with_port(), smscconn::connect_time, smscconn::data, error(), smscconn::flow_mutex, gwlist_extract_first(), gwthread_sleep(), privdata::host, info(), mutex_lock, mutex_unlock, octstr_get_cstr, smscconn::our_host, privdata::our_port, privdata::outgoing_queue, privdata::port, PrivData, privdata::shutdown, SMSCConn, SMSCCONN_FAILED_TEMPORARILY, and smscconn::status. Referenced by cgw_sender(). 00682 {
00683 PrivData *privdata = conn->data;
00684 int wait;
00685 Connection *server;
00686 Msg *msg;
00687
00688 wait = 0;
00689 while (!privdata->shutdown) {
00690
00691 /* Change status only if the first attempt to form a
00692 * connection fails, as it's possible that the SMSC closed the
00693 * connection because of idle timeout and a new one will be
00694 * created quickly. */
00695 if (wait) {
00696 if (conn->status == SMSCCONN_ACTIVE) {
00697 mutex_lock(conn->flow_mutex);
00698 conn->status = SMSCCONN_RECONNECTING;
00699 mutex_unlock(conn->flow_mutex);
00700 }
00701 while ((msg = gwlist_extract_first(privdata->outgoing_queue)))
00702 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
00703 info(0, "smsc_cgw: waiting for %d minutes before trying to connect again", wait);
00704 gwthread_sleep(wait * 60);
00705 wait = wait > 5 ? 10 : wait * 2;
00706 } else
00707 wait = 1;
00708
00709 server = conn_open_tcp_with_port(privdata->host, privdata->port,
00710 privdata->our_port, conn->our_host);
00711
00712 if (privdata->shutdown) {
00713 conn_destroy(server);
00714 return NULL;
00715 }
00716
00717 if (server == NULL) {
00718 error(0, "smsc_cgw: opening TCP connection to %s failed", octstr_get_cstr(privdata->host));
00719 continue;
00720 }
00721
00722 if (conn->status != SMSCCONN_ACTIVE) {
00723 mutex_lock(conn->flow_mutex);
00724 conn->status = SMSCCONN_ACTIVE;
00725 conn->connect_time = time(NULL);
00726 mutex_unlock(conn->flow_mutex);
00727 bb_smscconn_connected(conn);
00728 }
00729 return server;
00730 }
00731 return NULL;
00732 }
|
Here is the call graph for this function:

|
|
Definition at line 599 of file smsc_cgw.c. References smscconn::data, gwlist_len(), smscconn::load, privdata::outgoing_queue, PrivData, and SMSCConn. 00600 {
00601 PrivData *privdata = conn->data;
00602 long ret = gwlist_len(privdata->outgoing_queue);
00603
00604 /* use internal queue as load, maybe something else later */
00605
00606 conn->load = ret;
00607 return ret;
00608 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 856 of file smsc_cgw.c. References PrivData, and SMSCConn. Referenced by cgw_receiver(), and cgw_wait_command(). 00857 {
00858 Octstr *line, *name, *value;
00859 int finished = 0;
00860 int c = 0;
00861 struct cgwop *cgwop = NULL;
00862
00863 int op = CGW_OP_NOP;
00864
00865 if ((line = conn_read_line(server)) == NULL)
00866 return NULL; /* don't block */
00867
00868 do
00869 {
00870 while (line == NULL)
00871 line = conn_read_line(server); /* wait for more data */
00872
00873 c = octstr_search_char(line, ':', 0);
00874 if (c != -1) {
00875 name = octstr_copy(line, 0, c);
00876 value = octstr_copy(line, c + 1, octstr_len(line) - (c + 1));
00877
00878 if (octstr_compare(name, octstr_imm("hello")) == 0) {
00879 /* A connection is started by CGW by sending a
00880 * "hello: Provider Server..." line. */
00881
00882 cgwop = cgwop_create(CGW_OP_HELLO, 0);
00883 cgwop_add(cgwop, octstr_imm("hello"), value);
00884
00885 octstr_destroy(name);
00886 octstr_destroy(value);
00887 octstr_destroy(line);
00888
00889 return cgwop;
00890 }
00891
00892 if (octstr_compare(name, octstr_imm("op")) == 0) {
00893 /* check different ops */
00894 if (octstr_compare(value, octstr_imm("msg")) == 0)
00895 op = CGW_OP_MSG;
00896 else
00897 if (octstr_compare(value, octstr_imm("ok")) == 0)
00898 op = CGW_OP_OK;
00899 else
00900 if (octstr_compare(value, octstr_imm("delivery")) == 0)
00901 op = CGW_OP_DELIVERY;
00902 else
00903 if (octstr_compare(value, octstr_imm("err")) == 0)
00904 op = CGW_OP_ERR;
00905 else
00906 if (octstr_compare(value, octstr_imm("status")) == 0)
00907 op = CGW_OP_STATUS;
00908 else
00909 info(0, "CGW: Received unknown op: %s", octstr_get_cstr(value));
00910
00911 if (cgwop == NULL)
00912 cgwop = cgwop_create(op, 0);
00913 else
00914 info(0, "cgw: cgwop != null");
00915 }
00916
00917 if (op != CGW_OP_NOP) {
00918 /* All commands have to be inside an op:xx ... end:xx statement */
00919
00920 if (octstr_compare(name, octstr_imm("end")) == 0) { /* found end of op */
00921 finished = 1;
00922 } else {
00923 /* store in name/value fields in cgwop */
00924 if (cgwop != NULL) {
00925 cgwop_add(cgwop, name, value);
00926 }
00927 }
00928 }
00929 octstr_destroy(name);
00930 octstr_destroy(value);
00931 octstr_destroy(line);
00932
00933 if (!finished) line = conn_read_line(server);
00934 } else {
00935 info(0, "cgw: Received invalid input: %s", octstr_get_cstr(line));
00936 octstr_destroy(line);
00937 finished = 1;
00938 }
00939
00940 } while (!finished);
00941
00942 return cgwop;
00943 }
|
|
||||||||||||
|
Definition at line 1029 of file smsc_cgw.c. References cgw_handle_op(), cgw_read_op(), cgwop_destroy(), conn_eof(), conn_error(), conn_wait(), smscconn::data, error(), info(), smscconn::is_stopped, PrivData, privdata::shutdown, and SMSCConn. Referenced by cgw_listener(). 01030 {
01031 PrivData *privdata = conn->data;
01032 Octstr *str = NULL;
01033 struct cgwop *cgwop;
01034
01035 while (1) {
01036 if (conn_eof(server)) {
01037 info(0, "cgw: receive connection closed by SMSC");
01038 return ;
01039 }
01040 if (conn_error(server)) {
01041 error(0, "cgw: receive connection broken");
01042 return ;
01043 }
01044 if (conn->is_stopped)
01045 str = NULL;
01046
01047 cgwop = cgw_read_op(conn->data, conn, server, 0);
01048
01049 if (cgwop != NULL) {
01050 cgw_handle_op(conn, server, cgwop);
01051 cgwop_destroy(cgwop);
01052 } else
01053 conn_wait(server, -1);
01054
01055 if (privdata->shutdown)
01056 break;
01057 }
01058 return ;
01059 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 739 of file smsc_cgw.c. References cgwop_destroy(), cgwop_send(), smscconn::data, gwlist_extract_first(), gwlist_produce(), info(), msg_to_cgwop(), privdata::nexttrn, privdata::outgoing_queue, PrivData, privdata::sendmsg, privdata::sendtime, SMSCConn, and privdata::unacked. Referenced by cgw_sender(). 00740 {
00741 PrivData *privdata = conn->data;
00742 struct cgwop *cgwop;
00743 Msg *msg;
00744 int firsttrn;
00745
00746 /* Send messages in queue */
00747 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00748 firsttrn = privdata->nexttrn;
00749 while (privdata->sendtime[privdata->nexttrn] != 0) {
00750 if (++privdata->nexttrn >= CGW_TRN_MAX) privdata->nexttrn = 0;
00751 if (privdata->nexttrn == firsttrn) { /* no available trn */
00752 /* this happens too many messages are sent, and old messages
00753 * haven't been acked. In this case, increase size of
00754 * CGW_TRN_MAX */
00755 info(0, "cgw: Saturated, increase size of CGW_TRN_MAX!");
00756 gwlist_produce(privdata->outgoing_queue, msg);
00757 return 1; /* re-insert, and go check for acks */
00758 }
00759 }
00760
00761 cgwop = msg_to_cgwop(privdata, msg, privdata->nexttrn);
00762
00763 if (cgwop == NULL) {
00764 info(0, "cgw: cgwop == NULL");
00765 return 0;
00766 }
00767
00768 privdata->sendmsg[privdata->nexttrn] = msg;
00769 privdata->sendtime[privdata->nexttrn] = time(NULL);
00770
00771 if (cgwop_send(server, cgwop) == -1) {
00772 cgwop_destroy(cgwop);
00773 info(0, "cgw: Unable to send (cgwop_send() == -1)");
00774 return -1;
00775 }
00776
00777 privdata->unacked++;
00778
00779 cgwop_destroy(cgwop);
00780 }
00781 return 0;
00782 }
|
Here is the call graph for this function:

|
|
Definition at line 616 of file smsc_cgw.c. References privdata::allow_ip, bb_smscconn_connected(), bb_smscconn_killed(), bb_smscconn_send_failed(), cgw_check_acks(), cgw_open_send_connection(), cgw_send_loop(), cgw_wait_command(), conn_destroy(), smscconn::data, debug(), privdata::deny_ip, error(), smscconn::flow_mutex, gwlist_destroy(), gwlist_extract_first(), gwlist_len(), privdata::host, smscconn::log_idx, log_thread_to(), mutex_lock, mutex_unlock, octstr_destroy(), privdata::outgoing_queue, PrivData, privdata::shutdown, SMSCConn, SMSCCONN_FAILED_SHUTDOWN, and smscconn::status. Referenced by smsc_cgw_create(). 00617 {
00618 SMSCConn *conn = arg;
00619 PrivData *privdata = conn->data;
00620 Msg *msg = NULL;
00621 Connection *server = NULL;
00622 int l = 0;
00623 int ret = 0;
00624
00625 conn->status = SMSCCONN_CONNECTING;
00626
00627 /* Make sure we log into our own log-file if defined */
00628 log_thread_to(conn->log_idx);
00629
00630 while (!privdata->shutdown) {
00631
00632 /* check that connection is active */
00633 if (conn->status != SMSCCONN_ACTIVE) {
00634 if ((server = cgw_open_send_connection(conn)) == NULL) {
00635 privdata->shutdown = 1;
00636 error(0, "Unable to connect to CGW server");
00637 return ;
00638 }
00639
00640 conn->status = SMSCCONN_ACTIVE;
00641 bb_smscconn_connected(conn);
00642 } else {
00643 ret = 0;
00644 l = gwlist_len(privdata->outgoing_queue);
00645 if (l > 0)
00646 ret = cgw_send_loop(conn, server); /* send any messages in queue */
00647
00648 if (ret != -1) ret = cgw_wait_command(privdata, conn, server, 1); /* read ack's and delivery reports */
00649 if (ret != -1) cgw_check_acks(privdata); /* check un-acked messages */
00650
00651 if (ret == -1) {
00652 mutex_lock(conn->flow_mutex);
00653 conn->status = SMSCCONN_RECONNECTING;
00654 mutex_unlock(conn->flow_mutex);
00655 }
00656 }
00657 }
00658
00659 conn_destroy(server);
00660
00661 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL)
00662 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
00663 mutex_lock(conn->flow_mutex);
00664
00665 conn->status = SMSCCONN_DEAD;
00666
00667 gwlist_destroy(privdata->outgoing_queue, NULL);
00668 octstr_destroy(privdata->host);
00669 octstr_destroy(privdata->allow_ip);
00670 octstr_destroy(privdata->deny_ip);
00671
00672 gw_free(privdata);
00673 conn->data = NULL;
00674
00675 mutex_unlock(conn->flow_mutex);
00676 debug("bb.sms", 0, "smsc_cgw connection has completed shutdown.");
00677 bb_smscconn_killed();
00678 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 562 of file smsc_cgw.c. References bb_smscconn_send_failed(), smscconn::data, debug(), gwlist_extract_first(), gwthread_wakeup(), privdata::outgoing_queue, PrivData, privdata::receiver_thread, privdata::rport, privdata::shutdown, SMSCConn, SMSCCONN_FAILED_SHUTDOWN, and smscconn::why_killed. 00563 {
00564 PrivData *privdata = conn->data;
00565
00566 debug("bb.sms", 0, "Shutting down SMSCConn CGW, %s",
00567 finish_sending ? "slow" : "instant");
00568
00569 /* Documentation claims this would have been done by smscconn.c,
00570 but isn't when this code is being written. */
00571 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
00572 privdata->shutdown = 1; /* Separate from why_killed to avoid locking, as
00573 * why_killed may be changed from outside? */
00574
00575 if (finish_sending == 0) {
00576 Msg *msg;
00577 while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
00578 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
00579 }
00580 }
00581
00582 if (privdata->rport > 0)
00583 gwthread_wakeup(privdata->receiver_thread);
00584 return 0;
00585 }
|
Here is the call graph for this function:

|
|
Definition at line 588 of file smsc_cgw.c. References smscconn::data, debug(), gwthread_wakeup(), PrivData, privdata::receiver_thread, privdata::rport, and SMSCConn. 00589 {
00590 PrivData *privdata = conn->data;
00591
00592 /* in case there are messages in the buffer already */
00593 if (privdata->rport > 0)
00594 gwthread_wakeup(privdata->receiver_thread);
00595 debug("smsc.cgw", 0, "smsc_cgw: start called");
00596 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 811 of file smsc_cgw.c. References cgw_handle_op(), cgw_read_op(), cgwop_destroy(), conn_eof(), conn_error(), conn_wait(), error(), gwthread_pollfd(), info(), POLLIN, PrivData, privdata::send_socket, SMSCConn, SMSCCONN_DISCONNECTED, and smscconn::status. Referenced by cgw_sender(). 00812 {
00813 int ret;
00814 struct cgwop *cgwop;
00815
00816 /* is there data to be read? */
00817 ret = gwthread_pollfd(privdata->send_socket, POLLIN, 0.2);
00818
00819 if (ret != -1) {
00820 /* read all waiting ops */
00821 cgwop = cgw_read_op(privdata, conn, server, timeout);
00822 if (cgwop != NULL) {
00823 do {
00824 if (conn_eof(server)) {
00825 info(0, "cgw: Connection closed by SMSC");
00826 conn->status = SMSCCONN_DISCONNECTED;
00827 if (cgwop != NULL) cgwop_destroy(cgwop);
00828 return -1;
00829 }
00830 if (conn_error(server)) {
00831 error(0, "cgw: Error trying to read ACKs from SMSC");
00832 if (cgwop != NULL) cgwop_destroy(cgwop);
00833 return -1;
00834 }
00835
00836 cgw_handle_op(conn, server, cgwop);
00837 cgwop_destroy(cgwop);
00838 } while ((cgwop = cgw_read_op(privdata, conn, server, timeout)) != NULL);
00839 } else
00840 conn_wait(server, 1); /* added because gwthread_pollfd
00841 seems to always return 1. This will keep
00842 the load on a reasonable level */
00843 }
00844
00845 return 0;
00846 }
|
Here is the call graph for this function:

|
||||||||||||||||
|
Definition at line 199 of file smsc_cgw.c. References info(), name, cgwop::name, cgwop::num_fields, octstr_duplicate, and cgwop::value. Referenced by cgw_handle_op(), cgwop_create(), and msg_to_cgwop(). 00200 {
00201 if (cgwop->num_fields < CGWOP_MAXARGS)
00202 {
00203 cgwop->name[cgwop->num_fields] = octstr_duplicate(name);
00204 cgwop->value[cgwop->num_fields] = octstr_duplicate(value);
00205
00206 cgwop->num_fields++;
00207 } else
00208 {
00209 info(0, "cgw: CGWOP_MAXARGS exceeded.");
00210 }
00211 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 214 of file smsc_cgw.c. References cgwop_add(), CGWOP_MAXARGS, cgwop::name, cgwop::num_fields, Octstr, octstr_append_decimal(), octstr_create, octstr_destroy(), octstr_imm(), cgwop::op, cgwop::trn, and cgwop::value. Referenced by cgw_handle_op(), and msg_to_cgwop(). 00215 {
00216 struct cgwop *ret;
00217 Octstr *trnstr;
00218
00219 ret = gw_malloc(sizeof(struct cgwop));
00220
00221 ret->op = op;
00222 ret->num_fields = 0;
00223 ret->trn = trn;
00224
00225 ret->name = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
00226 ret->value = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
00227
00228 if (trn != -1)
00229 {
00230 trnstr = octstr_create("");
00231 octstr_append_decimal(trnstr, trn);
00232 cgwop_add(ret, octstr_imm("client-id"), trnstr);
00233 octstr_destroy(trnstr);
00234 }
00235
00236 return ret;
00237 }
|
Here is the call graph for this function:

|
|
Definition at line 239 of file smsc_cgw.c. References cgwop::name, cgwop::num_fields, octstr_destroy(), and cgwop::value. Referenced by cgw_handle_op(), cgw_receiver(), cgw_send_loop(), and cgw_wait_command(). 00240 {
00241 int len;
00242
00243 len = cgwop->num_fields;
00244 while (--len >= 0)
00245 {
00246 octstr_destroy(cgwop->name[len]); /* octstr_destroy(NULL) is ok */
00247 octstr_destroy(cgwop->value[len]);
00248 }
00249
00250 gw_free(cgwop->name);
00251 gw_free(cgwop->value);
00252 gw_free(cgwop);
00253 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 255 of file smsc_cgw.c. References cgwop::name, name, cgwop::num_fields, octstr_compare(), and cgwop::value. Referenced by cgw_handle_op(). 00256 {
00257 int len = cgwop->num_fields;
00258
00259 while (--len >= 0)
00260 if (octstr_compare(name, cgwop->name[len]) == 0)
00261 return cgwop->value[len];
00262 return NULL;
00263 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 292 of file smsc_cgw.c. References cgwop_tostr(), conn_write(), and octstr_destroy(). Referenced by cgw_handle_op(), and cgw_send_loop(). 00293 {
00294 Octstr *dta = cgwop_tostr(cgwop);
00295
00296 if (dta == NULL) return -1; /* couldn't convert to string */
00297
00298 if (conn_write(conn, dta) == -1)
00299 {
00300 octstr_destroy(dta);
00301 return -1;
00302 }
00303
00304 octstr_destroy(dta);
00305 return 1;
00306 }
|
Here is the call graph for this function:

|
|
Definition at line 265 of file smsc_cgw.c. References CGW_EOL, cgw_ops, cgwop::name, cgwop::num_fields, octstr_append(), octstr_append_char(), octstr_create, octstr_imm(), cgwop::op, and cgwop::value. Referenced by cgwop_send(). 00266 {
00267 int len = cgwop->num_fields;
00268 Octstr *str;
00269
00270 if (cgw_ops[cgwop->op] == NULL) return NULL; /* invalid operation */
00271
00272 str = octstr_create("");
00273
00274 octstr_append(str, octstr_imm("op:"));
00275 octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
00276 octstr_append_char(str, CGW_EOL);
00277
00278 while (--len >= 0)
00279 {
00280 octstr_append(str, cgwop->name[len]);
00281 octstr_append_char(str, ':');
00282 octstr_append(str, cgwop->value[len]);
00283 octstr_append_char(str, CGW_EOL);
00284 }
00285 octstr_append(str, octstr_imm("end:"));
00286 octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
00287 octstr_append_char(str, CGW_EOL);
00288
00289 return str;
00290 }
|
Here is the call graph for this function:

|
||||||||||||||||
|
Definition at line 380 of file smsc_cgw.c. References privdata::appname, cgw_encode_msg(), CGW_OP_MSG, cgwop_add(), cgwop_create(), DLR_IS_ENABLED_DEVICE, gw_isdigit(), octstr_append(), octstr_binary_to_hex(), octstr_check_range(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_imm(), octstr_len(), and PrivData. Referenced by cgw_send_loop(). 00381 {
00382 struct cgwop *cgwop;
00383 Octstr *sender, *udh, *dta;
00384
00385 cgwop = cgwop_create(CGW_OP_MSG, trn);
00386
00387 if (cgwop == NULL) return NULL;
00388
00389 if (!octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), gw_isdigit))
00390 {
00391 /* If alphanumeric, simply prefix sender with '$' char */
00392 sender = octstr_create("$");
00393 octstr_append(sender, msg->sms.sender);
00394 } else sender = octstr_duplicate(msg->sms.sender);
00395
00396 cgwop_add(cgwop, octstr_imm("app"), privdata->appname);
00397 cgwop_add(cgwop, octstr_imm("from"), sender);
00398 cgwop_add(cgwop, octstr_imm("to"), msg->sms.receiver);
00399
00400 /* If delivery reports are asked, ask for them by adding a nrq:anything field */
00401 if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
00402 cgwop_add(cgwop, octstr_imm("nrq"), octstr_imm("true"));
00403
00404 octstr_destroy(sender);
00405
00406 if (octstr_len(msg->sms.udhdata))
00407 {
00408 udh = octstr_duplicate(msg->sms.udhdata);
00409 octstr_binary_to_hex(udh, 1);
00410 cgwop_add(cgwop, octstr_imm("udh"), udh);
00411 octstr_destroy(udh);
00412
00413 dta = octstr_duplicate(msg->sms.msgdata);
00414 octstr_binary_to_hex(dta, 1);
00415 cgwop_add(cgwop, octstr_imm("msg"), dta);
00416 cgwop_add(cgwop, octstr_imm("type"), octstr_imm("bin"));
00417 octstr_destroy(dta);
00418 } else
00419 {
00420 cgwop_add(cgwop, octstr_imm("msg"), cgw_encode_msg(msg->sms.msgdata));
00421 }
00422
00423 return cgwop;
00424 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 431 of file smsc_cgw.c. References privdata::allow_ip, privdata::appname, cfg_get, cfg_get_integer(), CGW_DEFPORT, cgw_listener(), cgw_open_listening_socket(), cgw_sender(), privdata::check_time, smscconn::connect_time, smscconn::data, privdata::deny_ip, privdata::dlr, error(), gwlist_create, gwlist_destroy(), gwthread_create, privdata::host, info(), privdata::listening_socket, smscconn::name, privdata::nexttrn, octstr_create, octstr_destroy(), octstr_format(), octstr_imm(), privdata::our_port, privdata::outgoing_queue, privdata::port, PrivData, smscconn::queued, privdata::receiver_thread, privdata::rport, smscconn::send_msg, privdata::sender_thread, privdata::sendtime, privdata::shutdown, smscconn::shutdown, SMSCConn, smscconn::start_conn, smscconn::status, privdata::waitack, and smscconn::why_killed. Referenced by smscconn_create(). 00432 {
00433 PrivData *privdata;
00434 Octstr *allow_ip, *deny_ip, *host, *appname;
00435 long portno, our_port, waitack;
00436 int i;
00437
00438 privdata = gw_malloc(sizeof(PrivData));
00439 privdata->outgoing_queue = gwlist_create();
00440 privdata->listening_socket = -1;
00441
00442 if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
00443 portno = 0;
00444 privdata->port = portno;
00445
00446 if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0)
00447 portno = 0;
00448 privdata->rport = portno;
00449
00450 host = cfg_get(cfg, octstr_imm("host"));
00451 appname = cfg_get(cfg, octstr_imm("appname"));
00452
00453 if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1)
00454 privdata->our_port = 0; /* 0 means use any port */
00455 else
00456 privdata->our_port = our_port;
00457
00458 allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
00459 if (allow_ip)
00460 deny_ip = octstr_create("*.*.*.*");
00461 else
00462 deny_ip = NULL;
00463
00464 if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0)
00465 privdata->waitack = 60;
00466 else
00467 privdata->waitack = waitack;
00468
00469 if (privdata->port <= 0 || privdata->port > 65535) {
00470 info(1, "No port defined for cgw -> using default (%d)", CGW_DEFPORT);
00471 privdata->port = CGW_DEFPORT;
00472 }
00473
00474
00475 if (host == NULL) {
00476 error(0, "'host' missing in cgw configuration.");
00477 goto error;
00478 }
00479
00480 if (appname == NULL)
00481 appname = octstr_create("send");
00482
00483 privdata->allow_ip = allow_ip;
00484 privdata->deny_ip = deny_ip;
00485 privdata->host = host;
00486 privdata->appname = appname;
00487 privdata->nexttrn = 0;
00488 privdata->check_time = 0;
00489
00490 for (i = 0; i < CGW_TRN_MAX; i++) {
00491 privdata->sendtime[i] = 0;
00492 privdata->dlr[i] = 0;
00493 }
00494
00495 if (privdata->rport > 0 && cgw_open_listening_socket(conn,privdata) < 0) {
00496 gw_free(privdata);
00497 privdata = NULL;
00498 goto error;
00499 }
00500
00501
00502 conn->data = privdata;
00503
00504 conn->name = octstr_format("CGW:%d", privdata->port);
00505
00506 privdata->shutdown = 0;
00507
00508 conn->status = SMSCCONN_CONNECTING;
00509 conn->connect_time = time(NULL);
00510
00511 if (privdata->rport > 0 && (privdata->receiver_thread = gwthread_create(cgw_listener, conn)) == -1)
00512 goto error;
00513
00514 if ((privdata->sender_thread = gwthread_create(cgw_sender, conn)) == -1) {
00515 privdata->shutdown = 1;
00516 goto error;
00517 }
00518
00519 conn->shutdown = cgw_shutdown_cb;
00520 conn->queued = cgw_queued_cb;
00521 conn->start_conn = cgw_start_cb;
00522 conn->send_msg = cgw_add_msg_cb;
00523
00524 return 0;
00525
00526 error:
00527 error(0, "Failed to create CGW smsc connection");
00528 if (privdata != NULL)
00529 gwlist_destroy(privdata->outgoing_queue, NULL);
00530
00531 gw_free(privdata);
00532 octstr_destroy(host);
00533 octstr_destroy(allow_ip);
00534 octstr_destroy(deny_ip);
00535 octstr_destroy(appname);
00536
00537 conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
00538 conn->status = SMSCCONN_DEAD;
00539 info(0, "exiting");
00540 return -1;
00541 }
|
Here is the call graph for this function:

|
|
Definition at line 148 of file smsc_cgw.c. Referenced by cgwop_tostr(). |