blob: 900f2404259667e7ca9ec183caa8ca0e06a7a0a9 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002 Mondru AB.
4 *
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 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/*
18 * Queue.c
19 * Reliable delivery of signalling messages
20 */
21
22#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
32int queue_print(struct queue_t *queue) {
33 int n;
34 printf("Queue: %x Next: %d First: %d Last: %d\n", (int) queue, queue->next, queue->first, queue->last);
35 printf("# State seq next prev timeout retrans\n");
36 for (n=0; n<QUEUE_SIZE; n++) {
37 printf("%d %d %d %d %d %d %d\n",
38 n,
39 queue->qmsga[n].state,
40 queue->qmsga[n].seq,
41 queue->qmsga[n].next,
42 queue->qmsga[n].prev,
43 (int) queue->qmsga[n].timeout,
44 queue->qmsga[n].retrans);
45 }
46 return 0;
47}
48
49int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) {
50 /* With QUEUE_HASH_SIZE = 2^16 this describes all possible
51 seq values. Thus we have perfect hash for the request queue.
52 For the response queue we might have collisions, but not very
53 often.
54 For performance optimisation we should remove the modulus
55 operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */
56 return seq % QUEUE_HASH_SIZE;
57}
58
59int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg,
60 struct sockaddr_in *peer, uint16_t seq) {
61 int hash = queue_seqhash(peer, seq);
62 struct qmsg_t *qmsg2;
63 struct qmsg_t *qmsg_prev = NULL;
64
65 if (QUEUE_DEBUG) printf("Begin queue_seqset seq = %d\n", (int) seq);
66 if (QUEUE_DEBUG) printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), sizeof(*peer));
67
68 qmsg->seq = seq;
69 memcpy(&qmsg->peer, peer, sizeof(*peer));
70
71 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext)
72 qmsg_prev = qmsg2;
73 if (!qmsg_prev)
74 queue->hashseq[hash] = qmsg;
75 else
76 qmsg_prev->seqnext = qmsg;
77 if (QUEUE_DEBUG) printf("End queue_seqset\n");
78 return 0;
79}
80int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) {
81 int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
82 struct qmsg_t *qmsg2;
83 struct qmsg_t *qmsg_prev = NULL;
84 if (QUEUE_DEBUG) printf("Begin queue_seqdel seq = %d\n", (int) qmsg->seq);
85
86 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
87 if (qmsg == qmsg) {
88 if (!qmsg_prev)
89 queue->hashseq[hash] = qmsg2->seqnext;
90 else
91 qmsg_prev->seqnext = qmsg2->seqnext;
92 if (QUEUE_DEBUG) printf("End queue_seqset: SEQ found\n");
93 return 0;
94 }
95 qmsg_prev = qmsg2;
96 }
97 printf("End queue_seqset: SEQ not found\n");
98 return EOF; /* End of linked list and not found */
99}
100
101
102/* Allocates and initialises new queue structure */
103int queue_new(struct queue_t **queue) {
104 if (QUEUE_DEBUG) printf("queue_new\n");
105 *queue = calloc(1, sizeof(struct queue_t));
106 (*queue)->next = 0;
107 (*queue)->first = -1;
108 (*queue)->last = -1;
109
110 if (QUEUE_DEBUG) queue_print(*queue);
111 if (*queue) return 0;
112 else return EOF;
113}
114
115/* Deallocates queue structure */
116int queue_free(struct queue_t *queue) {
117 if (QUEUE_DEBUG) printf("queue_free\n");
118 if (QUEUE_DEBUG) queue_print(queue);
119 free(queue);
120 return 0;
121}
122
123int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
124 struct sockaddr_in *peer, uint16_t seq) {
125 if (QUEUE_DEBUG) printf("queue_newmsg %d\n", (int) seq);
126 if (queue->qmsga[queue->next].state == 1) {
127 return EOF; /* Queue is full */
128 }
129 else {
130 *qmsg = &queue->qmsga[queue->next];
131 queue_seqset(queue, *qmsg, peer, seq);
132 (*qmsg)->state = 1; /* Space taken */
133 (*qmsg)->this = queue->next;
134 (*qmsg)->next=-1; /* End of the queue */
135 (*qmsg)->prev=queue->last; /* Link to the previous */
jjakoa7cd2492003-04-11 09:40:12 +0000136 if (queue->last != -1)
137 queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
jjako52c24142002-12-16 13:33:51 +0000138 queue->last = queue->next; /* End of queue */
139 if (queue->first == -1) queue->first = queue->next;
140 queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */
141 if (QUEUE_DEBUG) queue_print(queue);
142 return 0;
143 }
144}
145
146int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) {
147 if (QUEUE_DEBUG) printf("queue_freemsg\n");
148 if (qmsg->state != 1) {
149 return EOF; /* Not in queue */
150 }
151
152 queue_seqdel(queue, qmsg);
153
154 if (qmsg->next == -1) /* Are we the last in queue? */
155 queue->last = qmsg->prev;
156 else
157 queue->qmsga[qmsg->next].prev = qmsg->prev;
158
159 if (qmsg->prev == -1) /* Are we the first in queue? */
160 queue->first = qmsg->next;
161 else
162 queue->qmsga[qmsg->prev].next = qmsg->next;
163
164 memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
165
166 if (QUEUE_DEBUG) queue_print(queue);
167
168 return 0;
169}
170
171int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) {
172 if (QUEUE_DEBUG) printf("queue_back\n");
173 if (qmsg->state != 1) {
174 return EOF; /* Not in queue */
175 }
176
177 /* Insert stuff to maintain hash table */
178
179 if (qmsg->next != -1) {/* Only swop if there are others */
180 queue->qmsga[qmsg->next].prev = qmsg->prev;
181 queue->first = qmsg->next;
182
183 qmsg->next = -1;
184 qmsg->prev = queue->last;
185 if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this;
186 queue->last = qmsg->this;
187 }
188 if (QUEUE_DEBUG) queue_print(queue);
189 return 0;
190}
191
192/* Get the element with a particular sequence number */
193int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) {
194 /*printf("queue_getfirst\n");*/
195 if (queue->first == -1) {
196 *qmsg = NULL;
197 return EOF; /* End of queue = queue is empty. */
198 }
199 *qmsg = &queue->qmsga[queue->first];
200 if (QUEUE_DEBUG) queue_print(queue);
201 return 0;
202}
203
204int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
205 struct sockaddr_in *peer, uint16_t seq) {
206 int n;
207 if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq);
208 if (QUEUE_DEBUG) queue_print(queue);
209 for (n=0; n<QUEUE_SIZE; n++) {
210 if ((queue->qmsga[n].seq == seq) &&
211 (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
212 *qmsg = &queue->qmsga[n];
213 return 0;
214 }
215 }
216 return EOF; /* Not found */
217}
218
219int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
220 struct sockaddr_in *peer, uint16_t seq) {
221 int hash = queue_seqhash(peer, seq);
222 struct qmsg_t *qmsg2;
223 if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq);
224 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
225 if ((qmsg2->seq == seq) &&
226 (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
227 *qmsg = qmsg2;
228 if (QUEUE_DEBUG) printf("End queue_seqget. Found\n");
229 return 0;
230 }
231 }
232 if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n");
233 return EOF; /* End of linked list and not found */
234}
235
236int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
237 uint16_t seq, uint8_t *type, void **aid) {
238 struct qmsg_t *qmsg;
239 if (queue_seqget(queue, &qmsg, peer, seq)) {
240 *aid = NULL;
241 *type = 0;
242 return EOF;
243 }
244 *aid = qmsg->aid;
245 *type = qmsg->type;
246 if (queue_freemsg(queue, qmsg)) {
247 return EOF;
248 }
249 return 0;
250}