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 "remoting/jingle_glue/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 remoting { | |
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 read_callback_(this, &SSLSocketAdapter::OnRead)), | |
67 ALLOW_THIS_IN_INITIALIZER_LIST( | |
68 write_callback_(this, &SSLSocketAdapter::OnWrite)), | |
69 ssl_state_(SSLSTATE_NONE), | |
70 read_state_(IOSTATE_NONE), | |
71 write_state_(IOSTATE_NONE) { | |
72 transport_socket_ = new TransportSocket(socket, this); | |
73 } | |
74 | |
75 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { | |
76 DCHECK(!restartable); | |
77 hostname_ = hostname; | |
78 | |
79 if (socket_->GetState() != Socket::CS_CONNECTED) { | |
80 ssl_state_ = SSLSTATE_WAIT; | |
81 return 0; | |
82 } else { | |
83 return BeginSSL(); | |
84 } | |
85 } | |
86 | |
87 int SSLSocketAdapter::BeginSSL() { | |
88 if (!MessageLoop::current()) { | |
89 // Certificate verification is done via the Chrome message loop. | |
90 // Without this check, if we don't have a chrome message loop the | |
91 // SSL connection just hangs silently. | |
92 LOG(DFATAL) << "Chrome message loop (needed by SSL certificate " | |
93 << "verification) does not exist"; | |
94 return net::ERR_UNEXPECTED; | |
95 } | |
96 | |
97 // SSLConfigService is not thread-safe, and the default values for SSLConfig | |
98 // are correct for us, so we don't use the config service to initialize this | |
99 // object. | |
100 net::SSLConfig ssl_config; | |
101 transport_socket_->set_addr(talk_base::SocketAddress(hostname_, 0)); | |
102 ssl_socket_.reset( | |
103 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( | |
104 transport_socket_, hostname_.c_str(), ssl_config)); | |
105 | |
106 int result = ssl_socket_->Connect(&connected_callback_); | |
107 | |
108 if (result == net::ERR_IO_PENDING || result == net::OK) { | |
109 return 0; | |
110 } else { | |
111 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); | |
112 return result; | |
113 } | |
114 } | |
115 | |
116 int SSLSocketAdapter::Send(const void* buf, size_t len) { | |
117 if (ssl_state_ != SSLSTATE_CONNECTED) { | |
118 return AsyncSocketAdapter::Send(buf, len); | |
119 } else { | |
120 scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len); | |
121 memcpy(transport_buf->data(), buf, len); | |
122 | |
123 int result = ssl_socket_->Write(transport_buf, len, NULL); | |
124 if (result == net::ERR_IO_PENDING) { | |
125 SetError(EWOULDBLOCK); | |
126 } | |
127 transport_buf = NULL; | |
128 return result; | |
129 } | |
130 } | |
131 | |
132 int SSLSocketAdapter::Recv(void* buf, size_t len) { | |
133 switch (ssl_state_) { | |
134 case SSLSTATE_NONE: | |
135 return AsyncSocketAdapter::Recv(buf, len); | |
136 | |
137 case SSLSTATE_WAIT: | |
138 SetError(EWOULDBLOCK); | |
139 return -1; | |
140 | |
141 case SSLSTATE_CONNECTED: | |
142 switch (read_state_) { | |
143 case IOSTATE_NONE: { | |
144 transport_buf_ = new net::IOBuffer(len); | |
145 int result = ssl_socket_->Read(transport_buf_, len, &read_callback_); | |
146 if (result >= 0) { | |
147 memcpy(buf, transport_buf_->data(), len); | |
148 } | |
149 | |
150 if (result == net::ERR_IO_PENDING) { | |
151 read_state_ = IOSTATE_PENDING; | |
152 SetError(EWOULDBLOCK); | |
153 } else { | |
154 if (result < 0) { | |
155 SetError(result); | |
156 LOG(INFO) << "Socket error " << result; | |
157 } | |
158 transport_buf_ = NULL; | |
159 } | |
160 return result; | |
161 } | |
162 case IOSTATE_PENDING: | |
163 SetError(EWOULDBLOCK); | |
164 return -1; | |
165 | |
166 case IOSTATE_COMPLETE: | |
167 memcpy(buf, transport_buf_->data(), len); | |
168 transport_buf_ = NULL; | |
169 read_state_ = IOSTATE_NONE; | |
170 return data_transferred_; | |
171 } | |
172 } | |
173 | |
174 NOTREACHED(); | |
175 return -1; | |
176 } | |
177 | |
178 void SSLSocketAdapter::OnConnected(int result) { | |
179 if (result == net::OK) { | |
180 ssl_state_ = SSLSTATE_CONNECTED; | |
181 OnConnectEvent(this); | |
182 } else { | |
183 LOG(WARNING) << "OnConnected failed with error " << result; | |
184 } | |
185 } | |
186 | |
187 void SSLSocketAdapter::OnRead(int result) { | |
188 DCHECK(read_state_ == IOSTATE_PENDING); | |
189 read_state_ = IOSTATE_COMPLETE; | |
190 data_transferred_ = result; | |
191 AsyncSocketAdapter::OnReadEvent(this); | |
192 } | |
193 | |
194 void SSLSocketAdapter::OnWrite(int result) { | |
195 DCHECK(write_state_ == IOSTATE_PENDING); | |
196 write_state_ = IOSTATE_COMPLETE; | |
197 data_transferred_ = result; | |
198 AsyncSocketAdapter::OnWriteEvent(this); | |
199 } | |
200 | |
201 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { | |
202 if (ssl_state_ != SSLSTATE_WAIT) { | |
203 AsyncSocketAdapter::OnConnectEvent(socket); | |
204 } else { | |
205 ssl_state_ = SSLSTATE_NONE; | |
206 int result = BeginSSL(); | |
207 if (0 != result) { | |
208 // TODO(zork): Handle this case gracefully. | |
209 LOG(WARNING) << "BeginSSL() failed with " << result; | |
210 } | |
211 } | |
212 } | |
213 | |
214 TransportSocket::TransportSocket(talk_base::AsyncSocket* socket, | |
215 SSLSocketAdapter *ssl_adapter) | |
216 : read_callback_(NULL), | |
217 write_callback_(NULL), | |
218 read_buffer_len_(0), | |
219 write_buffer_len_(0), | |
220 socket_(socket) { | |
221 socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent); | |
222 socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent); | |
223 } | |
224 | |
225 int TransportSocket::Connect(net::CompletionCallback* callback) { | |
226 // Connect is never called by SSLClientSocket, instead SSLSocketAdapter | |
227 // calls Connect() on socket_ directly. | |
228 NOTREACHED(); | |
229 return false; | |
230 } | |
231 | |
232 void TransportSocket::Disconnect() { | |
233 socket_->Close(); | |
234 } | |
235 | |
236 bool TransportSocket::IsConnected() const { | |
237 return (socket_->GetState() == talk_base::Socket::CS_CONNECTED); | |
238 } | |
239 | |
240 bool TransportSocket::IsConnectedAndIdle() const { | |
241 // Not implemented. | |
242 NOTREACHED(); | |
243 return false; | |
244 } | |
245 | |
246 int TransportSocket::GetPeerAddress(net::AddressList* address) const { | |
247 talk_base::SocketAddress socket_address = socket_->GetRemoteAddress(); | |
248 | |
249 // libjingle supports only IPv4 addresses. | |
250 sockaddr_in ipv4addr; | |
251 socket_address.ToSockAddr(&ipv4addr); | |
252 | |
253 struct addrinfo ai; | |
254 memset(&ai, 0, sizeof(ai)); | |
255 ai.ai_family = ipv4addr.sin_family; | |
256 ai.ai_socktype = SOCK_STREAM; | |
257 ai.ai_protocol = IPPROTO_TCP; | |
258 ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr); | |
259 ai.ai_addrlen = sizeof(ipv4addr); | |
260 | |
261 address->Copy(&ai, false); | |
262 return net::OK; | |
263 } | |
264 | |
265 int TransportSocket::Read(net::IOBuffer* buf, int buf_len, | |
266 net::CompletionCallback* callback) { | |
267 DCHECK(buf); | |
268 DCHECK(!read_callback_); | |
269 DCHECK(!read_buffer_.get()); | |
270 int result = socket_->Recv(buf->data(), buf_len); | |
271 if (result < 0) { | |
272 result = MapPosixError(socket_->GetError()); | |
273 if (result == net::ERR_IO_PENDING) { | |
274 read_callback_ = callback; | |
275 read_buffer_ = buf; | |
276 read_buffer_len_ = buf_len; | |
277 } | |
278 } | |
279 return result; | |
280 } | |
281 | |
282 int TransportSocket::Write(net::IOBuffer* buf, int buf_len, | |
283 net::CompletionCallback* callback) { | |
284 DCHECK(buf); | |
285 DCHECK(!write_callback_); | |
286 DCHECK(!write_buffer_.get()); | |
287 int result = socket_->Send(buf->data(), buf_len); | |
288 if (result < 0) { | |
289 result = MapPosixError(socket_->GetError()); | |
290 if (result == net::ERR_IO_PENDING) { | |
291 write_callback_ = callback; | |
292 write_buffer_ = buf; | |
293 write_buffer_len_ = buf_len; | |
294 } | |
295 } | |
296 return result; | |
297 } | |
298 | |
299 bool TransportSocket::SetReceiveBufferSize(int32 size) { | |
300 // Not implemented. | |
301 return false; | |
302 } | |
303 | |
304 bool TransportSocket::SetSendBufferSize(int32 size) { | |
305 // Not implemented. | |
306 return false; | |
307 } | |
308 | |
309 void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) { | |
310 if (read_callback_) { | |
311 DCHECK(read_buffer_.get()); | |
312 net::CompletionCallback* callback = read_callback_; | |
313 scoped_refptr<net::IOBuffer> buffer = read_buffer_; | |
314 int buffer_len = read_buffer_len_; | |
315 | |
316 read_callback_ = NULL; | |
317 read_buffer_ = NULL; | |
318 read_buffer_len_ = 0; | |
319 | |
320 int result = socket_->Recv(buffer->data(), buffer_len); | |
321 if (result < 0) { | |
322 result = MapPosixError(socket_->GetError()); | |
323 if (result == net::ERR_IO_PENDING) { | |
324 read_callback_ = callback; | |
325 read_buffer_ = buffer; | |
326 read_buffer_len_ = buffer_len; | |
327 return; | |
328 } | |
329 } | |
330 callback->RunWithParams(Tuple1<int>(result)); | |
331 } | |
332 } | |
333 | |
334 void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) { | |
335 if (write_callback_) { | |
336 DCHECK(write_buffer_.get()); | |
337 net::CompletionCallback* callback = write_callback_; | |
338 scoped_refptr<net::IOBuffer> buffer = write_buffer_; | |
339 int buffer_len = write_buffer_len_; | |
340 | |
341 write_callback_ = NULL; | |
342 write_buffer_ = NULL; | |
343 write_buffer_len_ = 0; | |
344 | |
345 int result = socket_->Send(buffer->data(), buffer_len); | |
346 if (result < 0) { | |
347 result = MapPosixError(socket_->GetError()); | |
348 if (result == net::ERR_IO_PENDING) { | |
349 write_callback_ = callback; | |
350 write_buffer_ = buffer; | |
351 write_buffer_len_ = buffer_len; | |
352 return; | |
353 } | |
354 } | |
355 callback->RunWithParams(Tuple1<int>(result)); | |
356 } | |
357 } | |
358 | |
359 } // namespace remoting | |
OLD | NEW |