Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: chrome/browser/chromeos/net/webproxy/conn.cc

Issue 6801008: Websocket to TCP proxy running in a separate thread (only on ChromeOS). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: g Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "conn.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <vector>
14
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <netinet/in.h>
18 #include <signal.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21
22 #include "base/base64.h"
23 #include "base/basictypes.h"
24 #include "base/logging.h"
25 #include "base/string_number_conversions.h"
26 #include "base/string_util.h"
27 #include "third_party/libevent/evdns.h"
28
29 namespace {
30
31 const uint8 kSpaceOctet = 0x20;
32 const uint8 kCRLF[] = "\r\n";
33 const uint8 kCRLFCRLF[] = "\r\n\r\n";
34
35 // Not a constant but preprocessor definition for easy concatenation.
36 #define kWebproxyPath "/webproxy"
37
38 int CountSpaces(const std::string& s) {
39 int rv = 0;
40 for (size_t i = 0; i < s.size(); ++i)
41 rv += (s[i] == kSpaceOctet);
42 return rv;
43 }
44
45 std::string FetchLowerCasedASCIISnippet(uint8* begin, uint8* end) {
46 std::string rv;
47 for (; begin < end; ++begin) {
48 if (!isascii(*begin))
49 return rv;
50 rv += base::ToLowerASCII(*begin);
51 }
52 return rv;
53 }
54
55 // Returns true on success.
56 bool FetchDecimalDigits(const std::string& s, uint32* result) {
57 *result = 0;
58 bool got_something = false;
59 for (size_t i = 0; i < s.size(); ++i) {
60 if (IsAsciiDigit(s[i])) {
61 got_something = true;
62 if (*result > std::numeric_limits<uint32>::max() / 10)
63 return false;
64 *result *= 10;
65 int digit = s[i] - '0';
66 if (*result > std::numeric_limits<uint32>::max() - digit)
67 return false;
68 *result += digit;
69 }
70 }
71 return got_something;
72 }
73
74 // Parses hostname:port:token string. Returns true on success.
75 bool FetchNamePortToken(
76 uint8* begin, uint8* end,
77 std::string* name, uint32* port, std::string* token) {
78 std::string input(begin, end);
79
80 size_t pos = input.find_last_of(':');
81 if (pos == std::string::npos)
82 return false;
83 token->assign(input, pos + 1, std::string::npos);
84 input.resize(pos);
85
86 pos = input.find_last_of(':');
87 if (pos == std::string::npos)
88 return false;
89 std::string port_str(input, pos + 1);
90 if (port_str.empty())
91 return false;
92 const char kAsciiDigits[] = "0123456789";
93 COMPILE_ASSERT(sizeof(kAsciiDigits) == 10 + 1, mess_with_digits);
94 if (port_str.find_first_not_of(kAsciiDigits) != std::string::npos)
95 return false;
96 if (!FetchDecimalDigits(port_str, port) ||
97 *port <= 0 ||
98 *port >= (1 << 16)) {
99 return false;
100 }
101 name->assign(input, 0, pos);
102 return !name->empty();
103 }
104
105 std::string FetchExtensionIdFromOrigin(const std::string origin) {
106 // Origin of extension looks like "chrome-extension://EXTENSION_ID".
107 return origin.substr(origin.find_last_of('/'));
108 }
109
110 inline size_t strlen(const uint8* s) {
111 return ::strlen(reinterpret_cast<const char*>(s));
112 }
113
114 } // namespace
115
116 namespace chromeos {
117 namespace webproxy {
118
119 Conn::Conn(Serv* master)
120 : master_(master),
121 phase_(PHASE_WAIT_HANDSHAKE),
122 destresolution_ipv4_failed_(false),
123 destresolution_ipv6_failed_(false) {
124 while (token_map_.find(last_token_) != token_map_.end()) {
125 token_ = last_token_ =
126 reinterpret_cast<Token>(reinterpret_cast<size_t>(last_token_) + 1);
127 }
128 token_map_[token_] = this;
129 // Schedule timeout for initial phase of connection.
130 evtimer_set(&destconnect_timeout_event_,
131 &OnDestConnectTimeout, token_);
132 event_base_set(master_->evbase(),
133 &destconnect_timeout_event_);
134 struct timeval tv;
135 tv.tv_sec = 30;
136 tv.tv_usec = 0;
137 evtimer_add(&destconnect_timeout_event_, &tv);
138 }
139
140 Conn::~Conn() {
141 phase_ = PHASE_DEFUNCT;
142 event_del(&destconnect_timeout_event_);
143 if (token_map_[token_] == this)
144 token_map_.erase(token_);
145 }
146
147 Conn* Conn::Get(Token token) {
148 TokenMap::iterator it = token_map_.find(token);
149 if (it == token_map_.end())
150 return NULL;
151 Conn* cs = it->second;
152 if (cs == NULL ||
153 cs->token_ != token ||
154 cs->master_ == NULL ||
155 cs->phase_ < 0 ||
156 cs->phase_ > PHASE_SHUT ||
157 !cs->master_->IsConnSane(cs)) {
158 return NULL;
159 }
160 return cs;
161 }
162
163 void Conn::Shut() {
164 if (phase_ >= PHASE_SHUT)
165 return;
166 master_->MarkConnImportance(this, false);
167 if (primchan_.sock >= 0 && primchan_.bev != NULL) {
168 static const uint8 closing_handshake[9] = { 0 };
169 bufferevent_write(primchan_.bev,
170 closing_handshake, sizeof(closing_handshake));
171 }
172 phase_ = PHASE_SHUT;
173 }
174
175 Conn::Status Conn::ConsumeHeader(struct evbuffer* evb) {
176 uint8* buf = EVBUFFER_DATA(evb);
177 size_t buf_size = EVBUFFER_LENGTH(evb);
178
179 static const uint8 kGetMagic[] = "GET " kWebproxyPath " ";
180 static const uint8 kKeyValueDelimiter[] = ": ";
181
182 if (buf_size <= 0)
183 return STATUS_INCOMPLETE;
184 if (!buf)
185 return STATUS_ABORT;
186 if (!std::equal(buf, buf + std::min(buf_size, strlen(kGetMagic)),
187 kGetMagic)) {
188 // Data head does not match what is expected.
189 return STATUS_ABORT;
190 }
191
192 if (buf_size >= Serv::kReadBufferLimit)
193 return STATUS_ABORT;
194 uint8* buf_end = buf + buf_size;
195 uint8* term_pos = std::search(buf, buf_end, kCRLFCRLF,
196 kCRLFCRLF + strlen(kCRLFCRLF));
197 uint8 key3[8]; // Notation (key3) matches websocket RFC.
198 if (buf_end - term_pos - strlen(kCRLFCRLF) < sizeof(key3))
199 return STATUS_INCOMPLETE;
200 term_pos += strlen(kCRLFCRLF);
201 memcpy(key3, term_pos, sizeof(key3));
202 term_pos += sizeof(key3);
203 // First line is "GET /webproxy" line, so we skip it.
204 uint8* pos = std::search(buf, term_pos, kCRLF, kCRLF + strlen(kCRLF));
205 if (pos == term_pos)
206 return STATUS_ABORT;
207 for (;;) {
208 pos += strlen(kCRLF);
209 if (term_pos - pos <
210 static_cast<ptrdiff_t>(sizeof(key3) + strlen(kCRLF))) {
211 return STATUS_ABORT;
212 }
213 if (term_pos - pos ==
214 static_cast<ptrdiff_t>(sizeof(key3) + strlen(kCRLF))) {
215 break;
216 }
217 uint8* npos = std::search(pos, term_pos, kKeyValueDelimiter,
218 kKeyValueDelimiter + strlen(kKeyValueDelimiter));
219 if (npos == term_pos)
220 return STATUS_ABORT;
221 std::string key = FetchLowerCasedASCIISnippet(pos, npos);
222 pos = std::search(npos += strlen(kKeyValueDelimiter), term_pos,
223 kCRLF, kCRLF + strlen(kCRLF));
224 if (pos == term_pos)
225 return STATUS_ABORT;
226 if (!key.empty())
227 header_fields_[key] = FetchLowerCasedASCIISnippet(npos, pos);
228 }
229
230 // Values of Upgrade and Connection fields are hardcoded in the protocol.
231 if (header_fields_["upgrade"] != "websocket" ||
232 header_fields_["connection"] != "upgrade") {
233 return STATUS_ABORT;
234 }
235
236 if (!master_->IsOriginAllowed(header_fields_["origin"]))
237 return STATUS_ABORT;
238
239 static const std::string kSecKey1 = "sec-websocket-key1";
240 static const std::string kSecKey2 = "sec-websocket-key2";
241 uint32 key_number1, key_number2;
242 if (!FetchDecimalDigits(header_fields_[kSecKey1],
243 &key_number1) ||
244 !FetchDecimalDigits(header_fields_[kSecKey2],
245 &key_number2)) {
246 return STATUS_ABORT;
247 }
248
249 // We limit incoming header size so following numbers shall not be too high.
250 int spaces1 = CountSpaces(header_fields_[kSecKey1]);
251 int spaces2 = CountSpaces(header_fields_[kSecKey2]);
252 if (spaces1 == 0 ||
253 spaces2 == 0 ||
254 key_number1 % spaces1 != 0 ||
255 key_number2 % spaces2 != 0) {
256 return STATUS_ABORT;
257 }
258
259 uint8 challenge[4 + 4 + sizeof(key3)];
260 uint32 part1 = htonl(key_number1 / spaces1);
261 uint32 part2 = htonl(key_number2 / spaces2);
262 memcpy(challenge, &part1, 4);
263 memcpy(challenge + 4, &part2, 4);
264 memcpy(challenge + sizeof(challenge) - sizeof(key3), key3, sizeof(key3));
265 MD5Sum(challenge, sizeof(challenge), &handshake_response_);
266
267 evbuffer_drain(evb, term_pos - buf);
268 return STATUS_OK;
269 }
270
271 bool Conn::EmitHandshake(struct bufferevent* bev) {
272 std::vector<std::string> boilerplate;
273 boilerplate.push_back("HTTP/1.1 101 WebSocket Protocol Handshake");
274 boilerplate.push_back("Upgrade: WebSocket");
275 boilerplate.push_back("Connection: Upgrade");
276
277 {
278 // Take care of Location field.
279 char buf[128];
280 int rv = snprintf(buf, sizeof(buf),
281 "Sec-WebSocket-Location: ws://%s%s",
282 header_fields_["host"].c_str(),
283 kWebproxyPath);
284 if (rv <= 0 || rv + 0u >= sizeof(buf))
285 return false;
286 boilerplate.push_back(buf);
287 }
288 {
289 // Take care of Origin field.
290 if (header_fields_.find("origin") != header_fields_.end()) {
291 char buf[128];
292 int rv = snprintf(buf, sizeof(buf),
293 "Sec-WebSocket-Origin: %s",
294 header_fields_["origin"].c_str());
295 if (rv <= 0 || rv + 0u >= sizeof(buf))
296 return false;
297 boilerplate.push_back(buf);
298 }
299 }
300
301 boilerplate.push_back("");
302 for (size_t i = 0; i < boilerplate.size(); ++i) {
303 if (bufferevent_write(bev, boilerplate[i].c_str(),
304 boilerplate[i].size()) ||
305 bufferevent_write(bev, kCRLF, strlen(kCRLF))) {
306 return false;
307 }
308 }
309 return !bufferevent_write(bev, &handshake_response_,
310 sizeof(handshake_response_));
311 }
312
313 Conn::Status Conn::ConsumeDestframe(struct evbuffer* evb) {
314 uint8* buf = EVBUFFER_DATA(evb);
315 size_t buf_size = EVBUFFER_LENGTH(evb);
316
317 if (buf_size < 1)
318 return STATUS_INCOMPLETE;
319 if (buf[0] != 0)
320 return STATUS_ABORT;
321 if (buf_size < 1 + 1)
322 return STATUS_INCOMPLETE;
323 uint8* buf_end = buf + buf_size;
324 uint8* term_pos = std::find(buf + 1, buf_end, 0xff);
325 if (term_pos == buf_end) {
326 if (buf_size >= Serv::kReadBufferLimit) {
327 // So big and still worth nothing.
328 return STATUS_ABORT;
329 }
330 return STATUS_INCOMPLETE;
331 }
332 std::string token;
333 if (!FetchNamePortToken(buf + 1, term_pos, &destname_, &destport_, &token))
334 return STATUS_ABORT;
335
336 #if 0
337 // TODO(dilmah): enable this code once webProxyPrivate.getToken is wired.
338 std::map<std::string, std::string> map;
339 map["Hostname"] = destname;
340 map["Port"] = base::IntToString(destport);
341 map["ExtensionId"] = FetchExtensionIdFromOrigin(header_fields_["origin"]);
342 if (!browser::InternalAuthVerification::VerifyToken("Webproxy", token, map))
343 return STATUS_ABORT;
344 #endif
345
346 evbuffer_drain(evb, term_pos - buf + 1);
347 return STATUS_OK;
348 }
349
350 Conn::Status Conn::ConsumeFrameHeader(struct evbuffer* evb) {
351 uint8* buf = EVBUFFER_DATA(evb);
352 size_t buf_size = EVBUFFER_LENGTH(evb);
353
354 if (buf_size < 1)
355 return STATUS_INCOMPLETE;
356 if (buf[0] != 0)
357 return STATUS_ABORT;
358 evbuffer_drain(evb, 1);
359 return STATUS_OK;
360 }
361
362 Conn::Status Conn::ProcessFrameData(struct evbuffer* evb) {
363 uint8* buf = EVBUFFER_DATA(evb);
364 size_t buf_size = EVBUFFER_LENGTH(evb);
365
366 if (buf_size < 1)
367 return STATUS_INCOMPLETE;
368 uint8* buf_end = buf + buf_size;
369 uint8* term_pos = std::find(buf, buf_end, 0xff);
370 bool term_detected = (term_pos != buf_end);
371 if (term_detected)
372 buf_size = term_pos - buf;
373 switch (phase_) {
374 case PHASE_INSIDE_FRAME_BASE64: {
375 if (term_detected && buf_size % 4) {
376 // base64 is encoded in chunks of 4 bytes.
377 return STATUS_ABORT;
378 }
379 if (buf_size < 4) {
380 DCHECK(!term_detected);
381 return STATUS_INCOMPLETE;
382 }
383 size_t bytes_to_process_atm = (buf_size / 4) * 4;
384 std::string out_bytes;
385 base::Base64Decode(std::string(buf, buf + bytes_to_process_atm),
386 &out_bytes);
387 evbuffer_drain(evb, bytes_to_process_atm);
388 DCHECK(destchan_.bev != NULL);
389 if (bufferevent_write(destchan_.bev,
390 out_bytes.c_str(), out_bytes.size())) {
391 return STATUS_ABORT;
392 }
393 break;
394 }
395 case PHASE_INSIDE_FRAME_SKIP: {
396 evbuffer_drain(evb, buf_size);
397 break;
398 }
399 default: {
400 return STATUS_ABORT;
401 }
402 }
403 if (term_detected) {
404 evbuffer_drain(evb, 1);
405 return STATUS_OK;
406 }
407 return STATUS_INCOMPLETE;
408 }
409
410 bool Conn::TryConnectDest(const struct sockaddr* addr,
411 socklen_t addrlen) {
412 if (destchan_.sock >= 0 ||
413 destchan_.bev != NULL) {
414 return false;
415 }
416 destchan_.sock = socket(addr->sa_family, SOCK_STREAM, 0);
417 if (destchan_.sock < 0)
418 return false;
419 if (!Serv::SetNonBlock(destchan_.sock))
420 return false;
421 if (connect(destchan_.sock, addr, addrlen)) {
422 if (errno != EINPROGRESS)
423 return false;
424 }
425 destchan_.bev = bufferevent_new(destchan_.sock,
426 &OnDestchanRead,
427 &OnDestchanWrite,
428 &OnDestchanError,
429 token_);
430 if (destchan_.bev == NULL)
431 return false;
432 if (bufferevent_base_set(master_->evbase(), destchan_.bev))
433 return false;
434 bufferevent_setwatermark(destchan_.bev, EV_READ,
435 0, Serv::kReadBufferLimit);
436 return !bufferevent_enable(destchan_.bev, EV_READ | EV_WRITE);
437 }
438
439 // static
440 void Conn::OnPrimchanRead(struct bufferevent* bev, Token token) {
441 Conn* cs = Conn::Get(token);
442 if (bev == NULL ||
443 cs == NULL ||
444 bev != cs->primchan_.bev) {
445 // Sanity check failed.
446 return;
447 }
448 if (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)) <= 0)
449 return;
450 cs->master_->MarkConnImportance(cs, true);
451 for (;;) {
452 switch (cs->phase_) {
453 case PHASE_WAIT_HANDSHAKE: {
454 switch (cs->ConsumeHeader(EVBUFFER_INPUT(bev))) {
455 case STATUS_OK: {
456 break;
457 }
458 case STATUS_INCOMPLETE: {
459 return;
460 }
461 case STATUS_ABORT:
462 default: {
463 cs->master_->ZapConn(cs);
464 return;
465 }
466 }
467 // Header consumed OK. Do respond.
468 if (!cs->EmitHandshake(bev)) {
469 cs->master_->ZapConn(cs);
470 return;
471 }
472 cs->phase_ = PHASE_WAIT_DESTFRAME;
473 return;
474 }
475 case PHASE_WAIT_DESTFRAME: {
476 switch (cs->ConsumeDestframe(EVBUFFER_INPUT(bev))) {
477 case STATUS_OK: {
478 {
479 struct sockaddr_in sa;
480 memset(&sa, 0, sizeof(sa));
481 sa.sin_port = htons(cs->destport_);
482 if (inet_pton(sa.sin_family = AF_INET,
483 cs->destname_.c_str(),
484 &sa.sin_addr) == 1) {
485 // valid IPv4 address supplied.
486 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) {
487 cs->phase_ = PHASE_WAIT_DESTCONNECT;
488 return;
489 }
490 }
491 }
492 {
493 if (cs->destname_.size() >= 2 &&
494 cs->destname_[0] == '[' &&
495 cs->destname_[cs->destname_.size() - 1] == ']') {
496 // Literal IPv6 address in brackets.
497 cs->destname_ =
498 cs->destname_.substr(1, cs->destname_.size() - 2);
499 }
500 struct sockaddr_in6 sa;
501 memset(&sa, 0, sizeof(sa));
502 sa.sin6_port = htons(cs->destport_);
503 if (inet_pton(sa.sin6_family = AF_INET6,
504 cs->destname_.c_str(),
505 &sa.sin6_addr) == 1) {
506 // valid IPv6 address supplied.
507 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa))) {
508 cs->phase_ = PHASE_WAIT_DESTCONNECT;
509 return;
510 }
511 }
512 }
513 // Try to asynchronously perform DNS resolution.
514 evdns_resolve_ipv4(cs->destname_.c_str(), 0,
515 &OnDestResolutionIPv4, token);
516 evdns_resolve_ipv6(cs->destname_.c_str(), 0,
517 &OnDestResolutionIPv6, token);
518 cs->phase_ = PHASE_WAIT_DESTCONNECT;
519 return;
520 }
521 case STATUS_INCOMPLETE: {
522 return;
523 }
524 case STATUS_ABORT:
525 default: {
526 cs->Shut();
527 return;
528 }
529 }
530 }
531 case PHASE_WAIT_DESTCONNECT: {
532 if (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)) >=
533 Serv::kReadBufferLimit) {
534 cs->Shut();
535 }
536 return;
537 }
538 case PHASE_OUTSIDE_FRAME: {
539 switch (cs->ConsumeFrameHeader(EVBUFFER_INPUT(bev))) {
540 case STATUS_OK: {
541 cs->phase_ = PHASE_INSIDE_FRAME_BASE64;
542 // Process remaining data if any.
543 break;
544 }
545 case STATUS_SKIP: {
546 cs->phase_ = PHASE_INSIDE_FRAME_SKIP;
547 // Process remaining data if any.
548 break;
549 }
550 case STATUS_INCOMPLETE: {
551 return;
552 }
553 case STATUS_ABORT:
554 default: {
555 cs->Shut();
556 return;
557 }
558 }
559 break;
560 }
561 case PHASE_INSIDE_FRAME_BASE64:
562 case PHASE_INSIDE_FRAME_SKIP: {
563 switch (cs->ProcessFrameData(EVBUFFER_INPUT(bev))) {
564 case STATUS_OK: {
565 cs->phase_ = PHASE_OUTSIDE_FRAME;
566 // Handle remaining data if any.
567 break;
568 }
569 case STATUS_INCOMPLETE: {
570 return;
571 }
572 case STATUS_ABORT:
573 default: {
574 cs->Shut();
575 return;
576 }
577 }
578 break;
579 }
580 case PHASE_SHUT: {
581 evbuffer_drain(EVBUFFER_INPUT(bev),
582 EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)));
583 return;
584 }
585 case PHASE_DEFUNCT:
586 default: {
587 NOTREACHED();
588 cs->master_->ZapConn(cs);
589 return;
590 }
591 }
592 }
593 }
594
595 // static
596 void Conn::OnPrimchanWrite(struct bufferevent* bev, Token token) {
597 Conn* cs = Conn::Get(token);
598 if (bev == NULL ||
599 cs == NULL ||
600 bev != cs->primchan_.bev) {
601 // Sanity check failed.
602 return;
603 }
604 if (cs->phase_ >= PHASE_SHUT) {
605 cs->master_->ZapConn(cs);
606 return;
607 }
608 if (cs->phase_ > PHASE_WAIT_DESTCONNECT)
609 OnDestchanRead(cs->destchan_.bev, token);
610 }
611
612 // static
613 void Conn::OnPrimchanError(struct bufferevent* bev,
614 short what, Token token) {
615 Conn* cs = Conn::Get(token);
616 if (bev == NULL ||
617 cs == NULL ||
618 bev != cs->primchan_.bev) {
619 // Sanity check failed.
620 return;
621 }
622 if (cs->phase_ >= PHASE_SHUT)
623 cs->master_->ZapConn(cs);
624 else
625 cs->Shut();
626 }
627
628 // static
629 void Conn::OnDestResolutionIPv4(int result, char type,
630 int count, int ttl,
631 void* addr_list, Token token) {
632 Conn* cs = Conn::Get(token);
633 if (cs == NULL) {
634 // Sanity check failed.
635 return;
636 }
637 if (cs->phase_ != PHASE_WAIT_DESTCONNECT)
638 return;
639 if (result == DNS_ERR_NONE &&
640 count >= 1 &&
641 addr_list != NULL &&
642 type == DNS_IPv4_A) {
643 for (int i = 0; i < count; ++i) {
644 struct sockaddr_in sa;
645 memset(&sa, 0, sizeof(sa));
646 sa.sin_family = AF_INET;
647 sa.sin_port = htons(cs->destport_);
648 DCHECK(sizeof(sa.sin_addr) == sizeof(struct in_addr));
649 memcpy(&sa.sin_addr,
650 static_cast<struct in_addr*>(addr_list) + i,
651 sizeof(sa.sin_addr));
652 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa)))
653 return;
654 }
655 }
656 cs->destresolution_ipv4_failed_ = true;
657 if (cs->destresolution_ipv4_failed_ && cs->destresolution_ipv6_failed_)
658 cs->Shut();
659 }
660
661 // static
662 void Conn::OnDestResolutionIPv6(int result, char type,
663 int count, int ttl,
664 void* addr_list, Token token) {
665 Conn* cs = Conn::Get(token);
666 if (cs == NULL) {
667 // Sanity check failed.
668 return;
669 }
670 if (cs->phase_ != PHASE_WAIT_DESTCONNECT)
671 return;
672 if (result == DNS_ERR_NONE &&
673 count >= 1 &&
674 addr_list != NULL &&
675 type == DNS_IPv6_AAAA) {
676 for (int i = 0; i < count; ++i) {
677 struct sockaddr_in6 sa;
678 memset(&sa, 0, sizeof(sa));
679 sa.sin6_family = AF_INET6;
680 sa.sin6_port = htons(cs->destport_);
681 DCHECK(sizeof(sa.sin6_addr) == sizeof(struct in6_addr));
682 memcpy(&sa.sin6_addr,
683 static_cast<struct in6_addr*>(addr_list) + i,
684 sizeof(sa.sin6_addr));
685 if (cs->TryConnectDest((struct sockaddr*)&sa, sizeof(sa)))
686 return;
687 }
688 }
689 cs->destresolution_ipv6_failed_ = true;
690 if (cs->destresolution_ipv4_failed_ && cs->destresolution_ipv6_failed_)
691 cs->Shut();
692 }
693
694 // static
695 void Conn::OnDestConnectTimeout(int, short, Token token) {
696 Conn* cs = Conn::Get(token);
697 if (cs == NULL) {
698 // Sanity check failed.
699 }
700 if (cs->phase_ > PHASE_WAIT_DESTCONNECT)
701 return;
702 cs->Shut();
703 }
704
705 // static
706 void Conn::OnDestchanRead(struct bufferevent* bev, Token token) {
707 Conn* cs = Conn::Get(token);
708 if (bev == NULL ||
709 cs == NULL ||
710 bev != cs->destchan_.bev) {
711 // Sanity check failed.
712 return;
713 }
714 if (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)) <= 0)
715 return;
716 if (cs->primchan_.bev == NULL) {
717 cs->master_->ZapConn(cs);
718 return;
719 }
720 cs->master_->MarkConnImportance(cs, true);
721 std::string out_bytes;
722 base::Base64Encode(
723 std::string(
724 static_cast<const char*>(static_cast<void*>(
725 EVBUFFER_DATA(EVBUFFER_INPUT(bev)))),
726 EVBUFFER_LENGTH(EVBUFFER_INPUT(bev))),
727 &out_bytes);
728 evbuffer_drain(EVBUFFER_INPUT(bev), EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)));
729 static const uint8 frame_header[] = { 0x00 };
730 static const uint8 frame_terminator[] = { 0xff };
731 if (bufferevent_write(cs->primchan_.bev,
732 frame_header, sizeof(frame_header)) ||
733 bufferevent_write(cs->primchan_.bev,
734 out_bytes.c_str(), out_bytes.size()) ||
735 bufferevent_write(cs->primchan_.bev,
736 frame_terminator, sizeof(frame_terminator))) {
737 cs->Shut();
738 }
739 }
740
741 // static
742 void Conn::OnDestchanWrite(struct bufferevent* bev, Token token) {
743 Conn* cs = Conn::Get(token);
744 if (bev == NULL ||
745 cs == NULL ||
746 bev != cs->destchan_.bev) {
747 // Sanity check failed.
748 return;
749 }
750 if (cs->phase_ == PHASE_WAIT_DESTCONNECT)
751 cs->phase_ = PHASE_OUTSIDE_FRAME;
752 OnPrimchanRead(cs->primchan_.bev, token);
753 }
754
755 // static
756 void Conn::OnDestchanError(struct bufferevent* bev,
757 short what, Token token) {
758 Conn* cs = Conn::Get(token);
759 if (bev == NULL ||
760 cs == NULL ||
761 bev != cs->destchan_.bev) {
762 // Sanity check failed.
763 return;
764 }
765 if (cs->phase_ >= PHASE_SHUT)
766 cs->master_->ZapConn(cs);
767 else
768 cs->Shut();
769 }
770
771 Conn::Token Conn::last_token_ = 0;
772 Conn::TokenMap Conn::token_map_;
773
774 } // namespace chromeos
775 } // namespace webproxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698