blob: a477f98aa5cd489c8a3248ebc110b1e660db606d [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.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * Queue.c
14 * Reliable delivery of signalling messages
15 */
16
jjako0fe0df02004-09-17 11:30:40 +000017#include <../config.h>
18#ifdef HAVE_STDINT_H
19#include <stdint.h>
20#endif
21
jjako52c24142002-12-16 13:33:51 +000022#include <stdlib.h>
23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/time.h>
26#include <netinet/in.h>
27#include <string.h>
28#include "pdp.h"
29#include "gtp.h"
30#include "queue.h"
31
Harald Weltebb47c352011-11-02 13:30:37 +010032static int queue_print(struct queue_t *queue)
Harald Weltebed35df2011-11-02 13:06:18 +010033{
34 int n;
Harald Weltee65c7392011-11-02 13:12:53 +010035 printf("Queue: %p Next: %d First: %d Last: %d\n", queue,
Harald Weltebed35df2011-11-02 13:06:18 +010036 queue->next, queue->first, queue->last);
37 printf("# State seq next prev timeout retrans\n");
38 for (n = 0; n < QUEUE_SIZE; n++) {
39 printf("%d %d %d %d %d %d %d\n",
40 n,
41 queue->qmsga[n].state,
42 queue->qmsga[n].seq,
43 queue->qmsga[n].next,
44 queue->qmsga[n].prev,
45 (int)queue->qmsga[n].timeout, queue->qmsga[n].retrans);
46 }
47 return 0;
jjako52c24142002-12-16 13:33:51 +000048}
49
Harald Weltebb47c352011-11-02 13:30:37 +010050static int queue_seqhash(struct sockaddr_in *peer, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +010051{
52 /* With QUEUE_HASH_SIZE = 2^16 this describes all possible
53 seq values. Thus we have perfect hash for the request queue.
54 For the response queue we might have collisions, but not very
55 often.
56 For performance optimisation we should remove the modulus
57 operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */
58 return seq % QUEUE_HASH_SIZE;
jjako52c24142002-12-16 13:33:51 +000059}
60
Harald Weltebb47c352011-11-02 13:30:37 +010061static int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
62 struct sockaddr_in *peer, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +010063{
64 int hash = queue_seqhash(peer, seq);
65 struct qmsg_t *qmsg2;
66 struct qmsg_t *qmsg_prev = NULL;
jjako52c24142002-12-16 13:33:51 +000067
Harald Weltebed35df2011-11-02 13:06:18 +010068 if (QUEUE_DEBUG)
69 printf("Begin queue_seqset seq = %d\n", (int)seq);
70 if (QUEUE_DEBUG)
71 printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer),
72 sizeof(*peer));
jjako52c24142002-12-16 13:33:51 +000073
Harald Weltebed35df2011-11-02 13:06:18 +010074 qmsg->seq = seq;
75 memcpy(&qmsg->peer, peer, sizeof(*peer));
jjako52c24142002-12-16 13:33:51 +000076
Harald Weltebed35df2011-11-02 13:06:18 +010077 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext)
78 qmsg_prev = qmsg2;
79 if (!qmsg_prev)
80 queue->hashseq[hash] = qmsg;
81 else
82 qmsg_prev->seqnext = qmsg;
83 if (QUEUE_DEBUG)
84 printf("End queue_seqset\n");
85 return 0;
jjako52c24142002-12-16 13:33:51 +000086}
jjako08d331d2003-10-13 20:33:30 +000087
Harald Weltebb47c352011-11-02 13:30:37 +010088static int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg)
Harald Weltebed35df2011-11-02 13:06:18 +010089{
90 int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
91 struct qmsg_t *qmsg2;
92 struct qmsg_t *qmsg_prev = NULL;
93 if (QUEUE_DEBUG)
94 printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq);
jjako08d331d2003-10-13 20:33:30 +000095
Harald Weltebed35df2011-11-02 13:06:18 +010096 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
97 if (qmsg == qmsg) {
98 if (!qmsg_prev)
99 queue->hashseq[hash] = qmsg2->seqnext;
100 else
101 qmsg_prev->seqnext = qmsg2->seqnext;
102 if (QUEUE_DEBUG)
103 printf("End queue_seqset: SEQ found\n");
104 return 0;
105 }
106 qmsg_prev = qmsg2;
107 }
108 printf("End queue_seqset: SEQ not found\n");
109 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000110}
111
jjako52c24142002-12-16 13:33:51 +0000112/* Allocates and initialises new queue structure */
Harald Weltebed35df2011-11-02 13:06:18 +0100113int queue_new(struct queue_t **queue)
114{
115 if (QUEUE_DEBUG)
116 printf("queue_new\n");
117 *queue = calloc(1, sizeof(struct queue_t));
118 (*queue)->next = 0;
119 (*queue)->first = -1;
120 (*queue)->last = -1;
jjako52c24142002-12-16 13:33:51 +0000121
Harald Weltebed35df2011-11-02 13:06:18 +0100122 if (QUEUE_DEBUG)
123 queue_print(*queue);
124 if (*queue)
125 return 0;
126 else
127 return EOF;
jjako52c24142002-12-16 13:33:51 +0000128}
129
130/* Deallocates queue structure */
Harald Weltebed35df2011-11-02 13:06:18 +0100131int queue_free(struct queue_t *queue)
132{
133 if (QUEUE_DEBUG)
134 printf("queue_free\n");
135 if (QUEUE_DEBUG)
136 queue_print(queue);
137 free(queue);
138 return 0;
jjako52c24142002-12-16 13:33:51 +0000139}
140
141int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100142 struct sockaddr_in *peer, uint16_t seq)
143{
144 if (QUEUE_DEBUG)
145 printf("queue_newmsg %d\n", (int)seq);
146 if (queue->qmsga[queue->next].state == 1) {
147 return EOF; /* Queue is full */
148 } else {
149 *qmsg = &queue->qmsga[queue->next];
150 queue_seqset(queue, *qmsg, peer, seq);
151 (*qmsg)->state = 1; /* Space taken */
152 (*qmsg)->this = queue->next;
153 (*qmsg)->next = -1; /* End of the queue */
154 (*qmsg)->prev = queue->last; /* Link to the previous */
155 if (queue->last != -1)
156 queue->qmsga[queue->last].next = queue->next; /* Link previous to us */
157 queue->last = queue->next; /* End of queue */
158 if (queue->first == -1)
159 queue->first = queue->next;
160 queue->next = (queue->next + 1) % QUEUE_SIZE; /* Increment */
161 if (QUEUE_DEBUG)
162 queue_print(queue);
163 return 0;
164 }
jjako52c24142002-12-16 13:33:51 +0000165}
166
Harald Weltebed35df2011-11-02 13:06:18 +0100167int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg)
168{
169 if (QUEUE_DEBUG)
170 printf("queue_freemsg\n");
171 if (qmsg->state != 1) {
172 return EOF; /* Not in queue */
173 }
jjako52c24142002-12-16 13:33:51 +0000174
Harald Weltebed35df2011-11-02 13:06:18 +0100175 queue_seqdel(queue, qmsg);
jjako52c24142002-12-16 13:33:51 +0000176
Harald Weltebed35df2011-11-02 13:06:18 +0100177 if (qmsg->next == -1) /* Are we the last in queue? */
178 queue->last = qmsg->prev;
179 else
180 queue->qmsga[qmsg->next].prev = qmsg->prev;
jjako52c24142002-12-16 13:33:51 +0000181
Harald Weltebed35df2011-11-02 13:06:18 +0100182 if (qmsg->prev == -1) /* Are we the first in queue? */
183 queue->first = qmsg->next;
184 else
185 queue->qmsga[qmsg->prev].next = qmsg->next;
jjako52c24142002-12-16 13:33:51 +0000186
Harald Weltebed35df2011-11-02 13:06:18 +0100187 memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
jjako52c24142002-12-16 13:33:51 +0000188
Harald Weltebed35df2011-11-02 13:06:18 +0100189 if (QUEUE_DEBUG)
190 queue_print(queue);
191
192 return 0;
jjako52c24142002-12-16 13:33:51 +0000193}
194
Harald Weltebed35df2011-11-02 13:06:18 +0100195int queue_back(struct queue_t *queue, struct qmsg_t *qmsg)
196{
197 if (QUEUE_DEBUG)
198 printf("queue_back\n");
199 if (qmsg->state != 1) {
200 return EOF; /* Not in queue */
201 }
jjako52c24142002-12-16 13:33:51 +0000202
Harald Weltebed35df2011-11-02 13:06:18 +0100203 /* Insert stuff to maintain hash table */
jjako52c24142002-12-16 13:33:51 +0000204
Harald Weltebed35df2011-11-02 13:06:18 +0100205 if (qmsg->next != -1) { /* Only swop if there are others */
206 queue->qmsga[qmsg->next].prev = qmsg->prev;
207 queue->first = qmsg->next;
208
209 qmsg->next = -1;
210 qmsg->prev = queue->last;
211 if (queue->last != -1)
212 queue->qmsga[queue->last].next = qmsg->this;
213 queue->last = qmsg->this;
214 }
215 if (QUEUE_DEBUG)
216 queue_print(queue);
217 return 0;
jjako52c24142002-12-16 13:33:51 +0000218}
219
220/* Get the element with a particular sequence number */
Harald Weltebed35df2011-11-02 13:06:18 +0100221int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg)
222{
223 /*printf("queue_getfirst\n"); */
224 if (queue->first == -1) {
225 *qmsg = NULL;
226 return EOF; /* End of queue = queue is empty. */
227 }
228 *qmsg = &queue->qmsga[queue->first];
229 if (QUEUE_DEBUG)
230 queue_print(queue);
231 return 0;
jjako52c24142002-12-16 13:33:51 +0000232}
233
234int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100235 struct sockaddr_in *peer, uint16_t seq)
236{
237 int n;
238 if (QUEUE_DEBUG)
239 printf("queue_getseq, %d\n", (int)seq);
240 if (QUEUE_DEBUG)
241 queue_print(queue);
242 for (n = 0; n < QUEUE_SIZE; n++) {
243 if ((queue->qmsga[n].seq == seq) &&
244 (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
245 *qmsg = &queue->qmsga[n];
246 return 0;
247 }
248 }
249 return EOF; /* Not found */
jjako52c24142002-12-16 13:33:51 +0000250}
251
252int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
Harald Weltebed35df2011-11-02 13:06:18 +0100253 struct sockaddr_in *peer, uint16_t seq)
254{
255 int hash = queue_seqhash(peer, seq);
256 struct qmsg_t *qmsg2;
257 if (QUEUE_DEBUG)
258 printf("Begin queue_seqget seq = %d\n", (int)seq);
259 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
260 if ((qmsg2->seq == seq) &&
261 (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
262 *qmsg = qmsg2;
263 if (QUEUE_DEBUG)
264 printf("End queue_seqget. Found\n");
265 return 0;
266 }
267 }
268 if (QUEUE_DEBUG)
269 printf("End queue_seqget. Not found\n");
270 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000271}
272
Harald Weltebed35df2011-11-02 13:06:18 +0100273int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
274 uint16_t seq, uint8_t * type, void **cbp)
275{
276 struct qmsg_t *qmsg;
277 if (queue_seqget(queue, &qmsg, peer, seq)) {
278 *cbp = NULL;
279 *type = 0;
280 return EOF;
281 }
282 *cbp = qmsg->cbp;
283 *type = qmsg->type;
284 if (queue_freemsg(queue, qmsg)) {
285 return EOF;
286 }
287 return 0;
jjako52c24142002-12-16 13:33:51 +0000288}