blob: 160b99556e49278d9c753703893c8f2cd14de6d1 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welteb841e572011-11-02 13:45:50 +01004 * Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
jjako52c24142002-12-16 13:33:51 +00005 *
6 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
10 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/*
14 * Queue.c
15 * Reliable delivery of signalling messages
16 */
17
jjako0fe0df02004-09-17 11:30:40 +000018#include <../config.h>
19#ifdef HAVE_STDINT_H
20#include <stdint.h>
21#endif
22
jjako52c24142002-12-16 13:33:51 +000023#include <stdlib.h>
24#include <stdio.h>
25#include <sys/types.h>
26#include <sys/time.h>
27#include <netinet/in.h>
28#include <string.h>
29#include "pdp.h"
30#include "gtp.h"
31#include "queue.h"
32
Harald Welteb841e572011-11-02 13:45:50 +010033/*! \brief dump a queue_t to stdout */
Harald Weltebb47c352011-11-02 13:30:37 +010034static int queue_print(struct queue_t *queue)
Harald Weltebed35df2011-11-02 13:06:18 +010035{
36 int n;
Harald Weltee65c7392011-11-02 13:12:53 +010037 printf("Queue: %p Next: %d First: %d Last: %d\n", queue,
Harald Weltebed35df2011-11-02 13:06:18 +010038 queue->next, queue->first, queue->last);
39 printf("# State seq next prev timeout retrans\n");
40 for (n = 0; n < QUEUE_SIZE; n++) {
41 printf("%d %d %d %d %d %d %d\n",
42 n,
43 queue->qmsga[n].state,
44 queue->qmsga[n].seq,
45 queue->qmsga[n].next,
46 queue->qmsga[n].prev,
47 (int)queue->qmsga[n].timeout, queue->qmsga[n].retrans);
48 }
49 return 0;
jjako52c24142002-12-16 13:33:51 +000050}
51
Harald Welteb841e572011-11-02 13:45:50 +010052/*! \brief compute the hash function */
Harald Weltebb47c352011-11-02 13:30:37 +010053static int queue_seqhash(struct sockaddr_in *peer, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +010054{
55 /* With QUEUE_HASH_SIZE = 2^16 this describes all possible
56 seq values. Thus we have perfect hash for the request queue.
57 For the response queue we might have collisions, but not very
58 often.
59 For performance optimisation we should remove the modulus
60 operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */
61 return seq % QUEUE_HASH_SIZE;
jjako52c24142002-12-16 13:33:51 +000062}
63
Harald Welteb841e572011-11-02 13:45:50 +010064/*! \brief Insert a message with given sequence number into the hash
65 *
66 * This function sets the peer and the seq of the qmsg and then inserts
67 * the qmsg into the queue hash. To do so, it does a hashtable lookup
68 * and appends the new entry as the last into the double-linked list of
69 * entries for this sequence number.
70 */
Harald Weltebb47c352011-11-02 13:30:37 +010071static int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
72 struct sockaddr_in *peer, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +010073{
74 int hash = queue_seqhash(peer, seq);
75 struct qmsg_t *qmsg2;
76 struct qmsg_t *qmsg_prev = NULL;
jjako52c24142002-12-16 13:33:51 +000077
Harald Weltebed35df2011-11-02 13:06:18 +010078 if (QUEUE_DEBUG)
79 printf("Begin queue_seqset seq = %d\n", (int)seq);
80 if (QUEUE_DEBUG)
81 printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer),
82 sizeof(*peer));
jjako52c24142002-12-16 13:33:51 +000083
Harald Weltebed35df2011-11-02 13:06:18 +010084 qmsg->seq = seq;
85 memcpy(&qmsg->peer, peer, sizeof(*peer));
jjako52c24142002-12-16 13:33:51 +000086
Harald Weltebed35df2011-11-02 13:06:18 +010087 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext)
88 qmsg_prev = qmsg2;
89 if (!qmsg_prev)
90 queue->hashseq[hash] = qmsg;
91 else
92 qmsg_prev->seqnext = qmsg;
93 if (QUEUE_DEBUG)
94 printf("End queue_seqset\n");
95 return 0;
jjako52c24142002-12-16 13:33:51 +000096}
jjako08d331d2003-10-13 20:33:30 +000097
Harald Welteb841e572011-11-02 13:45:50 +010098/*! \brief Remove a given qmsg_t from the queue hash */
Harald Weltebb47c352011-11-02 13:30:37 +010099static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
Harald Weltebed35df2011-11-02 13:06:18 +0100100{
101 int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
102 struct qmsg_t *qmsg2;
103 struct qmsg_t *qmsg_prev = NULL;
104 if (QUEUE_DEBUG)
105 printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq);
jjako08d331d2003-10-13 20:33:30 +0000106
Harald Weltebed35df2011-11-02 13:06:18 +0100107 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
Harald Welteb841e572011-11-02 13:45:50 +0100108 /* FIXME: this is always true !?! */
Harald Weltebed35df2011-11-02 13:06:18 +0100109 if (qmsg == qmsg) {
110 if (!qmsg_prev)
111 queue->hashseq[hash] = qmsg2->seqnext;
112 else
113 qmsg_prev->seqnext = qmsg2->seqnext;
114 if (QUEUE_DEBUG)
Harald Welteef711622011-11-02 18:07:02 +0100115 printf("End queue_seqdel: SEQ found\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100116 return 0;
117 }
118 qmsg_prev = qmsg2;
119 }
Harald Welteef711622011-11-02 18:07:02 +0100120 printf("End queue_seqdel: SEQ not found\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100121 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000122}
123
Harald Welteb841e572011-11-02 13:45:50 +0100124/*! \brief Allocates and initialises new queue structure */
Harald Weltebed35df2011-11-02 13:06:18 +0100125int queue_new(struct queue_t **queue)
126{
127 if (QUEUE_DEBUG)
128 printf("queue_new\n");
129 *queue = calloc(1, sizeof(struct queue_t));
130 (*queue)->next = 0;
131 (*queue)->first = -1;
132 (*queue)->last = -1;
jjako52c24142002-12-16 13:33:51 +0000133
Harald Weltebed35df2011-11-02 13:06:18 +0100134 if (QUEUE_DEBUG)
135 queue_print(*queue);
136 if (*queue)
137 return 0;
138 else
139 return EOF;
jjako52c24142002-12-16 13:33:51 +0000140}
141
Harald Welteb841e572011-11-02 13:45:50 +0100142/*! \brief Deallocates queue structure */
Harald Weltebed35df2011-11-02 13:06:18 +0100143int queue_free(struct queue_t *queue)
144{
145 if (QUEUE_DEBUG)
146 printf("queue_free\n");
147 if (QUEUE_DEBUG)
148 queue_print(queue);
149 free(queue);
150 return 0;
jjako52c24142002-12-16 13:33:51 +0000151}
152
Harald Welteb841e572011-11-02 13:45:50 +0100153/*! \brief Add a new message to the queue */
jjako52c24142002-12-16 13:33:51 +0000154int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100155 struct sockaddr_in *peer, uint16_t seq)
156{
157 if (QUEUE_DEBUG)
158 printf("queue_newmsg %d\n", (int)seq);
159 if (queue->qmsga[queue->next].state == 1) {
160 return EOF; /* Queue is full */
161 } else {
162 *qmsg = &queue->qmsga[queue->next];
163 queue_seqset(queue, *qmsg, peer, seq);
164 (*qmsg)->state = 1; /* Space taken */
165 (*qmsg)->this = queue->next;
166 (*qmsg)->next = -1; /* End of the queue */
167 (*qmsg)->prev = queue->last; /* Link to the previous */
168 if (queue->last != -1)
169 queue->qmsga[queue->last].next = queue->next; /* Link previous to us */
170 queue->last = queue->next; /* End of queue */
171 if (queue->first == -1)
172 queue->first = queue->next;
173 queue->next = (queue->next + 1) % QUEUE_SIZE; /* Increment */
174 if (QUEUE_DEBUG)
175 queue_print(queue);
176 return 0;
177 }
jjako52c24142002-12-16 13:33:51 +0000178}
179
Harald Welteb841e572011-11-02 13:45:50 +0100180/*! \brief Simply remoev a given qmsg_t from the queue
181 *
182 * Internally, we first delete the entry from the queue, and then update
183 * up our global queue->first / queue->last pointers. Finally,
184 * the qmsg_t is re-initialized with zero bytes. No memory is released.
185 */
Harald Weltebed35df2011-11-02 13:06:18 +0100186int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
187{
188 if (QUEUE_DEBUG)
189 printf("queue_freemsg\n");
190 if (qmsg->state != 1) {
191 return EOF; /* Not in queue */
192 }
jjako52c24142002-12-16 13:33:51 +0000193
Harald Weltebed35df2011-11-02 13:06:18 +0100194 queue_seqdel(queue, qmsg);
jjako52c24142002-12-16 13:33:51 +0000195
Harald Weltebed35df2011-11-02 13:06:18 +0100196 if (qmsg->next == -1) /* Are we the last in queue? */
197 queue->last = qmsg->prev;
198 else
199 queue->qmsga[qmsg->next].prev = qmsg->prev;
jjako52c24142002-12-16 13:33:51 +0000200
Harald Weltebed35df2011-11-02 13:06:18 +0100201 if (qmsg->prev == -1) /* Are we the first in queue? */
202 queue->first = qmsg->next;
203 else
204 queue->qmsga[qmsg->prev].next = qmsg->next;
jjako52c24142002-12-16 13:33:51 +0000205
Harald Weltebed35df2011-11-02 13:06:18 +0100206 memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
jjako52c24142002-12-16 13:33:51 +0000207
Harald Weltebed35df2011-11-02 13:06:18 +0100208 if (QUEUE_DEBUG)
209 queue_print(queue);
210
211 return 0;
jjako52c24142002-12-16 13:33:51 +0000212}
213
Harald Welteb841e572011-11-02 13:45:50 +0100214/*! \brief Move a given qmsg_t to the end of the queue ?!? */
Harald Weltebed35df2011-11-02 13:06:18 +0100215int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
216{
217 if (QUEUE_DEBUG)
218 printf("queue_back\n");
219 if (qmsg->state != 1) {
220 return EOF; /* Not in queue */
221 }
jjako52c24142002-12-16 13:33:51 +0000222
Harald Weltebed35df2011-11-02 13:06:18 +0100223 /* Insert stuff to maintain hash table */
jjako52c24142002-12-16 13:33:51 +0000224
Harald Weltebed35df2011-11-02 13:06:18 +0100225 if (qmsg->next != -1) { /* Only swop if there are others */
226 queue->qmsga[qmsg->next].prev = qmsg->prev;
227 queue->first = qmsg->next;
228
229 qmsg->next = -1;
230 qmsg->prev = queue->last;
231 if (queue->last != -1)
232 queue->qmsga[queue->last].next = qmsg->this;
233 queue->last = qmsg->this;
234 }
235 if (QUEUE_DEBUG)
236 queue_print(queue);
237 return 0;
jjako52c24142002-12-16 13:33:51 +0000238}
239
Harald Welteb841e572011-11-02 13:45:50 +0100240/*! \brief Get the first element in the entire queue */
Harald Weltebed35df2011-11-02 13:06:18 +0100241int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
242{
243 /*printf("queue_getfirst\n"); */
244 if (queue->first == -1) {
245 *qmsg = NULL;
246 return EOF; /* End of queue = queue is empty. */
247 }
248 *qmsg = &queue->qmsga[queue->first];
249 if (QUEUE_DEBUG)
250 queue_print(queue);
251 return 0;
jjako52c24142002-12-16 13:33:51 +0000252}
253
Harald Welteb841e572011-11-02 13:45:50 +0100254/*! \brief Linear search over entire queue to get given peer + seq*/
255/* FIXME: unused, dead code! */
jjako52c24142002-12-16 13:33:51 +0000256int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100257 struct sockaddr_in *peer, uint16_t seq)
258{
259 int n;
260 if (QUEUE_DEBUG)
261 printf("queue_getseq, %d\n", (int)seq);
262 if (QUEUE_DEBUG)
263 queue_print(queue);
264 for (n = 0; n < QUEUE_SIZE; n++) {
265 if ((queue->qmsga[n].seq == seq) &&
266 (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
267 *qmsg = &queue->qmsga[n];
268 return 0;
269 }
270 }
271 return EOF; /* Not found */
jjako52c24142002-12-16 13:33:51 +0000272}
273
Harald Welteb841e572011-11-02 13:45:50 +0100274/*! \brief Get a queue entry for a given peer + seq */
jjako52c24142002-12-16 13:33:51 +0000275int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100276 struct sockaddr_in *peer, uint16_t seq)
277{
278 int hash = queue_seqhash(peer, seq);
279 struct qmsg_t *qmsg2;
280 if (QUEUE_DEBUG)
281 printf("Begin queue_seqget seq = %d\n", (int)seq);
282 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
283 if ((qmsg2->seq == seq) &&
284 (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
285 *qmsg = qmsg2;
286 if (QUEUE_DEBUG)
287 printf("End queue_seqget. Found\n");
288 return 0;
289 }
290 }
291 if (QUEUE_DEBUG)
292 printf("End queue_seqget. Not found\n");
293 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000294}
295
Harald Welteb841e572011-11-02 13:45:50 +0100296/*! \brief look-up a given seq/peer, return cbp + type and free entry */
Harald Weltebed35df2011-11-02 13:06:18 +0100297int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
298 uint16_t seq, uint8_t * type, void **cbp)
299{
300 struct qmsg_t *qmsg;
301 if (queue_seqget(queue, &qmsg, peer, seq)) {
302 *cbp = NULL;
303 *type = 0;
304 return EOF;
305 }
306 *cbp = qmsg->cbp;
307 *type = qmsg->type;
308 if (queue_freemsg(queue, qmsg)) {
309 return EOF;
310 }
311 return 0;
jjako52c24142002-12-16 13:33:51 +0000312}