blob: 9f18f4febf29b2573a9f01e2c17fe07019f03479 [file] [log] [blame]
Martin Hauke3f07dac2019-11-14 17:49:08 +01001/* SMS queue to continuously attempt to deliver SMS */
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +01002/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +01009 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010018 *
19 */
20
21/**
22 * The difficulty of such a queue is to send a lot of SMS without
23 * overloading the paging subsystem and the database and other users
24 * of the MSC. To make the best use we would need to know the number
25 * of pending paging requests, then throttle the number of SMS we
26 * want to send and such.
27 * We will start with a very simple SMS Queue and then try to speed
28 * things up by collecting data from other parts of the system.
29 */
30
Harald Welte2483f1b2016-06-19 18:06:02 +020031#include <limits.h>
32
Neels Hofmeyr90843962017-09-04 15:04:35 +020033#include <osmocom/msc/sms_queue.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020034#include <osmocom/msc/db.h>
35#include <osmocom/msc/debug.h>
36#include <osmocom/msc/gsm_data.h>
37#include <osmocom/msc/gsm_04_11.h>
38#include <osmocom/msc/gsm_subscriber.h>
39#include <osmocom/msc/signal.h>
40#include <osmocom/msc/vlr.h>
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010041
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte63494a62022-05-15 13:03:57 +020043#include <osmocom/core/utils.h>
44#include <osmocom/core/rate_ctr.h>
45#include <osmocom/core/stat_item.h>
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010046
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +010047#include <osmocom/vty/vty.h>
48
Harald Welte63494a62022-05-15 13:03:57 +020049enum smsq_stat_item_idx {
50 SMSQ_STAT_SMS_RAM_PENDING,
51};
52
53static const struct osmo_stat_item_desc smsq_stat_item_desc[] = {
54 [SMSQ_STAT_SMS_RAM_PENDING] = { "ram:pending",
55 "Number of SMSs in the in-RAM pending delivery queue" },
56};
57
58static const struct osmo_stat_item_group_desc smsq_statg_desc = {
59 "sms_queue",
60 "SMS queue",
61 OSMO_STATS_CLASS_GLOBAL,
62 ARRAY_SIZE(smsq_stat_item_desc),
63 smsq_stat_item_desc,
64};
65
66enum smsq_rate_ctr_idx {
67 SMSQ_CTR_SMS_DELIVERY_ATTEMPTS,
68 SMSQ_CTR_SMS_DELIVERY_ACK,
69 SMSQ_CTR_SMS_DELIVERY_ERR,
70 SMSQ_CTR_SMS_DELIVERY_NOMEM,
71 SMSQ_CTR_SMS_DELIVERY_TIMEOUT,
72};
73
74static const struct rate_ctr_desc smsq_ctr_desc[] = {
75 [SMSQ_CTR_SMS_DELIVERY_ATTEMPTS] = { "delivery:attempts",
76 "Attempted MT SMS deliveries to subscriber" },
77 [SMSQ_CTR_SMS_DELIVERY_ACK] = { "deliver:ack",
78 "Successful MT SMS delivery to subscriber" },
79 [SMSQ_CTR_SMS_DELIVERY_ERR] = { "deliver:error",
80 "Erroneous MT SMS delivery" },
81 [SMSQ_CTR_SMS_DELIVERY_NOMEM] = { "deliver:no_memory",
82 "Failed MT SMS delivery due to no memory on MS" },
83 [SMSQ_CTR_SMS_DELIVERY_TIMEOUT] = { "deliver:paging_timeout",
84 "Failed MT SMS delivery due to paging timeout (MS gone?)" },
85};
86
87static const struct rate_ctr_group_desc smsq_ctrg_desc = {
88 "sms_queue",
89 "SMS queue",
90 OSMO_STATS_CLASS_GLOBAL,
91 ARRAY_SIZE(smsq_ctr_desc),
92 smsq_ctr_desc,
93};
94
95#define smsq_rate_ctr_inc(smsq, idx) \
96 rate_ctr_inc(rate_ctr_group_get_ctr((smsq)->ctrg, idx))
97#define smsq_rate_ctr_add(smsq, idx, val) \
98 rate_ctr_add(rate_ctr_group_get_ctr((smsq)->ctrg, idx), val)
99
100#define smsq_stat_item_inc(smsq, idx) \
101 osmo_stat_item_inc(osmo_stat_item_group_get_item((smsq)->statg, idx), 1)
102#define smsq_stat_item_dec(smsq, idx) \
103 osmo_stat_item_dec(osmo_stat_item_group_get_item((smsq)->statg, idx), 1)
104#define smsq_stat_item_set(smsq, idx, val) \
105 osmo_stat_item_set(osmo_stat_item_group_get_item((smsq)->statg, idx), val)
106
107
Harald Weltedc7d8412022-05-14 09:54:15 +0200108/* One in-RAM record of a "pending SMS". This is not the SMS itself, but merely
109 * a pointer to the database record. It holds a reference on the vlr_subscriber
110 * and some counters. While this object exists in RAM, we are regularly attempting
111 * to deliver the related SMS. */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100112struct gsm_sms_pending {
Harald Weltedc7d8412022-05-14 09:54:15 +0200113 struct llist_head entry; /* gsm_sms_queue.pending_sms */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100114
Harald Weltedc7d8412022-05-14 09:54:15 +0200115 struct vlr_subscr *vsub; /* destination subscriber for this SMS */
116 struct msc_a *msc_a; /* MSC_A associated with this SMS */
117 unsigned long long sms_id; /* unique ID (in SQL database) of this SMS */
118 int failed_attempts; /* count of failed deliver attempts so far */
119 int resend; /* should we try re-sending it (now) ? */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100120};
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100121
Harald Weltedc7d8412022-05-14 09:54:15 +0200122/* (global) state of the SMS queue. */
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100123struct gsm_sms_queue {
Harald Weltedc7d8412022-05-14 09:54:15 +0200124 struct osmo_timer_list resend_pending; /* timer triggering sms_resend_pending() */
125 struct osmo_timer_list push_queue; /* timer triggering sms_submit_pending() */
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100126 struct gsm_network *network;
Harald Weltedc7d8412022-05-14 09:54:15 +0200127 struct llist_head pending_sms; /* list of gsm_sms_pending */
Harald Welted302bb12022-05-17 13:31:14 +0200128 struct sms_queue_config *cfg;
129 int pending; /* current number of gsm_sms_pending in RAM */
Harald Welte2483f1b2016-06-19 18:06:02 +0200130
Harald Weltedc7d8412022-05-14 09:54:15 +0200131 /* last MSISDN for which we read SMS from the database and created gsm_sms_pending records */
Vadim Yanitskiy8b0737f2019-05-25 19:27:17 +0700132 char last_msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
Harald Welte63494a62022-05-15 13:03:57 +0200133
134 /* statistics / counters */
135 struct osmo_stat_item_group *statg;
136 struct rate_ctr_group *ctrg;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100137};
138
Harald Welte63494a62022-05-15 13:03:57 +0200139/* private wrapper function to make sure we count all SMS delivery attempts */
140static void _gsm411_send_sms(struct gsm_network *net, struct vlr_subscr *vsub, struct gsm_sms *sms)
141{
142 smsq_rate_ctr_inc(net->sms_queue, SMSQ_CTR_SMS_DELIVERY_ATTEMPTS);
143 gsm411_send_sms(net, vsub, sms);
144}
145
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100146static int sms_subscr_cb(unsigned int, unsigned int, void *, void *);
147static int sms_sms_cb(unsigned int, unsigned int, void *, void *);
148
Harald Weltedc7d8412022-05-14 09:54:15 +0200149/* look-up a 'gsm_sms_pending' for the given sms_id; return NULL if none */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100150static struct gsm_sms_pending *sms_find_pending(struct gsm_sms_queue *smsq,
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100151 unsigned long long sms_id)
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100152{
153 struct gsm_sms_pending *pending;
154
155 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100156 if (pending->sms_id == sms_id)
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100157 return pending;
158 }
159
160 return NULL;
161}
162
Harald Weltedc7d8412022-05-14 09:54:15 +0200163/* do we currently have a gsm_sms_pending object for the given SMS id? */
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100164int sms_queue_sms_is_pending(struct gsm_sms_queue *smsq, unsigned long long sms_id)
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100165{
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100166 return sms_find_pending(smsq, sms_id) != NULL;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100167}
168
Harald Weltedc7d8412022-05-14 09:54:15 +0200169/* find the first pending SMS (in RAM) for the given subscriber */
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200170static struct gsm_sms_pending *sms_subscriber_find_pending(
171 struct gsm_sms_queue *smsq,
Harald Welte2483f1b2016-06-19 18:06:02 +0200172 struct vlr_subscr *vsub)
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100173{
174 struct gsm_sms_pending *pending;
175
176 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
Harald Welte2483f1b2016-06-19 18:06:02 +0200177 if (pending->vsub == vsub)
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200178 return pending;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100179 }
180
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200181 return NULL;
182}
183
Harald Weltedc7d8412022-05-14 09:54:15 +0200184/* do we have any pending SMS (in RAM) for the given subscriber? */
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200185static int sms_subscriber_is_pending(struct gsm_sms_queue *smsq,
Harald Welte2483f1b2016-06-19 18:06:02 +0200186 struct vlr_subscr *vsub)
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200187{
Harald Welte2483f1b2016-06-19 18:06:02 +0200188 return sms_subscriber_find_pending(smsq, vsub) != NULL;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100189}
190
Harald Weltedc7d8412022-05-14 09:54:15 +0200191/* allocate a new gsm_sms_pending record and fill it with information from 'sms' */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100192static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
193 struct gsm_sms *sms)
194{
195 struct gsm_sms_pending *pending;
196
197 pending = talloc_zero(smsq, struct gsm_sms_pending);
198 if (!pending)
199 return NULL;
200
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100201 vlr_subscr_get(sms->receiver, VSUB_USE_SMS_PENDING);
202 pending->vsub = sms->receiver;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100203 pending->sms_id = sms->id;
Harald Welte7262d082022-05-15 14:58:50 +0200204 llist_add_tail(&pending->entry, &smsq->pending_sms);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100205
Harald Welte7f918af2022-05-15 14:55:56 +0200206 smsq->pending += 1;
207 smsq_stat_item_inc(smsq, SMSQ_STAT_SMS_RAM_PENDING);
Harald Welte7262d082022-05-15 14:58:50 +0200208
209 return pending;
Harald Welte7f918af2022-05-15 14:55:56 +0200210}
211
212/* release a gsm_sms_pending object */
213static void sms_pending_free(struct gsm_sms_queue *smsq, struct gsm_sms_pending *pending)
214{
215 smsq->pending -= 1;
216 smsq_stat_item_dec(smsq, SMSQ_STAT_SMS_RAM_PENDING);
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100217 vlr_subscr_put(pending->vsub, VSUB_USE_SMS_PENDING);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100218 llist_del(&pending->entry);
219 talloc_free(pending);
220}
221
Harald Weltedc7d8412022-05-14 09:54:15 +0200222/* this sets the 'resend' flag of the gsm_sms_pending and schedules
223 * the timer for re-sending */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100224static void sms_pending_resend(struct gsm_sms_pending *pending)
225{
Harald Welte2483f1b2016-06-19 18:06:02 +0200226 struct gsm_network *net = pending->vsub->vlr->user_ctx;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100227 struct gsm_sms_queue *smsq;
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100228 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100229 "Scheduling resend of SMS %llu.\n", pending->sms_id);
230
231 pending->resend = 1;
232
Harald Welte2483f1b2016-06-19 18:06:02 +0200233 smsq = net->sms_queue;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200234 if (osmo_timer_pending(&smsq->resend_pending))
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100235 return;
236
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200237 osmo_timer_schedule(&smsq->resend_pending, 1, 0);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100238}
239
Harald Weltedc7d8412022-05-14 09:54:15 +0200240/* call-back when a pending SMS has failed; try another re-send if number of
241 * attempts is < smsq->max_fail */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100242static void sms_pending_failed(struct gsm_sms_pending *pending, int paging_error)
243{
Harald Welte2483f1b2016-06-19 18:06:02 +0200244 struct gsm_network *net = pending->vsub->vlr->user_ctx;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100245 struct gsm_sms_queue *smsq;
246
Neels Hofmeyr34a36da2019-03-06 16:00:41 +0100247 pending->failed_attempts++;
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100248 LOGP(DLSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100249 pending->sms_id, pending->failed_attempts);
250
Harald Welte2483f1b2016-06-19 18:06:02 +0200251 smsq = net->sms_queue;
Harald Welted302bb12022-05-17 13:31:14 +0200252 if (pending->failed_attempts < smsq->cfg->max_fail)
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100253 return sms_pending_resend(pending);
254
Harald Welte7f918af2022-05-15 14:55:56 +0200255 sms_pending_free(smsq, pending);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100256}
257
Harald Weltedc7d8412022-05-14 09:54:15 +0200258/* Resend all SMS that are scheduled for a resend. This is done to
259 * avoid an immediate failure. This iterates over all the (in RAM)
260 * pending_sms records, checks for resend == true, reads them from the
Harald Welte63494a62022-05-15 13:03:57 +0200261 * DB and attempts to send them via _gsm411_send_sms() */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100262static void sms_resend_pending(void *_data)
263{
264 struct gsm_sms_pending *pending, *tmp;
265 struct gsm_sms_queue *smsq = _data;
266
267 llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
268 struct gsm_sms *sms;
269 if (!pending->resend)
270 continue;
271
272 sms = db_sms_get(smsq->network, pending->sms_id);
273
274 /* the sms is gone? Move to the next */
275 if (!sms) {
Harald Welte7f918af2022-05-15 14:55:56 +0200276 sms_pending_free(smsq, pending);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100277 sms_queue_trigger(smsq);
278 } else {
279 pending->resend = 0;
Harald Welte63494a62022-05-15 13:03:57 +0200280 _gsm411_send_sms(smsq->network, sms->receiver, sms);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100281 }
282 }
283}
284
Harald Welte2483f1b2016-06-19 18:06:02 +0200285/* Find the next pending SMS by cycling through the recipients. We could also
286 * cycle through the pending SMS, but that might cause us to keep trying to
287 * send SMS to the same few subscribers repeatedly while not servicing other
288 * subscribers for a long time. By walking the list of recipient MSISDNs, we
289 * ensure that all subscribers get their fair time to receive SMS. */
290struct gsm_sms *smsq_take_next_sms(struct gsm_network *net,
291 char *last_msisdn,
292 size_t last_msisdn_buflen)
Holger Hans Peter Freytherf7e23892010-12-25 17:45:23 +0100293{
294 struct gsm_sms *sms;
Harald Welte2483f1b2016-06-19 18:06:02 +0200295 int wrapped = 0;
296 int sanity = 100;
297 char started_with_msisdn[last_msisdn_buflen];
Holger Hans Peter Freytherf7e23892010-12-25 17:45:23 +0100298
Max98f74672018-02-05 12:57:06 +0100299 OSMO_STRLCPY_ARRAY(started_with_msisdn, last_msisdn);
Harald Welte2483f1b2016-06-19 18:06:02 +0200300
301 while (wrapped < 2 && (--sanity)) {
302 /* If we wrapped around and passed the first msisdn, we're
303 * through the entire SMS DB; end it. */
304 if (wrapped && strcmp(last_msisdn, started_with_msisdn) >= 0)
305 break;
306
307 sms = db_sms_get_next_unsent_rr_msisdn(net, last_msisdn, 9);
308 if (!sms) {
309 last_msisdn[0] = '\0';
Max5e2e9bd2018-02-06 19:31:08 +0100310 wrapped++;
Harald Welte2483f1b2016-06-19 18:06:02 +0200311 continue;
312 }
313
314 /* Whatever happens, next time around service another recipient
315 */
316 osmo_strlcpy(last_msisdn, sms->dst.addr, last_msisdn_buflen);
317
318 /* Is the subscriber attached? If not, go to next SMS */
Vadim Yanitskiy96262a72019-03-28 21:25:14 +0700319 if (!sms->receiver || !sms->receiver->lu_complete) {
320 LOGP(DLSMS, LOGL_DEBUG,
Pau Espin Pedrolf8af7762019-04-09 12:44:35 +0200321 "Subscriber %s%s is not attached, skipping SMS %llu\n",
322 sms->receiver ? "" : "MSISDN-",
323 sms->receiver ? vlr_subscr_msisdn_or_name(sms->receiver)
324 : sms->dst.addr, sms->id);
Vadim Yanitskiy96262a72019-03-28 21:25:14 +0700325 sms_free(sms);
Harald Welte2483f1b2016-06-19 18:06:02 +0200326 continue;
Vadim Yanitskiy96262a72019-03-28 21:25:14 +0700327 }
Harald Welte2483f1b2016-06-19 18:06:02 +0200328
Holger Hans Peter Freytherf7e23892010-12-25 17:45:23 +0100329 return sms;
330 }
331
Harald Welte2483f1b2016-06-19 18:06:02 +0200332 DEBUGP(DLSMS, "SMS queue: no SMS to be sent\n");
333 return NULL;
Holger Hans Peter Freytherf7e23892010-12-25 17:45:23 +0100334}
335
Harald Weltedc7d8412022-05-14 09:54:15 +0200336/* read up to 'max_pending' pending SMS from the database and add them to the in-memory
337 * sms_queue; trigger the first delivery attempt. 'submit' in this context means
338 * "read from the database and add to the in-memory gsm_sms_queue" and is not to be
339 * confused with the SMS SUBMIT operation a MS performs when sending a MO-SMS. */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100340static void sms_submit_pending(void *_data)
341{
342 struct gsm_sms_queue *smsq = _data;
Harald Welted302bb12022-05-17 13:31:14 +0200343 int attempts = smsq->cfg->max_pending - smsq->pending;
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100344 int initialized = 0;
345 unsigned long long first_sub = 0;
Holger Hans Peter Freyther5479fc82010-12-25 19:32:12 +0100346 int attempted = 0, rounds = 0;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100347
Pau Espin Pedrolfe5b7042019-06-20 10:45:35 +0200348 LOGP(DLSMS, LOGL_DEBUG, "Attempting to send up to %d SMS\n", attempts);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100349
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100350 do {
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100351 struct gsm_sms_pending *pending;
352 struct gsm_sms *sms;
353
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100354
Harald Welte2483f1b2016-06-19 18:06:02 +0200355 sms = smsq_take_next_sms(smsq->network, smsq->last_msisdn,
356 sizeof(smsq->last_msisdn));
Neels Hofmeyr1e918c32016-05-09 21:48:53 +0200357 if (!sms) {
358 LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (%d attempted)\n",
359 attempted);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100360 break;
Neels Hofmeyr1e918c32016-05-09 21:48:53 +0200361 }
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100362
Holger Hans Peter Freyther5479fc82010-12-25 19:32:12 +0100363 rounds += 1;
Neels Hofmeyr3d6a8be2019-11-18 07:15:56 +0100364 LOGP(DLSMS, LOGL_DEBUG, "Checking whether to send SMS %llu\n", sms->id);
Holger Hans Peter Freyther5479fc82010-12-25 19:32:12 +0100365
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100366 /*
367 * This code needs to detect a loop. It assumes that no SMS
368 * will vanish during the time this is executed. We will remember
369 * the id of the first GSM subscriber we see and then will
370 * compare this. The Database code should make sure that we will
371 * see all other subscribers first before seeing this one again.
372 *
373 * It is always scary to have an infinite loop like this.
374 */
375 if (!initialized) {
376 first_sub = sms->receiver->id;
377 initialized = 1;
378 } else if (first_sub == sms->receiver->id) {
Neels Hofmeyr1e918c32016-05-09 21:48:53 +0200379 LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (loop) (%d attempted)\n",
380 attempted);
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100381 sms_free(sms);
382 break;
383 }
384
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100385 /* no need to send a pending sms */
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100386 if (sms_queue_sms_is_pending(smsq, sms->id)) {
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100387 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freytherdc53af62010-12-27 20:12:25 +0100388 "SMSqueue with pending sms: %llu. Skipping\n", sms->id);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100389 sms_free(sms);
390 continue;
391 }
392
393 /* no need to send a SMS with the same receiver */
394 if (sms_subscriber_is_pending(smsq, sms->receiver)) {
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100395 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100396 "SMSqueue with pending sub: %llu. Skipping\n", sms->receiver->id);
397 sms_free(sms);
398 continue;
399 }
400
Harald Weltedc7d8412022-05-14 09:54:15 +0200401 /* allocate a new gsm_sms_pending object in RAM */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100402 pending = sms_pending_from(smsq, sms);
403 if (!pending) {
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100404 LOGP(DLSMS, LOGL_ERROR,
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100405 "Failed to create pending SMS entry.\n");
406 sms_free(sms);
407 continue;
408 }
409
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100410 attempted += 1;
Harald Welte63494a62022-05-15 13:03:57 +0200411 _gsm411_send_sms(smsq->network, sms->receiver, sms);
Holger Hans Peter Freyther5479fc82010-12-25 19:32:12 +0100412 } while (attempted < attempts && rounds < 1000);
Holger Hans Peter Freyther20384572010-12-25 19:28:44 +0100413
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100414 LOGP(DLSMS, LOGL_DEBUG, "SMSqueue added %d messages in %d rounds\n", attempted, rounds);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100415}
416
Harald Weltedc7d8412022-05-14 09:54:15 +0200417/* obtain the next pending SMS for given subscriber from database,
418 * create gsm_sms_pending object and attempt first delivery. If there
419 * are no SMS pending for the given subscriber, call sms_submit_pending()
420 * to read more SMS (for any subscriber) into the in-RAM pending queue */
Harald Welte2483f1b2016-06-19 18:06:02 +0200421static void sms_send_next(struct vlr_subscr *vsub)
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100422{
Harald Welte2483f1b2016-06-19 18:06:02 +0200423 struct gsm_network *net = vsub->vlr->user_ctx;
424 struct gsm_sms_queue *smsq = net->sms_queue;
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100425 struct gsm_sms_pending *pending;
426 struct gsm_sms *sms;
427
428 /* the subscriber should not be in the queue */
Harald Welte2483f1b2016-06-19 18:06:02 +0200429 OSMO_ASSERT(!sms_subscriber_is_pending(smsq, vsub));
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100430
431 /* check for more messages for this subscriber */
Harald Welted43c22e2022-05-14 15:35:49 +0200432 sms = db_sms_get_unsent_for_subscr(vsub, INT_MAX);
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100433 if (!sms)
434 goto no_pending_sms;
435
Harald Welte2483f1b2016-06-19 18:06:02 +0200436 /* The sms should not be scheduled right now */
Stefan Sperling87cba1f2018-01-22 17:05:37 +0100437 OSMO_ASSERT(!sms_queue_sms_is_pending(smsq, sms->id));
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100438
439 /* Remember that we deliver this SMS and send it */
440 pending = sms_pending_from(smsq, sms);
441 if (!pending) {
442 LOGP(DLSMS, LOGL_ERROR,
443 "Failed to create pending SMS entry.\n");
444 sms_free(sms);
445 goto no_pending_sms;
446 }
447
Harald Welte63494a62022-05-15 13:03:57 +0200448 _gsm411_send_sms(smsq->network, sms->receiver, sms);
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100449 return;
450
451no_pending_sms:
452 /* Try to send the SMS to avoid the queue being stuck */
Harald Welte2483f1b2016-06-19 18:06:02 +0200453 sms_submit_pending(net->sms_queue);
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100454}
455
Harald Weltedc7d8412022-05-14 09:54:15 +0200456/* Trigger a call to sms_submit_pending() in one second */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100457int sms_queue_trigger(struct gsm_sms_queue *smsq)
458{
Neels Hofmeyr1e918c32016-05-09 21:48:53 +0200459 LOGP(DLSMS, LOGL_DEBUG, "Triggering SMS queue\n");
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200460 if (osmo_timer_pending(&smsq->push_queue))
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100461 return 0;
462
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200463 osmo_timer_schedule(&smsq->push_queue, 1, 0);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100464 return 0;
465}
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100466
Harald Welted302bb12022-05-17 13:31:14 +0200467/* allocate + initialize SMS queue configuration with some default values */
468struct sms_queue_config *sms_queue_cfg_alloc(void *ctx)
469{
470 struct sms_queue_config *sqcfg = talloc_zero(ctx, struct sms_queue_config);
471 OSMO_ASSERT(sqcfg);
472
473 sqcfg->max_pending = 20;
474 sqcfg->max_fail = 1;
Harald Welte53e2e5f2022-05-17 14:39:51 +0200475 sqcfg->delete_delivered = true;
476 sqcfg->delete_expired = true;
Harald Welte2765a182022-05-17 18:56:55 +0200477 sqcfg->default_validity_mins = 7 * 24 * 60; /* 7 days */
Harald Weltea3c639f2022-05-17 19:01:43 +0200478 sqcfg->minimum_validity_mins = 1;
Harald Welted302bb12022-05-17 13:31:14 +0200479 sqcfg->db_file_path = talloc_strdup(ctx, SMS_DEFAULT_DB_FILE_PATH);
480
481 return sqcfg;
482}
483
Harald Weltedc7d8412022-05-14 09:54:15 +0200484/* initialize the sms_queue subsystem and read the first batch of SMS from
485 * the database for delivery */
Harald Welted302bb12022-05-17 13:31:14 +0200486int sms_queue_start(struct gsm_network *network)
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100487{
488 struct gsm_sms_queue *sms = talloc_zero(network, struct gsm_sms_queue);
489 if (!sms) {
490 LOGP(DMSC, LOGL_ERROR, "Failed to create the SMS queue.\n");
491 return -1;
492 }
493
Harald Welted302bb12022-05-17 13:31:14 +0200494 sms->cfg = network->sms_queue_cfg;
Harald Welte63494a62022-05-15 13:03:57 +0200495 sms->statg = osmo_stat_item_group_alloc(sms, &smsq_statg_desc, 0);
496 if (!sms->statg)
497 goto err_free;
498
499 sms->ctrg = rate_ctr_group_alloc(sms, &smsq_ctrg_desc, 0);
500 if (!sms->ctrg)
501 goto err_statg;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100502
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100503 network->sms_queue = sms;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100504 INIT_LLIST_HEAD(&sms->pending_sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100505 sms->network = network;
Pablo Neira Ayuso51215762017-05-08 20:57:52 +0200506 osmo_timer_setup(&sms->push_queue, sms_submit_pending, sms);
507 osmo_timer_setup(&sms->resend_pending, sms_resend_pending, sms);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100508
Harald Welte63494a62022-05-15 13:03:57 +0200509 osmo_signal_register_handler(SS_SUBSCR, sms_subscr_cb, network);
510 osmo_signal_register_handler(SS_SMS, sms_sms_cb, network);
511
Harald Welted302bb12022-05-17 13:31:14 +0200512 if (db_init(sms, sms->cfg->db_file_path, true)) {
513 LOGP(DMSC, LOGL_FATAL, "DB: Failed to init database: %s\n",
514 osmo_quote_str(sms->cfg->db_file_path, -1));
515 return -1;
516 }
517
518 if (db_prepare()) {
519 LOGP(DMSC, LOGL_FATAL, "DB: Failed to prepare database.\n");
520 return -1;
521 }
522
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100523 sms_submit_pending(sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100524
525 return 0;
Harald Welte63494a62022-05-15 13:03:57 +0200526
527err_statg:
528 osmo_stat_item_group_free(sms->statg);
529err_free:
530 talloc_free(sms);
531
532 return -ENOMEM;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100533}
534
Harald Weltedc7d8412022-05-14 09:54:15 +0200535/* call-back: Given subscriber is now ready for short messages. */
Harald Welte2483f1b2016-06-19 18:06:02 +0200536static int sub_ready_for_sm(struct gsm_network *net, struct vlr_subscr *vsub)
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100537{
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100538 struct gsm_sms *sms;
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200539 struct gsm_sms_pending *pending;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100540
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200541 /*
542 * The code used to be very clever and tried to submit
543 * a SMS during the Location Updating Request. This has
544 * two issues:
545 * 1.) The Phone might not be ready yet, e.g. the C155
546 * will not respond to the Submit when it is booting.
547 * 2.) The queue is already trying to submit SMS to the
548 * user and by not responding to the paging request
549 * we will set the LAC back to 0. We would have to
550 * stop the paging and move things over.
551 *
552 * We need to be careful in what we try here.
553 */
554
555 /* check if we have pending requests */
Harald Welte2483f1b2016-06-19 18:06:02 +0200556 pending = sms_subscriber_find_pending(net->sms_queue, vsub);
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200557 if (pending) {
558 LOGP(DMSC, LOGL_NOTICE,
559 "Pending paging while subscriber %llu attached.\n",
Harald Welte2483f1b2016-06-19 18:06:02 +0200560 vsub->id);
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200561 return 0;
562 }
563
Holger Hans Peter Freyther074b2b22011-07-25 00:13:06 +0200564 /* Now try to deliver any pending SMS to this sub */
Harald Welted43c22e2022-05-14 15:35:49 +0200565 sms = db_sms_get_unsent_for_subscr(vsub, INT_MAX);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100566 if (!sms)
567 return -1;
Vadim Yanitskiy24e025e2018-11-22 15:42:39 +0700568
Harald Welte63494a62022-05-15 13:03:57 +0200569 _gsm411_send_sms(net, vsub, sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100570 return 0;
571}
572
Harald Weltedc7d8412022-05-14 09:54:15 +0200573/* call-back for SS_SUBSCR signals */
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100574static int sms_subscr_cb(unsigned int subsys, unsigned int signal,
575 void *handler_data, void *signal_data)
576{
Harald Welte2483f1b2016-06-19 18:06:02 +0200577 struct vlr_subscr *vsub = signal_data;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100578
579 if (signal != S_SUBSCR_ATTACHED)
580 return 0;
581
582 /* this is readyForSM */
Harald Welte2483f1b2016-06-19 18:06:02 +0200583 return sub_ready_for_sm(handler_data, vsub);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100584}
585
Harald Weltedc7d8412022-05-14 09:54:15 +0200586/* call-back for SS_SMS signals */
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100587static int sms_sms_cb(unsigned int subsys, unsigned int signal,
588 void *handler_data, void *signal_data)
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100589{
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100590 struct gsm_network *network = handler_data;
Harald Welte03e85832022-05-17 14:38:45 +0200591 struct gsm_sms_queue *smq = network->sms_queue;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100592 struct sms_signal_data *sig_sms = signal_data;
593 struct gsm_sms_pending *pending;
Harald Welte2483f1b2016-06-19 18:06:02 +0200594 struct vlr_subscr *vsub;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100595
596 /* We got a new SMS and maybe should launch the queue again. */
597 if (signal == S_SMS_SUBMITTED || signal == S_SMS_SMMA) {
Holger Hans Peter Freyther024dc772014-02-24 14:29:27 +0100598 /* TODO: For SMMA we might want to re-use the radio connection. */
Harald Welte03e85832022-05-17 14:38:45 +0200599 sms_queue_trigger(smq);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100600 return 0;
601 }
602
603 if (!sig_sms->sms)
604 return -1;
605
606
607 /*
608 * Find the entry of our queue. The SMS subsystem will submit
609 * sms that are not in our control as we just have a channel
610 * open anyway.
611 */
Harald Welte03e85832022-05-17 14:38:45 +0200612 pending = sms_find_pending(smq, sig_sms->sms->id);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100613 if (!pending)
614 return 0;
615
616 switch (signal) {
617 case S_SMS_DELIVERED:
Harald Welte03e85832022-05-17 14:38:45 +0200618 smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_ACK);
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100619 /* Remember the subscriber and clear the pending entry */
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100620 vsub = pending->vsub;
621 vlr_subscr_get(vsub, __func__);
Harald Welte53e2e5f2022-05-17 14:39:51 +0200622 if (smq->cfg->delete_delivered)
623 db_sms_delete_sent_message_by_id(pending->sms_id);
Harald Welte03e85832022-05-17 14:38:45 +0200624 sms_pending_free(smq, pending);
Holger Hans Peter Freyther93de8b22014-02-24 16:13:04 +0100625 /* Attempt to send another SMS to this subscriber */
Harald Welte2483f1b2016-06-19 18:06:02 +0200626 sms_send_next(vsub);
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100627 vlr_subscr_put(vsub, __func__);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100628 break;
629 case S_SMS_MEM_EXCEEDED:
Harald Welte03e85832022-05-17 14:38:45 +0200630 smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_NOMEM);
631 sms_pending_free(smq, pending);
632 sms_queue_trigger(smq);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100633 break;
634 case S_SMS_UNKNOWN_ERROR:
635 /*
636 * There can be many reasons for this failure. E.g. the paging
637 * timed out, the subscriber was not paged at all, or there was
638 * a protocol error. The current strategy is to try sending the
639 * next SMS for busy/oom and to retransmit when we have paged.
640 *
641 * When the paging expires three times we will disable the
642 * subscriber. If we have some kind of other transmit error we
643 * should flag the SMS as bad.
644 */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100645 if (sig_sms->paging_result) {
Harald Welte03e85832022-05-17 14:38:45 +0200646 smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_ERR);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100647 /* BAD SMS? */
648 db_sms_inc_deliver_attempts(sig_sms->sms);
649 sms_pending_failed(pending, 0);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100650 } else {
Harald Welte03e85832022-05-17 14:38:45 +0200651 smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_TIMEOUT);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100652 sms_pending_failed(pending, 1);
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100653 }
654 break;
655 default:
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100656 LOGP(DLSMS, LOGL_ERROR, "Unhandled result: %d\n",
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100657 sig_sms->paging_result);
658 }
659
Stefan Sperling14e05172018-01-22 17:31:20 +0100660 /* While here, attempt to remove an expired SMS from the DB. */
Harald Welte53e2e5f2022-05-17 14:39:51 +0200661 if (smq->cfg->delete_expired)
662 db_sms_delete_oldest_expired_message();
Stefan Sperling14e05172018-01-22 17:31:20 +0100663
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100664 return 0;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100665}
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +0100666
667/* VTY helper functions */
668int sms_queue_stats(struct gsm_sms_queue *smsq, struct vty *vty)
669{
670 struct gsm_sms_pending *pending;
671
672 vty_out(vty, "SMSqueue with max_pending: %d pending: %d%s",
Harald Welted302bb12022-05-17 13:31:14 +0200673 smsq->cfg->max_pending, smsq->pending, VTY_NEWLINE);
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +0100674
675 llist_for_each_entry(pending, &smsq->pending_sms, entry)
Holger Hans Peter Freyther583e9ae2010-12-27 20:19:48 +0100676 vty_out(vty, " SMS Pending for Subscriber: %llu SMS: %llu Failed: %d.%s",
Harald Welte2483f1b2016-06-19 18:06:02 +0200677 pending->vsub->id, pending->sms_id,
Holger Hans Peter Freyther583e9ae2010-12-27 20:19:48 +0100678 pending->failed_attempts, VTY_NEWLINE);
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +0100679 return 0;
680}
Holger Hans Peter Freyther3c6f6c22010-12-25 14:25:12 +0100681
Holger Hans Peter Freyther4dcc5e52010-12-25 14:38:30 +0100682int sms_queue_clear(struct gsm_sms_queue *smsq)
683{
684 struct gsm_sms_pending *pending, *tmp;
685
686 llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
Holger Hans Peter Freythereff409492012-11-10 19:46:58 +0100687 LOGP(DLSMS, LOGL_NOTICE,
Harald Welte2483f1b2016-06-19 18:06:02 +0200688 "SMSqueue clearing for sub %llu\n", pending->vsub->id);
Harald Welte7f918af2022-05-15 14:55:56 +0200689 sms_pending_free(smsq, pending);
Holger Hans Peter Freyther4dcc5e52010-12-25 14:38:30 +0100690 }
691
692 return 0;
693}