BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file PacketPassPriorityQueue.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdlib.h>
31  
32 #include <misc/debug.h>
33 #include <misc/offset.h>
34 #include <misc/compare.h>
35  
36 #include <flow/PacketPassPriorityQueue.h>
37  
38 static int compare_flows (PacketPassPriorityQueueFlow *f1, PacketPassPriorityQueueFlow *f2)
39 {
40 int cmp = B_COMPARE(f1->priority, f2->priority);
41 if (cmp) {
42 return cmp;
43 }
44  
45 return B_COMPARE((uintptr_t)f1, (uintptr_t)f2);
46 }
47  
48 #include "PacketPassPriorityQueue_tree.h"
49 #include <structure/SAvl_impl.h>
50  
51 static void schedule (PacketPassPriorityQueue *m)
52 {
53 ASSERT(!m->sending_flow)
54 ASSERT(!m->freeing)
55 ASSERT(!PacketPassPriorityQueue__Tree_IsEmpty(&m->queued_tree))
56  
57 // get first queued flow
58 PacketPassPriorityQueueFlow *qflow = PacketPassPriorityQueue__Tree_GetFirst(&m->queued_tree, 0);
59 ASSERT(qflow->is_queued)
60  
61 // remove flow from queue
62 PacketPassPriorityQueue__Tree_Remove(&m->queued_tree, 0, qflow);
63 qflow->is_queued = 0;
64  
65 // schedule send
66 PacketPassInterface_Sender_Send(m->output, qflow->queued.data, qflow->queued.data_len);
67 m->sending_flow = qflow;
68 }
69  
70 static void schedule_job_handler (PacketPassPriorityQueue *m)
71 {
72 ASSERT(!m->sending_flow)
73 ASSERT(!m->freeing)
74 DebugObject_Access(&m->d_obj);
75  
76 if (!PacketPassPriorityQueue__Tree_IsEmpty(&m->queued_tree)) {
77 schedule(m);
78 }
79 }
80  
81 static void input_handler_send (PacketPassPriorityQueueFlow *flow, uint8_t *data, int data_len)
82 {
83 PacketPassPriorityQueue *m = flow->m;
84  
85 ASSERT(flow != m->sending_flow)
86 ASSERT(!flow->is_queued)
87 ASSERT(!m->freeing)
88 DebugObject_Access(&flow->d_obj);
89  
90 // queue flow
91 flow->queued.data = data;
92 flow->queued.data_len = data_len;
93 int res = PacketPassPriorityQueue__Tree_Insert(&m->queued_tree, 0, flow, NULL);
94 ASSERT_EXECUTE(res)
95 flow->is_queued = 1;
96  
97 if (!m->sending_flow && !BPending_IsSet(&m->schedule_job)) {
98 schedule(m);
99 }
100 }
101  
102 static void output_handler_done (PacketPassPriorityQueue *m)
103 {
104 ASSERT(m->sending_flow)
105 ASSERT(!BPending_IsSet(&m->schedule_job))
106 ASSERT(!m->freeing)
107 ASSERT(!m->sending_flow->is_queued)
108  
109 PacketPassPriorityQueueFlow *flow = m->sending_flow;
110  
111 // sending finished
112 m->sending_flow = NULL;
113  
114 // schedule schedule
115 BPending_Set(&m->schedule_job);
116  
117 // finish flow packet
118 PacketPassInterface_Done(&flow->input);
119  
120 // call busy handler if set
121 if (flow->handler_busy) {
122 // handler is one-shot, unset it before calling
123 PacketPassPriorityQueue_handler_busy handler = flow->handler_busy;
124 flow->handler_busy = NULL;
125  
126 // call handler
127 handler(flow->user);
128 return;
129 }
130 }
131  
132 void PacketPassPriorityQueue_Init (PacketPassPriorityQueue *m, PacketPassInterface *output, BPendingGroup *pg, int use_cancel)
133 {
134 ASSERT(use_cancel == 0 || use_cancel == 1)
135 ASSERT(!use_cancel || PacketPassInterface_HasCancel(output))
136  
137 // init arguments
138 m->output = output;
139 m->pg = pg;
140 m->use_cancel = use_cancel;
141  
142 // init output
143 PacketPassInterface_Sender_Init(m->output, (PacketPassInterface_handler_done)output_handler_done, m);
144  
145 // not sending
146 m->sending_flow = NULL;
147  
148 // init queued tree
149 PacketPassPriorityQueue__Tree_Init(&m->queued_tree);
150  
151 // not freeing
152 m->freeing = 0;
153  
154 // init schedule job
155 BPending_Init(&m->schedule_job, m->pg, (BPending_handler)schedule_job_handler, m);
156  
157 DebugObject_Init(&m->d_obj);
158 DebugCounter_Init(&m->d_ctr);
159 }
160  
161 void PacketPassPriorityQueue_Free (PacketPassPriorityQueue *m)
162 {
163 ASSERT(PacketPassPriorityQueue__Tree_IsEmpty(&m->queued_tree))
164 ASSERT(!m->sending_flow)
165 DebugCounter_Free(&m->d_ctr);
166 DebugObject_Free(&m->d_obj);
167  
168 // free schedule job
169 BPending_Free(&m->schedule_job);
170 }
171  
172 void PacketPassPriorityQueue_PrepareFree (PacketPassPriorityQueue *m)
173 {
174 DebugObject_Access(&m->d_obj);
175  
176 // set freeing
177 m->freeing = 1;
178 }
179  
180 int PacketPassPriorityQueue_GetMTU (PacketPassPriorityQueue *m)
181 {
182 DebugObject_Access(&m->d_obj);
183  
184 return PacketPassInterface_GetMTU(m->output);
185 }
186  
187 void PacketPassPriorityQueueFlow_Init (PacketPassPriorityQueueFlow *flow, PacketPassPriorityQueue *m, int priority)
188 {
189 ASSERT(!m->freeing)
190 DebugObject_Access(&m->d_obj);
191  
192 // init arguments
193 flow->m = m;
194 flow->priority = priority;
195  
196 // have no canfree handler
197 flow->handler_busy = NULL;
198  
199 // init input
200 PacketPassInterface_Init(&flow->input, PacketPassInterface_GetMTU(flow->m->output), (PacketPassInterface_handler_send)input_handler_send, flow, m->pg);
201  
202 // is not queued
203 flow->is_queued = 0;
204  
205 DebugObject_Init(&flow->d_obj);
206 DebugCounter_Increment(&m->d_ctr);
207 }
208  
209 void PacketPassPriorityQueueFlow_Free (PacketPassPriorityQueueFlow *flow)
210 {
211 PacketPassPriorityQueue *m = flow->m;
212  
213 ASSERT(m->freeing || flow != m->sending_flow)
214 DebugCounter_Decrement(&m->d_ctr);
215 DebugObject_Free(&flow->d_obj);
216  
217 // remove from current flow
218 if (flow == m->sending_flow) {
219 m->sending_flow = NULL;
220 }
221  
222 // remove from queue
223 if (flow->is_queued) {
224 PacketPassPriorityQueue__Tree_Remove(&m->queued_tree, 0, flow);
225 }
226  
227 // free input
228 PacketPassInterface_Free(&flow->input);
229 }
230  
231 void PacketPassPriorityQueueFlow_AssertFree (PacketPassPriorityQueueFlow *flow)
232 {
233 PacketPassPriorityQueue *m = flow->m;
234 B_USE(m)
235  
236 ASSERT(m->freeing || flow != m->sending_flow)
237 DebugObject_Access(&flow->d_obj);
238 }
239  
240 int PacketPassPriorityQueueFlow_IsBusy (PacketPassPriorityQueueFlow *flow)
241 {
242 PacketPassPriorityQueue *m = flow->m;
243  
244 ASSERT(!m->freeing)
245 DebugObject_Access(&flow->d_obj);
246  
247 return (flow == m->sending_flow);
248 }
249  
250 void PacketPassPriorityQueueFlow_RequestCancel (PacketPassPriorityQueueFlow *flow)
251 {
252 PacketPassPriorityQueue *m = flow->m;
253  
254 ASSERT(flow == m->sending_flow)
255 ASSERT(m->use_cancel)
256 ASSERT(!m->freeing)
257 ASSERT(!BPending_IsSet(&m->schedule_job))
258 DebugObject_Access(&flow->d_obj);
259  
260 // request cancel
261 PacketPassInterface_Sender_RequestCancel(m->output);
262 }
263  
264 void PacketPassPriorityQueueFlow_SetBusyHandler (PacketPassPriorityQueueFlow *flow, PacketPassPriorityQueue_handler_busy handler, void *user)
265 {
266 PacketPassPriorityQueue *m = flow->m;
267 B_USE(m)
268  
269 ASSERT(flow == m->sending_flow)
270 ASSERT(!m->freeing)
271 DebugObject_Access(&flow->d_obj);
272  
273 // set handler
274 flow->handler_busy = handler;
275 flow->user = user;
276 }
277  
278 PacketPassInterface * PacketPassPriorityQueueFlow_GetInput (PacketPassPriorityQueueFlow *flow)
279 {
280 DebugObject_Access(&flow->d_obj);
281  
282 return &flow->input;
283 }