BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file FragmentProtoDisassembler.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 <stddef.h>
31 #include <string.h>
32  
33 #include <misc/debug.h>
34 #include <misc/byteorder.h>
35 #include <misc/minmax.h>
36  
37 #include "client/FragmentProtoDisassembler.h"
38  
39 static void write_chunks (FragmentProtoDisassembler *o)
40 {
41 #define IN_AVAIL (o->in_len - o->in_used)
42 #define OUT_AVAIL ((o->output_mtu - o->out_used) - (int)sizeof(struct fragmentproto_chunk_header))
43  
44 ASSERT(o->in_len >= 0)
45 ASSERT(o->out)
46 ASSERT(OUT_AVAIL > 0)
47  
48 // write chunks to output packet
49 do {
50 // calculate chunk length
51 int chunk_len = bmin_int(IN_AVAIL, OUT_AVAIL);
52 if (o->chunk_mtu > 0) {
53 chunk_len = bmin_int(chunk_len, o->chunk_mtu);
54 }
55  
56 // write chunk header
57 struct fragmentproto_chunk_header header;
58 header.frame_id = htol16(o->frame_id);
59 header.chunk_start = htol16(o->in_used);
60 header.chunk_len = htol16(chunk_len);
61 header.is_last = (chunk_len == IN_AVAIL);
62 memcpy(o->out + o->out_used, &header, sizeof(header));
63  
64 // write chunk data
65 memcpy(o->out + o->out_used + sizeof(struct fragmentproto_chunk_header), o->in + o->in_used, chunk_len);
66  
67 // increment pointers
68 o->in_used += chunk_len;
69 o->out_used += sizeof(struct fragmentproto_chunk_header) + chunk_len;
70 } while (IN_AVAIL > 0 && OUT_AVAIL > 0);
71  
72 // have we finished the input packet?
73 if (IN_AVAIL == 0) {
74 // set no input packet
75 o->in_len = -1;
76  
77 // increment frame ID
78 o->frame_id++;
79  
80 // finish input
81 PacketPassInterface_Done(&o->input);
82 }
83  
84 // should we finish the output packet?
85 if (OUT_AVAIL <= 0 || o->latency < 0) {
86 // set no output packet
87 o->out = NULL;
88  
89 // stop timer (if it's running)
90 if (o->latency >= 0) {
91 BReactor_RemoveTimer(o->reactor, &o->timer);
92 }
93  
94 // finish output
95 PacketRecvInterface_Done(&o->output, o->out_used);
96 } else {
97 // start timer if we have output and it's not running (output was empty before)
98 if (!BTimer_IsRunning(&o->timer)) {
99 BReactor_SetTimer(o->reactor, &o->timer);
100 }
101 }
102 }
103  
104 static void input_handler_send (FragmentProtoDisassembler *o, uint8_t *data, int data_len)
105 {
106 ASSERT(data_len >= 0)
107 ASSERT(o->in_len == -1)
108  
109 // set input packet
110 o->in_len = data_len;
111 o->in = data;
112 o->in_used = 0;
113  
114 // if there is no output, wait for it
115 if (!o->out) {
116 return;
117 }
118  
119 write_chunks(o);
120 }
121  
122 static void input_handler_requestcancel (FragmentProtoDisassembler *o)
123 {
124 ASSERT(o->in_len >= 0)
125 ASSERT(!o->out)
126  
127 // set no input packet
128 o->in_len = -1;
129  
130 // finish input
131 PacketPassInterface_Done(&o->input);
132 }
133  
134 static void output_handler_recv (FragmentProtoDisassembler *o, uint8_t *data)
135 {
136 ASSERT(data)
137 ASSERT(!o->out)
138  
139 // set output packet
140 o->out = data;
141 o->out_used = 0;
142  
143 // if there is no input, wait for it
144 if (o->in_len < 0) {
145 return;
146 }
147  
148 write_chunks(o);
149 }
150  
151 static void timer_handler (FragmentProtoDisassembler *o)
152 {
153 ASSERT(o->latency >= 0)
154 ASSERT(o->out)
155 ASSERT(o->in_len == -1)
156  
157 // set no output packet
158 o->out = NULL;
159  
160 // finish output
161 PacketRecvInterface_Done(&o->output, o->out_used);
162 }
163  
164 void FragmentProtoDisassembler_Init (FragmentProtoDisassembler *o, BReactor *reactor, int input_mtu, int output_mtu, int chunk_mtu, btime_t latency)
165 {
166 ASSERT(input_mtu >= 0)
167 ASSERT(input_mtu <= UINT16_MAX)
168 ASSERT(output_mtu > sizeof(struct fragmentproto_chunk_header))
169 ASSERT(chunk_mtu > 0 || chunk_mtu < 0)
170  
171 // init arguments
172 o->reactor = reactor;
173 o->output_mtu = output_mtu;
174 o->chunk_mtu = chunk_mtu;
175 o->latency = latency;
176  
177 // init input
178 PacketPassInterface_Init(&o->input, input_mtu, (PacketPassInterface_handler_send)input_handler_send, o, BReactor_PendingGroup(reactor));
179 PacketPassInterface_EnableCancel(&o->input, (PacketPassInterface_handler_requestcancel)input_handler_requestcancel);
180  
181 // init output
182 PacketRecvInterface_Init(&o->output, o->output_mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, BReactor_PendingGroup(reactor));
183  
184 // init timer
185 if (o->latency >= 0) {
186 BTimer_Init(&o->timer, o->latency, (BTimer_handler)timer_handler, o);
187 }
188  
189 // have no input packet
190 o->in_len = -1;
191  
192 // have no output packet
193 o->out = NULL;
194  
195 // start with zero frame ID
196 o->frame_id = 0;
197  
198 DebugObject_Init(&o->d_obj);
199 }
200  
201 void FragmentProtoDisassembler_Free (FragmentProtoDisassembler *o)
202 {
203 DebugObject_Free(&o->d_obj);
204  
205 // free timer
206 if (o->latency >= 0) {
207 BReactor_RemoveTimer(o->reactor, &o->timer);
208 }
209  
210 // free output
211 PacketRecvInterface_Free(&o->output);
212  
213 // free input
214 PacketPassInterface_Free(&o->input);
215 }
216  
217 PacketPassInterface * FragmentProtoDisassembler_GetInput (FragmentProtoDisassembler *o)
218 {
219 DebugObject_Access(&o->d_obj);
220  
221 return &o->input;
222 }
223  
224 PacketRecvInterface * FragmentProtoDisassembler_GetOutput (FragmentProtoDisassembler *o)
225 {
226 DebugObject_Access(&o->d_obj);
227  
228 return &o->output;
229 }