2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
4 * Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
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.
15 * Reliable delivery of signalling messages
18 #include <../config.h>
25 #include <sys/types.h>
27 #include <netinet/in.h>
33 /*! \brief dump a queue_t to stdout */
34 static int queue_print(struct queue_t
*queue
)
37 printf("Queue: %p Next: %d First: %d Last: %d\n", queue
,
38 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",
43 queue
->qmsga
[n
].state
,
47 (int)queue
->qmsga
[n
].timeout
, queue
->qmsga
[n
].retrans
);
52 /*! \brief compute the hash function */
53 static int queue_seqhash(struct sockaddr_in
*peer
, uint16_t seq
)
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
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
;
64 /*! \brief Insert a message with given sequence number into the hash
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.
71 static int queue_seqset(struct queue_t
*queue
, struct qmsg_t
*qmsg
,
72 struct sockaddr_in
*peer
, uint16_t seq
)
74 int hash
= queue_seqhash(peer
, seq
);
76 struct qmsg_t
*qmsg_prev
= NULL
;
79 printf("Begin queue_seqset seq = %d\n", (int)seq
);
81 printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer
),
85 memcpy(&qmsg
->peer
, peer
, sizeof(*peer
));
87 for (qmsg2
= queue
->hashseq
[hash
]; qmsg2
; qmsg2
= qmsg2
->seqnext
)
90 queue
->hashseq
[hash
] = qmsg
;
92 qmsg_prev
->seqnext
= qmsg
;
94 printf("End queue_seqset\n");
98 /*! \brief Remove a given qmsg_t from the queue hash */
99 static int queue_seqdel(struct queue_t
*queue
, struct qmsg_t
*qmsg
)
101 int hash
= queue_seqhash(&qmsg
->peer
, qmsg
->seq
);
102 struct qmsg_t
*qmsg2
;
103 struct qmsg_t
*qmsg_prev
= NULL
;
105 printf("Begin queue_seqdel seq = %d\n", (int)qmsg
->seq
);
107 for (qmsg2
= queue
->hashseq
[hash
]; qmsg2
; qmsg2
= qmsg2
->seqnext
) {
110 queue
->hashseq
[hash
] = qmsg2
->seqnext
;
112 qmsg_prev
->seqnext
= qmsg2
->seqnext
;
114 printf("End queue_seqdel: SEQ found\n");
119 printf("End queue_seqdel: SEQ not found\n");
120 return EOF
; /* End of linked list and not found */
123 /*! \brief Allocates and initialises new queue structure */
124 int queue_new(struct queue_t
**queue
)
127 printf("queue_new\n");
128 *queue
= calloc(1, sizeof(struct queue_t
));
132 (*queue
)->first
= -1;
140 /*! \brief Deallocates queue structure */
141 int queue_free(struct queue_t
*queue
)
144 printf("queue_free\n");
151 /*! \brief Add a new message to the queue */
152 int queue_newmsg(struct queue_t
*queue
, struct qmsg_t
**qmsg
,
153 struct sockaddr_in
*peer
, uint16_t seq
)
156 printf("queue_newmsg %d\n", (int)seq
);
157 if (queue
->qmsga
[queue
->next
].state
== 1) {
158 return EOF
; /* Queue is full */
160 *qmsg
= &queue
->qmsga
[queue
->next
];
161 queue_seqset(queue
, *qmsg
, peer
, seq
);
162 (*qmsg
)->state
= 1; /* Space taken */
163 (*qmsg
)->this = queue
->next
;
164 (*qmsg
)->next
= -1; /* End of the queue */
165 (*qmsg
)->prev
= queue
->last
; /* Link to the previous */
166 if (queue
->last
!= -1)
167 queue
->qmsga
[queue
->last
].next
= queue
->next
; /* Link previous to us */
168 queue
->last
= queue
->next
; /* End of queue */
169 if (queue
->first
== -1)
170 queue
->first
= queue
->next
;
171 queue
->next
= (queue
->next
+ 1) % QUEUE_SIZE
; /* Increment */
178 /*! \brief Simply remoev a given qmsg_t from the queue
180 * Internally, we first delete the entry from the queue, and then update
181 * up our global queue->first / queue->last pointers. Finally,
182 * the qmsg_t is re-initialized with zero bytes. No memory is released.
184 int queue_freemsg(struct queue_t
*queue
, struct qmsg_t
*qmsg
)
187 printf("queue_freemsg\n");
188 if (qmsg
->state
!= 1) {
189 return EOF
; /* Not in queue */
192 queue_seqdel(queue
, qmsg
);
194 if (qmsg
->next
== -1) /* Are we the last in queue? */
195 queue
->last
= qmsg
->prev
;
197 queue
->qmsga
[qmsg
->next
].prev
= qmsg
->prev
;
199 if (qmsg
->prev
== -1) /* Are we the first in queue? */
200 queue
->first
= qmsg
->next
;
202 queue
->qmsga
[qmsg
->prev
].next
= qmsg
->next
;
204 memset(qmsg
, 0, sizeof(struct qmsg_t
)); /* Just to be safe */
212 /*! \brief Move a given qmsg_t to the end of the queue ?!? */
213 int queue_back(struct queue_t
*queue
, struct qmsg_t
*qmsg
)
216 printf("queue_back\n");
217 if (qmsg
->state
!= 1) {
218 return EOF
; /* Not in queue */
221 /* Insert stuff to maintain hash table */
223 if (qmsg
->next
!= -1) { /* Only swop if there are others */
224 queue
->qmsga
[qmsg
->next
].prev
= qmsg
->prev
;
225 queue
->first
= qmsg
->next
;
228 qmsg
->prev
= queue
->last
;
229 if (queue
->last
!= -1)
230 queue
->qmsga
[queue
->last
].next
= qmsg
->this;
231 queue
->last
= qmsg
->this;
238 /*! \brief Get the first element in the entire queue */
239 int queue_getfirst(struct queue_t
*queue
, struct qmsg_t
**qmsg
)
241 /*printf("queue_getfirst\n"); */
242 if (queue
->first
== -1) {
244 return EOF
; /* End of queue = queue is empty. */
246 *qmsg
= &queue
->qmsga
[queue
->first
];
252 /*! \brief Get a queue entry for a given peer + seq */
253 int queue_seqget(struct queue_t
*queue
, struct qmsg_t
**qmsg
,
254 struct sockaddr_in
*peer
, uint16_t seq
)
256 int hash
= queue_seqhash(peer
, seq
);
257 struct qmsg_t
*qmsg2
;
259 printf("Begin queue_seqget seq = %d\n", (int)seq
);
260 for (qmsg2
= queue
->hashseq
[hash
]; qmsg2
; qmsg2
= qmsg2
->seqnext
) {
261 if ((qmsg2
->seq
== seq
) &&
262 (!memcmp(&qmsg2
->peer
, peer
, sizeof(*peer
)))) {
265 printf("End queue_seqget. Found\n");
270 printf("End queue_seqget. Not found\n");
271 return EOF
; /* End of linked list and not found */
274 /*! \brief look-up a given seq/peer, return cbp + type and free entry */
275 int queue_freemsg_seq(struct queue_t
*queue
, struct sockaddr_in
*peer
,
276 uint16_t seq
, uint8_t * type
, void **cbp
)
279 if (queue_seqget(queue
, &qmsg
, peer
, seq
)) {
286 if (queue_freemsg(queue
, qmsg
)) {