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

Side by Side Diff: remoting/jingle_glue/ssl_socket_adapter.cc

Issue 10543069: Fix SSLSocketAdapter to handle asynchronous writes appropriately. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 months 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
« no previous file with comments | « remoting/jingle_glue/ssl_socket_adapter.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/jingle_glue/ssl_socket_adapter.h" 5 #include "remoting/jingle_glue/ssl_socket_adapter.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "jingle/glue/utils.h" 10 #include "jingle/glue/utils.h"
11 #include "net/base/address_list.h" 11 #include "net/base/address_list.h"
12 #include "net/base/cert_verifier.h" 12 #include "net/base/cert_verifier.h"
13 #include "net/base/host_port_pair.h" 13 #include "net/base/host_port_pair.h"
14 #include "net/base/net_errors.h" 14 #include "net/base/net_errors.h"
15 #include "net/base/ssl_config_service.h" 15 #include "net/base/ssl_config_service.h"
16 #include "net/socket/client_socket_factory.h" 16 #include "net/socket/client_socket_factory.h"
17 #include "net/url_request/url_request_context.h" 17 #include "net/url_request/url_request_context.h"
18 18
19 namespace remoting { 19 namespace remoting {
20 20
21 SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) { 21 SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
22 return new SSLSocketAdapter(socket); 22 return new SSLSocketAdapter(socket);
23 } 23 }
24 24
25 SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket) 25 SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
26 : SSLAdapter(socket), 26 : SSLAdapter(socket),
27 ignore_bad_cert_(false), 27 ignore_bad_cert_(false),
28 cert_verifier_(net::CertVerifier::CreateDefault()), 28 cert_verifier_(net::CertVerifier::CreateDefault()),
29 ssl_state_(SSLSTATE_NONE), 29 ssl_state_(SSLSTATE_NONE),
30 read_state_(IOSTATE_NONE), 30 read_pending_(false),
31 write_state_(IOSTATE_NONE), 31 write_pending_(false) {
32 data_transferred_(0) {
33 transport_socket_ = new TransportSocket(socket, this); 32 transport_socket_ = new TransportSocket(socket, this);
34 } 33 }
35 34
36 SSLSocketAdapter::~SSLSocketAdapter() { 35 SSLSocketAdapter::~SSLSocketAdapter() {
37 } 36 }
38 37
39 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { 38 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
40 DCHECK(!restartable); 39 DCHECK(!restartable);
41 hostname_ = hostname; 40 hostname_ = hostname;
42 41
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 75
77 if (result == net::ERR_IO_PENDING || result == net::OK) { 76 if (result == net::ERR_IO_PENDING || result == net::OK) {
78 return 0; 77 return 0;
79 } else { 78 } else {
80 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); 79 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result);
81 return result; 80 return result;
82 } 81 }
83 } 82 }
84 83
85 int SSLSocketAdapter::Send(const void* buf, size_t len) { 84 int SSLSocketAdapter::Send(const void* buf, size_t len) {
85 if (ssl_state_ == SSLSTATE_ERROR) {
86 SetError(EINVAL);
87 return -1;
88 }
89
86 if (ssl_state_ != SSLSTATE_CONNECTED) { 90 if (ssl_state_ != SSLSTATE_CONNECTED) {
91 // Propagate the call to underlying socket if SSL is not connected yet.
Wez 2012/06/13 00:48:57 This explains what you're doing, but not _why_? Wh
Sergey Ulanov 2012/06/13 01:30:31 XMPP connections are not encrypted until <starttls
87 return AsyncSocketAdapter::Send(buf, len); 92 return AsyncSocketAdapter::Send(buf, len);
88 } else { 93 }
89 scoped_refptr<net::IOBuffer> transport_buf(new net::IOBuffer(len));
90 memcpy(transport_buf->data(), buf, len);
91 94
92 int result = ssl_socket_->Write(transport_buf, len, 95 if (write_pending_) {
93 net::CompletionCallback()); 96 SetError(EWOULDBLOCK);
94 if (result == net::ERR_IO_PENDING) { 97 return -1;
95 SetError(EWOULDBLOCK);
96 }
97 transport_buf = NULL;
98 return result;
99 } 98 }
99
100 write_buffer_ = new net::DrainableIOBuffer(new net::IOBuffer(len), len);
101 memcpy(write_buffer_->data(), buf, len);
102
103 DoWrite();
104
105 return len;
100 } 106 }
101 107
102 int SSLSocketAdapter::Recv(void* buf, size_t len) { 108 int SSLSocketAdapter::Recv(void* buf, size_t len) {
103 switch (ssl_state_) { 109 switch (ssl_state_) {
104 case SSLSTATE_NONE: 110 case SSLSTATE_NONE: {
105 return AsyncSocketAdapter::Recv(buf, len); 111 return AsyncSocketAdapter::Recv(buf, len);
112 }
106 113
107 case SSLSTATE_WAIT: 114 case SSLSTATE_WAIT: {
108 SetError(EWOULDBLOCK); 115 SetError(EWOULDBLOCK);
109 return -1; 116 return -1;
117 }
110 118
111 case SSLSTATE_CONNECTED: 119 case SSLSTATE_CONNECTED: {
112 switch (read_state_) { 120 if (read_pending_) {
113 case IOSTATE_NONE: { 121 SetError(EWOULDBLOCK);
114 transport_buf_ = new net::IOBuffer(len); 122 return -1;
Wez 2012/06/13 00:48:57 nit: Define a constant for the error return-valie
Sergey Ulanov 2012/06/13 01:30:31 Don't think it is necessary. The current code is c
115 int result = ssl_socket_->Read( 123 }
116 transport_buf_, len,
117 base::Bind(&SSLSocketAdapter::OnRead, base::Unretained(this)));
118 if (result >= 0) {
119 memcpy(buf, transport_buf_->data(), len);
120 }
121 124
122 if (result == net::ERR_IO_PENDING) { 125 int bytes_read = 0;
123 read_state_ = IOSTATE_PENDING; 126
124 SetError(EWOULDBLOCK); 127 if (read_buffer_) {
Wez 2012/06/13 00:48:57 nit:Add a comment to clarify that this is the case
Sergey Ulanov 2012/06/13 01:30:31 Done.
125 } else { 128 int size = std::min(read_buffer_->RemainingCapacity(),
126 if (result < 0) { 129 static_cast<int>(len));
127 SetError(result); 130 memcpy(buf, read_buffer_->data(), size);
128 VLOG(1) << "Socket error " << result; 131 read_buffer_->set_offset(read_buffer_->offset() + size);
129 } 132 if (!read_buffer_->RemainingCapacity())
Wez 2012/06/13 00:48:57 nit: Inconsistent use of {} in ifs.
Sergey Ulanov 2012/06/13 01:30:31 It is consistent - all other single-line ifs in th
130 transport_buf_ = NULL; 133 read_buffer_ = NULL;
131 } 134
132 return result; 135 if (size == static_cast<int>(len))
Wez 2012/06/13 00:48:57 nit: Ditto
Sergey Ulanov 2012/06/13 01:30:31 Ditto
136 return size;
137
138 // If we haven't filled in the buffer with the data we had
139 // then try to read from again to fill in the buffer space we
140 // have left.
Wez 2012/06/13 00:48:57 nit: Suggest "If we didn't fill the caller's buffe
Sergey Ulanov 2012/06/13 01:30:31 Done.
141 buf = reinterpret_cast<char*>(buf) + size;
142 len -= size;
143 bytes_read = size;
144 DCHECK(!read_buffer_);
145 }
146
147 read_buffer_ = new net::GrowableIOBuffer();
148 read_buffer_->SetCapacity(len);
149 int result = ssl_socket_->Read(
150 read_buffer_, len,
151 base::Bind(&SSLSocketAdapter::OnRead, base::Unretained(this)));
Wez 2012/06/13 00:48:57 Add a comment before this block to clarify that th
Sergey Ulanov 2012/06/13 01:30:31 Done.
152 if (result >= 0)
Wez 2012/06/13 00:48:57 nit: Inconsistent use of {} on if
Sergey Ulanov 2012/06/13 01:30:31 It is consistent - all other single-line ifs in th
153 memcpy(buf, read_buffer_->data(), len);
154
155 if (result == net::ERR_IO_PENDING) {
156 read_pending_ = true;
157 SetError(EWOULDBLOCK);
158 return bytes_read ? bytes_read : -1;
159 } else {
Wez 2012/06/13 00:48:57 I don't think this needs to be in an else, since t
Sergey Ulanov 2012/06/13 01:30:31 Done.
160 if (result < 0) {
161 SetError(EINVAL);
162 ssl_state_ = SSLSTATE_ERROR;
163 LOG(ERROR) << "Error reading from SSL socket " << result;
164 return -1;
133 } 165 }
134 case IOSTATE_PENDING: 166 read_buffer_ = NULL;
135 SetError(EWOULDBLOCK); 167 }
136 return -1; 168 return result + bytes_read;
169 }
137 170
138 case IOSTATE_COMPLETE: 171 case SSLSTATE_ERROR: {
139 memcpy(buf, transport_buf_->data(), len); 172 SetError(EINVAL);
140 transport_buf_ = NULL; 173 return -1;
141 read_state_ = IOSTATE_NONE; 174 }
142 return data_transferred_;
143 }
144 } 175 }
145 176
146 NOTREACHED(); 177 NOTREACHED();
147 return -1; 178 return -1;
148 } 179 }
149 180
150 void SSLSocketAdapter::OnConnected(int result) { 181 void SSLSocketAdapter::OnConnected(int result) {
151 if (result == net::OK) { 182 if (result == net::OK) {
152 ssl_state_ = SSLSTATE_CONNECTED; 183 ssl_state_ = SSLSTATE_CONNECTED;
153 OnConnectEvent(this); 184 OnConnectEvent(this);
154 } else { 185 } else {
155 LOG(WARNING) << "OnConnected failed with error " << result; 186 LOG(WARNING) << "OnConnected failed with error " << result;
156 } 187 }
157 } 188 }
158 189
159 void SSLSocketAdapter::OnRead(int result) { 190 void SSLSocketAdapter::OnRead(int result) {
160 DCHECK(read_state_ == IOSTATE_PENDING); 191 DCHECK(read_pending_);
161 read_state_ = IOSTATE_COMPLETE; 192 read_pending_ = false;
162 data_transferred_ = result; 193 if (result > 0) {
194 DCHECK_GE(read_buffer_->capacity(), result);
195 read_buffer_->SetCapacity(result);
196 } else {
197 if (result < 0)
198 ssl_state_ = SSLSTATE_ERROR;
199 }
163 AsyncSocketAdapter::OnReadEvent(this); 200 AsyncSocketAdapter::OnReadEvent(this);
164 } 201 }
165 202
166 void SSLSocketAdapter::OnWrite(int result) { 203 void SSLSocketAdapter::OnWritten(int result) {
167 DCHECK(write_state_ == IOSTATE_PENDING); 204 DCHECK(write_pending_);
168 write_state_ = IOSTATE_COMPLETE; 205 write_pending_ = false;
169 data_transferred_ = result; 206 if (result >= 0) {
207 write_buffer_->DidConsume(result);
208 if (!write_buffer_->BytesRemaining()) {
209 write_buffer_ = NULL;
210 } else {
211 DoWrite();
212 }
213 } else {
214 ssl_state_ = SSLSTATE_ERROR;
215 }
170 AsyncSocketAdapter::OnWriteEvent(this); 216 AsyncSocketAdapter::OnWriteEvent(this);
171 } 217 }
172 218
219 void SSLSocketAdapter::DoWrite() {
220 DCHECK_GT(write_buffer_->BytesRemaining(), 0);
221 DCHECK(!write_pending_);
222
223 while (write_buffer_ && !write_pending_) {
Wez 2012/06/13 00:48:57 I'd suggest structuring this as a while (true) and
Sergey Ulanov 2012/06/13 01:30:31 Done.
224 int result = ssl_socket_->Write(
225 write_buffer_, write_buffer_->BytesRemaining(),
226 base::Bind(&SSLSocketAdapter::OnWritten, base::Unretained(this)));
227
228 if (result == net::ERR_IO_PENDING) {
229 write_pending_ = true;
230 } else if (result < 0) {
231 SetError(EINVAL);
232 ssl_state_ = SSLSTATE_ERROR;
233 } else {
234 write_buffer_->DidConsume(result);
235 if (!write_buffer_->BytesRemaining())
236 write_buffer_ = NULL;
237 }
238 }
239 }
240
173 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { 241 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) {
174 if (ssl_state_ != SSLSTATE_WAIT) { 242 if (ssl_state_ != SSLSTATE_WAIT) {
175 AsyncSocketAdapter::OnConnectEvent(socket); 243 AsyncSocketAdapter::OnConnectEvent(socket);
176 } else { 244 } else {
177 ssl_state_ = SSLSTATE_NONE; 245 ssl_state_ = SSLSTATE_NONE;
178 int result = BeginSSL(); 246 int result = BeginSSL();
179 if (0 != result) { 247 if (0 != result) {
180 // TODO(zork): Handle this case gracefully. 248 // TODO(zork): Handle this case gracefully.
181 LOG(WARNING) << "BeginSSL() failed with " << result; 249 LOG(WARNING) << "BeginSSL() failed with " << result;
182 } 250 }
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 write_buffer_len_ = buffer_len; 434 write_buffer_len_ = buffer_len;
367 return; 435 return;
368 } 436 }
369 } 437 }
370 was_used_to_convey_data_ = true; 438 was_used_to_convey_data_ = true;
371 callback.Run(result); 439 callback.Run(result);
372 } 440 }
373 } 441 }
374 442
375 } // namespace remoting 443 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/jingle_glue/ssl_socket_adapter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698