1 /* Copyright (C) 2007-2020 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Flow queue handler functions
24 */
25
26 #include "suricata-common.h"
27 #include "threads.h"
28 #include "debug.h"
29 #include "flow-private.h"
30 #include "flow-queue.h"
31 #include "flow-util.h"
32 #include "util-error.h"
33 #include "util-debug.h"
34 #include "util-print.h"
35
FlowQueueNew()36 FlowQueue *FlowQueueNew()
37 {
38 FlowQueue *q = (FlowQueue *)SCMalloc(sizeof(FlowQueue));
39 if (q == NULL) {
40 SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowQueueNew. Exiting...");
41 exit(EXIT_SUCCESS);
42 }
43 q = FlowQueueInit(q);
44 return q;
45 }
46
FlowQueueInit(FlowQueue * q)47 FlowQueue *FlowQueueInit (FlowQueue *q)
48 {
49 if (q != NULL) {
50 memset(q, 0, sizeof(FlowQueue));
51 FQLOCK_INIT(q);
52 }
53 return q;
54 }
55
56 /**
57 * \brief Destroy a flow queue
58 *
59 * \param q the flow queue to destroy
60 */
FlowQueueDestroy(FlowQueue * q)61 void FlowQueueDestroy (FlowQueue *q)
62 {
63 FQLOCK_DESTROY(q);
64 }
65
FlowQueuePrivateAppendFlow(FlowQueuePrivate * fqc,Flow * f)66 void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f)
67 {
68 if (fqc->top == NULL) {
69 fqc->top = fqc->bot = f;
70 fqc->len = 1;
71 } else {
72 fqc->bot->next = f;
73 fqc->bot = f;
74 fqc->len++;
75 }
76 f->next = NULL;
77 }
78
FlowQueuePrivatePrependFlow(FlowQueuePrivate * fqc,Flow * f)79 void FlowQueuePrivatePrependFlow(FlowQueuePrivate *fqc, Flow *f)
80 {
81 f->next = fqc->top;
82 fqc->top = f;
83 if (f->next == NULL) {
84 fqc->bot = f;
85 }
86 fqc->len++;
87 }
88
FlowQueuePrivateAppendPrivate(FlowQueuePrivate * dest,FlowQueuePrivate * src)89 void FlowQueuePrivateAppendPrivate(FlowQueuePrivate *dest, FlowQueuePrivate *src)
90 {
91 if (src->top == NULL)
92 return;
93
94 if (dest->bot == NULL) {
95 dest->top = src->top;
96 dest->bot = src->bot;
97 dest->len = src->len;
98 } else {
99 dest->bot->next = src->top;
100 dest->bot = src->bot;
101 dest->len += src->len;
102 }
103 src->top = src->bot = NULL;
104 src->len = 0;
105 }
106
FlowQueueAtomicSetNonEmpty(FlowQueue * fq)107 static inline void FlowQueueAtomicSetNonEmpty(FlowQueue *fq)
108 {
109 if (SC_ATOMIC_GET(fq->non_empty) == false) {
110 SC_ATOMIC_SET(fq->non_empty, true);
111 }
112 }
FlowQueueAtomicSetEmpty(FlowQueue * fq)113 static inline void FlowQueueAtomicSetEmpty(FlowQueue *fq)
114 {
115 if (SC_ATOMIC_GET(fq->non_empty) == true) {
116 SC_ATOMIC_SET(fq->non_empty, false);
117 }
118 }
119
FlowQueueAppendPrivate(FlowQueue * fq,FlowQueuePrivate * fqc)120 void FlowQueueAppendPrivate(FlowQueue *fq, FlowQueuePrivate *fqc)
121 {
122 if (fqc->top == NULL)
123 return;
124
125 FQLOCK_LOCK(fq);
126 if (fq->qbot == NULL) {
127 fq->qtop = fqc->top;
128 fq->qbot = fqc->bot;
129 fq->qlen = fqc->len;
130 } else {
131 fq->qbot->next = fqc->top;
132 fq->qbot = fqc->bot;
133 fq->qlen += fqc->len;
134 }
135 FlowQueueAtomicSetNonEmpty(fq);
136 FQLOCK_UNLOCK(fq);
137 fqc->top = fqc->bot = NULL;
138 fqc->len = 0;
139 }
140
FlowQueueExtractPrivate(FlowQueue * fq)141 FlowQueuePrivate FlowQueueExtractPrivate(FlowQueue *fq)
142 {
143 FQLOCK_LOCK(fq);
144 FlowQueuePrivate fqc = fq->priv;
145 fq->qtop = fq->qbot = NULL;
146 fq->qlen = 0;
147 FlowQueueAtomicSetEmpty(fq);
148 FQLOCK_UNLOCK(fq);
149 return fqc;
150 }
151
FlowQueuePrivateGetFromTop(FlowQueuePrivate * fqc)152 Flow *FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc)
153 {
154 Flow *f = fqc->top;
155 if (f == NULL) {
156 return NULL;
157 }
158
159 fqc->top = f->next;
160 f->next = NULL;
161 fqc->len--;
162 if (fqc->top == NULL) {
163 fqc->bot = NULL;
164 }
165 return f;
166 }
167
168 /**
169 * \brief add a flow to a queue
170 *
171 * \param q queue
172 * \param f flow
173 */
FlowEnqueue(FlowQueue * q,Flow * f)174 void FlowEnqueue (FlowQueue *q, Flow *f)
175 {
176 #ifdef DEBUG
177 BUG_ON(q == NULL || f == NULL);
178 #endif
179 FQLOCK_LOCK(q);
180 FlowQueuePrivateAppendFlow(&q->priv, f);
181 FlowQueueAtomicSetNonEmpty(q);
182 FQLOCK_UNLOCK(q);
183 }
184
185 /**
186 * \brief remove a flow from the queue
187 *
188 * \param q queue
189 *
190 * \retval f flow or NULL if empty list.
191 */
FlowDequeue(FlowQueue * q)192 Flow *FlowDequeue (FlowQueue *q)
193 {
194 FQLOCK_LOCK(q);
195 Flow *f = FlowQueuePrivateGetFromTop(&q->priv);
196 if (f == NULL)
197 FlowQueueAtomicSetEmpty(q);
198 FQLOCK_UNLOCK(q);
199 return f;
200 }
201