blob: 076b434abd560cf8aad59ad37f32a90ce8927de1 [file] [log] [blame]
Harald Weltec0de14d2012-11-23 23:35:01 +01001#include <stdio.h>
2#include <unistd.h>
3#include <stdint.h>
4#include <errno.h>
5#include <string.h>
6
7#include <netinet/in.h>
8
9#include <smpp34.h>
10#include <smpp34_structs.h>
11#include <smpp34_params.h>
12
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +020013#include <osmocom/core/application.h>
Harald Weltec0de14d2012-11-23 23:35:01 +010014#include <osmocom/core/utils.h>
15#include <osmocom/core/msgb.h>
16#include <osmocom/core/talloc.h>
17#include <osmocom/core/select.h>
18#include <osmocom/core/socket.h>
19#include <osmocom/core/write_queue.h>
20
Neels Hofmeyr90843962017-09-04 15:04:35 +020021#include <osmocom/msc/debug.h>
Max5346f692022-07-28 14:19:22 +070022#include <osmocom/smpp/smpp.h>
Harald Weltec0de14d2012-11-23 23:35:01 +010023
Harald Weltec0de14d2012-11-23 23:35:01 +010024
25/* FIXME: merge with smpp_smsc.c */
Harald Weltec0de14d2012-11-23 23:35:01 +010026static uint32_t esme_inc_seq_nr(struct esme *esme)
27{
28 esme->own_seq_nr++;
29 if (esme->own_seq_nr > 0x7fffffff)
30 esme->own_seq_nr = 1;
31
32 return esme->own_seq_nr;
33}
34static int pack_and_send(struct esme *esme, uint32_t type, void *ptr)
35{
36 struct msgb *msg = msgb_alloc(4096, "SMPP_Tx");
37 int rc, rlen;
38 if (!msg)
39 return -ENOMEM;
40
41 rc = smpp34_pack(type, msg->tail, msgb_tailroom(msg), &rlen, ptr);
42 if (rc != 0) {
Max62977d02022-08-01 22:50:52 +070043 LOGPESMERR(esme, "during smpp34_pack()\n");
Harald Weltec0de14d2012-11-23 23:35:01 +010044 msgb_free(msg);
45 return -EINVAL;
46 }
47 msgb_put(msg, rlen);
48
Holger Hans Peter Freytherfd603ed2015-03-28 18:09:31 +010049 if (osmo_wqueue_enqueue(&esme->wqueue, msg) != 0) {
Max62977d02022-08-01 22:50:52 +070050 LOGPESME(esme, LOGL_ERROR, "Write queue full. Dropping message\n");
Holger Hans Peter Freytherfd603ed2015-03-28 18:09:31 +010051 msgb_free(msg);
52 return -EAGAIN;
53 }
54 return 0;
Harald Weltec0de14d2012-11-23 23:35:01 +010055}
56/* FIXME: merge with smpp_smsc.c */
57
Pablo Neira Ayuso59622b62017-08-07 14:01:28 +010058static struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
59{
60 struct tlv_t *t;
61
62 for (t = head; t != NULL; t = t->next) {
63 if (t->tag == tag)
64 return t;
65 }
66 return NULL;
67}
Harald Weltec0de14d2012-11-23 23:35:01 +010068
69static int smpp_handle_deliver(struct esme *esme, struct msgb *msg)
70{
71 struct deliver_sm_t deliver;
72 struct deliver_sm_resp_t deliver_r;
73 struct submit_sm_t submit;
Pablo Neira Ayuso59622b62017-08-07 14:01:28 +010074 tlv_t *t;
Harald Weltec0de14d2012-11-23 23:35:01 +010075 int rc;
76
77 memset(&deliver, 0, sizeof(deliver));
78 SMPP34_UNPACK(rc, DELIVER_SM, &deliver, msgb_data(msg), msgb_length(msg));
79 if (rc < 0)
80 return rc;
81
82 INIT_RESP(DELIVER_SM_RESP, &deliver_r, &deliver);
83
84 PACK_AND_SEND(esme, &deliver_r);
85
86 memset(&submit, 0, sizeof(submit));
87 submit.command_id = SUBMIT_SM;
88 submit.command_status = ESME_ROK;
89 submit.sequence_number = esme_inc_seq_nr(esme);
90
91 submit.dest_addr_ton = deliver.source_addr_ton;
92 submit.dest_addr_npi = deliver.source_addr_npi;
93 memcpy(submit.destination_addr, deliver.source_addr,
94 OSMO_MIN(sizeof(submit.destination_addr),
95 sizeof(deliver.source_addr)));
96
97 submit.source_addr_ton = deliver.dest_addr_ton;
98 submit.source_addr_npi = deliver.dest_addr_npi;
99 memcpy(submit.source_addr, deliver.destination_addr,
100 OSMO_MIN(sizeof(submit.source_addr),
101 sizeof(deliver.destination_addr)));
102
Pablo Neira Ayusoeacb4002017-08-07 14:01:35 +0100103 /* Mirror delivery receipts as a delivery acknowledgements. */
104 if (deliver.esm_class == 0x04) {
105 LOGP(DSMPP, LOGL_DEBUG, "%s\n", deliver.short_message);
106 submit.esm_class = 0x08;
107 } else {
108 submit.esm_class = deliver.esm_class;
109 }
110
Pablo Neira Ayusoe2681c52017-08-07 14:01:23 +0100111 submit.registered_delivery = deliver.registered_delivery;
Harald Weltec0de14d2012-11-23 23:35:01 +0100112 submit.protocol_id = deliver.protocol_id;
113 submit.priority_flag = deliver.priority_flag;
114 memcpy(submit.schedule_delivery_time, deliver.schedule_delivery_time,
115 OSMO_MIN(sizeof(submit.schedule_delivery_time),
116 sizeof(deliver.schedule_delivery_time)));
117 memcpy(submit.validity_period, deliver.validity_period,
118 OSMO_MIN(sizeof(submit.validity_period),
119 sizeof(deliver.validity_period)));
120 submit.registered_delivery = deliver.registered_delivery;
121 submit.replace_if_present_flag = deliver.replace_if_present_flag;
122 submit.data_coding = deliver.data_coding;
123 submit.sm_default_msg_id = deliver.sm_default_msg_id;
124 submit.sm_length = deliver.sm_length;
125 memcpy(submit.short_message, deliver.short_message,
126 OSMO_MIN(sizeof(submit.short_message),
127 sizeof(deliver.short_message)));
Pablo Neira Ayuso59622b62017-08-07 14:01:28 +0100128
129 /* FIXME: More TLV? */
130 t = find_tlv(deliver.tlv, TLVID_user_message_reference);
131 if (t) {
132 tlv_t tlv;
133
134 memset(&tlv, 0, sizeof(tlv));
135 tlv.tag = TLVID_user_message_reference;
136 tlv.length = 2;
137 tlv.value.val16 = t->value.val16;
138 build_tlv(&submit.tlv, &tlv);
139 }
Harald Weltec0de14d2012-11-23 23:35:01 +0100140
141 return PACK_AND_SEND(esme, &submit);
142}
143
144static int bind_transceiver(struct esme *esme)
145{
146 struct bind_transceiver_t bind;
147
148 memset(&bind, 0, sizeof(bind));
149 bind.command_id = BIND_TRANSCEIVER;
150 bind.sequence_number = esme_inc_seq_nr(esme);
151 snprintf((char *)bind.system_id, sizeof(bind.system_id), "%s", esme->system_id);
152 snprintf((char *)bind.password, sizeof(bind.password), "%s", esme->password);
153 snprintf((char *)bind.system_type, sizeof(bind.system_type), "mirror");
154 bind.interface_version = esme->smpp_version;
155
156 return PACK_AND_SEND(esme, &bind);
157}
158
159static int smpp_pdu_rx(struct esme *esme, struct msgb *msg)
160{
161 uint32_t cmd_id = smpp_msgb_cmdid(msg);
162 int rc;
163
164 switch (cmd_id) {
165 case DELIVER_SM:
166 rc = smpp_handle_deliver(esme, msg);
167 break;
168 default:
Holger Hans Peter Freyther7672db32013-12-12 15:23:26 +0100169 LOGP(DSMPP, LOGL_NOTICE, "unhandled case %d\n", cmd_id);
170 rc = 0;
Harald Weltec0de14d2012-11-23 23:35:01 +0100171 break;
172 }
173
174 return rc;
175}
176
Harald Welte065b23a2021-10-25 08:18:26 +0200177static void esme_read_state_reset(struct esme *esme)
178{
179 esme->read_msg = NULL;
180 esme->read_idx = 0;
181 esme->read_len = 0;
182 esme->read_state = READ_ST_IN_LEN;
183}
184
Harald Weltec0de14d2012-11-23 23:35:01 +0100185/* FIXME: merge with smpp_smsc.c */
186static int esme_read_cb(struct osmo_fd *ofd)
187{
188 struct esme *esme = ofd->data;
189 uint32_t len;
190 uint8_t *lenptr = (uint8_t *) &len;
191 uint8_t *cur;
192 struct msgb *msg;
193 int rdlen;
194 int rc;
195
196 switch (esme->read_state) {
197 case READ_ST_IN_LEN:
198 rdlen = sizeof(uint32_t) - esme->read_idx;
199 rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
200 if (rc < 0) {
Max62977d02022-08-01 22:50:52 +0700201 LOGPESME(esme, LOGL_ERROR, "read returned %d\n", rc);
Harald Weltec0de14d2012-11-23 23:35:01 +0100202 } else if (rc == 0) {
203 goto dead_socket;
204 } else
205 esme->read_idx += rc;
206 if (esme->read_idx >= sizeof(uint32_t)) {
207 esme->read_len = ntohl(len);
Harald Welte890ece12021-10-25 08:18:58 +0200208 if (esme->read_len > 65535) {
209 /* unrealistic */
210 goto dead_socket;
211 }
Harald Weltec0de14d2012-11-23 23:35:01 +0100212 msg = msgb_alloc(esme->read_len, "SMPP Rx");
213 if (!msg)
214 return -ENOMEM;
215 esme->read_msg = msg;
216 cur = msgb_put(msg, sizeof(uint32_t));
217 memcpy(cur, lenptr, sizeof(uint32_t));
218 esme->read_state = READ_ST_IN_MSG;
219 esme->read_idx = sizeof(uint32_t);
220 }
221 break;
222 case READ_ST_IN_MSG:
223 msg = esme->read_msg;
224 rdlen = esme->read_len - esme->read_idx;
225 rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
226 if (rc < 0) {
Max62977d02022-08-01 22:50:52 +0700227 LOGPESME(esme, LOGL_ERROR, "read returned %d\n", rc);
Harald Weltec0de14d2012-11-23 23:35:01 +0100228 } else if (rc == 0) {
229 goto dead_socket;
230 } else {
231 esme->read_idx += rc;
232 msgb_put(msg, rc);
233 }
234
235 if (esme->read_idx >= esme->read_len) {
236 rc = smpp_pdu_rx(esme, esme->read_msg);
Harald Welte065b23a2021-10-25 08:18:26 +0200237 esme_read_state_reset(esme);
Harald Weltec0de14d2012-11-23 23:35:01 +0100238 }
239 break;
240 }
241
242 return 0;
243dead_socket:
244 msgb_free(esme->read_msg);
245 osmo_fd_unregister(&esme->wqueue.bfd);
246 close(esme->wqueue.bfd.fd);
247 esme->wqueue.bfd.fd = -1;
Harald Welte890ece12021-10-25 08:18:58 +0200248 esme_read_state_reset(esme);
Harald Weltec0de14d2012-11-23 23:35:01 +0100249 exit(2342);
250
251 return 0;
252}
253
Harald Welte7b1d25a2015-01-01 12:32:03 +0100254static int esme_write_cb(struct osmo_fd *ofd, struct msgb *msg)
Harald Weltec0de14d2012-11-23 23:35:01 +0100255{
256 struct esme *esme = ofd->data;
257 int rc;
258
259 rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
260 if (rc == 0) {
261 osmo_fd_unregister(&esme->wqueue.bfd);
262 close(esme->wqueue.bfd.fd);
263 esme->wqueue.bfd.fd = -1;
264 exit(99);
265 } else if (rc < msgb_length(msg)) {
Max62977d02022-08-01 22:50:52 +0700266 LOGPESME(esme, LOGL_ERROR, "Short write\n");
Harald Welte7b1d25a2015-01-01 12:32:03 +0100267 return 0;
Harald Weltec0de14d2012-11-23 23:35:01 +0100268 }
Harald Welte7b1d25a2015-01-01 12:32:03 +0100269
270 return 0;
Harald Weltec0de14d2012-11-23 23:35:01 +0100271}
272
273static int smpp_esme_init(struct esme *esme, const char *host, uint16_t port)
274{
275 int rc;
276
277 if (port == 0)
278 port = 2775;
279
Harald Weltec0de14d2012-11-23 23:35:01 +0100280 esme->wqueue.bfd.data = esme;
281 esme->wqueue.read_cb = esme_read_cb;
282 esme->wqueue.write_cb = esme_write_cb;
283
284 rc = osmo_sock_init_ofd(&esme->wqueue.bfd, AF_UNSPEC, SOCK_STREAM,
285 IPPROTO_TCP, host, port, OSMO_SOCK_F_CONNECT);
286 if (rc < 0)
287 return rc;
288
289 return bind_transceiver(esme);
290}
291
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +0100292static const struct log_info_cat smpp_mirror_default_categories[] = {
293 [DSMPP] = {
294 .name = "DSMPP",
295 .description = "SMPP interface for external SMS apps",
296 .enabled = 1, .loglevel = LOGL_DEBUG,
297 },
298};
299
300const struct log_info log_info = {
301 .cat = smpp_mirror_default_categories,
302 .num_cat = ARRAY_SIZE(smpp_mirror_default_categories),
303};
Harald Weltec0de14d2012-11-23 23:35:01 +0100304
305int main(int argc, char **argv)
306{
Max366a3402022-08-01 23:01:24 +0700307 struct esme *esme;
Harald Weltec0de14d2012-11-23 23:35:01 +0100308 char *host = "localhost";
309 int port = 0;
310 int rc;
Neels Hofmeyr08b38282018-03-30 23:04:04 +0200311 void *ctx = talloc_named_const(NULL, 0, "smpp_mirror");
Harald Weltec0de14d2012-11-23 23:35:01 +0100312
Neels Hofmeyr08b38282018-03-30 23:04:04 +0200313 msgb_talloc_ctx_init(ctx, 0);
Neels Hofmeyr4c2d4ab2016-09-16 02:31:17 +0200314
Neels Hofmeyr08b38282018-03-30 23:04:04 +0200315 osmo_init_logging2(ctx, &log_info);
Harald Weltec0de14d2012-11-23 23:35:01 +0100316
Max366a3402022-08-01 23:01:24 +0700317 esme = esme_alloc(ctx);
318 if (!esme)
319 exit(2);
320
321 snprintf((char *) esme->system_id, sizeof(esme->system_id), "mirror");
322 snprintf((char *) esme->password, sizeof(esme->password), "mirror");
323 esme->smpp_version = 0x34;
Harald Weltec0de14d2012-11-23 23:35:01 +0100324
325 if (argc >= 2)
326 host = argv[1];
327 if (argc >= 3)
328 port = atoi(argv[2]);
329
Max366a3402022-08-01 23:01:24 +0700330 rc = smpp_esme_init(esme, host, port);
Harald Weltec0de14d2012-11-23 23:35:01 +0100331 if (rc < 0)
332 exit(1);
333
334 while (1) {
335 osmo_select_main(0);
336 }
337
338 exit(0);
339}