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

Side by Side Diff: net/web2socket_proxy/web2socket_serv.cc

Issue 5484001: Web2socket proxy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: additional files Created 10 years 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) 2010 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 "web2socket_serv.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
tyoshino (SeeGerritForStatus) 2010/12/03 07:53:33 vertical space here?
Denis Lagno 2010/12/03 16:28:50 Done.
10 #include <vector>
11
12 #include <arpa/inet.h>
13 #include <fcntl.h>
14 #include <netinet/in.h>
15 #include <signal.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18
19 #include "base/logging.h"
20 #include "net/web2socket_proxy/web2socket_conn.h"
21 #include "third_party/libevent/evdns.h"
22
23 Web2SocketServ::Web2SocketServ(const std::string& origin, int port)
24 : origin_(origin),
25 port_(port),
26 evbase_(NULL),
27 listening_sock_(-1) {}
28
29 Web2SocketServ::~Web2SocketServ() {
30 while (!conn_pool_.empty()) {
31 ZapConn(conn_pool_.back());
32 }
33 if (listening_sock_ >= 0) {
34 shutdown(listening_sock_, SHUT_RDWR);
35 close(listening_sock_);
36 }
37 if (evbase_) {
38 event_base_free(evbase_);
39 }
40 }
41
42 void Web2SocketServ::Run() {
43 if (evbase_) {
44 // One run at a time is all we do. One run at a time is good for you.
45 return;
46 }
47 if (port_ <= 0 || port_ >= (1 << 16)) {
48 return;
49 }
50
51 evbase_ = event_init();
52 if (!evbase_) {
53 perror("Couldn't create libevent base");
54 return;
55 }
56
57 listening_sock_ = socket(AF_INET, SOCK_STREAM, 0);
58 if (listening_sock_ < 0) {
59 perror("Failed to create socket");
60 return;
61 }
62 struct sockaddr_in sa;
63 memset(&sa, 0, sizeof(sa));
64 sa.sin_family = AF_INET;
65 sa.sin_port = htons(port_);
66 sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
67 if (bind(listening_sock_,
68 static_cast<sockaddr*>(static_cast<void*>(&sa)), sizeof(sa))) {
69 perror("Failed to bind server socket");
70 return;
71 }
72 if (listen(listening_sock_, 12)) {
73 perror("Failed to listen server socket");
74 return;
75 }
76 {
77 int on = 1;
78 setsockopt(listening_sock_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
79 }
80 if (!SetNonBlock(listening_sock_)) {
81 perror("Failed to go non block");
82 }
83 {
84 struct event listen_event;
85 event_set(&listen_event, listening_sock_, EV_READ | EV_PERSIST,
86 &OnConnect, this);
87 event_base_set(evbase_, &listen_event);
88 if (event_add(&listen_event, NULL)) {
89 perror("Failed to add listening event");
90 return;
91 }
92 }
93 if (evdns_init()) {
94 perror("Failed to initialize evDNS");
95 return;
96 }
97 if (!IgnoreSigPipe()) {
98 return;
99 }
100 event_base_dispatch(evbase_);
101 perror("Event dispatch loop terminated");
102 }
103
104 void Web2SocketServ::ZapConn(Conn* cs) {
105 RevMap::iterator rit = rev_map_.find(cs);
106 if (rit != rev_map_.end()) {
107 conn_pool_.erase(rit->second);
108 rev_map_.erase(rit);
109 delete cs;
110 }
111 }
112
113 void Web2SocketServ::MarkConnImportance(Conn* cs,
114 bool important) {
115 if (conn_pool_.size() < kConnPoolLimit / 4) {
116 // Fast common path.
117 return;
118 }
119 RevMap::iterator rit = rev_map_.find(cs);
120 if (rit != rev_map_.end()) {
121 ConnPool::iterator it = rit->second;
122 CHECK(*it == cs);
123 if (important && it == conn_pool_.begin()) {
124 // Already at the top. Shortcut.
125 return;
126 }
127 conn_pool_.erase(it);
128 }
129 if (important) {
130 conn_pool_.push_front(cs);
131 rev_map_[cs] = conn_pool_.begin();
132 } else {
133 conn_pool_.push_back(cs);
134 rev_map_[cs] = conn_pool_.end();
135 --rev_map_[cs];
136 }
137 }
138
139 Conn* Web2SocketServ::GetFreshConn() {
140 if (conn_pool_.size() > kConnPoolLimit) {
141 // Connections overflow. Shut those oldest not active.
142 ConnPool::iterator it = conn_pool_.end();
143 --it;
144 for (int i = conn_pool_.size() - kConnPoolLimit; i-- > 0;) {
145 // Shut may invalidate an iterator; hence postdecrement.
146 (*it--)->Shut();
147 }
148 if (conn_pool_.size() > kConnPoolLimit + 12) {
149 // Connections overflow. Zap the oldest not active.
150 ZapConn(conn_pool_.back());
151 }
152 }
153 Conn* cs = new Conn(this);
154 conn_pool_.push_front(cs);
155 rev_map_[cs] = conn_pool_.begin();
156 return cs;
157 }
158
159 bool Web2SocketServ::IsConnSane(Conn* cs) {
160 return rev_map_.find(cs) != rev_map_.end();
161 }
162
163 void Web2SocketServ::OnConnect(int listening_sock,
164 short event, void* ctx) {
165 Web2SocketServ* self = static_cast<Web2SocketServ*>(ctx);
166 Conn* cs = self->GetFreshConn();
167 cs->primchan_.sock_ = accept(listening_sock, NULL, NULL);
168 if (cs->primchan_.sock_ < 0
169 || !SetNonBlock(cs->primchan_.sock_)) {
170 self->ZapConn(cs);
171 // Read readiness was triggered on listening socket
172 // yet we failed to accept a connection;
173 // definitely weird, sleep to avoid CPU burn.
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 Web2SocketServ::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 Web2SocketServ::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 perror("Failed to disable sigpipe");
207 return false;
208 }
209 return true;
210 }
211
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698