blob: 7fdf9df52f47779131516605811c6e03499d7135 [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
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}
jjako08d331d2003-10-13 20:33:30 +000080
81
jjako52c24142002-12-16 13:33:51 +000082int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) {
83 int hash = queue_seqhash(&qmsg->peer, qmsg->seq);
84 struct qmsg_t *qmsg2;
85 struct qmsg_t *qmsg_prev = NULL;
86 if (QUEUE_DEBUG) printf("Begin queue_seqdel seq = %d\n", (int) qmsg->seq);
87
88 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
89 if (qmsg == qmsg) {
90 if (!qmsg_prev)
91 queue->hashseq[hash] = qmsg2->seqnext;
92 else
93 qmsg_prev->seqnext = qmsg2->seqnext;
94 if (QUEUE_DEBUG) printf("End queue_seqset: SEQ found\n");
95 return 0;
96 }
97 qmsg_prev = qmsg2;
98 }
99 printf("End queue_seqset: SEQ not found\n");
100 return EOF; /* End of linked list and not found */
101}
102
103
104/* Allocates and initialises new queue structure */
105int queue_new(struct queue_t **queue) {
106 if (QUEUE_DEBUG) printf("queue_new\n");
107 *queue = calloc(1, sizeof(struct queue_t));
108 (*queue)->next = 0;
109 (*queue)->first = -1;
110 (*queue)->last = -1;
111
112 if (QUEUE_DEBUG) queue_print(*queue);
113 if (*queue) return 0;
114 else return EOF;
115}
116
117/* Deallocates queue structure */
118int queue_free(struct queue_t *queue) {
119 if (QUEUE_DEBUG) printf("queue_free\n");
120 if (QUEUE_DEBUG) queue_print(queue);
121 free(queue);
122 return 0;
123}
124
125int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
126 struct sockaddr_in *peer, uint16_t seq) {
127 if (QUEUE_DEBUG) printf("queue_newmsg %d\n", (int) seq);
128 if (queue->qmsga[queue->next].state == 1) {
129 return EOF; /* Queue is full */
130 }
131 else {
132 *qmsg = &queue->qmsga[queue->next];
133 queue_seqset(queue, *qmsg, peer, seq);
134 (*qmsg)->state = 1; /* Space taken */
135 (*qmsg)->this = queue->next;
136 (*qmsg)->next=-1; /* End of the queue */
137 (*qmsg)->prev=queue->last; /* Link to the previous */
jjakoa7cd2492003-04-11 09:40:12 +0000138 if (queue->last != -1)
139 queue->qmsga[queue->last].next=queue->next; /* Link previous to us */
jjako52c24142002-12-16 13:33:51 +0000140 queue->last = queue->next; /* End of queue */
141 if (queue->first == -1) queue->first = queue->next;
142 queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */
143 if (QUEUE_DEBUG) queue_print(queue);
144 return 0;
145 }
146}
147
148int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) {
149 if (QUEUE_DEBUG) printf("queue_freemsg\n");
150 if (qmsg->state != 1) {
151 return EOF; /* Not in queue */
152 }
153
154 queue_seqdel(queue, qmsg);
155
156 if (qmsg->next == -1) /* Are we the last in queue? */
157 queue->last = qmsg->prev;
158 else
159 queue->qmsga[qmsg->next].prev = qmsg->prev;
160
161 if (qmsg->prev == -1) /* Are we the first in queue? */
162 queue->first = qmsg->next;
163 else
164 queue->qmsga[qmsg->prev].next = qmsg->next;
165
166 memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */
167
168 if (QUEUE_DEBUG) queue_print(queue);
169
170 return 0;
171}
172
173int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) {
174 if (QUEUE_DEBUG) printf("queue_back\n");
175 if (qmsg->state != 1) {
176 return EOF; /* Not in queue */
177 }
178
179 /* Insert stuff to maintain hash table */
180
181 if (qmsg->next != -1) {/* Only swop if there are others */
182 queue->qmsga[qmsg->next].prev = qmsg->prev;
183 queue->first = qmsg->next;
184
185 qmsg->next = -1;
186 qmsg->prev = queue->last;
187 if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this;
188 queue->last = qmsg->this;
189 }
190 if (QUEUE_DEBUG) queue_print(queue);
191 return 0;
192}
193
194/* Get the element with a particular sequence number */
195int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) {
196 /*printf("queue_getfirst\n");*/
197 if (queue->first == -1) {
198 *qmsg = NULL;
199 return EOF; /* End of queue = queue is empty. */
200 }
201 *qmsg = &queue->qmsga[queue->first];
202 if (QUEUE_DEBUG) queue_print(queue);
203 return 0;
204}
205
206int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg,
207 struct sockaddr_in *peer, uint16_t seq) {
208 int n;
209 if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq);
210 if (QUEUE_DEBUG) queue_print(queue);
211 for (n=0; n<QUEUE_SIZE; n++) {
212 if ((queue->qmsga[n].seq == seq) &&
213 (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) {
214 *qmsg = &queue->qmsga[n];
215 return 0;
216 }
217 }
218 return EOF; /* Not found */
219}
220
221int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
222 struct sockaddr_in *peer, uint16_t seq) {
223 int hash = queue_seqhash(peer, seq);
224 struct qmsg_t *qmsg2;
225 if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq);
226 for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) {
227 if ((qmsg2->seq == seq) &&
228 (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) {
229 *qmsg = qmsg2;
230 if (QUEUE_DEBUG) printf("End queue_seqget. Found\n");
231 return 0;
232 }
233 }
234 if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n");
235 return EOF; /* End of linked list and not found */
236}
237
238int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
jjako08d331d2003-10-13 20:33:30 +0000239 uint16_t seq, uint8_t *type, void **cbp) {
jjako52c24142002-12-16 13:33:51 +0000240 struct qmsg_t *qmsg;
241 if (queue_seqget(queue, &qmsg, peer, seq)) {
jjako08d331d2003-10-13 20:33:30 +0000242 *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000243 *type = 0;
244 return EOF;
245 }
jjako08d331d2003-10-13 20:33:30 +0000246 *cbp = qmsg->cbp;
jjako52c24142002-12-16 13:33:51 +0000247 *type = qmsg->type;
248 if (queue_freemsg(queue, qmsg)) {
249 return EOF;
250 }
251 return 0;
252}