blob: 1161b6cb77119502c460523e36de4da7c8c9fb8a [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 Freyther81c0e252010-12-25 14:08:00 +010043#include <osmocom/vty/vty.h>
44
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010045/*
46 * One pending SMS that we wait for.
47 */
48struct gsm_sms_pending {
49 struct llist_head entry;
50
51 struct gsm_subscriber *subscr;
52 unsigned long long sms_id;
53 int failed_attempts;
54 int resend;
55};
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010056
57struct gsm_sms_queue {
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010058 struct timer_list resend_pending;
59 struct timer_list push_queue;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010060 struct gsm_network *network;
61 int max_pending;
62 int pending;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010063
64 struct llist_head pending_sms;
65 unsigned long long last_subscr_id;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +010066};
67
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +010068static int sms_subscr_cb(unsigned int, unsigned int, void *, void *);
69static int sms_sms_cb(unsigned int, unsigned int, void *, void *);
70
71static struct gsm_sms_pending *sms_find_pending(struct gsm_sms_queue *smsq,
72 struct gsm_sms *sms)
73{
74 struct gsm_sms_pending *pending;
75
76 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
77 if (pending->sms_id == sms->id)
78 return pending;
79 }
80
81 return NULL;
82}
83
84static int sms_is_in_pending(struct gsm_sms_queue *smsq, struct gsm_sms *sms)
85{
86 return sms_find_pending(smsq, sms) != NULL;
87}
88
89static int sms_subscriber_is_pending(struct gsm_sms_queue *smsq,
90 struct gsm_subscriber *subscr)
91{
92 struct gsm_sms_pending *pending;
93
94 llist_for_each_entry(pending, &smsq->pending_sms, entry) {
95 if (pending->subscr == subscr)
96 return 1;
97 }
98
99 return 0;
100}
101
102static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
103 struct gsm_sms *sms)
104{
105 struct gsm_sms_pending *pending;
106
107 pending = talloc_zero(smsq, struct gsm_sms_pending);
108 if (!pending)
109 return NULL;
110
111 pending->subscr = subscr_get(sms->receiver);
112 pending->sms_id = sms->id;
113 return pending;
114}
115
116static void sms_pending_free(struct gsm_sms_pending *pending)
117{
118 subscr_put(pending->subscr);
119 llist_del(&pending->entry);
120 talloc_free(pending);
121}
122
123static void sms_pending_resend(struct gsm_sms_pending *pending)
124{
125 struct gsm_sms_queue *smsq;
126 LOGP(DSMS, LOGL_DEBUG,
127 "Scheduling resend of SMS %llu.\n", pending->sms_id);
128
129 pending->resend = 1;
130
131 smsq = pending->subscr->net->sms_queue;
132 if (bsc_timer_pending(&smsq->resend_pending))
133 return;
134
135 bsc_schedule_timer(&smsq->resend_pending, 1, 0);
136}
137
138static void sms_pending_failed(struct gsm_sms_pending *pending, int paging_error)
139{
140 struct gsm_sms_queue *smsq;
141
142 LOGP(DSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
143 pending->sms_id, pending->failed_attempts);
144
145 smsq = pending->subscr->net->sms_queue;
146 if (++pending->failed_attempts < 3)
147 return sms_pending_resend(pending);
148
149 if (paging_error) {
150 LOGP(DSMS, LOGL_NOTICE,
151 "Subscriber %llu is not reachable. Setting LAC=0.\n", pending->subscr->id);
152 pending->subscr->lac = GSM_LAC_RESERVED_DETACHED;
153 db_sync_subscriber(pending->subscr);
154 }
155
156 sms_pending_free(pending);
157 smsq->pending -= 1;
158 sms_queue_trigger(smsq);
159}
160
161/*
162 * Resend all SMS that are scheduled for a resend. This is done to
163 * avoid an immediate failure.
164 */
165static void sms_resend_pending(void *_data)
166{
167 struct gsm_sms_pending *pending, *tmp;
168 struct gsm_sms_queue *smsq = _data;
169
170 llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
171 struct gsm_sms *sms;
172 if (!pending->resend)
173 continue;
174
175 sms = db_sms_get(smsq->network, pending->sms_id);
176
177 /* the sms is gone? Move to the next */
178 if (!sms) {
179 sms_pending_free(pending);
180 smsq->pending -= 1;
181 sms_queue_trigger(smsq);
182 } else {
183 pending->resend = 0;
184 gsm411_send_sms_subscr(sms->receiver, sms);
185 }
186 }
187}
188
189/**
190 * I will submit up to max_pending - pending SMS to the
191 * subsystem.
192 */
193static void sms_submit_pending(void *_data)
194{
195 struct gsm_sms_queue *smsq = _data;
196 int attempts = smsq->max_pending - smsq->pending;
197 int i;
198
199 LOGP(DSMS, LOGL_NOTICE, "Attempting to send %d SMS\n", attempts);
200
201 for (i = 0; i < attempts; ++i) {
202 struct gsm_sms_pending *pending;
203 struct gsm_sms *sms;
204
205 sms = db_sms_get_unsent_by_subscr(smsq->network, smsq->last_subscr_id, 10);
206
207 /* handle wrapping around */
208 if (!sms) {
209 smsq->last_subscr_id = 0;
210 sms = db_sms_get_unsent_by_subscr(smsq->network,
211 smsq->last_subscr_id, 10);
212 }
213
214 if (!sms)
215 break;
216
217 /* no need to send a pending sms */
218 if (sms_is_in_pending(smsq, sms)) {
219 LOGP(DSMS, LOGL_DEBUG,
220 "SMSqueue with pending sms: %llu\n. Skipping", sms->id);
221 sms_free(sms);
222 continue;
223 }
224
225 /* no need to send a SMS with the same receiver */
226 if (sms_subscriber_is_pending(smsq, sms->receiver)) {
227 LOGP(DSMS, LOGL_DEBUG,
228 "SMSqueue with pending sub: %llu. Skipping\n", sms->receiver->id);
229 sms_free(sms);
230 continue;
231 }
232
233 pending = sms_pending_from(smsq, sms);
234 if (!pending) {
235 LOGP(DSMS, LOGL_ERROR,
236 "Failed to create pending SMS entry.\n");
237 sms_free(sms);
238 continue;
239 }
240
241 smsq->last_subscr_id = sms->receiver->id + 1;
242 smsq->pending += 1;
243 llist_add(&pending->entry, &smsq->pending_sms);
244 gsm411_send_sms_subscr(sms->receiver, sms);
245 }
246}
247
248/*
249 * Kick off the queue again.
250 */
251int sms_queue_trigger(struct gsm_sms_queue *smsq)
252{
253 if (bsc_timer_pending(&smsq->push_queue))
254 return 0;
255
256 bsc_schedule_timer(&smsq->push_queue, 1, 0);
257 return 0;
258}
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100259
260int sms_queue_start(struct gsm_network *network, int max_pending)
261{
262 struct gsm_sms_queue *sms = talloc_zero(network, struct gsm_sms_queue);
263 if (!sms) {
264 LOGP(DMSC, LOGL_ERROR, "Failed to create the SMS queue.\n");
265 return -1;
266 }
267
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100268 register_signal_handler(SS_SUBSCR, sms_subscr_cb, network);
269 register_signal_handler(SS_SMS, sms_sms_cb, network);
270
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100271 network->sms_queue = sms;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100272 INIT_LLIST_HEAD(&sms->pending_sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100273 sms->network = network;
274 sms->max_pending = max_pending;
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100275 sms->push_queue.data = sms;
276 sms->push_queue.cb = sms_submit_pending;
277 sms->resend_pending.data = sms;
278 sms->resend_pending.cb = sms_resend_pending;
279
280 sms_submit_pending(sms);
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100281
282 return 0;
283}
284
285static int sub_ready_for_sm(struct gsm_subscriber *subscr)
286{
287 struct gsm_subscriber_connection *conn;
288 struct gsm_sms *sms;
289
290 /* A subscriber has attached. Check if there are
291 * any pending SMS for him to be delivered */
292 conn = connection_for_subscr(subscr);
293 if (!conn)
294 return -1;
295 sms = db_sms_get_unsent_for_subscr(subscr);
296 if (!sms)
297 return -1;
298 gsm411_send_sms(conn, sms);
299 return 0;
300}
301
302static int sms_subscr_cb(unsigned int subsys, unsigned int signal,
303 void *handler_data, void *signal_data)
304{
305 struct gsm_subscriber *subscr = signal_data;
306
307 if (signal != S_SUBSCR_ATTACHED)
308 return 0;
309
310 /* this is readyForSM */
311 return sub_ready_for_sm(subscr);
312}
313
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100314static int sms_sms_cb(unsigned int subsys, unsigned int signal,
315 void *handler_data, void *signal_data)
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100316{
Holger Hans Peter Freyther17164062010-12-24 21:39:55 +0100317 struct gsm_network *network = handler_data;
318 struct sms_signal_data *sig_sms = signal_data;
319 struct gsm_sms_pending *pending;
320
321 /* We got a new SMS and maybe should launch the queue again. */
322 if (signal == S_SMS_SUBMITTED || signal == S_SMS_SMMA) {
323 sms_queue_trigger(network->sms_queue);
324 return 0;
325 }
326
327 if (!sig_sms->sms)
328 return -1;
329
330
331 /*
332 * Find the entry of our queue. The SMS subsystem will submit
333 * sms that are not in our control as we just have a channel
334 * open anyway.
335 */
336 pending = sms_find_pending(network->sms_queue, sig_sms->sms);
337 if (!pending)
338 return 0;
339
340 switch (signal) {
341 case S_SMS_DELIVERED:
342 /*
343 * Create place for a new SMS but keep the pending data
344 * so we will not attempt to send the SMS for this subscriber
345 * as we still have an open channel and will attempt to submit
346 * SMS to it anyway.
347 */
348 network->sms_queue->pending -= 1;
349 sms_submit_pending(network->sms_queue);
350 sms_pending_free(pending);
351 break;
352 case S_SMS_MEM_EXCEEDED:
353 network->sms_queue->pending -= 1;
354 sms_pending_free(pending);
355 sms_queue_trigger(network->sms_queue);
356 break;
357 case S_SMS_UNKNOWN_ERROR:
358 /*
359 * There can be many reasons for this failure. E.g. the paging
360 * timed out, the subscriber was not paged at all, or there was
361 * a protocol error. The current strategy is to try sending the
362 * next SMS for busy/oom and to retransmit when we have paged.
363 *
364 * When the paging expires three times we will disable the
365 * subscriber. If we have some kind of other transmit error we
366 * should flag the SMS as bad.
367 */
368 switch (sig_sms->paging_result) {
369 case 0:
370 /* BAD SMS? */
371 db_sms_inc_deliver_attempts(sig_sms->sms);
372 sms_pending_failed(pending, 0);
373 break;
374 case GSM_PAGING_EXPIRED:
375 sms_pending_failed(pending, 1);
376 break;
377
378 case GSM_PAGING_OOM:
379 case GSM_PAGING_BUSY:
380 network->sms_queue->pending -= 1;
381 sms_pending_free(pending);
382 sms_queue_trigger(network->sms_queue);
383 break;
384 default:
385 LOGP(DSMS, LOGL_ERROR, "Unhandled result: %d\n",
386 sig_sms->paging_result);
387 }
388 break;
389 default:
390 LOGP(DSMS, LOGL_ERROR, "Unhandled result: %d\n",
391 sig_sms->paging_result);
392 }
393
394 return 0;
Holger Hans Peter Freyther11b28f92010-12-24 13:48:27 +0100395}
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +0100396
397/* VTY helper functions */
398int sms_queue_stats(struct gsm_sms_queue *smsq, struct vty *vty)
399{
400 struct gsm_sms_pending *pending;
401
402 vty_out(vty, "SMSqueue with max_pending: %d pending: %d%s",
403 smsq->max_pending, smsq->pending, VTY_NEWLINE);
404
405 llist_for_each_entry(pending, &smsq->pending_sms, entry)
Holger Hans Peter Freyther7a0e1662010-12-25 14:15:32 +0100406 vty_out(vty, " SMS Pending for Subscriber: %llu%s",
Holger Hans Peter Freyther81c0e252010-12-25 14:08:00 +0100407 pending->subscr->id, VTY_NEWLINE);
408 return 0;
409}