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

Unified Diff: chrome/browser/chromeos/net/webproxy/serv.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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/net/webproxy/serv.cc
diff --git a/chrome/browser/chromeos/net/webproxy/serv.cc b/chrome/browser/chromeos/net/webproxy/serv.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e57d32f3c5e462093f6b717ea01793ea3873a4ac
--- /dev/null
+++ b/chrome/browser/chromeos/net/webproxy/serv.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "serv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/logging.h"
+#include "chrome/browser/chromeos/net/webproxy/conn.h"
+#include "third_party/libevent/evdns.h"
+
+namespace chromeos {
+namespace webproxy {
+
+Serv::Serv(const std::vector<std::string>& allowed_origins,
+ struct sockaddr* addr, int addr_len)
+ : allowed_origins_(allowed_origins),
+ addr_(addr),
+ addr_len_(addr_len),
+ evbase_(NULL),
+ listening_sock_(-1) {
+ std::sort(allowed_origins_.begin(), allowed_origins_.end());
+}
+
+Serv::~Serv() {
+ while (!conn_pool_.empty())
+ ZapConn(conn_pool_.back());
+ if (listening_sock_ >= 0) {
+ shutdown(listening_sock_, SHUT_RDWR);
+ close(listening_sock_);
+ }
+ if (evbase_)
+ event_base_free(evbase_);
+}
+
+void Serv::Run() {
+ if (evbase_) {
+ // One run at a time is all we do.
+ return;
+ }
+
+ evbase_ = event_init();
+ if (!evbase_) {
+ LOG(ERROR) << "Webproxy: Couldn't create libevent base";
+ return;
+ }
+
+ listening_sock_ = socket(AF_INET, SOCK_STREAM, 0);
+ if (listening_sock_ < 0) {
+ LOG(ERROR) << "Webproxy: Failed to create socket";
+ return;
+ }
+ if (bind(listening_sock_, addr_, addr_len_)) {
+ LOG(ERROR) << "Webproxy: Failed to bind server socket";
+ return;
+ }
+ if (listen(listening_sock_, 12)) {
+ LOG(ERROR) << "Webproxy: Failed to listen server socket";
+ return;
+ }
+ {
+ int on = 1;
+ setsockopt(listening_sock_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ }
+ if (!SetNonBlock(listening_sock_)) {
+ LOG(ERROR) << "Webproxy: Failed to go non block";
+ return;
+ }
+ {
+ struct event listen_event;
+ event_set(&listen_event, listening_sock_, EV_READ | EV_PERSIST,
+ &OnConnect, this);
+ event_base_set(evbase_, &listen_event);
+ if (event_add(&listen_event, NULL)) {
+ LOG(ERROR) << "Webproxy: Failed to add listening event";
+ return;
+ }
+ }
+ if (evdns_init()) {
+ LOG(ERROR) << "Webproxy: Failed to initialize evDNS";
+ return;
+ }
+ if (!IgnoreSigPipe())
+ return;
+ LOG(INFO) << "Webproxy: Starting event dispatch loop, accepting connections.";
+ event_base_dispatch(evbase_);
+ LOG(ERROR) << "Webproxy: Event dispatch loop terminated";
+}
+
+void Serv::ZapConn(Conn* cs) {
+ RevMap::iterator rit = rev_map_.find(cs);
+ if (rit != rev_map_.end()) {
+ conn_pool_.erase(rit->second);
+ rev_map_.erase(rit);
+ delete cs;
+ }
+}
+
+void Serv::MarkConnImportance(Conn* cs, bool important) {
+ if (conn_pool_.size() < kConnPoolLimit / 4) {
+ // Fast common path.
+ return;
+ }
+ RevMap::iterator rit = rev_map_.find(cs);
+ if (rit != rev_map_.end()) {
+ ConnPool::iterator it = rit->second;
+ CHECK(*it == cs);
+ if (important && it == conn_pool_.begin()) {
+ // Already at the top. Shortcut.
+ return;
+ }
+ conn_pool_.erase(it);
+ }
+ if (important) {
+ conn_pool_.push_front(cs);
+ rev_map_[cs] = conn_pool_.begin();
+ } else {
+ conn_pool_.push_back(cs);
+ rev_map_[cs] = conn_pool_.end();
+ --rev_map_[cs];
+ }
+}
+
+Conn* Serv::GetFreshConn() {
+ if (conn_pool_.size() > kConnPoolLimit) {
+ // Connections overflow. Shut those oldest not active.
+ ConnPool::iterator it = conn_pool_.end();
+ --it;
+ for (int i = conn_pool_.size() - kConnPoolLimit; i-- > 0;) {
+ // Shut may invalidate an iterator; hence postdecrement.
+ (*it--)->Shut();
+ }
+ if (conn_pool_.size() > kConnPoolLimit + 12) {
+ // Connections overflow. Zap the oldest not active.
+ ZapConn(conn_pool_.back());
+ }
+ }
+ Conn* cs = new Conn(this);
+ conn_pool_.push_front(cs);
+ rev_map_[cs] = conn_pool_.begin();
+ return cs;
+}
+
+bool Serv::IsConnSane(Conn* cs) {
+ return rev_map_.find(cs) != rev_map_.end();
+}
+
+bool Serv::IsOriginAllowed(const std::string& origin) {
+ return allowed_origins_.empty() || std::binary_search(
+ allowed_origins_.begin(), allowed_origins_.end(), origin);
+}
+
+void Serv::OnConnect(int listening_sock, short event, void* ctx) {
+ Serv* self = static_cast<Serv*>(ctx);
+ Conn* cs = self->GetFreshConn();
+ cs->primchan().sock = accept(listening_sock, NULL, NULL);
+ if (cs->primchan().sock < 0
+ || !SetNonBlock(cs->primchan().sock)) {
+ self->ZapConn(cs);
+ // Read readiness was triggered on listening socket
+ // yet we failed to accept a connection; definitely weird.
+ sleep(1);
+ return;
+ }
+
+ cs->primchan().bev = bufferevent_new(cs->primchan().sock,
+ &Conn::OnPrimchanRead,
+ &Conn::OnPrimchanWrite,
+ &Conn::OnPrimchanError,
+ cs->token());
+ if (cs->primchan().bev == NULL) {
+ self->ZapConn(cs);
+ return;
+ }
+ bufferevent_base_set(self->evbase_, cs->primchan().bev);
+ bufferevent_setwatermark(cs->primchan().bev, EV_READ, 0, kReadBufferLimit);
+ if (bufferevent_enable(cs->primchan().bev, EV_READ | EV_WRITE)) {
+ self->ZapConn(cs);
+ return;
+ }
+}
+
+bool Serv::SetNonBlock(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ return flags >= 0 && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0;
+}
+
+bool Serv::IgnoreSigPipe() {
+ struct sigaction sa;
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ if (sigemptyset(&sa.sa_mask) ||
+ sigaction(SIGPIPE, &sa, 0)) {
+ LOG(ERROR) << "Webproxy: Failed to disable sigpipe";
+ return false;
+ }
+ return true;
+}
+
+} // namespace chromeos
+} // namespace webproxy

Powered by Google App Engine
This is Rietveld 408576698