Chromium Code Reviews| 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 |