… | |
… | |
73 | enum { ERROR, IDLE, CONNECTING, ESTABLISHED } state; |
73 | enum { ERROR, IDLE, CONNECTING, ESTABLISHED } state; |
74 | |
74 | |
75 | vpn_packet *r_pkt; |
75 | vpn_packet *r_pkt; |
76 | u32 r_len, r_ofs; |
76 | u32 r_len, r_ofs; |
77 | |
77 | |
|
|
78 | vpn_packet *w_pkt; |
|
|
79 | u32 w_len, w_ofs; |
|
|
80 | |
78 | void tcpv4_ev (io_watcher &w, short revents); |
81 | void tcpv4_ev (io_watcher &w, short revents); |
79 | |
82 | |
80 | void send_packet (vpn_packet *pkt, int tos); |
83 | bool send_packet (vpn_packet *pkt, int tos); |
|
|
84 | bool write_packet (); |
81 | |
85 | |
82 | void error (); // abort conenction && cleanup |
86 | void error (); // abort conenction && cleanup |
83 | |
87 | |
84 | operator tcp_si_map::value_type() |
88 | operator tcp_si_map::value_type() |
85 | { |
89 | { |
… | |
… | |
128 | tcp_si.insert (*i); |
132 | tcp_si.insert (*i); |
129 | } |
133 | } |
130 | } |
134 | } |
131 | } |
135 | } |
132 | |
136 | |
133 | void |
137 | bool |
134 | vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) |
138 | vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) |
135 | { |
139 | { |
136 | tcp_si_map::iterator info = tcp_si.find (&si); |
140 | tcp_si_map::iterator info = tcp_si.find (&si); |
137 | |
141 | |
138 | tcp_connection *i; |
142 | tcp_connection *i; |
… | |
… | |
143 | tcp_si.insert (*i); |
147 | tcp_si.insert (*i); |
144 | } |
148 | } |
145 | else |
149 | else |
146 | i = info->second; |
150 | i = info->second; |
147 | |
151 | |
148 | i->send_packet (pkt, tos); |
152 | return i->send_packet (pkt, tos); |
149 | } |
153 | } |
150 | |
154 | |
151 | void tcp_connection::error () |
155 | void tcp_connection::error () |
152 | { |
156 | { |
153 | if (fd >= 0) |
157 | if (fd >= 0) |
154 | { |
158 | { |
155 | close (fd); |
159 | close (fd); |
156 | fd = -1; |
160 | fd = -1; |
157 | } |
161 | } |
158 | |
162 | |
159 | delete r_pkt; |
163 | delete r_pkt; r_pkt = 0; |
160 | r_pkt = 0; |
164 | delete w_pkt; w_pkt = 0; |
161 | |
165 | |
162 | stop (); |
166 | stop (); |
163 | state = active ? IDLE : ERROR; |
167 | state = active ? IDLE : ERROR; |
164 | } |
168 | } |
165 | |
169 | |
|
|
170 | bool |
|
|
171 | tcp_connection::write_packet () |
|
|
172 | { |
|
|
173 | ssize_t len; |
|
|
174 | |
|
|
175 | if (w_ofs < 2) |
|
|
176 | { |
|
|
177 | u16 plen = htons (w_pkt->len); |
|
|
178 | |
|
|
179 | iovec vec[2]; |
|
|
180 | vec[0].iov_base = ((u8 *)&plen) + w_ofs; |
|
|
181 | vec[0].iov_len = 2 - w_ofs; |
|
|
182 | vec[1].iov_base = &((*w_pkt)[0]); |
|
|
183 | vec[1].iov_len = w_len - 2; |
|
|
184 | |
|
|
185 | len = writev (fd, vec, 2); |
|
|
186 | } |
|
|
187 | else |
|
|
188 | len = write (fd, &((*w_pkt)[w_ofs - 2]), w_len); |
|
|
189 | |
|
|
190 | if (len > 0) |
|
|
191 | { |
|
|
192 | w_ofs += len; |
|
|
193 | w_len -= len; |
|
|
194 | |
|
|
195 | return w_len == 0; |
|
|
196 | } |
|
|
197 | else if (len < 0 && (errno == EAGAIN || errno == EINTR)) |
|
|
198 | return false; |
|
|
199 | else |
|
|
200 | { |
|
|
201 | error (); |
|
|
202 | return false; |
|
|
203 | } |
|
|
204 | } |
|
|
205 | |
166 | void |
206 | void |
167 | tcp_connection::tcpv4_ev (io_watcher &w, short revents) |
207 | tcp_connection::tcpv4_ev (io_watcher &w, short revents) |
168 | { |
208 | { |
169 | last_activity = NOW; |
209 | last_activity = NOW; |
170 | |
210 | |
171 | if (revents & (POLLERR | POLLHUP)) |
211 | if (revents & (POLLERR | POLLHUP)) |
|
|
212 | { |
172 | error (); |
213 | error (); |
173 | else if (revents & POLLOUT && state == CONNECTING) |
214 | return; |
174 | { |
215 | } |
|
|
216 | |
|
|
217 | if (revents & POLLOUT) |
|
|
218 | { |
|
|
219 | if (state == CONNECTING) |
|
|
220 | { |
175 | state = ESTABLISHED; |
221 | state = ESTABLISHED; |
|
|
222 | set (POLLIN); |
|
|
223 | } |
|
|
224 | else if (state == ESTABLISHED) |
|
|
225 | { |
|
|
226 | if (w_pkt) |
|
|
227 | { |
|
|
228 | if (write_packet ()) |
|
|
229 | { |
|
|
230 | delete w_pkt; w_pkt = 0; |
|
|
231 | |
|
|
232 | set (POLLIN); |
|
|
233 | } |
|
|
234 | } |
|
|
235 | else |
|
|
236 | set (POLLIN); |
|
|
237 | } |
|
|
238 | else |
176 | set (POLLIN); |
239 | set (POLLIN); |
177 | } |
240 | } |
178 | |
241 | |
179 | else if (revents & POLLIN) |
242 | if (revents & POLLIN) |
180 | { |
243 | { |
181 | for (;;) |
244 | for (;;) |
182 | { |
245 | { |
183 | if (!r_pkt) |
246 | if (!r_pkt) |
184 | { |
247 | { |
… | |
… | |
211 | r_pkt = 0; |
274 | r_pkt = 0; |
212 | |
275 | |
213 | continue; |
276 | continue; |
214 | } |
277 | } |
215 | } |
278 | } |
216 | |
279 | else |
|
|
280 | break; |
217 | } |
281 | } |
218 | else if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
282 | else if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
219 | return; |
283 | break; |
220 | |
284 | |
221 | error (); |
285 | error (); |
222 | return; |
286 | break; |
223 | } |
287 | } |
224 | } |
288 | } |
225 | } |
289 | } |
226 | |
290 | |
227 | void |
291 | bool |
228 | tcp_connection::send_packet (vpn_packet *pkt, int tos) |
292 | tcp_connection::send_packet (vpn_packet *pkt, int tos) |
229 | { |
293 | { |
230 | last_activity = NOW; |
294 | last_activity = NOW; |
231 | |
295 | |
232 | if (state == IDLE) |
296 | if (state == IDLE) |
… | |
… | |
248 | close (fd); |
312 | close (fd); |
249 | } |
313 | } |
250 | } |
314 | } |
251 | else if (state == ESTABLISHED) |
315 | else if (state == ESTABLISHED) |
252 | { |
316 | { |
|
|
317 | // drop packet if the tcp write buffer is full. this *is* the |
|
|
318 | // right thing to do, not using tcp *is* the right thing to do. |
|
|
319 | if (!w_pkt) |
|
|
320 | { |
253 | // how this maps to the underlying tcp packet we don't know |
321 | // how this maps to the underlying tcp packets we don't know |
254 | // and we don't care. at least we tried ;) |
322 | // and we don't care. at least we tried ;) |
255 | setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos); |
323 | setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos); |
256 | |
324 | |
257 | // we use none of the advantages of tcp; if an error occurs, just drop |
325 | w_pkt = pkt; |
258 | // (this happens when a tcp connection gets stuck, too, which might not be |
326 | w_ofs = 0; |
259 | // the wisest thing to do.. either drop packet (too late) or make sure |
327 | w_len = pkt->len + 2; // length + size header |
260 | // it gets delivered) |
|
|
261 | u16 len = htons (pkt->len); |
|
|
262 | |
328 | |
263 | iovec vec[2]; |
329 | if (write_packet ()) |
264 | vec[0].iov_base = &len; |
330 | w_pkt = 0; |
265 | vec[0].iov_len = sizeof len; |
331 | else |
266 | vec[1].iov_base = &((*pkt)[0]); |
332 | { |
267 | vec[1].iov_len = pkt->len; |
333 | w_pkt = new vpn_packet; |
|
|
334 | w_pkt->set (*pkt); |
|
|
335 | |
|
|
336 | set (POLLIN | POLLOUT); |
|
|
337 | } |
268 | |
338 | } |
269 | if (sizeof (u16) + pkt->len != writev (fd, vec, 2)) |
|
|
270 | error (); |
|
|
271 | } |
339 | } |
|
|
340 | |
|
|
341 | return state != ERROR; |
272 | } |
342 | } |
273 | |
343 | |
274 | tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_) |
344 | tcp_connection::tcp_connection (int fd_, const sockinfo &si_, vpn &v_) |
275 | : v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev) |
345 | : v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev) |
276 | { |
346 | { |
277 | last_activity = NOW; |
347 | last_activity = NOW; |
278 | r_pkt = 0; |
348 | r_pkt = 0; |
|
|
349 | w_pkt = 0; |
279 | fd = fd_; |
350 | fd = fd_; |
280 | |
351 | |
281 | if (fd < 0) |
352 | if (fd < 0) |
282 | { |
353 | { |
283 | active = true; |
354 | active = true; |