OLD | NEW |
---|---|
(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 | |
OLD | NEW |