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

Side by Side 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 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 "serv.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <algorithm>
12
13 #include <arpa/inet.h>
14 #include <fcntl.h>
15 #include <netinet/in.h>
16 #include <signal.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19
20 #include "base/logging.h"
21 #include "chrome/browser/chromeos/net/webproxy/conn.h"
22 #include "third_party/libevent/evdns.h"
23
24 namespace chromeos {
25 namespace webproxy {
26
27 Serv::Serv(const std::vector<std::string>& allowed_origins,
28 struct sockaddr* addr, int addr_len)
29 : allowed_origins_(allowed_origins),
30 addr_(addr),
31 addr_len_(addr_len),
32 evbase_(NULL),
33 listening_sock_(-1) {
34 std::sort(allowed_origins_.begin(), allowed_origins_.end());
35 }
36
37 Serv::~Serv() {
38 while (!conn_pool_.empty())
39 ZapConn(conn_pool_.back());
40 if (listening_sock_ >= 0) {
41 shutdown(listening_sock_, SHUT_RDWR);
42 close(listening_sock_);
43 }
44 if (evbase_)
45 event_base_free(evbase_);
46 }
47
48 void Serv::Run() {
49 if (evbase_) {
50 // One run at a time is all we do.
51 return;
52 }
53
54 evbase_ = event_init();
55 if (!evbase_) {
56 LOG(ERROR) << "Webproxy: Couldn't create libevent base";
57 return;
58 }
59
60 listening_sock_ = socket(AF_INET, SOCK_STREAM, 0);
61 if (listening_sock_ < 0) {
62 LOG(ERROR) << "Webproxy: Failed to create socket";
63 return;
64 }
65 if (bind(listening_sock_, addr_, addr_len_)) {
66 LOG(ERROR) << "Webproxy: Failed to bind server socket";
67 return;
68 }
69 if (listen(listening_sock_, 12)) {
70 LOG(ERROR) << "Webproxy: Failed to listen server socket";
71 return;
72 }
73 {
74 int on = 1;
75 setsockopt(listening_sock_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
76 }
77 if (!SetNonBlock(listening_sock_)) {
78 LOG(ERROR) << "Webproxy: Failed to go non block";
79 return;
80 }
81 {
82 struct event listen_event;
83 event_set(&listen_event, listening_sock_, EV_READ | EV_PERSIST,
84 &OnConnect, this);
85 event_base_set(evbase_, &listen_event);
86 if (event_add(&listen_event, NULL)) {
87 LOG(ERROR) << "Webproxy: Failed to add listening event";
88 return;
89 }
90 }
91 if (evdns_init()) {
92 LOG(ERROR) << "Webproxy: Failed to initialize evDNS";
93 return;
94 }
95 if (!IgnoreSigPipe())
96 return;
97 LOG(INFO) << "Webproxy: Starting event dispatch loop, accepting connections.";
98 event_base_dispatch(evbase_);
99 LOG(ERROR) << "Webproxy: Event dispatch loop terminated";
100 }
101
102 void Serv::ZapConn(Conn* cs) {
103 RevMap::iterator rit = rev_map_.find(cs);
104 if (rit != rev_map_.end()) {
105 conn_pool_.erase(rit->second);
106 rev_map_.erase(rit);
107 delete cs;
108 }
109 }
110
111 void Serv::MarkConnImportance(Conn* cs, bool important) {
112 if (conn_pool_.size() < kConnPoolLimit / 4) {
113 // Fast common path.
114 return;
115 }
116 RevMap::iterator rit = rev_map_.find(cs);
117 if (rit != rev_map_.end()) {
118 ConnPool::iterator it = rit->second;
119 CHECK(*it == cs);
120 if (important && it == conn_pool_.begin()) {
121 // Already at the top. Shortcut.
122 return;
123 }
124 conn_pool_.erase(it);
125 }
126 if (important) {
127 conn_pool_.push_front(cs);
128 rev_map_[cs] = conn_pool_.begin();
129 } else {
130 conn_pool_.push_back(cs);
131 rev_map_[cs] = conn_pool_.end();
132 --rev_map_[cs];
133 }
134 }
135
136 Conn* Serv::GetFreshConn() {
137 if (conn_pool_.size() > kConnPoolLimit) {
138 // Connections overflow. Shut those oldest not active.
139 ConnPool::iterator it = conn_pool_.end();
140 --it;
141 for (int i = conn_pool_.size() - kConnPoolLimit; i-- > 0;) {
142 // Shut may invalidate an iterator; hence postdecrement.
143 (*it--)->Shut();
144 }
145 if (conn_pool_.size() > kConnPoolLimit + 12) {
146 // Connections overflow. Zap the oldest not active.
147 ZapConn(conn_pool_.back());
148 }
149 }
150 Conn* cs = new Conn(this);
151 conn_pool_.push_front(cs);
152 rev_map_[cs] = conn_pool_.begin();
153 return cs;
154 }
155
156 bool Serv::IsConnSane(Conn* cs) {
157 return rev_map_.find(cs) != rev_map_.end();
158 }
159
160 bool Serv::IsOriginAllowed(const std::string& origin) {
161 return allowed_origins_.empty() || std::binary_search(
162 allowed_origins_.begin(), allowed_origins_.end(), origin);
163 }
164
165 void Serv::OnConnect(int listening_sock, short event, void* ctx) {
166 Serv* self = static_cast<Serv*>(ctx);
167 Conn* cs = self->GetFreshConn();
168 cs->primchan().sock = accept(listening_sock, NULL, NULL);
169 if (cs->primchan().sock < 0
170 || !SetNonBlock(cs->primchan().sock)) {
171 self->ZapConn(cs);
172 // Read readiness was triggered on listening socket
173 // yet we failed to accept a connection; definitely weird.
174 sleep(1);
175 return;
176 }
177
178 cs->primchan().bev = bufferevent_new(cs->primchan().sock,
179 &Conn::OnPrimchanRead,
180 &Conn::OnPrimchanWrite,
181 &Conn::OnPrimchanError,
182 cs->token());
183 if (cs->primchan().bev == NULL) {
184 self->ZapConn(cs);
185 return;
186 }
187 bufferevent_base_set(self->evbase_, cs->primchan().bev);
188 bufferevent_setwatermark(cs->primchan().bev, EV_READ, 0, kReadBufferLimit);
189 if (bufferevent_enable(cs->primchan().bev, EV_READ | EV_WRITE)) {
190 self->ZapConn(cs);
191 return;
192 }
193 }
194
195 bool Serv::SetNonBlock(int fd) {
196 int flags = fcntl(fd, F_GETFL, 0);
197 return flags >= 0 && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0;
198 }
199
200 bool Serv::IgnoreSigPipe() {
201 struct sigaction sa;
202 sa.sa_handler = SIG_IGN;
203 sa.sa_flags = 0;
204 if (sigemptyset(&sa.sa_mask) ||
205 sigaction(SIGPIPE, &sa, 0)) {
206 LOG(ERROR) << "Webproxy: Failed to disable sigpipe";
207 return false;
208 }
209 return true;
210 }
211
212 } // namespace chromeos
213 } // namespace webproxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698