blob: f6d09cf76eeaba84a5adae8727745bf30290f5da [file] [log] [blame]
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +01001/* SMS queue to continously attempt to deliver SMS */
2/*
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
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22/**
23 * The difficulty of such a queue is to send a lot of SMS without
24 * overloading the paging subsystem and the database and other users
25 * of the MSC. To make the best use we would need to know the number
26 * of pending paging requests, then throttle the number of SMS we
27 * want to send and such.
28 * We will start with a very simple SMS Queue and then try to speed
29 * things up by collecting data from other parts of the system.
30 */
31
32#include <openbsc/sms_queue.h>
33#include <openbsc/chan_alloc.h>
34#include <openbsc/db.h>
35#include <openbsc/debug.h>
36#include <openbsc/gsm_data.h>
37#include <openbsc/gsm_04_11.h>
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010038#include <openbsc/gsm_subscriber.h>
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010039#include <openbsc/signal.h>
40
41#include <osmocore/talloc.h>
42
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010043/*
44 * One pending SMS that we wait for.
45 */
46struct gsm_sms_pending {
47 struct llist_head entry;
48
49 struct gsm_subscriber *subscr;
50 unsigned long long sms_id;
51 int failed_attempts;
52 int resend;
53};
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010054
55struct gsm_sms_queue {
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010056 struct timer_list resend_pending;
57 struct timer_list push_queue;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010058 struct gsm_network *network;
59 int max_pending;
60 int pending;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010061
62 struct llist_head pending_sms;
63 unsigned long long last_subscr_id;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010064};
65
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010066static int sms_subscr_cb(unsigned int, unsigned int, void *, void *);
67static int sms_sms_cb(unsigned int, unsigned int, void *, void *);
68
69static struct gsm_sms_pending *sms_find_pending(struct gsm_sms_queue *smsq,
70 struct gsm_sms *sms)
71{
72 struct gsm_sms_pending *pending;
73
74 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
75 if (pending->sms_id == sms->id)
76 return pending;
77 }
78
79 return NULL;
80}
81
82static int sms_is_in_pending(struct gsm_sms_queue *smsq, struct gsm_sms *sms)
83{
84 return sms_find_pending(smsq, sms) != NULL;
85}
86
87static int sms_subscriber_is_pending(struct gsm_sms_queue *smsq,
88 struct gsm_subscriber *subscr)
89{
90 struct gsm_sms_pending *pending;
91
92 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
93 if (pending->subscr == subscr)
94 return 1;
95 }
96
97 return 0;
98}
99
100static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
101 struct gsm_sms *sms)
102{
103 struct gsm_sms_pending *pending;
104
105 pending = talloc_zero(smsq, struct gsm_sms_pending);
106 if (!pending)
107 return NULL;
108
109 pending->subscr = subscr_get(sms->receiver);
110 pending->sms_id = sms->id;
111 return pending;
112}
113
114static void sms_pending_free(struct gsm_sms_pending *pending)
115{
116 subscr_put(pending->subscr);
117 llist_del(&pending->entry);
118 talloc_free(pending);
119}
120
121static void sms_pending_resend(struct gsm_sms_pending *pending)
122{
123 struct gsm_sms_queue *smsq;
124 LOGP(DSMS, LOGL_DEBUG,
125 "Scheduling resend of SMS %llu.\n", pending->sms_id);
126
127 pending->resend = 1;
128
129 smsq = pending->subscr->net->sms_queue;
130 if (bsc_timer_pending(&smsq->resend_pending))
131 return;
132
133 bsc_schedule_timer(&smsq->resend_pending, 1, 0);
134}
135
136static void sms_pending_failed(struct gsm_sms_pending *pending, int paging_error)
137{
138 struct gsm_sms_queue *smsq;
139
140 LOGP(DSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
141 pending->sms_id, pending->failed_attempts);
142
143 smsq = pending->subscr->net->sms_queue;
144 if (++pending->failed_attempts < 3)
145 return sms_pending_resend(pending);
146
147 if (paging_error) {
148 LOGP(DSMS, LOGL_NOTICE,
149 "Subscriber %llu is not reachable. Setting LAC=0.\n", pending->subscr->id);
150 pending->subscr->lac = GSM_LAC_RESERVED_DETACHED;
151 db_sync_subscriber(pending->subscr);
152 }
153
154 sms_pending_free(pending);
155 smsq->pending -= 1;
156 sms_queue_trigger(smsq);
157}
158
159/*
160 * Resend all SMS that are scheduled for a resend. This is done to
161 * avoid an immediate failure.
162 */
163static void sms_resend_pending(void *_data)
164{
165 struct gsm_sms_pending *pending, *tmp;
166 struct gsm_sms_queue *smsq = _data;
167
168 llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
169 struct gsm_sms *sms;
170 if (!pending->resend)
171 continue;
172
173 sms = db_sms_get(smsq->network, pending->sms_id);
174
175 /* the sms is gone? Move to the next */
176 if (!sms) {
177 sms_pending_free(pending);
178 smsq->pending -= 1;
179 sms_queue_trigger(smsq);
180 } else {
181 pending->resend = 0;
182 gsm411_send_sms_subscr(sms->receiver, sms);
183 }
184 }
185}
186
187/**
188 * I will submit up to max_pending - pending SMS to the
189 * subsystem.
190 */
191static void sms_submit_pending(void *_data)
192{
193 struct gsm_sms_queue *smsq = _data;
194 int attempts = smsq->max_pending - smsq->pending;
195 int i;
196
197 LOGP(DSMS, LOGL_NOTICE, "Attempting to send %d SMS\n", attempts);
198
199 for (i = 0; i < attempts; ++i) {
200 struct gsm_sms_pending *pending;
201 struct gsm_sms *sms;
202
203 sms = db_sms_get_unsent_by_subscr(smsq->network, smsq->last_subscr_id, 10);
204
205 /* handle wrapping around */
206 if (!sms) {
207 smsq->last_subscr_id = 0;
208 sms = db_sms_get_unsent_by_subscr(smsq->network,
209 smsq->last_subscr_id, 10);
210 }
211
212 if (!sms)
213 break;
214
215 /* no need to send a pending sms */
216 if (sms_is_in_pending(smsq, sms)) {
217 LOGP(DSMS, LOGL_DEBUG,
218 "SMSqueue with pending sms: %llu\n. Skipping", sms->id);
219 sms_free(sms);
220 continue;
221 }
222
223 /* no need to send a SMS with the same receiver */
224 if (sms_subscriber_is_pending(smsq, sms->receiver)) {
225 LOGP(DSMS, LOGL_DEBUG,
226 "SMSqueue with pending sub: %llu. Skipping\n", sms->receiver->id);
227 sms_free(sms);
228 continue;
229 }
230
231 pending = sms_pending_from(smsq, sms);
232 if (!pending) {
233 LOGP(DSMS, LOGL_ERROR,
234 "Failed to create pending SMS entry.\n");
235 sms_free(sms);
236 continue;
237 }
238
239 smsq->last_subscr_id = sms->receiver->id + 1;
240 smsq->pending += 1;
241 llist_add(&pending->entry, &smsq->pending_sms);
242 gsm411_send_sms_subscr(sms->receiver, sms);
243 }
244}
245
246/*
247 * Kick off the queue again.
248 */
249int sms_queue_trigger(struct gsm_sms_queue *smsq)
250{
251 if (bsc_timer_pending(&smsq->push_queue))
252 return 0;
253
254 bsc_schedule_timer(&smsq->push_queue, 1, 0);
255 return 0;
256}
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100257
258int sms_queue_start(struct gsm_network *network, int max_pending)
259{
260 struct gsm_sms_queue *sms = talloc_zero(network, struct gsm_sms_queue);
261 if (!sms) {
262 LOGP(DMSC, LOGL_ERROR, "Failed to create the SMS queue.\n");
263 return -1;
264 }
265
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100266 register_signal_handler(SS_SUBSCR, sms_subscr_cb, network);
267 register_signal_handler(SS_SMS, sms_sms_cb, network);
268
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100269 network->sms_queue = sms;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100270 INIT_LLIST_HEAD(&sms->pending_sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100271 sms->network = network;
272 sms->max_pending = max_pending;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100273 sms->push_queue.data = sms;
274 sms->push_queue.cb = sms_submit_pending;
275 sms->resend_pending.data = sms;
276 sms->resend_pending.cb = sms_resend_pending;
277
278 sms_submit_pending(sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100279
280 return 0;
281}
282
283static int sub_ready_for_sm(struct gsm_subscriber *subscr)
284{
285 struct gsm_subscriber_connection *conn;
286 struct gsm_sms *sms;
287
288 /* A subscriber has attached. Check if there are
289 * any pending SMS for him to be delivered */
290 conn = connection_for_subscr(subscr);
291 if (!conn)
292 return -1;
293 sms = db_sms_get_unsent_for_subscr(subscr);
294 if (!sms)
295 return -1;
296 gsm411_send_sms(conn, sms);
297 return 0;
298}
299
300static int sms_subscr_cb(unsigned int subsys, unsigned int signal,
301 void *handler_data, void *signal_data)
302{
303 struct gsm_subscriber *subscr = signal_data;
304
305 if (signal != S_SUBSCR_ATTACHED)
306 return 0;
307
308 /* this is readyForSM */
309 return sub_ready_for_sm(subscr);
310}
311
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100312static int sms_sms_cb(unsigned int subsys, unsigned int signal,
313 void *handler_data, void *signal_data)
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100314{
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100315 struct gsm_network *network = handler_data;
316 struct sms_signal_data *sig_sms = signal_data;
317 struct gsm_sms_pending *pending;
318
319 /* We got a new SMS and maybe should launch the queue again. */
320 if (signal == S_SMS_SUBMITTED || signal == S_SMS_SMMA) {
321 sms_queue_trigger(network->sms_queue);
322 return 0;
323 }
324
325 if (!sig_sms->sms)
326 return -1;
327
328
329 /*
330 * Find the entry of our queue. The SMS subsystem will submit
331 * sms that are not in our control as we just have a channel
332 * open anyway.
333 */
334 pending = sms_find_pending(network->sms_queue, sig_sms->sms);
335 if (!pending)
336 return 0;
337
338 switch (signal) {
339 case S_SMS_DELIVERED:
340 /*
341 * Create place for a new SMS but keep the pending data
342 * so we will not attempt to send the SMS for this subscriber
343 * as we still have an open channel and will attempt to submit
344 * SMS to it anyway.
345 */
346 network->sms_queue->pending -= 1;
347 sms_submit_pending(network->sms_queue);
348 sms_pending_free(pending);
349 break;
350 case S_SMS_MEM_EXCEEDED:
351 network->sms_queue->pending -= 1;
352 sms_pending_free(pending);
353 sms_queue_trigger(network->sms_queue);
354 break;
355 case S_SMS_UNKNOWN_ERROR:
356 /*
357 * There can be many reasons for this failure. E.g. the paging
358 * timed out, the subscriber was not paged at all, or there was
359 * a protocol error. The current strategy is to try sending the
360 * next SMS for busy/oom and to retransmit when we have paged.
361 *
362 * When the paging expires three times we will disable the
363 * subscriber. If we have some kind of other transmit error we
364 * should flag the SMS as bad.
365 */
366 switch (sig_sms->paging_result) {
367 case 0:
368 /* BAD SMS? */
369 db_sms_inc_deliver_attempts(sig_sms->sms);
370 sms_pending_failed(pending, 0);
371 break;
372 case GSM_PAGING_EXPIRED:
373 sms_pending_failed(pending, 1);
374 break;
375
376 case GSM_PAGING_OOM:
377 case GSM_PAGING_BUSY:
378 network->sms_queue->pending -= 1;
379 sms_pending_free(pending);
380 sms_queue_trigger(network->sms_queue);
381 break;
382 default:
383 LOGP(DSMS, LOGL_ERROR, "Unhandled result: %d\n",
384 sig_sms->paging_result);
385 }
386 break;
387 default:
388 LOGP(DSMS, LOGL_ERROR, "Unhandled result: %d\n",
389 sig_sms->paging_result);
390 }
391
392 return 0;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100393}