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