Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
smsc_cimd2.c File Reference
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "gwlib/gwlib.h"
#include "smscconn.h"
#include "smscconn_p.h"
#include "bb_smscconn_cb.h"
#include "shared.h"
#include "sms.h"
#include "dlr.h"

Go to the source code of this file.

Data Structures

struct  privdata
 
struct  packet
 

Macros

#define RESPONSE_TIMEOUT   (60 * 1000000)
 
#define STX   2 /* Start of packet */
 
#define ETX   3 /* End of packet */
 
#define TAB   9 /* End of parameter */
 
#define STX_str   "\02"
 
#define ETX_str   "\03"
 
#define TAB_str   "\011"
 
#define BOGUS_SEQUENCE   0
 

Typedefs

typedef struct privdata PrivData
 

Enumerations

enum  {
  LOGIN = 1, LOGOUT = 2, SUBMIT_MESSAGE = 3, ENQUIRE_MESSAGE_STATUS = 4,
  DELIVERY_REQUEST = 5, CANCEL_MESSAGE = 6, SET_REQ = 8, GET_REQ = 9,
  DELIVER_MESSAGE = 20, DELIVER_STATUS_REPORT = 23, ALIVE = 40, RESPONSE = 50,
  GENERAL_ERROR_RESPONSE = 98, NACK = 99
}
 
enum  {
  P_USER_IDENTITY = 10, P_PASSWORD = 11, P_DESTINATION_ADDRESS = 21, P_ORIGINATING_ADDRESS = 23,
  P_ORIGINATING_IMSI = 26, P_ALPHANUMERIC_ORIGINATING_ADDRESS = 27, P_ORIGINATED_VISITED_MSC = 28, P_DATA_CODING_SCHEME = 30,
  P_USER_DATA_HEADER = 32, P_USER_DATA = 33, P_USER_DATA_BINARY = 34, P_MORE_MESSAGES_TO_SEND = 44,
  P_VALIDITY_PERIOD_RELATIVE = 50, P_VALIDITY_PERIOD_ABSOLUTE = 51, P_PROTOCOL_IDENTIFIER = 52, P_FIRST_DELIVERY_TIME_RELATIVE = 53,
  P_FIRST_DELIVERY_TIME_ABSOLUTE = 54, P_REPLY_PATH = 55, P_STATUS_REPORT_REQUEST = 56, P_CANCEL_ENABLED = 58,
  P_CANCEL_MODE = 59, P_MC_TIMESTAMP = 60, P_STATUS_CODE = 61, P_STATUS_ERROR_CODE = 62,
  P_DISCHARGE_TIME = 63, P_TARIFF_CLASS = 64, P_SERVICE_DESCRIPTION = 65, P_MESSAGE_COUNT = 66,
  P_PRIORITY = 67, P_DELIVERY_REQUEST_MODE = 68, P_SERVICE_CENTER_ADDRESS = 69, P_GET_PARAMETER = 500,
  P_MC_TIME = 501, P_ERROR_CODE = 900, P_ERROR_TEXT = 901
}
 
enum  {
  P_INT, P_STRING, P_ADDRESS, P_TIME,
  P_HEX, P_SMS
}
 

Functions

static int parm_index (int parmno)
 
static int parm_type (int parmno)
 
static int parm_maxlen (int parmno)
 
static const char * parm_name (int parmno)
 
static int parm_in_range (int parmno, long value)
 
static int isphonedigit (int c)
 
static int parm_valid_address (Octstr *value)
 
static int operation_find (int operation)
 
static Octstroperation_name (int operation)
 
static int operation_can_send (int operation)
 
static int operation_can_receive (int operation)
 
static Msgcimd2_accept_delivery_report_message (struct packet *request, SMSCConn *conn)
 
static void packet_parse_header (struct packet *packet)
 
static struct packetpacket_parse (Octstr *packet_data)
 
static void packet_destroy (struct packet *packet)
 
static struct packetpacket_extract (Octstr *in, SMSCConn *conn)
 
static Octstrpacket_get_parm (struct packet *packet, int parmno)
 
static long packet_get_int_parm (struct packet *packet, int parmno)
 
static Octstrpacket_get_string_parm (struct packet *packet, int parmno)
 
static Octstrpacket_get_address_parm (struct packet *packet, int parmno)
 
static Octstrpacket_get_sms_parm (struct packet *packet, int parmno)
 
static Octstrpacket_get_hex_parm (struct packet *packet, int parmno)
 
static int packet_check_header (struct packet *packet, SMSCConn *conn)
 
static int packet_check_parameter (struct packet *packet, long pos, long len, SMSCConn *conn)
 
static int packet_check (struct packet *packet, SMSCConn *conn)
 
static void packet_check_can_receive (struct packet *packet, SMSCConn *conn)
 
static int packet_display_error (struct packet *packet, SMSCConn *conn)
 
static void convert_cimd2_to_gsm (Octstr *text, SMSCConn *conn)
 
static void convert_gsm_to_cimd2 (Octstr *text)
 
static struct packetpacket_create (int operation, int seq)
 
static void packet_add_parm (struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
 
static void packet_add_string_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static void packet_add_address_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static void packet_add_sms_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static void packet_add_hex_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static void packet_add_int_parm (struct packet *packet, int parmno, long value, SMSCConn *conn)
 
static void packet_set_checksum (struct packet *packet)
 
static void packet_set_sequence (struct packet *packet, int seq)
 
static struct packetpacket_encode_message (Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
 
static void packet_set_send_sequence (struct packet *packet, PrivData *pdata)
 
static struct packetcimd2_get_packet (PrivData *pdata, Octstr **ts)
 
static void cimd2_send_response (struct packet *request, PrivData *pdata)
 
static Msgcimd2_accept_message (struct packet *request, SMSCConn *conn)
 
static void cimd2_handle_request (struct packet *request, SMSCConn *conn)
 
static int cimd2_request (struct packet *request, SMSCConn *conn, Octstr **ts)
 
static void cimd2_close_socket (PrivData *pdata)
 
static int cimd2_login (SMSCConn *conn)
 
static void cimd2_logout (SMSCConn *conn)
 
static int cimd2_send_alive (SMSCConn *conn)
 
static void cimd2_destroy (PrivData *pdata)
 
static int cimd2_submit_msg (SMSCConn *conn, Msg *msg)
 
static int cimd2_receive_msg (SMSCConn *conn, Msg **msg)
 
static Msgsms_receive (SMSCConn *conn)
 
static void io_thread (void *arg)
 
static int cimd2_add_msg_cb (SMSCConn *conn, Msg *sms)
 
static int cimd2_shutdown_cb (SMSCConn *conn, int finish_sending)
 
static void cimd2_start_cb (SMSCConn *conn)
 
static void cimd2_stop_cb (SMSCConn *conn)
 
static long cimd2_queued_cb (SMSCConn *conn)
 
int smsc_cimd2_create (SMSCConn *conn, CfgGroup *grp)
 

Variables

struct {
   char *   name
 
   int   number
 
   int   maxlen
 
   int   type
 
   int   minval
 
   int   maxval
 
parameters []
 
struct {
   char *   name
 
   int   code
 
   int   can_send
 
   int   can_receive
 
operations []
 
struct {
   int   code
 
   char *   text
 
cimd2_errors []
 
struct {
   unsigned char   cimd1
 
   unsigned char   cimd2
 
   unsigned char   gsm
 
cimd_combinations []
 

Macro Definition Documentation

#define BOGUS_SEQUENCE   0

Definition at line 471 of file smsc_cimd2.c.

Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), and packet_encode_message().

#define ETX   3 /* End of packet */

Definition at line 462 of file smsc_cimd2.c.

Referenced by packet_extract().

#define ETX_str   "\03"

Definition at line 467 of file smsc_cimd2.c.

Referenced by packet_create(), and packet_extract().

#define RESPONSE_TIMEOUT   (60 * 1000000)

Definition at line 128 of file smsc_cimd2.c.

Referenced by cimd2_get_packet().

#define STX   2 /* Start of packet */

Definition at line 461 of file smsc_cimd2.c.

Referenced by packet_extract().

#define STX_str   "\02"

Definition at line 466 of file smsc_cimd2.c.

Referenced by packet_create().

#define TAB   9 /* End of parameter */
#define TAB_str   "\011"

Definition at line 468 of file smsc_cimd2.c.

Referenced by packet_add_parm(), and packet_create().

Typedef Documentation

typedef struct privdata PrivData

Enumeration Type Documentation

anonymous enum
Enumerator
LOGIN 
LOGOUT 
SUBMIT_MESSAGE 
ENQUIRE_MESSAGE_STATUS 
DELIVERY_REQUEST 
CANCEL_MESSAGE 
SET_REQ 
GET_REQ 
DELIVER_MESSAGE 
DELIVER_STATUS_REPORT 
ALIVE 
RESPONSE 
GENERAL_ERROR_RESPONSE 
NACK 

Definition at line 132 of file smsc_cimd2.c.

132  {
133  /* Requests from client */
134  LOGIN = 1,
135  LOGOUT = 2,
136  SUBMIT_MESSAGE = 3,
138  DELIVERY_REQUEST = 5,
139  CANCEL_MESSAGE = 6,
140  SET_REQ = 8,
141  GET_REQ = 9,
142 
143  /* Requests from server */
144  DELIVER_MESSAGE = 20,
146 
147  /* Requests from either */
148  ALIVE = 40,
149 
150  /* Not a request; add to any request to make it a response */
151  RESPONSE = 50,
152 
153  /* Responses not related to requests */
155  NACK = 99
156 };
anonymous enum
Enumerator
P_USER_IDENTITY 
P_PASSWORD 
P_DESTINATION_ADDRESS 
P_ORIGINATING_ADDRESS 
P_ORIGINATING_IMSI 
P_ALPHANUMERIC_ORIGINATING_ADDRESS 
P_ORIGINATED_VISITED_MSC 
P_DATA_CODING_SCHEME 
P_USER_DATA_HEADER 
P_USER_DATA 
P_USER_DATA_BINARY 
P_MORE_MESSAGES_TO_SEND 
P_VALIDITY_PERIOD_RELATIVE 
P_VALIDITY_PERIOD_ABSOLUTE 
P_PROTOCOL_IDENTIFIER 
P_FIRST_DELIVERY_TIME_RELATIVE 
P_FIRST_DELIVERY_TIME_ABSOLUTE 
P_REPLY_PATH 
P_STATUS_REPORT_REQUEST 
P_CANCEL_ENABLED 
P_CANCEL_MODE 
P_MC_TIMESTAMP 
P_STATUS_CODE 
P_STATUS_ERROR_CODE 
P_DISCHARGE_TIME 
P_TARIFF_CLASS 
P_SERVICE_DESCRIPTION 
P_MESSAGE_COUNT 
P_PRIORITY 
P_DELIVERY_REQUEST_MODE 
P_SERVICE_CENTER_ADDRESS 
P_GET_PARAMETER 
P_MC_TIME 
P_ERROR_CODE 
P_ERROR_TEXT 

Definition at line 160 of file smsc_cimd2.c.

160  {
161  P_USER_IDENTITY = 10,
162  P_PASSWORD = 11,
165  P_ORIGINATING_IMSI = 26,
169  P_USER_DATA_HEADER = 32,
170  P_USER_DATA = 33,
171  P_USER_DATA_BINARY = 34,
178  P_REPLY_PATH = 55,
180  P_CANCEL_ENABLED = 58,
181  P_CANCEL_MODE = 59,
182  P_MC_TIMESTAMP = 60,
183  P_STATUS_CODE = 61,
184  P_STATUS_ERROR_CODE = 62,
185  P_DISCHARGE_TIME = 63,
186  P_TARIFF_CLASS = 64,
188  P_MESSAGE_COUNT = 66,
189  P_PRIORITY = 67,
192  P_GET_PARAMETER = 500,
193  P_MC_TIME = 501,
194  P_ERROR_CODE = 900,
195  P_ERROR_TEXT = 901
196 };
anonymous enum
Enumerator
P_INT 
P_STRING 
P_ADDRESS 
P_TIME 
P_HEX 
P_SMS 

Definition at line 205 of file smsc_cimd2.c.

Function Documentation

static Msg * cimd2_accept_delivery_report_message ( struct packet request,
SMSCConn conn 
)
static

Definition at line 2084 of file smsc_cimd2.c.

References code, DLR_EXPIRED, DLR_FAIL, dlr_find(), DLR_SUCCESS, msg, smscconn::name, octstr_destroy(), octstr_get_cstr, P_DESTINATION_ADDRESS, P_MC_TIMESTAMP, P_STATUS_CODE, P_USER_DATA, and packet_get_parm().

Referenced by cimd2_handle_request().

2086 {
2087  Msg *msg = NULL;
2088  Octstr *destination = NULL;
2089  Octstr *timestamp = NULL;
2090  Octstr *statuscode = NULL;
2091  int st_code;
2092  int code;
2093 
2094  destination = packet_get_parm(request, P_DESTINATION_ADDRESS);
2095  timestamp = packet_get_parm(request, P_MC_TIMESTAMP);
2096  statuscode = packet_get_parm(request, P_STATUS_CODE);
2097 
2098  st_code = atoi(octstr_get_cstr(statuscode));
2099 
2100  switch(st_code)
2101  {
2102  case 2: /* validity period expired */
2103  code = DLR_EXPIRED;
2104  break;
2105  case 3: /* delivery failed */
2106  case 6: /* last no response */
2107  case 7: /* message cancelled */
2108  case 8: /* message deleted */
2109  case 9: /* message deleted by cancel */
2110  code = DLR_FAIL;
2111  break;
2112  case 4: /* delivery successful */
2113  code = DLR_SUCCESS;
2114  break;
2115  default:
2116  code = 0;
2117  }
2118  if(code)
2119  msg = dlr_find(conn->name, timestamp, destination, code, 1);
2120  else
2121  msg = NULL;
2122 
2123  /* recode the body into msgdata */
2124  if (msg) {
2125  msg->sms.msgdata = packet_get_parm(request, P_USER_DATA);
2126  if (!msg->sms.msgdata) {
2127  msg->sms.msgdata = statuscode;
2128  statuscode = NULL;
2129  }
2130  }
2131 
2132  octstr_destroy(statuscode);
2133  octstr_destroy(destination);
2134  octstr_destroy(timestamp);
2135 
2136  return msg;
2137  }
Octstr * name
Definition: smscconn_p.h:173
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
int code
Definition: smsc_cimd2.c:346
#define DLR_EXPIRED
Definition: dlr.h:77
Msg * dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst)
Definition: dlr.c:387
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define DLR_SUCCESS
Definition: dlr.h:72
Definition: msg.h:79
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
Definition: octstr.c:118
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define DLR_FAIL
Definition: dlr.h:73
static Msg* cimd2_accept_message ( struct packet request,
SMSCConn conn 
)
static

Definition at line 1588 of file smsc_cimd2.c.

References charset_gsm_to_utf8(), convert_cimd2_to_gsm(), dcs_to_fields(), debug(), error(), smscconn::id, info(), msg_create, msg_destroy(), octstr_destroy(), octstr_get_cstr, octstr_len(), P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_ORIGINATING_ADDRESS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and text.

Referenced by cimd2_handle_request().

1589 {
1590  Msg *message = NULL;
1591  Octstr *destination = NULL;
1592  Octstr *origin = NULL;
1593  Octstr *UDH = NULL;
1594  Octstr *text = NULL;
1595  int DCS;
1596 
1597  /* See GSM 03.38. The bit patterns we can handle are:
1598  * 000xyyxx Uncompressed text, yy indicates alphabet.
1599  * yy = 00, default alphabet
1600  * yy = 01, 8-bit data
1601  * yy = 10, UCS-2
1602  * yy = 11, reserved
1603  * 1111xyxx Data, y indicates alphabet.
1604  * y = 0, default alphabet
1605  * y = 1, 8-bit data
1606  */
1607  DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME);
1608 
1609  destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS);
1611  UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER);
1612  /* Text is either in User Data or User Data Binary field. */
1613  text = packet_get_sms_parm(request, P_USER_DATA);
1614  if (text != NULL) {
1615  convert_cimd2_to_gsm(text,conn);
1616  charset_gsm_to_utf8(text);
1617  } else {
1618  /*
1619  * FIXME: If DCS indicates GSM charset, and we get it in binary,
1620  * then it's probably bit-packed. We'll have to undo it because
1621  * our "charset_gsm" means one gsm character per octet. This is
1622  * not currently supported. -- RB
1623  */
1624  text = packet_get_hex_parm(request, P_USER_DATA_BINARY);
1625  }
1626 
1627  /* Code elsewhere in the gateway always expects the sender and
1628  * receiver fields to be filled, so we discard messages that
1629  * lack them. If they should not be discarded, then the code
1630  * handling sms messages should be reviewed. -- RB */
1631  if (!destination || octstr_len(destination) == 0) {
1632  info(0, "CIMD2[%s]: Got SMS without receiver, discarding.",
1633  octstr_get_cstr(conn->id));
1634  goto error;
1635  }
1636  if (!origin || octstr_len(origin) == 0) {
1637  info(0, "CIMD2[%s]: Got SMS without sender, discarding.",
1638  octstr_get_cstr(conn->id));
1639  goto error;
1640  }
1641 
1642  if (!text && (!UDH || octstr_len(UDH) == 0)) {
1643  info(0, "CIMD2[%s]: Got empty SMS, ignoring.",
1644  octstr_get_cstr(conn->id));
1645  goto error;
1646  }
1647 
1648  message = msg_create(sms);
1649  if (! dcs_to_fields(&message, DCS)) {
1650  /* XXX Should reject this message ? */
1651  debug("bb.sms.cimd2", 0, "CIMD2[%s]: Invalid DCS",
1652  octstr_get_cstr(conn->id));
1653  dcs_to_fields(&message, 0);
1654  }
1655  time(&message->sms.time);
1656  message->sms.sender = origin;
1657  message->sms.receiver = destination;
1658  if (UDH) {
1659  message->sms.udhdata = UDH;
1660  }
1661  message->sms.msgdata = text;
1662  return message;
1663 
1664 error:
1665  msg_destroy(message);
1666  octstr_destroy(destination);
1667  octstr_destroy(origin);
1668  octstr_destroy(UDH);
1669  octstr_destroy(text);
1670  return NULL;
1671 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
static Octstr * packet_get_sms_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:665
static Octstr * packet_get_hex_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:681
Octstr * id
Definition: smscconn_p.h:174
static Octstr * packet_get_address_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:653
#define msg_create(type)
Definition: msg.h:136
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static long packet_get_int_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:616
Definition: msg.h:79
char * text
Definition: smsc_cimd2.c:921
void msg_destroy(Msg *msg)
Definition: msg.c:132
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int dcs_to_fields(Msg **msg, int dcs)
Definition: sms.c:139
static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn)
Definition: smsc_cimd2.c:1081
void charset_gsm_to_utf8(Octstr *ostr)
Definition: charset.c:220
static int cimd2_add_msg_cb ( SMSCConn conn,
Msg sms 
)
static

Definition at line 2239 of file smsc_cimd2.c.

References smscconn::data, gwlist_produce(), gwthread_wakeup(), privdata::io_thread, msg_duplicate(), and privdata::outgoing_queue.

Referenced by smsc_cimd2_create().

2240 {
2241  PrivData *pdata = conn->data;
2242  Msg *copy;
2243 
2244  copy = msg_duplicate(sms);
2245  gwlist_produce(pdata->outgoing_queue, copy);
2246  gwthread_wakeup(pdata->io_thread);
2247 
2248  return 0;
2249 }
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
void gwlist_produce(List *list, void *item)
Definition: list.c:411
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
int io_thread
Definition: smsc_cimd2.c:119
Definition: msg.h:79
void gwthread_wakeup(long thread)
static void cimd2_close_socket ( PrivData pdata)
static

Definition at line 1837 of file smsc_cimd2.c.

References privdata::conn, gw_assert(), smscconn::id, octstr_get_cstr, privdata::socket, and warning().

Referenced by cimd2_login(), cimd2_shutdown_cb(), cimd2_submit_msg(), and sms_receive().

1838 {
1839  gw_assert(pdata != NULL);
1840 
1841  if (pdata->socket < 0)
1842  return;
1843 
1844  if (close(pdata->socket) < 0)
1845  warning(errno, "CIMD2[%s]: error closing socket",
1846  octstr_get_cstr(pdata->conn->id));
1847  pdata->socket = -1;
1848 }
Octstr * id
Definition: smscconn_p.h:174
int socket
Definition: smsc_cimd2.c:108
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
SMSCConn * conn
Definition: smsc_cimd2.c:118
static void cimd2_destroy ( PrivData pdata)
static

Definition at line 1929 of file smsc_cimd2.c.

References privdata::conn, gwlist_destroy(), gwlist_len(), privdata::host, smscconn::id, privdata::inbuffer, msg_destroy_item(), privdata::my_number, octstr_destroy(), octstr_get_cstr, privdata::outgoing_queue, privdata::password, privdata::received, privdata::stopped, privdata::username, and warning().

Referenced by cimd2_shutdown_cb(), and smsc_cimd2_create().

1930 {
1931  int discarded;
1932 
1933  if (pdata == NULL)
1934  return;
1935 
1936  octstr_destroy(pdata->host);
1937  octstr_destroy(pdata->username);
1938  octstr_destroy(pdata->password);
1939  octstr_destroy(pdata->inbuffer);
1940  octstr_destroy(pdata->my_number);
1941 
1942  discarded = gwlist_len(pdata->received);
1943  if (discarded > 0)
1944  warning(0, "CIMD2[%s]: discarded %d received messages",
1945  octstr_get_cstr(pdata->conn->id),
1946  discarded);
1947 
1949  gwlist_destroy(pdata->outgoing_queue, NULL);
1950  gwlist_destroy(pdata->stopped, NULL);
1951 
1952  gw_free(pdata);
1953 }
Octstr * inbuffer
Definition: smsc_cimd2.c:112
Octstr * id
Definition: smscconn_p.h:174
long gwlist_len(List *list)
Definition: list.c:166
List * outgoing_queue
Definition: smsc_cgw.c:153
Octstr * password
Definition: smsc_cimd2.c:100
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
List * stopped
Definition: smsc_cimd2.c:121
void msg_destroy_item(void *msg)
Definition: msg.c:147
Octstr * my_number
Definition: smsc_cimd2.c:105
Octstr * username
Definition: smsc_cimd2.c:99
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * host
Definition: smsc_cgw.c:163
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
List * received
Definition: smsc_cimd2.c:113
SMSCConn * conn
Definition: smsc_cimd2.c:118
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
static struct packet* cimd2_get_packet ( PrivData pdata,
Octstr **  ts 
)
static

Definition at line 1526 of file smsc_cimd2.c.

References privdata::conn, packet::data, debug(), error(), gw_assert(), smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_get_cstr, P_MC_TIMESTAMP, packet_check(), packet_check_can_receive(), packet_extract(), packet_get_parm(), read_available(), RESPONSE_TIMEOUT, privdata::socket, and warning().

Referenced by cimd2_request().

1527 {
1528  struct packet *packet = NULL;
1529 
1530  gw_assert(pdata != NULL);
1531 
1532  /* If packet is already available, don't try to read anything */
1533  packet = packet_extract(pdata->inbuffer, pdata->conn);
1534 
1535  while (packet == NULL) {
1536  if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
1537  warning(0, "CIMD2[%s]: SMSC is not responding",
1538  octstr_get_cstr(pdata->conn->id));
1539  return NULL;
1540  }
1541 
1542  if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
1543  error(0, "CIMD2[%s]: cimd2_get_packet: read failed",
1544  octstr_get_cstr(pdata->conn->id));
1545  return NULL;
1546  }
1547 
1548  packet = packet_extract(pdata->inbuffer, pdata->conn);
1549  }
1550 
1551  packet_check(packet,pdata->conn);
1552  packet_check_can_receive(packet,pdata->conn);
1553  debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
1554  octstr_get_cstr(pdata->conn->id),
1555  octstr_get_cstr(packet->data));
1556  if (ts)
1557  *ts = packet_get_parm(packet,P_MC_TIMESTAMP);
1558 
1559  if (pdata->keepalive > 0)
1560  pdata->next_ping = time(NULL) + pdata->keepalive;
1561 
1562  return packet;
1563 }
void error(int err, const char *fmt,...)
Definition: log.c:612
Octstr * inbuffer
Definition: smsc_cimd2.c:112
Octstr * id
Definition: smscconn_p.h:174
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
int octstr_append_from_socket(Octstr *ostr, int socket)
Definition: octstr.c:1278
static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:904
int socket
Definition: smsc_cimd2.c:108
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
time_t next_ping
Definition: smsc_cimd2.c:115
Octstr * data
Definition: smsc_cimd2.c:446
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
static int packet_check(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:846
int read_available(int fd, long wait_usec)
Definition: socket.c:406
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define RESPONSE_TIMEOUT
Definition: smsc_cimd2.c:128
static struct packet * packet_extract(Octstr *in, SMSCConn *conn)
Definition: smsc_cimd2.c:533
long keepalive
Definition: smsc_cimd2.c:104
SMSCConn * conn
Definition: smsc_cimd2.c:118
static void cimd2_handle_request ( struct packet request,
SMSCConn conn 
)
static

Definition at line 1674 of file smsc_cimd2.c.

References cimd2_accept_delivery_report_message(), cimd2_accept_message(), cimd2_send_response(), smscconn::data, DELIVER_MESSAGE, DELIVER_STATUS_REPORT, gwlist_append(), smscconn::id, octstr_get_cstr, packet::operation, privdata::receive_seq, privdata::received, packet::seq, and warning().

Referenced by cimd2_receive_msg(), and cimd2_request().

1675 {
1676  PrivData *pdata = conn->data;
1677  Msg *message = NULL;
1678 
1679  if ((request->seq == 254 && pdata->receive_seq == 0) ||
1680  request->seq == pdata->receive_seq - 2) {
1681  warning(0, "CIMD2[%s]: request had same sequence number as previous.",
1682  octstr_get_cstr(conn->id));
1683  }
1684  else {
1685  pdata->receive_seq = request->seq + 2;
1686  if (pdata->receive_seq > 254)
1687  pdata->receive_seq = 0;
1688 
1689  if (request->operation == DELIVER_STATUS_REPORT) {
1690  message = cimd2_accept_delivery_report_message(request, conn);
1691  if (message)
1692  gwlist_append(pdata->received, message);
1693  }
1694  else if (request->operation == DELIVER_MESSAGE) {
1695  message = cimd2_accept_message(request,conn);
1696  if (message)
1697  gwlist_append(pdata->received, message);
1698  }
1699  }
1700 
1701  cimd2_send_response(request, pdata);
1702 }
int operation
Definition: smsc_cimd2.c:444
void gwlist_append(List *list, void *item)
Definition: list.c:179
static void cimd2_send_response(struct packet *request, PrivData *pdata)
Definition: smsc_cimd2.c:1567
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
int receive_seq
Definition: smsc_cimd2.c:110
static Msg * cimd2_accept_delivery_report_message(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:2084
Definition: msg.h:79
int seq
Definition: smsc_cimd2.c:445
void warning(int err, const char *fmt,...)
Definition: log.c:624
static Msg * cimd2_accept_message(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:1588
List * received
Definition: smsc_cimd2.c:113
static int cimd2_login ( SMSCConn conn)
static

Definition at line 1854 of file smsc_cimd2.c.

References BOGUS_SEQUENCE, cimd2_close_socket(), cimd2_request(), smscconn::data, error(), gw_assert(), privdata::host, smscconn::id, info(), LOGIN, octstr_get_cstr, smscconn::our_host, privdata::our_port, P_PASSWORD, P_USER_IDENTITY, packet_add_string_parm(), packet_create(), packet_destroy(), privdata::password, privdata::port, privdata::socket, tcpip_connect_to_server_with_port(), privdata::username, and warning().

Referenced by io_thread().

1855 {
1856  PrivData *pdata = conn->data;
1857  int ret;
1858  struct packet *packet = NULL;
1859 
1860  gw_assert(pdata != NULL);
1861 
1862  if (pdata->socket >= 0) {
1863  warning(0, "CIMD2[%s]: login: socket was already open; closing",
1864  octstr_get_cstr(conn->id));
1865  cimd2_close_socket(pdata);
1866  }
1867 
1869  octstr_get_cstr(pdata->host),
1870  pdata->port,
1871  pdata->our_port,
1872  (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL));
1873  if (pdata->socket != -1) {
1874 
1875  packet = packet_create(LOGIN, BOGUS_SEQUENCE);
1876  packet_add_string_parm(packet, P_USER_IDENTITY, pdata->username, conn);
1877  packet_add_string_parm(packet, P_PASSWORD, pdata->password, conn);
1878 
1879  ret = cimd2_request(packet, conn, NULL);
1880 
1881  if (ret >= 0) {
1882  packet_destroy(packet);
1883  info(0, "CIMD2[%s] logged in.",
1884  octstr_get_cstr(conn->id));
1885  return 0;
1886  }
1887  }
1888  error(0, "CIMD2[%s] login failed.",
1889  octstr_get_cstr(conn->id));
1890  cimd2_close_socket(pdata);
1891  packet_destroy(packet);
1892  return -1;
1893 }
int port
Definition: smsc_cgw.c:159
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
int socket
Definition: smsc_cimd2.c:108
Octstr * password
Definition: smsc_cimd2.c:100
Octstr * our_host
Definition: smscconn_p.h:192
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define BOGUS_SEQUENCE
Definition: smsc_cimd2.c:471
static void cimd2_close_socket(PrivData *pdata)
Definition: smsc_cimd2.c:1837
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_cimd2.c:1718
static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1227
Octstr * username
Definition: smsc_cimd2.c:99
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * host
Definition: smsc_cgw.c:163
int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr)
Definition: socket.c:156
gw_assert(wtls_machine->packet_to_send!=NULL)
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
int our_port
Definition: smsc_cgw.c:161
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
static void cimd2_logout ( SMSCConn conn)
static

Definition at line 1895 of file smsc_cimd2.c.

References BOGUS_SEQUENCE, cimd2_request(), smscconn::id, info(), LOGOUT, octstr_get_cstr, packet_create(), and packet_destroy().

Referenced by cimd2_shutdown_cb().

1896 {
1897  struct packet *packet = NULL;
1898  int ret;
1899 
1900  packet = packet_create(LOGOUT, BOGUS_SEQUENCE);
1901 
1902  /* TODO: Don't wait very long for a response in this case. */
1903  ret = cimd2_request(packet, conn, NULL);
1904 
1905  if (ret == 0) {
1906  info(0, "CIMD2[%s] logged out.",
1907  octstr_get_cstr(conn->id));
1908  }
1909  packet_destroy(packet);
1910 }
void info(int err, const char *fmt,...)
Definition: log.c:636
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define BOGUS_SEQUENCE
Definition: smsc_cimd2.c:471
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_cimd2.c:1718
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
static long cimd2_queued_cb ( SMSCConn conn)
static

Definition at line 2313 of file smsc_cimd2.c.

References smscconn::data, gwlist_len(), smscconn::load, privdata::outgoing_queue, SMSCCONN_DEAD, and smscconn::status.

Referenced by smsc_cimd2_create().

2314 {
2315  PrivData *pdata = conn->data;
2316  conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ?
2317  gwlist_len(pdata->outgoing_queue) : 0) : 0);
2318  return conn->load;
2319 }
long gwlist_len(List *list)
Definition: list.c:166
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
smscconn_status_t status
Definition: smscconn_p.h:151
int load
Definition: smscconn_p.h:152
static int cimd2_receive_msg ( SMSCConn conn,
Msg **  msg 
)
static

Definition at line 2002 of file smsc_cimd2.c.

References cimd2_handle_request(), cimd2_send_alive(), privdata::conn, smscconn::data, packet::data, debug(), error(), gw_assert(), gwlist_consume(), gwlist_len(), smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_dump, octstr_get_cstr, packet::operation, packet_check(), packet_check_can_receive(), packet_destroy(), packet_extract(), read_available(), privdata::received, RESPONSE, privdata::socket, and warning().

Referenced by sms_receive().

2003 {
2004  PrivData *pdata = conn->data;
2005  long ret;
2006  struct packet *packet;
2007 
2008  gw_assert(pdata != NULL);
2009 
2010  if (gwlist_len(pdata->received) > 0) {
2011  *msg = gwlist_consume(pdata->received);
2012  return 1;
2013  }
2014 
2015  if (pdata->socket < 0) {
2016  /* XXX We have to assume that smsc_send_message is
2017  * currently trying to reopen, so we have to make
2018  * this thread wait. It should be done in a nicer
2019  * way. */
2020  return 0;
2021  }
2022 
2023  ret = read_available(pdata->socket, 0);
2024  if (ret == 0) {
2025  if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
2026  if (cimd2_send_alive(conn) < 0)
2027  return -1;
2028  }
2029  return 0;
2030  }
2031 
2032  if (ret < 0) {
2033  warning(errno, "CIMD2[%s]: cimd2_receive_msg: read_available failed",
2034  octstr_get_cstr(conn->id));
2035  return -1;
2036  }
2037 
2038  /* We have some data waiting... see if it is an sms delivery. */
2039  ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
2040 
2041  if (ret == 0) {
2042  warning(0, "CIMD2[%s]: cimd2_receive_msg: service center closed connection.",
2043  octstr_get_cstr(conn->id));
2044  return -1;
2045  }
2046  if (ret < 0) {
2047  warning(0, "CIMD2[%s]: cimd2_receive_msg: read failed",
2048  octstr_get_cstr(conn->id));
2049  return -1;
2050  }
2051 
2052 
2053  for (;;) {
2054  packet = packet_extract(pdata->inbuffer,conn);
2055  if (!packet)
2056  break;
2057 
2058  packet_check(packet,conn);
2059  packet_check_can_receive(packet,conn);
2060  debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
2061  octstr_get_cstr(pdata->conn->id),
2062  octstr_get_cstr(packet->data));
2063 
2064  if (packet->operation < RESPONSE)
2065  cimd2_handle_request(packet, conn);
2066  else {
2067  error(0, "CIMD2[%s]: cimd2_receive_msg: unexpected response packet",
2068  octstr_get_cstr(conn->id));
2069  octstr_dump(packet->data, 0);
2070  }
2071 
2072  packet_destroy(packet);
2073  }
2074 
2075  if (gwlist_len(pdata->received) > 0) {
2076  *msg = gwlist_consume(pdata->received);
2077  return 1;
2078  }
2079  return 0;
2080 }
void error(int err, const char *fmt,...)
Definition: log.c:612
int operation
Definition: smsc_cimd2.c:444
Octstr * inbuffer
Definition: smsc_cimd2.c:112
Octstr * id
Definition: smscconn_p.h:174
long gwlist_len(List *list)
Definition: list.c:166
void * data
Definition: smscconn_p.h:249
int octstr_append_from_socket(Octstr *ostr, int socket)
Definition: octstr.c:1278
static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:904
int socket
Definition: smsc_cimd2.c:108
static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:1674
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
time_t next_ping
Definition: smsc_cimd2.c:115
static int cimd2_send_alive(SMSCConn *conn)
Definition: smsc_cimd2.c:1912
Octstr * data
Definition: smsc_cimd2.c:446
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
static int packet_check(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:846
void * gwlist_consume(List *list)
Definition: list.c:427
int read_available(int fd, long wait_usec)
Definition: socket.c:406
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
List * received
Definition: smsc_cimd2.c:113
static struct packet * packet_extract(Octstr *in, SMSCConn *conn)
Definition: smsc_cimd2.c:533
long keepalive
Definition: smsc_cimd2.c:104
SMSCConn * conn
Definition: smsc_cimd2.c:118
static int cimd2_request ( struct packet request,
SMSCConn conn,
Octstr **  ts 
)
static

Definition at line 1718 of file smsc_cimd2.c.

References cimd2_get_packet(), cimd2_handle_request(), smscconn::data, packet::data, debug(), error(), GENERAL_ERROR_RESPONSE, gw_assert(), smscconn::id, NACK, octstr_destroy(), octstr_dump, octstr_get_cstr, octstr_write_to_socket(), packet::operation, operation_can_send(), operation_name(), packet_destroy(), packet_display_error(), packet_set_checksum(), packet_set_send_sequence(), reply(), RESPONSE, privdata::send_seq, packet::seq, privdata::socket, and warning().

Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), and cimd2_submit_msg().

1719 {
1720  PrivData *pdata = conn->data;
1721  int ret;
1722  struct packet *reply = NULL;
1723  int errorcode;
1724  int tries = 0;
1725 
1726  gw_assert(pdata != NULL);
1727  gw_assert(request != NULL);
1729 
1730  if (pdata->socket < 0) {
1731  warning(0, "CIMD2[%s]: cimd2_request: socket not open.",
1732  octstr_get_cstr(conn->id));
1733  return -2;
1734  }
1735 
1736 retransmit:
1737  packet_set_send_sequence(request, pdata);
1738  packet_set_checksum(request);
1739 
1740  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
1741  octstr_get_cstr(conn->id),
1742  octstr_get_cstr(request->data));
1743 
1744  ret = octstr_write_to_socket(pdata->socket, request->data);
1745  if (ret < 0)
1746  goto io_error;
1747 
1748 next_reply:
1749  packet_destroy(reply); /* destroy old, if any */
1750  reply = cimd2_get_packet(pdata, ts);
1751  if (!reply)
1752  goto io_error;
1753 
1754  errorcode = packet_display_error(reply,conn);
1755 
1756  if (reply->operation == NACK) {
1757  warning(0, "CIMD2[%s]: received NACK",
1758  octstr_get_cstr(conn->id));
1759  octstr_dump(reply->data, 0);
1760  /* Correct sequence number if server says it was wrong,
1761  * but only if server's number is sane. */
1762  if (reply->seq != request->seq && (reply->seq % 2) == 1) {
1763  warning(0, "CIMD2[%s]: correcting sequence number from %ld to %ld.",
1764  octstr_get_cstr(conn->id),
1765  (long) pdata->send_seq,
1766  (long) reply->seq);
1767  pdata->send_seq = reply->seq;
1768  }
1769  goto retry;
1770  }
1771 
1772  if (reply->operation == GENERAL_ERROR_RESPONSE) {
1773  error(0, "CIMD2[%s]: received general error response",
1774  octstr_get_cstr(conn->id));
1775  goto io_error;
1776  }
1777 
1778  /* The server sent us a request. Handle it, then wait for
1779  * a new reply. */
1780  if (reply->operation < RESPONSE) {
1781  cimd2_handle_request(reply, conn);
1782  goto next_reply;
1783  }
1784 
1785  if (reply->seq != request->seq) {
1786  /* We got a response to a different request number than
1787  * what we send. Strange. */
1788  warning(0, "CIMD2[%s]: response had unexpected sequence number; ignoring.",
1789  octstr_get_cstr(conn->id));
1790  goto next_reply;
1791  }
1792 
1793  if (reply->operation != request->operation + RESPONSE) {
1794  /* We got a response that didn't match our request */
1795  Octstr *request_name = operation_name(request->operation);
1796  Octstr *reply_name = operation_name(reply->operation);
1797  warning(0, "CIMD2[%s]: %s request got a %s",
1798  octstr_get_cstr(conn->id),
1799  octstr_get_cstr(request_name),
1800  octstr_get_cstr(reply_name));
1801 
1802  octstr_destroy(request_name);
1803  octstr_destroy(reply_name);
1804  octstr_dump(reply->data, 0);
1805  goto retry;
1806  }
1807 
1808  if (errorcode > 0)
1809  goto error;
1810 
1811  /* The reply passed all the checks... looks like the SMSC accepted
1812  * our request! */
1813  packet_destroy(reply);
1814  return 0;
1815 
1816 io_error:
1817  packet_destroy(reply);
1818  return -2;
1819 
1820 error:
1821  packet_destroy(reply);
1822  return -1;
1823 
1824 retry:
1825  if (++tries < 3) {
1826  warning(0, "CIMD2[%s]: Retransmitting (take %d)",
1827  octstr_get_cstr(conn->id),
1828  tries);
1829  goto retransmit;
1830  }
1831  warning(0, "CIMD2[%s]: Giving up.",
1832  octstr_get_cstr(conn->id));
1833  goto io_error;
1834 }
void error(int err, const char *fmt,...)
Definition: log.c:612
int operation
Definition: smsc_cimd2.c:444
int octstr_write_to_socket(int socket, Octstr *ostr)
Definition: octstr.c:1225
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
int socket
Definition: smsc_cimd2.c:108
static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:1674
static struct packet * cimd2_get_packet(PrivData *pdata, Octstr **ts)
Definition: smsc_cimd2.c:1526
static void packet_set_checksum(struct packet *packet)
Definition: smsc_cimd2.c:1274
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static int packet_display_error(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:979
static int operation_can_send(int operation)
Definition: smsc_cimd2.c:406
static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
Definition: smsc_cimd2.c:1511
Octstr * data
Definition: smsc_cimd2.c:446
static Octstr * operation_name(int operation)
Definition: smsc_cimd2.c:384
int seq
Definition: smsc_cimd2.c:445
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
gw_assert(wtls_machine->packet_to_send!=NULL)
int send_seq
Definition: smsc_cimd2.c:109
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static void reply(HTTPClient *c, List *push_headers)
static int cimd2_send_alive ( SMSCConn conn)
static

Definition at line 1912 of file smsc_cimd2.c.

References ALIVE, BOGUS_SEQUENCE, cimd2_request(), smscconn::id, octstr_get_cstr, packet_create(), packet_destroy(), and warning().

Referenced by cimd2_receive_msg().

1913 {
1914  struct packet *packet = NULL;
1915  int ret;
1916 
1917  packet = packet_create(ALIVE, BOGUS_SEQUENCE);
1918  ret = cimd2_request(packet, conn, NULL);
1919  packet_destroy(packet);
1920 
1921  if (ret < 0)
1922  warning(0, "CIMD2[%s]: SMSC not alive.",
1923  octstr_get_cstr(conn->id));
1924 
1925  return ret;
1926 }
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define BOGUS_SEQUENCE
Definition: smsc_cimd2.c:471
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_cimd2.c:1718
void warning(int err, const char *fmt,...)
Definition: log.c:624
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
static void cimd2_send_response ( struct packet request,
PrivData pdata 
)
static

Definition at line 1567 of file smsc_cimd2.c.

References privdata::conn, packet::data, debug(), gw_assert(), smscconn::id, octstr_get_cstr, octstr_write_to_socket(), packet::operation, packet_create(), packet_destroy(), packet_set_checksum(), response(), RESPONSE, packet::seq, and privdata::socket.

Referenced by cimd2_handle_request().

1568 {
1569  struct packet *response;
1570 
1571  gw_assert(request != NULL);
1572  gw_assert(request->operation < RESPONSE);
1573 
1574  response = packet_create(request->operation + RESPONSE, request->seq);
1575  packet_set_checksum(response);
1576 
1577  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
1578  octstr_get_cstr(pdata->conn->id),
1579  octstr_get_cstr(response->data));
1580 
1581  /* Don't check errors here because if there is something
1582  * wrong with the socket, the main loop will detect it. */
1583  octstr_write_to_socket(pdata->socket, response->data);
1584 
1585  packet_destroy(response);
1586 }
int operation
Definition: smsc_cimd2.c:444
int octstr_write_to_socket(int socket, Octstr *ostr)
Definition: octstr.c:1225
Octstr * id
Definition: smscconn_p.h:174
int socket
Definition: smsc_cimd2.c:108
static void packet_set_checksum(struct packet *packet)
Definition: smsc_cimd2.c:1274
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
Octstr * data
Definition: smsc_cimd2.c:446
int seq
Definition: smsc_cimd2.c:445
gw_assert(wtls_machine->packet_to_send!=NULL)
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static int response(List *push_headers, Octstr **username, Octstr **password)
SMSCConn * conn
Definition: smsc_cimd2.c:118
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
static int cimd2_shutdown_cb ( SMSCConn conn,
int  finish_sending 
)
static

Definition at line 2252 of file smsc_cimd2.c.

References bb_smscconn_killed(), bb_smscconn_send_failed(), cimd2_close_socket(), cimd2_destroy(), cimd2_logout(), smscconn::data, debug(), gwlist_extract_first(), gwlist_remove_producer(), gwthread_join(), gwthread_wakeup(), smscconn::id, privdata::io_thread, smscconn::is_stopped, msg, octstr_get_cstr, privdata::outgoing_queue, privdata::quitting, SMSCCONN_DEAD, SMSCCONN_FAILED_SHUTDOWN, SMSCCONN_KILLED_SHUTDOWN, smscconn::status, privdata::stopped, and smscconn::why_killed.

Referenced by smsc_cimd2_create().

2253 {
2254  PrivData *pdata = conn->data;
2255 
2256  debug("bb.sms", 0, "Shutting down SMSCConn CIMD2 %s (%s)",
2257  octstr_get_cstr(conn->id),
2258  finish_sending ? "slow" : "instant");
2259 
2260  /* Documentation claims this would have been done by smscconn.c,
2261  but isn't when this code is being written. */
2263  pdata->quitting = 1; /* Separate from why_killed to avoid locking, as
2264  * why_killed may be changed from outside? */
2265 
2266  if (finish_sending == 0) {
2267  Msg *msg;
2268  while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
2270  }
2271  }
2272 
2273  cimd2_logout(conn);
2274  if (conn->is_stopped) {
2276  conn->is_stopped = 0;
2277  }
2278 
2279  if (pdata->io_thread != -1) {
2280  gwthread_wakeup(pdata->io_thread);
2281  gwthread_join(pdata->io_thread);
2282  }
2283 
2284  cimd2_close_socket(pdata);
2285  cimd2_destroy(pdata);
2286 
2287  debug("bb.sms", 0, "SMSCConn CIMD2 %s shut down.",
2288  octstr_get_cstr(conn->id));
2289  conn->status = SMSCCONN_DEAD;
2290  bb_smscconn_killed();
2291  return 0;
2292 }
void bb_smscconn_killed(void)
Definition: bb_smscconn.c:199
Octstr * id
Definition: smscconn_p.h:174
void gwthread_join(long thread)
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
int io_thread
Definition: smsc_cimd2.c:119
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
List * stopped
Definition: smsc_cimd2.c:121
static void cimd2_logout(SMSCConn *conn)
Definition: smsc_cimd2.c:1895
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
static void cimd2_close_socket(PrivData *pdata)
Definition: smsc_cimd2.c:1837
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
void gwlist_remove_producer(List *list)
Definition: list.c:401
int quitting
Definition: smsc_cimd2.c:120
volatile sig_atomic_t is_stopped
Definition: smscconn_p.h:169
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwthread_wakeup(long thread)
smscconn_status_t status
Definition: smscconn_p.h:151
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static void cimd2_destroy(PrivData *pdata)
Definition: smsc_cimd2.c:1929
static void cimd2_start_cb ( SMSCConn conn)
static

Definition at line 2294 of file smsc_cimd2.c.

References smscconn::data, debug(), gwlist_remove_producer(), gwthread_wakeup(), smscconn::id, privdata::io_thread, octstr_get_cstr, and privdata::stopped.

Referenced by smsc_cimd2_create().

2295 {
2296  PrivData *pdata = conn->data;
2297 
2299  /* in case there are messages in the buffer already */
2300  gwthread_wakeup(pdata->io_thread);
2301  debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called",
2302  octstr_get_cstr(conn->id));
2303 }
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
int io_thread
Definition: smsc_cimd2.c:119
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
List * stopped
Definition: smsc_cimd2.c:121
void gwlist_remove_producer(List *list)
Definition: list.c:401
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwthread_wakeup(long thread)
static void cimd2_stop_cb ( SMSCConn conn)
static

Definition at line 2305 of file smsc_cimd2.c.

References smscconn::data, debug(), gwlist_add_producer(), smscconn::id, octstr_get_cstr, and privdata::stopped.

Referenced by smsc_cimd2_create().

2306 {
2307  PrivData *pdata = conn->data;
2308  gwlist_add_producer(pdata->stopped);
2309  debug("bb.sms", 0, "SMSCConn CIMD2 %s, stop called",
2310  octstr_get_cstr(conn->id));
2311 }
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
List * stopped
Definition: smsc_cimd2.c:121
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwlist_add_producer(List *list)
Definition: list.c:383
static int cimd2_submit_msg ( SMSCConn conn,
Msg msg 
)
static

Definition at line 1956 of file smsc_cimd2.c.

References bb_smscconn_send_failed(), bb_smscconn_sent(), cimd2_close_socket(), cimd2_request(), smscconn::data, debug(), dlr_add(), DLR_IS_SUCCESS_OR_FAIL, smscconn::flow_mutex, gw_assert(), smscconn::id, mutex_lock, mutex_unlock, privdata::my_number, smscconn::name, privdata::no_dlr, octstr_create, octstr_destroy(), octstr_get_cstr, packet_destroy(), packet_encode_message(), SMSCCONN_DISCONNECTED, SMSCCONN_FAILED_MALFORMED, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_TEMPORARILY, and smscconn::status.

Referenced by io_thread().

1957 {
1958  PrivData *pdata = conn->data;
1959  struct packet *packet;
1960  Octstr *ts = NULL;
1961  int ret;
1962 
1963  gw_assert(pdata != NULL);
1964  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending message",
1965  octstr_get_cstr(conn->id));
1966 
1967  packet = packet_encode_message(msg, pdata->my_number,conn);
1968  if (!packet) {
1969  /* This is a protocol error. Does this help? I doubt..
1970  * But nevermind that.
1971  */
1972  bb_smscconn_send_failed(conn, msg,
1974  return -1;
1975  }
1976 
1977  ret = cimd2_request(packet, conn, &ts);
1978  if ((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
1979  dlr_add(conn->name, ts, msg, 1);
1980  }
1981  octstr_destroy(ts);
1982  packet_destroy(packet);
1983 
1984  if (ret == -1) {
1985  bb_smscconn_send_failed(conn, msg,
1987  }
1988  else if (ret == -2) {
1989  cimd2_close_socket(pdata);
1991  mutex_lock(conn->flow_mutex);
1992  conn->status = SMSCCONN_DISCONNECTED;
1993  mutex_unlock(conn->flow_mutex);
1994  }
1995  else {
1996  bb_smscconn_sent(conn,msg, NULL);
1997  }
1998 
1999  return ret;
2000 }
Octstr * name
Definition: smscconn_p.h:173
#define mutex_unlock(m)
Definition: thread.h:136
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst)
Definition: dlr.c:330
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void cimd2_close_socket(PrivData *pdata)
Definition: smsc_cimd2.c:1837
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_cimd2.c:1718
Octstr * my_number
Definition: smsc_cimd2.c:105
Mutex * flow_mutex
Definition: smscconn_p.h:157
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
gw_assert(wtls_machine->packet_to_send!=NULL)
int no_dlr
Definition: smsc_cimd2.c:106
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
Definition: octstr.c:118
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
Definition: bb_smscconn.c:279
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
smscconn_status_t status
Definition: smscconn_p.h:151
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
static struct packet * packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
Definition: smsc_cimd2.c:1319
#define mutex_lock(m)
Definition: thread.h:130
#define DLR_IS_SUCCESS_OR_FAIL(dlr)
Definition: dlr.h:85
static void convert_cimd2_to_gsm ( Octstr text,
SMSCConn conn 
)
static

Definition at line 1081 of file smsc_cimd2.c.

References cimd1, cimd2, cimd_combinations, gsm, smscconn::id, octstr_delete(), octstr_get_char(), octstr_get_cstr, octstr_len(), octstr_set_char(), and warning().

Referenced by cimd2_accept_message().

1082 {
1083  long pos, len;
1084  int cimd1, cimd2;
1085  int c;
1086  int i;
1087 
1088  /* CIMD2 uses four single-character mappings that do not map
1089  * to themselves:
1090  * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring),
1091  * and '}' from 125 to 15 (a-ring).
1092  * Other than those, we only have to worry about the escape
1093  * sequences introduced by _ (underscore).
1094  */
1095 
1096  len = octstr_len(text);
1097  for (pos = 0; pos < len; pos++) {
1098  c = octstr_get_char(text, pos);
1099  if (c == '@')
1100  octstr_set_char(text, pos, 0);
1101  else if (c == '$')
1102  octstr_set_char(text, pos, 2);
1103  else if (c == ']')
1104  octstr_set_char(text, pos, 14);
1105  else if (c == '}')
1106  octstr_set_char(text, pos, 15);
1107  else if (c == '_' && pos + 2 < len) {
1108  cimd1 = octstr_get_char(text, pos + 1);
1109  cimd2 = octstr_get_char(text, pos + 2);
1110  for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
1111  if (cimd_combinations[i].cimd1 == cimd1 &&
1112  cimd_combinations[i].cimd2 == cimd2)
1113  break;
1114  }
1115  if (cimd_combinations[i].cimd1 == 0)
1116  warning(0, "CIMD2[%s]: Encountered unknown "
1117  "escape code _%c%c, ignoring.",
1118  octstr_get_cstr(conn->id),
1119  cimd1, cimd2);
1120  else {
1121  octstr_delete(text, pos, 2);
1122  octstr_set_char(text, pos, cimd_combinations[i].gsm);
1123  len = octstr_len(text);
1124  }
1125  }
1126  }
1127 }
unsigned char cimd1
Definition: smsc_cimd2.c:1024
unsigned char gsm
Definition: smsc_cimd2.c:1025
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
void warning(int err, const char *fmt,...)
Definition: log.c:624
static const struct @21 cimd_combinations[]
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
unsigned char cimd2
Definition: smsc_cimd2.c:1024
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
static void convert_gsm_to_cimd2 ( Octstr text)
static

Definition at line 1134 of file smsc_cimd2.c.

References cimd1, cimd2, cimd_combinations, gsm, gw_assert(), octstr_get_char(), octstr_insert_data(), octstr_len(), and octstr_set_char().

Referenced by packet_encode_message().

1135 {
1136  long pos, len;
1137 
1138  len = octstr_len(text);
1139  for (pos = 0; pos < len; pos++) {
1140  int c, i;
1141 
1142  c = octstr_get_char(text, pos);
1143  /* If c is not in the GSM alphabet at this point,
1144  * the caller did something badly wrong. */
1145  gw_assert(c >= 0);
1146  gw_assert(c < 128);
1147 
1148  for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
1149  if (cimd_combinations[i].gsm == c)
1150  break;
1151  }
1152 
1153  if (cimd_combinations[i].gsm == c) {
1154  /* Escape sequence */
1155  octstr_insert_data(text, pos, "_ ", 2);
1156  pos += 2;
1157  len += 2;
1158  octstr_set_char(text, pos - 1, cimd_combinations[i].cimd1);
1159  octstr_set_char(text, pos, cimd_combinations[i].cimd2);
1160  } else if (c == 2) {
1161  /* The dollar sign is the only GSM character that
1162  * does not have a CIMD escape sequence and does not
1163  * map to itself. */
1164  octstr_set_char(text, pos, '$');
1165  }
1166  }
1167 }
unsigned char cimd1
Definition: smsc_cimd2.c:1024
unsigned char gsm
Definition: smsc_cimd2.c:1025
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
static const struct @21 cimd_combinations[]
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
unsigned char cimd2
Definition: smsc_cimd2.c:1024
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
static void io_thread ( void *  arg)
static

Definition at line 2164 of file smsc_cimd2.c.

References bb_smscconn_connected(), bb_smscconn_receive(), cimd2_login(), cimd2_submit_msg(), smscconn::connect_time, smscconn::data, debug(), error(), smscconn::flow_mutex, gwlist_consume(), gwlist_extract_first(), gwthread_sleep(), smscconn::id, smscconn::log_idx, log_thread_to(), msg, mutex_lock, mutex_unlock, octstr_get_cstr, privdata::outgoing_queue, privdata::quitting, smscconn::reconnect_delay, sms_receive(), SMSCCONN_ACTIVE, SMSCCONN_RECONNECTING, smscconn::status, and privdata::stopped.

Referenced by smsc_cimd2_create().

2165 {
2166  Msg *msg;
2167  SMSCConn *conn = arg;
2168  PrivData *pdata = conn->data;
2169  double sleep = 0.0001;
2170 
2171  /* Make sure we log into our own log-file if defined */
2172  log_thread_to(conn->log_idx);
2173 
2174  /* remove messages from SMSC until we are killed */
2175  while (!pdata->quitting) {
2176 
2177  gwlist_consume(pdata->stopped); /* block here if suspended/isolated */
2178 
2179  /* check that connection is active */
2180  if (conn->status != SMSCCONN_ACTIVE) {
2181  if (cimd2_login(conn) != 0) {
2182  error(0, "CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
2183  octstr_get_cstr(conn->id),
2184  conn->reconnect_delay);
2186  mutex_lock(conn->flow_mutex);
2187  conn->status = SMSCCONN_RECONNECTING;
2188  mutex_unlock(conn->flow_mutex);
2189  continue;
2190  }
2191  mutex_lock(conn->flow_mutex);
2192  conn->status = SMSCCONN_ACTIVE;
2193  conn->connect_time = time(NULL);
2194  bb_smscconn_connected(conn);
2195  mutex_unlock(conn->flow_mutex);
2196  }
2197 
2198  /* receive messages */
2199  do {
2200  msg = sms_receive(conn);
2201  if (msg) {
2202  sleep = 0;
2203  debug("bb.sms.cimd2", 0, "CIMD2[%s]: new message received",
2204  octstr_get_cstr(conn->id));
2205  bb_smscconn_receive(conn, msg);
2206  }
2207  } while (msg);
2208 
2209  /* send messages */
2210  do {
2211  msg = gwlist_extract_first(pdata->outgoing_queue);
2212  if (msg) {
2213  sleep = 0;
2214  if (cimd2_submit_msg(conn,msg) != 0) break;
2215  }
2216  } while (msg);
2217 
2218  if (sleep > 0) {
2219 
2220  /* note that this implementations means that we sleep even
2221  * when we fail connection.. but time is very short, anyway
2222  */
2223  gwthread_sleep(sleep);
2224  /* gradually sleep longer and longer times until something starts to
2225  * happen - this of course reduces response time, but that's better than
2226  * extensive CPU usage when it is not used
2227  */
2228  sleep *= 2;
2229  if (sleep >= 2.0)
2230  sleep = 1.999999;
2231  }
2232  else {
2233  sleep = 0.0001;
2234  }
2235  }
2236 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void bb_smscconn_connected(SMSCConn *conn)
Definition: bb_smscconn.c:192
#define mutex_unlock(m)
Definition: thread.h:136
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
int log_idx
Definition: smscconn_p.h:197
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
long reconnect_delay
Definition: smscconn_p.h:199
void log_thread_to(int idx)
Definition: log.c:723
List * stopped
Definition: smsc_cimd2.c:121
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
Definition: bb_smscconn.c:478
time_t connect_time
Definition: smscconn_p.h:155
Mutex * flow_mutex
Definition: smscconn_p.h:157
static Msg * sms_receive(SMSCConn *conn)
Definition: smsc_cimd2.c:2139
int quitting
Definition: smsc_cimd2.c:120
void gwthread_sleep(double seconds)
void * gwlist_consume(List *list)
Definition: list.c:427
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static int cimd2_submit_msg(SMSCConn *conn, Msg *msg)
Definition: smsc_cimd2.c:1956
smscconn_status_t status
Definition: smscconn_p.h:151
static int cimd2_login(SMSCConn *conn)
Definition: smsc_cimd2.c:1854
#define mutex_lock(m)
Definition: thread.h:130
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int isphonedigit ( int  c)
static

Definition at line 324 of file smsc_cimd2.c.

Referenced by packet_add_address_parm(), packet_check_parameter(), and parm_valid_address().

325 {
326  return isdigit(c) || c == '+' || c == '-';
327 }
static int operation_can_receive ( int  operation)
static

Definition at line 422 of file smsc_cimd2.c.

References operation_can_send(), operation_find(), operations, and RESPONSE.

Referenced by operation_can_send(), and packet_check_can_receive().

423 {
424  int i = operation_find(operation);
425 
426  if (i >= 0)
427  return operations[i].can_receive;
428 
429  /* If we can send the request, then we can receive the response. */
430  if (operation >= RESPONSE)
432 
433  return 0;
434 }
int operation
Definition: smsc_cimd2.c:444
static const struct @19 operations[]
static int operation_can_send(int operation)
Definition: smsc_cimd2.c:406
static int operation_find(int operation)
Definition: smsc_cimd2.c:371
static int operation_can_send ( int  operation)
static

Definition at line 406 of file smsc_cimd2.c.

References operation_can_receive(), operation_find(), operations, and RESPONSE.

Referenced by cimd2_request(), and operation_can_receive().

407 {
408  int i = operation_find(operation);
409 
410  if (i >= 0)
411  return operations[i].can_send;
412 
413  /* If we can receive the request, then we can send the response. */
414  if (operation >= RESPONSE)
416 
417  return 0;
418 }
int operation
Definition: smsc_cimd2.c:444
static const struct @19 operations[]
static int operation_can_receive(int operation)
Definition: smsc_cimd2.c:422
static int operation_find(int operation)
Definition: smsc_cimd2.c:371
static int operation_find ( int  operation)
static

Definition at line 371 of file smsc_cimd2.c.

References code, and operations.

Referenced by operation_can_receive(), operation_can_send(), and operation_name().

372 {
373  int i;
374 
375  for (i = 0; operations[i].name != NULL; i++) {
376  if (operations[i].code == operation)
377  return i;
378  }
379 
380  return -1;
381 }
int operation
Definition: smsc_cimd2.c:444
static const struct @19 operations[]
int code
Definition: smsc_cimd2.c:346
static Octstr * operation_name ( int  operation)
static

Definition at line 384 of file smsc_cimd2.c.

References name, octstr_append_cstr(), octstr_create, operation_find(), operations, and RESPONSE.

Referenced by cimd2_request(), packet_check_can_receive(), and packet_display_error().

385 {
386  int i;
387 
389  if (i >= 0)
390  return octstr_create(operations[i].name);
391 
392  if (operation >= RESPONSE) {
394  if (i >= 0) {
395  Octstr *name = octstr_create(operations[i].name);
396  octstr_append_cstr(name, " response");
397  return name;
398  }
399  }
400 
401  /* Put the operation number here when we have octstr_format */
402  return octstr_create("(unknown)");
403 }
int operation
Definition: smsc_cimd2.c:444
static const struct @19 operations[]
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
char * name
Definition: smsc_cimd2.c:212
#define octstr_create(cstr)
Definition: octstr.h:125
Definition: octstr.c:118
static int operation_find(int operation)
Definition: smsc_cimd2.c:371
static void packet_add_address_parm ( struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn 
)
static

Definition at line 1233 of file smsc_cimd2.c.

References gw_assert(), isphonedigit(), octstr_check_range(), octstr_len(), P_ADDRESS, and packet_add_parm().

Referenced by packet_encode_message().

1234 {
1236  packet_add_parm(packet, P_ADDRESS, parmno, value, conn);
1237 }
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
static int isphonedigit(int c)
Definition: smsc_cimd2.c:324
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static void packet_add_hex_parm ( struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn 
)
static

Definition at line 1252 of file smsc_cimd2.c.

References octstr_binary_to_hex(), octstr_destroy(), octstr_duplicate, P_HEX, and packet_add_parm().

Referenced by packet_encode_message().

1253 {
1254  value = octstr_duplicate(value);
1255  octstr_binary_to_hex(value, 1); /* 1 for uppercase hex, i.e. A .. F */
1256  packet_add_parm(packet, P_HEX, parmno, value, conn);
1257  octstr_destroy(value);
1258 }
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
void octstr_binary_to_hex(Octstr *ostr, int uppercase)
Definition: octstr.c:463
#define octstr_duplicate(ostr)
Definition: octstr.h:187
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static void packet_add_int_parm ( struct packet packet,
int  parmno,
long  value,
SMSCConn conn 
)
static

Definition at line 1261 of file smsc_cimd2.c.

References gw_assert(), octstr_create, octstr_destroy(), P_INT, packet_add_parm(), and parm_in_range().

Referenced by packet_encode_message().

1262 {
1263  char buf[128];
1264  Octstr *valuestr;
1265 
1266  gw_assert(parm_in_range(parmno, value));
1267 
1268  sprintf(buf, "%ld", value);
1269  valuestr = octstr_create(buf);
1270  packet_add_parm(packet, P_INT, parmno, valuestr, conn);
1271  octstr_destroy(valuestr);
1272 }
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
gw_assert(wtls_machine->packet_to_send!=NULL)
Definition: octstr.c:118
static int parm_in_range(int parmno, long value)
Definition: smsc_cimd2.c:310
static void packet_add_parm ( struct packet packet,
int  parmtype,
int  parmno,
Octstr value,
SMSCConn conn 
)
static

Definition at line 1191 of file smsc_cimd2.c.

References packet::data, gw_assert(), smscconn::id, octstr_copy, octstr_destroy(), octstr_get_cstr, octstr_insert(), octstr_insert_data(), octstr_len(), parm_maxlen(), parm_name(), parm_type(), TAB_str, and warning().

Referenced by packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_sms_parm(), packet_add_string_parm(), and packet_encode_message().

1193 {
1194  char parmh[sizeof("tPPP:")];
1195  long position;
1196  long len;
1197  int copied = 0;
1198 
1199  len = octstr_len(value);
1200 
1201  gw_assert(packet != NULL);
1202  gw_assert(parm_type(parmno) == parmtype);
1203 
1204  if (len > parm_maxlen(parmno)) {
1205  warning(0, "CIMD2[%s]: %s parameter too long, truncating from "
1206  "%ld to %ld characters",
1207  octstr_get_cstr(conn->id),
1208  parm_name(parmno),
1209  len,
1210  (long) parm_maxlen(parmno));
1211  value = octstr_copy(value, 0, parm_maxlen(parmno));
1212  copied = 1;
1213  }
1214 
1215  /* There's a TAB and ETX at the end; insert it before those.
1216  * The new parameter will come with a new starting TAB. */
1217  position = octstr_len(packet->data) - 2;
1218 
1219  sprintf(parmh, TAB_str "%03d:", parmno);
1220  octstr_insert_data(packet->data, position, parmh, strlen(parmh));
1221  octstr_insert(packet->data, value, position + strlen(parmh));
1222  if (copied)
1223  octstr_destroy(value);
1224 }
#define TAB_str
Definition: smsc_cimd2.c:468
Octstr * id
Definition: smscconn_p.h:174
static int parm_maxlen(int parmno)
Definition: smsc_cimd2.c:287
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
static const char * parm_name(int parmno)
Definition: smsc_cimd2.c:297
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
Octstr * data
Definition: smsc_cimd2.c:446
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static void packet_add_sms_parm ( struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn 
)
static

Definition at line 1241 of file smsc_cimd2.c.

References P_SMS, and packet_add_parm().

Referenced by packet_encode_message().

1242 {
1243  packet_add_parm(packet, P_SMS, parmno, value, conn);
1244 }
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
static void packet_add_string_parm ( struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn 
)
static

Definition at line 1227 of file smsc_cimd2.c.

References P_STRING, and packet_add_parm().

Referenced by cimd2_login(), and packet_encode_message().

1228 {
1229  packet_add_parm(packet, P_STRING, parmno, value, conn);
1230 }
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
static int packet_check ( struct packet packet,
SMSCConn conn 
)
static

Definition at line 846 of file smsc_cimd2.c.

References packet::data, gw_assert(), gw_isxdigit(), smscconn::id, octstr_check_range(), octstr_dump, octstr_get_cstr, octstr_len(), octstr_search_char(), packet_check_header(), packet_check_parameter(), TAB, and warning().

Referenced by cimd2_get_packet(), and cimd2_receive_msg().

847 {
848  int errors = 0;
849  long pos, next;
850  Octstr *data;
851 
852  gw_assert(packet != NULL);
853  data = packet->data;
854 
855  if (octstr_search_char(data, 0, 0) >= 0) {
856  /* CIMD2 spec does not allow NUL bytes in a packet */
857  warning(0, "CIMD2[%s]: packet contains NULs",
858  octstr_get_cstr(conn->id));
859  errors++;
860  }
861 
862  /* Assume the packet starts with STX and ends with ETX,
863  * because we parsed it that way in the first place. */
864 
865  errors += (packet_check_header(packet,conn) < 0);
866 
867  /* Parameters are separated by tabs. After the last parameter
868  * there is a tab, an optional two-digit checksum, and the ETX.
869  * Check each parameter in turn, by skipping from tab to tab.
870  */
871  /* Start at the first tab, wherever it is, so that we can still
872  * check parameters if the header was weird. */
873  pos = octstr_search_char(data, TAB, 0);
874  for ( ; pos >= 0; pos = next) {
875  next = octstr_search_char(data, TAB, pos + 1);
876  if (next >= 0) {
877  errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0);
878  } else {
879  /* Check if the checksum has the right format. Don't
880  * check the sum itself here, that will be done in a
881  * separate call later. */
882  /* There are two valid formats: TAB ETX (no checksum)
883  * and TAB digit digit ETX. We already know the TAB
884  * and the ETX are there. */
885  if (!(octstr_len(data) - pos == 2 ||
886  (octstr_len(data) - pos == 4 &&
887  octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) {
888  warning(0, "CIMD2[%s]: packet checksum in wrong format",
889  octstr_get_cstr(conn->id));
890  errors++;
891  }
892  }
893  }
894 
895 
896  if (errors > 0) {
897  octstr_dump(packet->data, 0);
898  return -1;
899  }
900 
901  return 0;
902 }
#define TAB
Definition: smsc_cimd2.c:463
static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn)
Definition: smsc_cimd2.c:728
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
Octstr * data
Definition: smsc_cimd2.c:446
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
int gw_isxdigit(int c)
Definition: utils.c:994
static int packet_check_header(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:705
static void packet_check_can_receive ( struct packet packet,
SMSCConn conn 
)
static

Definition at line 904 of file smsc_cimd2.c.

References gw_assert(), smscconn::id, name, octstr_destroy(), octstr_get_cstr, packet::operation, operation_can_receive(), operation_name(), and warning().

Referenced by cimd2_get_packet(), and cimd2_receive_msg().

905 {
906  gw_assert(packet != NULL);
907 
908  if (!operation_can_receive(packet->operation)) {
909  Octstr *name = operation_name(packet->operation);
910  warning(0, "CIMD2[%s]: SMSC sent us %s request",
911  octstr_get_cstr(conn->id),
912  octstr_get_cstr(name));
913  octstr_destroy(name);
914  }
915 }
int operation
Definition: smsc_cimd2.c:444
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static Octstr * operation_name(int operation)
Definition: smsc_cimd2.c:384
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
gw_assert(wtls_machine->packet_to_send!=NULL)
static int operation_can_receive(int operation)
Definition: smsc_cimd2.c:422
Definition: octstr.c:118
static int packet_check_header ( struct packet packet,
SMSCConn conn 
)
static

Definition at line 705 of file smsc_cimd2.c.

References packet::data, gw_assert(), gw_isdigit(), smscconn::id, octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_len(), TAB, and warning().

Referenced by packet_check().

706 {
707  Octstr *data;
708 
709  gw_assert(packet != NULL);
710  data = packet->data;
711 
712  /* The header must have a two-digit operation code, a colon,
713  * and a three-digit sequence number, followed by a tab.
714  * (CIMD2, 3.1) */
715  if (octstr_len(data) < 8 ||
716  !octstr_check_range(data, 1, 2, gw_isdigit) ||
717  octstr_get_char(data, 3) != ':' ||
718  !octstr_check_range(data, 4, 3, gw_isdigit) ||
719  octstr_get_char(data, 7) != TAB) {
720  warning(0, "CIMD2[%s]: packet header in wrong format",
721  octstr_get_cstr(conn->id));
722  return -1;
723  }
724 
725  return 0;
726 }
#define TAB
Definition: smsc_cimd2.c:463
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
Octstr * id
Definition: smscconn_p.h:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
Octstr * data
Definition: smsc_cimd2.c:446
int gw_isdigit(int c)
Definition: utils.c:988
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static int packet_check_parameter ( struct packet packet,
long  pos,
long  len,
SMSCConn conn 
)
static

Definition at line 728 of file smsc_cimd2.c.

References packet::data, gw_assert(), gw_isdigit(), gw_isxdigit(), smscconn::id, isphonedigit(), maxlen, maxval, minval, octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_parse_long(), P_ADDRESS, P_HEX, P_INT, P_SMS, P_STRING, P_TIME, parameters, parm_index(), type, and warning().

Referenced by packet_check().

729 {
730  Octstr *data;
731  long parm;
732  long dpos, dlen;
733  int negative;
734  long value;
735  int i;
736  int errors = 0;
737 
738  gw_assert(packet != NULL);
739  data = packet->data;
740 
741  /* The parameter header should be TAB, followed by a three-digit
742  * parameter number, a colon, and the data. We already know about
743  * the tab. */
744 
745  if (len < 5 ||
746  !octstr_check_range(data, pos + 1, 3, gw_isdigit) ||
747  octstr_get_char(data, pos + 4) != ':') {
748  warning(0, "CIMD2[%s]: parameter at offset %ld in wrong format",
749  octstr_get_cstr(conn->id),
750  pos);
751  errors++;
752  }
753 
754  /* If we can't parse a parameter number, there's nothing more
755  * that we can check. */
756  dpos = octstr_parse_long(&parm, data, pos + 1, 10);
757  if (dpos < 0)
758  return -1;
759  if (octstr_get_char(data, dpos) == ':')
760  dpos++;
761  dlen = len - (dpos - pos);
762  /* dlen can not go negative because octstr_parse_long must have
763  * been stopped by the TAB at the end of the parameter data. */
764  gw_assert(dlen >= 0);
765 
766  i = parm_index(parm);
767 
768  if (i < 0) {
769  warning(0, "CIMD2[%s]: packet contains unknown parameter %ld",
770  octstr_get_cstr(conn->id),
771  parm);
772  return -1;
773  }
774 
775  if (dlen > parameters[i].maxlen) {
776  warning(0, "CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d",
777  octstr_get_cstr(conn->id),
778  parameters[i].name, len, parameters[i].maxlen);
779  errors++;
780  }
781 
782  switch (parameters[i].type) {
783  case P_INT:
784  /* Allow a leading - */
785  negative = (octstr_get_char(data, dpos) == '-');
786  if (!octstr_check_range(data, dpos + negative,
787  dlen - negative, gw_isdigit)) {
788  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents",
789  octstr_get_cstr(conn->id),
790  parameters[i].name);
791  errors++;
792  }
793  if (octstr_parse_long(&value, data, dpos, 10) >= 0 &&
794  (value < parameters[i].minval || value > parameters[i].maxval)) {
795  warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)",
796  octstr_get_cstr(conn->id),
797  parameters[i].name, value,
798  parameters[i].minval, parameters[i].maxval);
799  errors++;
800  }
801  break;
802  case P_TIME:
803  if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) {
804  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents",
805  octstr_get_cstr(conn->id),
806  parameters[i].name);
807  errors++;
808  }
809  break;
810  case P_ADDRESS:
811  if (!octstr_check_range(data, dpos, dlen, isphonedigit)) {
812  warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents",
813  octstr_get_cstr(conn->id),
814  parameters[i].name);
815  errors++;
816  }
817  break;
818  case P_HEX:
819  if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) {
820  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents",
821  octstr_get_cstr(conn->id),
822  parameters[i].name);
823  errors++;
824  }
825  if (dlen % 2 != 0) {
826  warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter",
827  octstr_get_cstr(conn->id),
828  parameters[i].name);
829  errors++;
830  }
831  break;
832  case P_SMS:
833  case P_STRING: /* nothing to check */
834  break;
835  }
836 
837  if (errors > 0)
838  return -1;
839  return 0;
840 }
int minval
Definition: smsc_cimd2.c:216
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
Octstr * id
Definition: smscconn_p.h:174
int type
Definition: smsc_cimd2.c:215
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
Octstr * data
Definition: smsc_cimd2.c:446
static int isphonedigit(int c)
Definition: smsc_cimd2.c:324
int gw_isdigit(int c)
Definition: utils.c:988
void warning(int err, const char *fmt,...)
Definition: log.c:624
Definition: seewbmp.c:154
gw_assert(wtls_machine->packet_to_send!=NULL)
int maxlen
Definition: smsc_cimd2.c:214
Definition: octstr.c:118
int maxval
Definition: smsc_cimd2.c:216
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
static const struct @18 parameters[]
int gw_isxdigit(int c)
Definition: utils.c:994
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static struct packet* packet_create ( int  operation,
int  seq 
)
static

Definition at line 1176 of file smsc_cimd2.c.

References ETX_str, octstr_create, packet::operation, packet::seq, STX_str, and TAB_str.

Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), cimd2_send_response(), and packet_encode_message().

1177 {
1178  struct packet *packet;
1179  char minpacket[sizeof("sOO:SSSte")];
1180 
1181  packet = gw_malloc(sizeof(*packet));
1182  packet->operation = operation;
1183  packet->seq = seq;
1184  sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq);
1185  packet->data = octstr_create(minpacket);
1186 
1187  return packet;
1188 }
int operation
Definition: smsc_cimd2.c:444
#define TAB_str
Definition: smsc_cimd2.c:468
#define ETX_str
Definition: smsc_cimd2.c:467
int seq
Definition: smsc_cimd2.c:445
#define octstr_create(cstr)
Definition: octstr.h:125
#define STX_str
Definition: smsc_cimd2.c:466
static void packet_destroy ( struct packet packet)
static

Definition at line 521 of file smsc_cimd2.c.

References packet::data, and octstr_destroy().

Referenced by cimd2_login(), cimd2_logout(), cimd2_receive_msg(), cimd2_request(), cimd2_send_alive(), cimd2_send_response(), and cimd2_submit_msg().

522 {
523  if (packet != NULL) {
524  octstr_destroy(packet->data);
525  gw_free(packet);
526  }
527 }
Octstr * data
Definition: smsc_cimd2.c:446
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int packet_display_error ( struct packet packet,
SMSCConn conn 
)
static

Definition at line 979 of file smsc_cimd2.c.

References cimd2_errors, code, error(), smscconn::id, octstr_create, octstr_destroy(), octstr_get_cstr, packet::operation, operation_name(), P_ERROR_CODE, P_ERROR_TEXT, packet_get_int_parm(), packet_get_string_parm(), and text.

Referenced by cimd2_request().

980 {
981  int code;
982  Octstr *text = NULL;
983  Octstr *opname = NULL;
984 
985  code = packet_get_int_parm(packet, P_ERROR_CODE);
986  text = packet_get_string_parm(packet, P_ERROR_TEXT);
987 
988  if (code <= 0) {
989  octstr_destroy(text);
990  return 0;
991  }
992 
993  if (text == NULL) {
994  /* No error text. Try to find it in the table. */
995  int i;
996  for (i = 0; cimd2_errors[i].text != NULL; i++) {
997  if (cimd2_errors[i].code == code) {
998  text = octstr_create(cimd2_errors[i].text);
999  break;
1000  }
1001  }
1002  }
1003 
1004  if (text == NULL) {
1005  /* Still no error text. Make one up. */
1006  text = octstr_create("Unknown error");
1007  }
1008 
1009  opname = operation_name(packet->operation);
1010  error(0, "CIMD2[%s]: %s contained error message:",
1011  octstr_get_cstr(conn->id),
1012  octstr_get_cstr(opname));
1013  error(0, "code %03d: %s", code, octstr_get_cstr(text));
1014  octstr_destroy(opname);
1015  octstr_destroy(text);
1016  return code;
1017 }
void error(int err, const char *fmt,...)
Definition: log.c:612
int operation
Definition: smsc_cimd2.c:444
Octstr * id
Definition: smscconn_p.h:174
int code
Definition: smsc_cimd2.c:346
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static struct @20 cimd2_errors[]
static long packet_get_int_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:616
char * text
Definition: smsc_cimd2.c:921
static Octstr * operation_name(int operation)
Definition: smsc_cimd2.c:384
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
Definition: octstr.c:118
static Octstr * packet_get_string_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:642
static struct packet* packet_encode_message ( Msg msg,
Octstr sender_prefix,
SMSCConn conn 
)
static

Definition at line 1319 of file smsc_cimd2.c.

References smscconn::alt_dcs, BOGUS_SEQUENCE, charset_gsm_truncate(), charset_utf8_to_gsm(), convert_gsm_to_cimd2(), smscconn::data, DC_7BIT, DC_8BIT, DC_UCS2, DC_UNDEF, DLR_IS_SUCCESS_OR_FAIL, fields_to_dcs(), gw_assert(), smscconn::id, MSG_PARAM_UNDEFINED, privdata::no_dlr, octstr_compare(), octstr_copy, octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), octstr_ncompare(), octstr_truncate(), P_ALPHANUMERIC_ORIGINATING_ADDRESS, P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_INT, P_MORE_MESSAGES_TO_SEND, P_ORIGINATING_ADDRESS, P_PROTOCOL_IDENTIFIER, P_REPLY_PATH, P_STATUS_REPORT_REQUEST, P_TARIFF_CLASS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, P_VALIDITY_PERIOD_RELATIVE, packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_parm(), packet_add_sms_parm(), packet_add_string_parm(), packet_create(), parm_valid_address(), SUBMIT_MESSAGE, text, Msg::type, and warning().

Referenced by cimd2_submit_msg().

1320 {
1321  struct packet *packet;
1322  PrivData *pdata = conn->data;
1323  Octstr *text;
1324  int spaceleft;
1325  long truncated;
1326  int dcs = 0;
1327  int setvalidity = 0;
1328 
1329  gw_assert(msg != NULL);
1330  gw_assert(msg->type == sms);
1331  gw_assert(msg->sms.receiver != NULL);
1332 
1333  dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ?
1334  msg->sms.alt_dcs : conn->alt_dcs));
1335  if (msg->sms.sender == NULL)
1336  msg->sms.sender = octstr_create("");
1337 
1338  if (!parm_valid_address(msg->sms.receiver)) {
1339  warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded",
1340  octstr_get_cstr(conn->id),
1341  octstr_get_cstr(msg->sms.receiver));
1342  return NULL;
1343  }
1344 
1346 
1347  packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver, conn);
1348 
1349  /* CIMD2 interprets the originating address as a sub-address to
1350  * our connection number (so if the connection is "400" and we
1351  * fill in "600" as the sender number, the user sees "400600").
1352  * Since we have no way to ask what this number is, it has to
1353  * be configured. */
1354 
1355  /* Quick and dirty check to see if we are using alphanumeric sender */
1356  if (parm_valid_address(msg->sms.sender)) {
1357  /* We are not, so send in the usual way */
1358  /* Speed up the default case */
1359  if (octstr_len(sender_prefix) == 0) {
1360  packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,msg->sms.sender, conn);
1361  }
1362  else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {
1363  if (octstr_ncompare(sender_prefix, msg->sms.sender,
1364  octstr_len(sender_prefix)) == 0) {
1365  Octstr *sender;
1366  sender = octstr_copy(msg->sms.sender,
1367  octstr_len(sender_prefix), octstr_len(msg->sms.sender));
1368  packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender, conn);
1369  octstr_destroy(sender);
1370  } else {
1371  warning(0, "CIMD2[%s]: Sending message with originating address <%s>, "
1372  "which does not start with the sender-prefix.",
1373  octstr_get_cstr(conn->id),
1374  octstr_get_cstr(msg->sms.sender));
1375  }
1376  }
1377  }
1378  else {
1379  /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */
1380  packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn);
1381  }
1382 
1383  /* Add the validity period if necessary. This sets the relative validity
1384  * period as this is the description of the "validity" parameter of the
1385  * sendsms interface.
1386  *
1387  * Convert from minutes to GSM 03.40 specification (section 9.2.3.12).
1388  * 0-143 = 0 to 12 hours in 5 minute increments.
1389  * 144-167 = 12hrs30min to 24hrs in 30 minute increments.
1390  * 168-196 = 2days to 30days in 1 day increments.
1391  * 197-255 = 5weeks to 63weeks in 1 week increments.
1392  *
1393  * This code was copied from smsc_at2.c.
1394  */
1395  if (msg->sms.validity != MSG_PARAM_UNDEFINED) {
1396  long val = (msg->sms.validity - time(NULL)) / 60;
1397  if (val > 635040)
1398  setvalidity = 255;
1399  if (val >= 50400 && val <= 635040)
1400  setvalidity = (val - 1) / 7 / 24 / 60 + 192 + 1;
1401  if (val > 43200 && val < 50400)
1402  setvalidity = 197;
1403  if (val >= 2880 && val <= 43200)
1404  setvalidity = (val - 1) / 24 / 60 + 166 + 1;
1405  if (val > 1440 && val < 2880)
1406  setvalidity = 168;
1407  if (val >= 750 && val <= 1440)
1408  setvalidity = (val - 720 - 1) / 30 + 143 + 1;
1409  if (val > 720 && val < 750)
1410  setvalidity = 144;
1411  if (val >= 5 && val <= 720)
1412  setvalidity = (val - 1) / 5 - 1 + 1;
1413  if (val < 5)
1414  setvalidity = 0;
1415 
1416  packet_add_int_parm(packet, P_VALIDITY_PERIOD_RELATIVE, setvalidity, conn);
1417  }
1418 
1419  /* Explicitly ask not to get status reports.
1420  * If we do not do this, the server's default might be to
1421  * send status reports in some cases, and we don't do anything
1422  * with those reports anyway. */
1423  /* ask for the delivery reports if needed*/
1424 
1425  if (!pdata->no_dlr)
1426  if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
1427  packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14, conn);
1428  else
1429  packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0, conn);
1430  else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
1431  warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true",
1432  octstr_get_cstr(conn->id));
1433 
1434  /* Turn off reply path as default.
1435  * This avoids phones automatically asking for a reply
1436  */
1437  if (msg->sms.rpi > 0)
1438  packet_add_int_parm(packet, P_REPLY_PATH, 1, conn);
1439  else
1440  packet_add_int_parm(packet, P_REPLY_PATH, 0, conn);
1441 
1442  /* Use binfo to set the tariff class */
1443  if (octstr_len(msg->sms.binfo))
1444  packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);
1445 
1446  /* Set the protocol identifier if requested */
1447  if (msg->sms.pid > 0)
1448  packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn);
1449 
1450  /* If there are more messages to the same destination, then set the
1451  * More Messages to Send flag. This allow faster delivery of many messages
1452  * to the same destination
1453  */
1454  if (msg->sms.msg_left > 0)
1455  packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 1, conn);
1456  else
1457  packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 0, conn);
1458 
1459  truncated = 0;
1460 
1461  spaceleft = 140;
1462  if (octstr_len(msg->sms.udhdata)) {
1463  /* udhdata will be truncated and warned about if
1464  * it does not fit. */
1465  packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn);
1466  }
1467  if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF)
1468  spaceleft = spaceleft * 8 / 7;
1469  if (spaceleft < 0)
1470  spaceleft = 0;
1471 
1472  text = octstr_duplicate(msg->sms.msgdata);
1473 
1474  if (octstr_len(text) > 0 && spaceleft == 0) {
1475  warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text",
1476  octstr_get_cstr(conn->id));
1477  } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
1478  if (octstr_len(text) > spaceleft) {
1479  truncated = octstr_len(text) - spaceleft;
1480  octstr_truncate(text, spaceleft);
1481  }
1482  packet_add_hex_parm(packet, P_USER_DATA_BINARY, text, conn);
1483  } else {
1484  /* Going from latin1 to GSM to CIMD2 may seem like a
1485  * detour, but it's the only way to get all the escape
1486  * codes right. */
1487  charset_utf8_to_gsm(text);
1488  truncated = charset_gsm_truncate(text, spaceleft);
1489  convert_gsm_to_cimd2(text);
1490  packet_add_sms_parm(packet, P_USER_DATA, text, conn);
1491  }
1492 
1493  if (dcs != 0)
1494  packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs, conn);
1495 
1496  if (truncated > 0) {
1497  warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.",
1498  octstr_get_cstr(conn->id),
1499  spaceleft);
1500  }
1501 
1502  octstr_destroy(text);
1503  return packet;
1504 }
int alt_dcs
Definition: smscconn_p.h:201
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
static int parm_valid_address(Octstr *value)
Definition: smsc_cimd2.c:329
void charset_utf8_to_gsm(Octstr *ostr)
Definition: charset.c:288
#define DC_8BIT
Definition: sms.h:111
static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1241
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
#define BOGUS_SEQUENCE
Definition: smsc_cimd2.c:471
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
char * text
Definition: smsc_cimd2.c:921
static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1227
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:950
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1252
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
int fields_to_dcs(Msg *msg, int mode)
Definition: sms.c:73
gw_assert(wtls_machine->packet_to_send!=NULL)
int no_dlr
Definition: smsc_cimd2.c:106
static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn)
Definition: smsc_cimd2.c:1261
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static void convert_gsm_to_cimd2(Octstr *text)
Definition: smsc_cimd2.c:1134
Definition: octstr.c:118
static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1233
#define MSG_PARAM_UNDEFINED
Definition: msg.h:71
enum msg_type type
Definition: msg.h:80
void octstr_truncate(Octstr *ostr, int new_len)
Definition: octstr.c:1325
#define DC_UNDEF
Definition: sms.h:109
#define DLR_IS_SUCCESS_OR_FAIL(dlr)
Definition: dlr.h:85
int charset_gsm_truncate(Octstr *gsm, long max)
Definition: charset.c:512
#define DC_UCS2
Definition: sms.h:112
#define DC_7BIT
Definition: sms.h:110
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
static struct packet* packet_extract ( Octstr in,
SMSCConn conn 
)
static

Definition at line 533 of file smsc_cimd2.c.

References ETX, ETX_str, smscconn::id, octstr_append_cstr(), octstr_copy, octstr_delete(), octstr_get_cstr, octstr_len(), octstr_search_char(), packet_parse(), STX, and warning().

Referenced by cimd2_get_packet(), and cimd2_receive_msg().

534 {
535  int stx, etx;
536  Octstr *packet;
537 
538  /* Find STX, and delete everything up to it */
539  stx = octstr_search_char(in, STX, 0);
540  if (stx < 0) {
541  octstr_delete(in, 0, octstr_len(in));
542  return NULL;
543  } else {
544  octstr_delete(in, 0, stx);
545  }
546 
547  /* STX is now in position 0. Find ETX. */
548  etx = octstr_search_char(in, ETX, 1);
549  if (etx < 0)
550  return NULL;
551 
552  /* What shall we do with STX data... STX data... ETX?
553  * Either skip to the second STX, or assume an ETX marker before
554  * the STX. Doing the latter has a chance of succeeding, and
555  * will at least allow good logging of the error. */
556  stx = octstr_search_char(in, STX, 1);
557  if (stx >= 0 && stx < etx) {
558  warning(0, "CIMD2[%s]: packet without end marker",
559  octstr_get_cstr(conn->id));
560  packet = octstr_copy(in, 0, stx);
561  octstr_delete(in, 0, stx);
562  octstr_append_cstr(packet, ETX_str);
563  } else {
564  /* Normal case. Copy packet, and cut it from the source. */
565  packet = octstr_copy(in, 0, etx + 1);
566  octstr_delete(in, 0, etx + 1);
567  }
568 
569  return packet_parse(packet);
570 }
#define ETX
Definition: smsc_cimd2.c:462
Octstr * id
Definition: smscconn_p.h:174
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
#define STX
Definition: smsc_cimd2.c:461
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
#define ETX_str
Definition: smsc_cimd2.c:467
void warning(int err, const char *fmt,...)
Definition: log.c:624
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
static struct packet * packet_parse(Octstr *packet_data)
Definition: smsc_cimd2.c:507
static Octstr* packet_get_address_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 653 of file smsc_cimd2.c.

References gw_assert(), P_ADDRESS, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

654 {
655  /* Our code should never even try a bad parameter access. */
656  gw_assert(parm_type(parmno) == P_ADDRESS);
657 
658  return packet_get_parm(packet, parmno);
659 }
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
static Octstr* packet_get_hex_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 681 of file smsc_cimd2.c.

References error(), gw_assert(), octstr_destroy(), octstr_hex_to_binary(), P_HEX, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

682 {
683  Octstr *value = NULL;
684 
685  /* Our code should never even try a bad parameter access. */
686  gw_assert(parm_type(parmno) == P_HEX);
687 
688  value = packet_get_parm(packet, parmno);
689  if (!value)
690  goto error;
691 
692  if (octstr_hex_to_binary(value) < 0)
693  goto error;
694 
695  return value;
696 
697 error:
698  octstr_destroy(value);
699  return NULL;
700 }
void error(int err, const char *fmt,...)
Definition: log.c:612
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
Definition: octstr.c:118
int octstr_hex_to_binary(Octstr *ostr)
Definition: octstr.c:492
static long packet_get_int_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 616 of file smsc_cimd2.c.

References error(), gw_assert(), octstr_destroy(), octstr_parse_long(), P_INT, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message(), and packet_display_error().

617 {
618  Octstr *valuestr = NULL;
619  long value;
620 
621  /* Our code should never even try a bad parameter access. */
622  gw_assert(parm_type(parmno) == P_INT);
623 
624  valuestr = packet_get_parm(packet, parmno);
625  if (!valuestr)
626  goto error;
627 
628  if (octstr_parse_long(&value, valuestr, 0, 10) < 0)
629  goto error;
630 
631  octstr_destroy(valuestr);
632  return value;
633 
634 error:
635  octstr_destroy(valuestr);
636  return INT_MIN;
637 }
void error(int err, const char *fmt,...)
Definition: log.c:612
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
Definition: octstr.c:118
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
static Octstr* packet_get_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 579 of file smsc_cimd2.c.

References packet::data, gw_assert(), number, octstr_copy, octstr_parse_long(), octstr_search_char(), and TAB.

Referenced by cimd2_accept_delivery_report_message(), cimd2_get_packet(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm().

580 {
581  long pos, next;
582  long valuepos;
583  long number;
584 
585  gw_assert(packet != NULL);
586  pos = octstr_search_char(packet->data, TAB, 0);
587  if (pos < 0)
588  return NULL; /* Bad packet, nothing we can do */
589 
590  /* Parameters have a tab on each end. If we don't find the
591  * closing tab, we're at the checksum, so we stop. */
592  for ( ;
593  (next = octstr_search_char(packet->data, TAB, pos + 1)) >= 0;
594  pos = next) {
595  if (octstr_parse_long(&number, packet->data, pos + 1, 10) < 0)
596  continue;
597  if (number != parmno)
598  continue;
599  valuepos = octstr_search_char(packet->data, ':', pos + 1);
600  if (valuepos < 0)
601  continue; /* badly formatted parm */
602  valuepos++; /* skip the ':' */
603 
604  /* Found the right parameter */
605  return octstr_copy(packet->data, valuepos, next - valuepos);
606  }
607 
608  return NULL;
609 }
int number
Definition: smsc_cimd2.c:213
#define TAB
Definition: smsc_cimd2.c:463
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
Octstr * data
Definition: smsc_cimd2.c:446
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
static Octstr* packet_get_sms_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 665 of file smsc_cimd2.c.

References gw_assert(), P_SMS, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

666 {
667  /* Our code should never even try a bad parameter access. */
668  gw_assert(parm_type(parmno) == P_SMS);
669 
670  return packet_get_parm(packet, parmno);
671 }
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
static Octstr* packet_get_string_parm ( struct packet packet,
int  parmno 
)
static

Definition at line 642 of file smsc_cimd2.c.

References gw_assert(), P_STRING, packet_get_parm(), and parm_type().

Referenced by packet_display_error().

643 {
644  /* Our code should never even try a bad parameter access. */
645  gw_assert(parm_type(parmno) == P_STRING);
646 
647  return packet_get_parm(packet, parmno);
648 }
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
gw_assert(wtls_machine->packet_to_send!=NULL)
static struct packet* packet_parse ( Octstr packet_data)
static

Definition at line 507 of file smsc_cimd2.c.

References packet::data, and packet_parse_header().

Referenced by packet_extract().

508 {
509  struct packet *packet;
510 
511  packet = gw_malloc(sizeof(*packet));
512  packet->data = packet_data;
513 
514  /* Fill in packet->operation and packet->seq */
515  packet_parse_header(packet);
516 
517  return packet;
518 }
static void packet_parse_header(struct packet *packet)
Definition: smsc_cimd2.c:480
Octstr * data
Definition: smsc_cimd2.c:446
static void packet_parse_header ( struct packet packet)
static

Definition at line 480 of file smsc_cimd2.c.

References packet::data, number, octstr_get_char(), octstr_parse_long(), packet::operation, and packet::seq.

Referenced by packet_parse().

481 {
482  int pos;
483  long number;
484 
485  /* Set default values, in case we can't parse the fields */
486  packet->operation = -1;
487  packet->seq = -1;
488 
489  pos = octstr_parse_long(&number, packet->data, 1, 10);
490  if (pos < 0)
491  return;
492  packet->operation = number;
493 
494  if (octstr_get_char(packet->data, pos++) != ':')
495  return;
496 
497  pos = octstr_parse_long(&number, packet->data, pos, 10);
498  if (pos < 0)
499  return;
500  packet->seq = number;
501 }
int operation
Definition: smsc_cimd2.c:444
int number
Definition: smsc_cimd2.c:213
Octstr * data
Definition: smsc_cimd2.c:446
int seq
Definition: smsc_cimd2.c:445
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static void packet_set_checksum ( struct packet packet)
static

Definition at line 1274 of file smsc_cimd2.c.

References packet::data, gw_assert(), octstr_delete(), octstr_get_char(), octstr_insert_data(), octstr_len(), and TAB.

Referenced by cimd2_request(), and cimd2_send_response().

1275 {
1276  Octstr *data;
1277  int checksum;
1278  long pos, len;
1279  char buf[16];
1280 
1281  gw_assert(packet != NULL);
1282 
1283  data = packet->data;
1284  if (octstr_get_char(data, octstr_len(data) - 2) != TAB) {
1285  /* Packet already has checksum; kill it. */
1286  octstr_delete(data, octstr_len(data) - 3, 2);
1287  }
1288 
1289  gw_assert(octstr_get_char(data, octstr_len(data) - 2) == TAB);
1290 
1291  /* Sum all the way up to the last TAB */
1292  checksum = 0;
1293  for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) {
1294  checksum += octstr_get_char(data, pos);
1295  checksum &= 0xff;
1296  }
1297 
1298  sprintf(buf, "%02X", checksum);
1299  octstr_insert_data(data, len - 1, buf, 2);
1300 }
#define TAB
Definition: smsc_cimd2.c:463
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
Octstr * data
Definition: smsc_cimd2.c:446
gw_assert(wtls_machine->packet_to_send!=NULL)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static void packet_set_send_sequence ( struct packet packet,
PrivData pdata 
)
static

Definition at line 1511 of file smsc_cimd2.c.

References gw_assert(), LOGIN, packet::operation, packet_set_sequence(), and privdata::send_seq.

Referenced by cimd2_request().

1512 {
1513  gw_assert(pdata != NULL);
1514  /* LOGIN packets always have sequence number 001 */
1515  if (packet->operation == LOGIN)
1516  pdata->send_seq = 1;
1517  /* Send sequence numbers are always odd, receiving are always even */
1518  gw_assert(pdata->send_seq % 2 == 1);
1519 
1520  packet_set_sequence(packet, pdata->send_seq);
1521  pdata->send_seq += 2;
1522  if (pdata->send_seq > 256)
1523  pdata->send_seq = 1;
1524 }
int operation
Definition: smsc_cimd2.c:444
static void packet_set_sequence(struct packet *packet, int seq)
Definition: smsc_cimd2.c:1302
gw_assert(wtls_machine->packet_to_send!=NULL)
int send_seq
Definition: smsc_cimd2.c:109
static void packet_set_sequence ( struct packet packet,
int  seq 
)
static

Definition at line 1302 of file smsc_cimd2.c.

References packet::data, gw_assert(), octstr_set_char(), and packet::seq.

Referenced by packet_set_send_sequence().

1303 {
1304  char buf[16];
1305 
1306  gw_assert(packet != NULL);
1307  gw_assert(seq >= 0);
1308  gw_assert(seq < 256);
1309 
1310  sprintf(buf, "%03d", seq);
1311 
1312  /* Start at 4 to skip the <STX> ZZ: part of the header. */
1313  octstr_set_char(packet->data, 4, buf[0]);
1314  octstr_set_char(packet->data, 5, buf[1]);
1315  octstr_set_char(packet->data, 6, buf[2]);
1316  packet->seq = seq;
1317 }
Octstr * data
Definition: smsc_cimd2.c:446
int seq
Definition: smsc_cimd2.c:445
gw_assert(wtls_machine->packet_to_send!=NULL)
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
static int parm_in_range ( int  parmno,
long  value 
)
static

Definition at line 310 of file smsc_cimd2.c.

References maxval, minval, parameters, and parm_index().

Referenced by packet_add_int_parm().

311 {
312  int i;
313 
314  i = parm_index(parmno);
315 
316  if (i < 0)
317  return -1;
318 
319  return (value >= parameters[i].minval && value <= parameters[i].maxval);
320 }
int minval
Definition: smsc_cimd2.c:216
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
int maxval
Definition: smsc_cimd2.c:216
static const struct @18 parameters[]
static int parm_index ( int  parmno)
static

Definition at line 260 of file smsc_cimd2.c.

References number, and parameters.

Referenced by packet_check_parameter(), parm_in_range(), parm_maxlen(), parm_name(), and parm_type().

261 {
262  int i;
263 
264  for (i = 0; parameters[i].name != NULL; i++) {
265  if (parameters[i].number == parmno)
266  return i;
267  }
268 
269  return -1;
270 }
int number
Definition: smsc_cimd2.c:213
static const struct @18 parameters[]
static int parm_maxlen ( int  parmno)
static

Definition at line 287 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm(), and smsc_cimd2_create().

288 {
289  int i = parm_index(parmno);
290 
291  if (i < 0)
292  return -1;
293 
294  return parameters[i].maxlen;
295 }
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
static const struct @18 parameters[]
static const char* parm_name ( int  parmno)
static

Definition at line 297 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm().

298 {
299  int i = parm_index(parmno);
300 
301  if (i < 0)
302  return NULL;
303 
304  return parameters[i].name;
305 }
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
static const struct @18 parameters[]
static int parm_type ( int  parmno)
static

Definition at line 274 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm().

275 {
276  int i = parm_index(parmno);
277 
278  if (i < 0)
279  return -1;
280 
281  return parameters[i].type;
282 }
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
static const struct @18 parameters[]
static int parm_valid_address ( Octstr value)
static

Definition at line 329 of file smsc_cimd2.c.

References isphonedigit(), octstr_check_range(), and octstr_len().

Referenced by packet_encode_message().

330 {
331  return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
332 }
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
static int isphonedigit(int c)
Definition: smsc_cimd2.c:324
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static Msg* sms_receive ( SMSCConn conn)
static

Definition at line 2139 of file smsc_cimd2.c.

References cimd2_close_socket(), cimd2_receive_msg(), smscconn::data, smscconn::flow_mutex, smscconn::id, msg_destroy(), mutex_lock, mutex_unlock, octstr_duplicate, SMSCCONN_DISCONNECTED, and smscconn::status.

Referenced by io_thread().

2140 {
2141  PrivData *pdata = conn->data;
2142  int ret;
2143  Msg *newmsg = NULL;
2144 
2145  ret = cimd2_receive_msg(conn, &newmsg);
2146  if (ret == 1) {
2147  /* if any smsc_id available, use it */
2148  newmsg->sms.smsc_id = octstr_duplicate(conn->id);
2149  return newmsg;
2150  }
2151  else if (ret == 0) { /* no message, just retry... */
2152  return NULL;
2153  }
2154  /* error. reconnect. */
2155  msg_destroy(newmsg);
2156  mutex_lock(conn->flow_mutex);
2157  cimd2_close_socket(pdata);
2158  conn->status = SMSCCONN_DISCONNECTED;
2159  mutex_unlock(conn->flow_mutex);
2160  return NULL;
2161 }
#define mutex_unlock(m)
Definition: thread.h:136
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
static void cimd2_close_socket(PrivData *pdata)
Definition: smsc_cimd2.c:1837
Definition: msg.h:79
static int cimd2_receive_msg(SMSCConn *conn, Msg **msg)
Definition: smsc_cimd2.c:2002
#define octstr_duplicate(ostr)
Definition: octstr.h:187
Mutex * flow_mutex
Definition: smscconn_p.h:157
void msg_destroy(Msg *msg)
Definition: msg.c:132
smscconn_status_t status
Definition: smscconn_p.h:151
#define mutex_lock(m)
Definition: thread.h:130
int smsc_cimd2_create ( SMSCConn conn,
CfgGroup grp 
)

Definition at line 2321 of file smsc_cimd2.c.

References cfg_get, cfg_get_bool(), cfg_get_integer(), cimd2_add_msg_cb(), cimd2_destroy(), cimd2_queued_cb(), cimd2_shutdown_cb(), cimd2_start_cb(), cimd2_stop_cb(), privdata::conn, smscconn::data, debug(), error(), gwlist_add_producer(), gwlist_create, gwthread_create, gwthread_join(), gwthread_wakeup(), privdata::host, smscconn::id, privdata::inbuffer, privdata::io_thread, io_thread(), smscconn::is_stopped, privdata::keepalive, maxlen, privdata::my_number, smscconn::name, privdata::next_ping, privdata::no_dlr, octstr_create, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_truncate(), ok, privdata::our_port, privdata::outgoing_queue, P_PASSWORD, P_USER_IDENTITY, parm_maxlen(), privdata::password, privdata::port, smscconn::queued, privdata::quitting, privdata::receive_seq, privdata::received, smscconn::send_msg, privdata::send_seq, smscconn::shutdown, privdata::socket, smscconn::start_conn, smscconn::stop_conn, privdata::stopped, privdata::username, and warning().

Referenced by smscconn_create().

2322 {
2323  PrivData *pdata;
2324  int ok;
2325  int maxlen;
2326 
2327  pdata = gw_malloc(sizeof(PrivData));
2328  conn->data = pdata;
2329  pdata->conn = conn;
2330 
2331  pdata->no_dlr = 0;
2332  pdata->quitting = 0;
2333  pdata->socket = -1;
2334  pdata->received = gwlist_create();
2335  pdata->inbuffer = octstr_create("");
2336  pdata->send_seq = 1;
2337  pdata->receive_seq = 0;
2338  pdata->outgoing_queue = gwlist_create();
2339  pdata->stopped = gwlist_create();
2341 
2342  if (conn->is_stopped)
2343  gwlist_add_producer(pdata->stopped);
2344 
2345  pdata->host = cfg_get(grp, octstr_imm("host"));
2346  if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
2347  pdata->port = 0;
2348  if (cfg_get_integer(&(pdata->our_port), grp, octstr_imm("our-port")) == -1)
2349  pdata->our_port = 0;
2350  pdata->username = cfg_get(grp, octstr_imm("smsc-username"));
2351  pdata->password = cfg_get(grp, octstr_imm("smsc-password"));
2352  pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
2353  if (cfg_get_integer(&(pdata->keepalive), grp,octstr_imm("keepalive")) == -1)
2354  pdata->keepalive = 0;
2355 
2356  cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
2357 
2358  /* Check that config is OK */
2359  ok = 1;
2360  if (pdata->host == NULL) {
2361  error(0,"CIMD2[%s]: Configuration file doesn't specify host",
2362  octstr_get_cstr(conn->id));
2363  ok = 0;
2364  }
2365  if (pdata->port == 0) {
2366  error(0,"CIMD2[%s]: Configuration file doesn't specify port",
2367  octstr_get_cstr(conn->id));
2368  ok = 0;
2369  }
2370  if (pdata->username == NULL) {
2371  error(0, "CIMD2[%s]: Configuration file doesn't specify username.",
2372  octstr_get_cstr(conn->id));
2373  ok = 0;
2374  }
2375  if (pdata->password == NULL) {
2376  error(0, "CIMD2[%s]: Configuration file doesn't specify password.",
2377  octstr_get_cstr(conn->id));
2378  ok = 0;
2379  }
2380 
2381  if (!ok) {
2382  cimd2_destroy(pdata);
2383  return -1;
2384  }
2385 
2386  conn->name = octstr_format("CIMD2:%s:%d:%s",
2387  octstr_get_cstr(pdata->host),
2388  pdata->port,
2389  octstr_get_cstr(pdata->username));
2390 
2391 
2392  if (pdata->keepalive > 0) {
2393  debug("bb.sms.cimd2", 0, "CIMD2[%s]: Keepalive set to %ld seconds",
2394  octstr_get_cstr(conn->id),
2395  pdata->keepalive);
2396  pdata->next_ping = time(NULL) + pdata->keepalive;
2397  }
2398 
2399  maxlen = parm_maxlen(P_USER_IDENTITY);
2400  if (octstr_len(pdata->username) > maxlen) {
2401  octstr_truncate(pdata->username, maxlen);
2402  warning(0, "CIMD2[%s]: Truncating username to %d chars",
2403  octstr_get_cstr(conn->id),
2404  maxlen);
2405  }
2406 
2407  maxlen = parm_maxlen(P_PASSWORD);
2408  if (octstr_len(pdata->password) > maxlen) {
2409  octstr_truncate(pdata->password, maxlen);
2410  warning(0, "CIMD2[%s]: Truncating password to %d chars",
2411  octstr_get_cstr(conn->id),
2412  maxlen);
2413  }
2414 
2415  pdata->io_thread = gwthread_create(io_thread, conn);
2416 
2417  if (pdata->io_thread == -1) {
2418 
2419  error(0,"CIMD2[%s]: Couldn't start I/O thread.",
2420  octstr_get_cstr(conn->id));
2421  pdata->quitting = 1;
2422  gwthread_wakeup(pdata->io_thread);
2423  gwthread_join(pdata->io_thread);
2424  cimd2_destroy(pdata);
2425  return -1;
2426  }
2427 
2428  conn->send_msg = cimd2_add_msg_cb;
2429  conn->shutdown = cimd2_shutdown_cb;
2430  conn->queued = cimd2_queued_cb;
2431  conn->start_conn = cimd2_start_cb;
2432  conn->stop_conn = cimd2_stop_cb;
2433 
2434  return 0;
2435 }
int port
Definition: smsc_cgw.c:159
Octstr * name
Definition: smscconn_p.h:173
void error(int err, const char *fmt,...)
Definition: log.c:612
Octstr * inbuffer
Definition: smsc_cimd2.c:112
Octstr * id
Definition: smscconn_p.h:174
void gwthread_join(long thread)
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
void(* stop_conn)(SMSCConn *conn)
Definition: smscconn_p.h:246
static int parm_maxlen(int parmno)
Definition: smsc_cimd2.c:287
int socket
Definition: smsc_cimd2.c:108
Octstr * password
Definition: smsc_cimd2.c:100
#define cfg_get(grp, varname)
Definition: cfg.h:86
int io_thread
Definition: smsc_cimd2.c:119
static int cimd2_shutdown_cb(SMSCConn *conn, int finish_sending)
Definition: smsc_cimd2.c:2252
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void(* start_conn)(SMSCConn *conn)
Definition: smscconn_p.h:245
List * stopped
Definition: smsc_cimd2.c:121
int receive_seq
Definition: smsc_cimd2.c:110
time_t next_ping
Definition: smsc_cimd2.c:115
static void io_thread(void *arg)
Definition: smsc_cimd2.c:2164
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Octstr * my_number
Definition: smsc_cimd2.c:105
static void cimd2_start_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2294
Octstr * username
Definition: smsc_cimd2.c:99
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * host
Definition: smsc_cgw.c:163
int quitting
Definition: smsc_cimd2.c:120
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
volatile sig_atomic_t is_stopped
Definition: smscconn_p.h:169
int send_seq
Definition: smsc_cimd2.c:109
int no_dlr
Definition: smsc_cimd2.c:106
int maxlen
Definition: smsc_cimd2.c:214
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:756
static int cimd2_add_msg_cb(SMSCConn *conn, Msg *sms)
Definition: smsc_cimd2.c:2239
int(* shutdown)(SMSCConn *conn, int finish_sending)
Definition: smscconn_p.h:229
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
Definition: wtp_tid.h:82
void gwthread_wakeup(long thread)
static long cimd2_queued_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2313
List * received
Definition: smsc_cimd2.c:113
#define gwlist_create()
Definition: list.h:136
long(* queued)(SMSCConn *conn)
Definition: smscconn_p.h:240
void octstr_truncate(Octstr *ostr, int new_len)
Definition: octstr.c:1325
int(* send_msg)(SMSCConn *conn, Msg *msg)
Definition: smscconn_p.h:235
void gwlist_add_producer(List *list)
Definition: list.c:383
int our_port
Definition: smsc_cgw.c:161
long keepalive
Definition: smsc_cimd2.c:104
static void cimd2_destroy(PrivData *pdata)
Definition: smsc_cimd2.c:1929
static void cimd2_stop_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2305
SMSCConn * conn
Definition: smsc_cimd2.c:118

Variable Documentation

int can_receive

Definition at line 348 of file smsc_cimd2.c.

int can_send

Definition at line 347 of file smsc_cimd2.c.

unsigned char cimd1

Definition at line 1024 of file smsc_cimd2.c.

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

unsigned char cimd2

Definition at line 1024 of file smsc_cimd2.c.

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

struct { ... } cimd2_errors[]

Referenced by packet_display_error().

const { ... } cimd_combinations[]
unsigned char gsm

Definition at line 1025 of file smsc_cimd2.c.

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

int maxlen

Definition at line 214 of file smsc_cimd2.c.

Referenced by octstr_set_bits(), packet_check_parameter(), and smsc_cimd2_create().

int maxval

Definition at line 216 of file smsc_cimd2.c.

Referenced by packet_check_parameter(), and parm_in_range().

int minval

Definition at line 216 of file smsc_cimd2.c.

Referenced by packet_check_parameter(), and parm_in_range().

const { ... } operations[]
Initial value:
= {
{ "Login", LOGIN, 1, 0 },
{ "Logout", LOGOUT, 1, 0 },
{ "Submit message", SUBMIT_MESSAGE, 1, 0 },
{ "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 },
{ "Delivery request", DELIVERY_REQUEST, 1, 0 },
{ "Cancel message", CANCEL_MESSAGE, 1, 0 },
{ "Set parameter", SET_REQ, 1, 0 },
{ "Get parameter", GET_REQ, 1, 0 },
{ "Deliver message", DELIVER_MESSAGE, 0, 1 },
{ "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 },
{ "Alive", ALIVE, 1, 1 },
{ "NACK", NACK, 1, 1 },
{ "General error response", GENERAL_ERROR_RESPONSE, 0, 1 },
{ NULL, 0, 0, 0 }
}

Referenced by operation_can_receive(), operation_can_send(), operation_find(), and operation_name().

const { ... } parameters[]
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.