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 "chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/message_loop.h" | |
9 #include "net/base/address_list.h" | |
10 #include "net/base/net_errors.h" | |
11 #include "net/base/ssl_config_service.h" | |
12 #include "net/base/sys_addrinfo.h" | |
13 #include "net/socket/client_socket_factory.h" | |
14 #include "net/url_request/url_request_context.h" | |
15 | |
16 namespace notifier { | |
17 | |
18 namespace { | |
19 | |
20 // Convert values from <errno.h> to values from "net/base/net_errors.h" | |
21 int MapPosixError(int err) { | |
22 // There are numerous posix error codes, but these are the ones we thus far | |
23 // find interesting. | |
24 switch (err) { | |
25 case EAGAIN: | |
26 #if EWOULDBLOCK != EAGAIN | |
27 case EWOULDBLOCK: | |
28 #endif | |
29 return net::ERR_IO_PENDING; | |
30 case ENETDOWN: | |
31 return net::ERR_INTERNET_DISCONNECTED; | |
32 case ETIMEDOUT: | |
33 return net::ERR_TIMED_OUT; | |
34 case ECONNRESET: | |
35 case ENETRESET: // Related to keep-alive | |
36 return net::ERR_CONNECTION_RESET; | |
37 case ECONNABORTED: | |
38 return net::ERR_CONNECTION_ABORTED; | |
39 case ECONNREFUSED: | |
40 return net::ERR_CONNECTION_REFUSED; | |
41 case EHOSTUNREACH: | |
42 case ENETUNREACH: | |
43 return net::ERR_ADDRESS_UNREACHABLE; | |
44 case EADDRNOTAVAIL: | |
45 return net::ERR_ADDRESS_INVALID; | |
46 case 0: | |
47 return net::OK; | |
48 default: | |
49 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
50 return net::ERR_FAILED; | |
51 } | |
52 } | |
53 | |
54 } // namespace | |
55 | |
56 SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) { | |
57 return new SSLSocketAdapter(socket); | |
58 } | |
59 | |
60 SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket) | |
61 : SSLAdapter(socket), | |
62 ignore_bad_cert_(false), | |
63 ALLOW_THIS_IN_INITIALIZER_LIST( | |
64 connected_callback_(this, &SSLSocketAdapter::OnConnected)), | |
65 ALLOW_THIS_IN_INITIALIZER_LIST( | |
66 io_callback_(this, &SSLSocketAdapter::OnIO)), | |
67 ssl_connected_(false), | |
68 state_(STATE_NONE) { | |
69 transport_socket_ = new TransportSocket(socket, this); | |
70 } | |
71 | |
72 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { | |
73 DCHECK(!restartable); | |
74 hostname_ = hostname; | |
75 | |
76 if (socket_->GetState() != Socket::CS_CONNECTED) { | |
77 state_ = STATE_SSL_WAIT; | |
78 return 0; | |
79 } else { | |
80 return BeginSSL(); | |
81 } | |
82 } | |
83 | |
84 int SSLSocketAdapter::BeginSSL() { | |
85 if (!MessageLoop::current()) { | |
86 // Certificate verification is done via the Chrome message loop. | |
87 // Without this check, if we don't have a chrome message loop the | |
88 // SSL connection just hangs silently. | |
89 LOG(DFATAL) << "Chrome message loop (needed by SSL certificate " | |
90 << "verification) does not exist"; | |
91 return net::ERR_UNEXPECTED; | |
92 } | |
93 | |
94 // SSLConfigService is not thread-safe, and the default values for SSLConfig | |
95 // are correct for us, so we don't use the config service to initialize this | |
96 // object. | |
97 net::SSLConfig ssl_config; | |
98 transport_socket_->set_addr(talk_base::SocketAddress(hostname_.c_str())); | |
99 ssl_socket_.reset( | |
100 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( | |
101 transport_socket_, hostname_.c_str(), ssl_config)); | |
102 | |
103 int result = ssl_socket_->Connect(&connected_callback_); | |
104 | |
105 if (result == net::ERR_IO_PENDING || result == net::OK) { | |
106 return 0; | |
107 } else { | |
108 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); | |
109 return result; | |
110 } | |
111 } | |
112 | |
113 int SSLSocketAdapter::Send(const void* buf, size_t len) { | |
114 if (!ssl_connected_) { | |
115 return AsyncSocketAdapter::Send(buf, len); | |
116 } else { | |
117 scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len); | |
118 memcpy(transport_buf->data(), buf, len); | |
119 | |
120 int result = ssl_socket_->Write(transport_buf, len, NULL); | |
121 if (result == net::ERR_IO_PENDING) { | |
122 SetError(EWOULDBLOCK); | |
123 } | |
124 transport_buf = NULL; | |
125 return result; | |
126 } | |
127 } | |
128 | |
129 int SSLSocketAdapter::Recv(void* buf, size_t len) { | |
130 if (!ssl_connected_) { | |
131 return AsyncSocketAdapter::Recv(buf, len); | |
132 } | |
133 | |
134 switch (state_) { | |
135 case STATE_NONE: { | |
136 transport_buf_ = new net::IOBuffer(len); | |
137 int result = ssl_socket_->Read(transport_buf_, len, &io_callback_); | |
138 if (result >= 0) { | |
139 memcpy(buf, transport_buf_->data(), len); | |
140 } | |
141 | |
142 if (result == net::ERR_IO_PENDING) { | |
143 state_ = STATE_READ; | |
144 SetError(EWOULDBLOCK); | |
145 } else { | |
146 if (result < 0) { | |
147 SetError(result); | |
148 LOG(INFO) << "Socket error " << result; | |
149 } | |
150 transport_buf_ = NULL; | |
151 } | |
152 return result; | |
153 } | |
154 case STATE_READ_COMPLETE: | |
155 memcpy(buf, transport_buf_->data(), len); | |
156 transport_buf_ = NULL; | |
157 state_ = STATE_NONE; | |
158 return data_transferred_; | |
159 | |
160 case STATE_READ: | |
161 case STATE_WRITE: | |
162 case STATE_WRITE_COMPLETE: | |
163 case STATE_SSL_WAIT: | |
164 SetError(EWOULDBLOCK); | |
165 return -1; | |
166 | |
167 default: | |
168 NOTREACHED(); | |
169 break; | |
170 } | |
171 return -1; | |
172 } | |
173 | |
174 void SSLSocketAdapter::OnConnected(int result) { | |
175 if (result == net::OK) { | |
176 ssl_connected_ = true; | |
177 OnConnectEvent(this); | |
178 } else { | |
179 LOG(WARNING) << "OnConnected failed with error " << result; | |
180 } | |
181 } | |
182 | |
183 void SSLSocketAdapter::OnIO(int result) { | |
184 switch (state_) { | |
185 case STATE_READ: | |
186 state_ = STATE_READ_COMPLETE; | |
187 data_transferred_ = result; | |
188 AsyncSocketAdapter::OnReadEvent(this); | |
189 break; | |
190 case STATE_WRITE: | |
191 state_ = STATE_WRITE_COMPLETE; | |
192 data_transferred_ = result; | |
193 AsyncSocketAdapter::OnWriteEvent(this); | |
194 break; | |
195 case STATE_NONE: | |
196 case STATE_READ_COMPLETE: | |
197 case STATE_WRITE_COMPLETE: | |
198 case STATE_SSL_WAIT: | |
199 default: | |
200 NOTREACHED(); | |
201 break; | |
202 } | |
203 } | |
204 | |
205 void SSLSocketAdapter::OnReadEvent(talk_base::AsyncSocket* socket) { | |
206 if (!transport_socket_->OnReadEvent(socket)) | |
207 AsyncSocketAdapter::OnReadEvent(socket); | |
208 } | |
209 | |
210 void SSLSocketAdapter::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
211 if (!transport_socket_->OnWriteEvent(socket)) | |
212 AsyncSocketAdapter::OnWriteEvent(socket); | |
213 } | |
214 | |
215 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { | |
216 if (state_ != STATE_SSL_WAIT) { | |
217 AsyncSocketAdapter::OnConnectEvent(socket); | |
218 } else { | |
219 state_ = STATE_NONE; | |
220 int result = BeginSSL(); | |
221 if (0 != result) { | |
222 // TODO(zork): Handle this case gracefully. | |
223 LOG(WARNING) << "BeginSSL() failed with " << result; | |
224 } | |
225 } | |
226 } | |
227 | |
228 TransportSocket::TransportSocket(talk_base::AsyncSocket* socket, | |
229 SSLSocketAdapter *ssl_adapter) | |
230 : connect_callback_(NULL), | |
231 read_callback_(NULL), | |
232 write_callback_(NULL), | |
233 read_buffer_len_(0), | |
234 write_buffer_len_(0), | |
235 socket_(socket) { | |
236 socket_->SignalConnectEvent.connect(this, &TransportSocket::OnConnectEvent); | |
237 } | |
238 | |
239 int TransportSocket::Connect(net::CompletionCallback* callback) { | |
240 connect_callback_ = callback; | |
241 return socket_->Connect(addr_); | |
242 } | |
243 | |
244 void TransportSocket::Disconnect() { | |
245 socket_->Close(); | |
246 } | |
247 | |
248 bool TransportSocket::IsConnected() const { | |
249 return (socket_->GetState() == talk_base::Socket::CS_CONNECTED); | |
250 } | |
251 | |
252 bool TransportSocket::IsConnectedAndIdle() const { | |
253 // Not implemented. | |
254 NOTREACHED(); | |
255 return false; | |
256 } | |
257 | |
258 int TransportSocket::GetPeerAddress(net::AddressList* address) const { | |
259 talk_base::SocketAddress socket_address = socket_->GetRemoteAddress(); | |
260 | |
261 // libjingle supports only IPv4 addresses. | |
262 sockaddr_in ipv4addr; | |
263 socket_address.ToSockAddr(&ipv4addr); | |
264 | |
265 struct addrinfo ai; | |
266 memset(&ai, 0, sizeof(ai)); | |
267 ai.ai_family = ipv4addr.sin_family; | |
268 ai.ai_socktype = SOCK_STREAM; | |
269 ai.ai_protocol = IPPROTO_TCP; | |
270 ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr); | |
271 ai.ai_addrlen = sizeof(ipv4addr); | |
272 | |
273 address->Copy(&ai, false); | |
274 return net::OK; | |
275 } | |
276 | |
277 int TransportSocket::Read(net::IOBuffer* buf, int buf_len, | |
278 net::CompletionCallback* callback) { | |
279 DCHECK(buf); | |
280 DCHECK(!read_callback_); | |
281 DCHECK(!read_buffer_.get()); | |
282 int result = socket_->Recv(buf->data(), buf_len); | |
283 if (result < 0) { | |
284 result = MapPosixError(socket_->GetError()); | |
285 if (result == net::ERR_IO_PENDING) { | |
286 read_callback_ = callback; | |
287 read_buffer_ = buf; | |
288 read_buffer_len_ = buf_len; | |
289 } | |
290 } | |
291 return result; | |
292 } | |
293 | |
294 int TransportSocket::Write(net::IOBuffer* buf, int buf_len, | |
295 net::CompletionCallback* callback) { | |
296 DCHECK(buf); | |
297 DCHECK(!write_callback_); | |
298 DCHECK(!write_buffer_.get()); | |
299 int result = socket_->Send(buf->data(), buf_len); | |
300 if (result < 0) { | |
301 result = MapPosixError(socket_->GetError()); | |
302 if (result == net::ERR_IO_PENDING) { | |
303 write_callback_ = callback; | |
304 write_buffer_ = buf; | |
305 write_buffer_len_ = buf_len; | |
306 } | |
307 } | |
308 return result; | |
309 } | |
310 | |
311 bool TransportSocket::SetReceiveBufferSize(int32 size) { | |
312 // Not implemented. | |
313 return false; | |
314 } | |
315 | |
316 bool TransportSocket::SetSendBufferSize(int32 size) { | |
317 // Not implemented. | |
318 return false; | |
319 } | |
320 | |
321 void TransportSocket::OnConnectEvent(talk_base::AsyncSocket * socket) { | |
322 if (connect_callback_) { | |
323 net::CompletionCallback *callback = connect_callback_; | |
324 connect_callback_ = NULL; | |
325 callback->RunWithParams(Tuple1<int>(MapPosixError(socket_->GetError()))); | |
326 } else { | |
327 LOG(WARNING) << "OnConnectEvent called with no callback."; | |
328 } | |
329 } | |
330 | |
331 bool TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) { | |
332 if (read_callback_) { | |
333 DCHECK(read_buffer_.get()); | |
334 net::CompletionCallback* callback = read_callback_; | |
335 scoped_refptr<net::IOBuffer> buffer = read_buffer_; | |
336 int buffer_len = read_buffer_len_; | |
337 | |
338 read_callback_ = NULL; | |
339 read_buffer_ = NULL; | |
340 read_buffer_len_ = 0; | |
341 | |
342 int result = socket_->Recv(buffer->data(), buffer_len); | |
343 if (result < 0) { | |
344 result = MapPosixError(socket_->GetError()); | |
345 if (result == net::ERR_IO_PENDING) { | |
346 read_callback_ = callback; | |
347 read_buffer_ = buffer; | |
348 read_buffer_len_ = buffer_len; | |
349 return true; | |
350 } | |
351 } | |
352 callback->RunWithParams(Tuple1<int>(result)); | |
353 return true; | |
354 } else { | |
355 LOG(WARNING) << "OnReadEvent called with no callback."; | |
356 return false; | |
357 } | |
358 } | |
359 | |
360 bool TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
361 if (write_callback_) { | |
362 DCHECK(write_buffer_.get()); | |
363 net::CompletionCallback* callback = write_callback_; | |
364 scoped_refptr<net::IOBuffer> buffer = write_buffer_; | |
365 int buffer_len = write_buffer_len_; | |
366 | |
367 write_callback_ = NULL; | |
368 write_buffer_ = NULL; | |
369 write_buffer_len_ = 0; | |
370 | |
371 int result = socket_->Send(buffer->data(), buffer_len); | |
372 if (result < 0) { | |
373 result = MapPosixError(socket_->GetError()); | |
374 if (result == net::ERR_IO_PENDING) { | |
375 write_callback_ = callback; | |
376 write_buffer_ = buffer; | |
377 write_buffer_len_ = buffer_len; | |
378 return true; | |
379 } | |
380 } | |
381 callback->RunWithParams(Tuple1<int>(result)); | |
382 return true; | |
383 } else { | |
384 LOG(WARNING) << "OnWriteEvent called with no callback."; | |
385 return false; | |
386 } | |
387 } | |
388 | |
389 } // namespace notifier | |
OLD | NEW |