blob: 0080e437c77df2023e41759ccffeb5facbe7bc16 [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 */
136 queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
137 queue->last = queue->next; /* End of queue */
138 if (queue->first == -1) queue->first = queue->next;
139 queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */
140 if (QUEUE_DEBUG) queue_print(queue);
141 return 0;
142 }
143}
144
145int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) {
146 if (QUEUE_DEBUG) printf("queue_freemsg\n");
147 if (qmsg->state != 1) {
148 return EOF; /* Not in queue */
149 }
150
151 queue_seqdel(queue, qmsg);
152
153 if (qmsg->next == -1) /* Are we the last in queue? */
154 queue->last = qmsg->prev;
155 else
156 queue->qmsga[qmsg->next].prev = qmsg->prev;
157
158 if (qmsg->prev == -1) /* Are we the first in queue? */
159 queue->first = qmsg->next;
160 else
161 queue->qmsga[qmsg->prev].next = qmsg->next;
162
163 memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
164
165 if (QUEUE_DEBUG) queue_print(queue);
166
167 return 0;
168}
169
170int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) {
171 if (QUEUE_DEBUG) printf("queue_back\n");
172 if (qmsg->state != 1) {
173 return EOF; /* Not in queue */
174 }
175
176 /* Insert stuff to maintain hash table */
177
178 if (qmsg->next != -1) {/* Only swop if there are others */
179 queue->qmsga[qmsg->next].prev = qmsg->prev;
180 queue->first = qmsg->next;
181
182 qmsg->next = -1;
183 qmsg->prev = queue->last;
184 if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this;
185 queue->last = qmsg->this;
186 }
187 if (QUEUE_DEBUG) queue_print(queue);
188 return 0;
189}
190
191/* Get the element with a particular sequence number */
192int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) {
193 /*printf("queue_getfirst\n");*/
194 if (queue->first == -1) {
195 *qmsg = NULL;
196 return EOF; /* End of queue = queue is empty. */
197 }
198 *qmsg = &queue->qmsga[queue->first];
199 if (QUEUE_DEBUG) queue_print(queue);
200 return 0;
201}
202
203int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
204 struct sockaddr_in *peer, uint16_t seq) {
205 int n;
206 if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq);
207 if (QUEUE_DEBUG) queue_print(queue);
208 for (n=0; n<QUEUE_SIZE; n++) {
209 if ((queue->qmsga[n].seq == seq) &&
210 (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
211 *qmsg = &queue->qmsga[n];
212 return 0;
213 }
214 }
215 return EOF; /* Not found */
216}
217
218int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
219 struct sockaddr_in *peer, uint16_t seq) {
220 int hash = queue_seqhash(peer, seq);
221 struct qmsg_t *qmsg2;
222 if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq);
223 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
224 if ((qmsg2->seq == seq) &&
225 (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
226 *qmsg = qmsg2;
227 if (QUEUE_DEBUG) printf("End queue_seqget. Found\n");
228 return 0;
229 }
230 }
231 if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n");
232 return EOF; /* End of linked list and not found */
233}
234
235int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
236 uint16_t seq, uint8_t *type, void **aid) {
237 struct qmsg_t *qmsg;
238 if (queue_seqget(queue, &qmsg, peer, seq)) {
239 *aid = NULL;
240 *type = 0;
241 return EOF;
242 }
243 *aid = qmsg->aid;
244 *type = qmsg->type;
245 if (queue_freemsg(queue, qmsg)) {
246 return EOF;
247 }
248 return 0;
249}