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

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"
(...skipping 10 matching lines...) Expand all
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_state_(IOSTATE_NONE),
31 write_state_(IOSTATE_NONE), 31 read_buffer_size_(0),
32 data_transferred_(0) { 32 read_buffer_position_(0),
33 write_state_(IOSTATE_NONE) {
33 transport_socket_ = new TransportSocket(socket, this); 34 transport_socket_ = new TransportSocket(socket, this);
34 } 35 }
35 36
36 SSLSocketAdapter::~SSLSocketAdapter() { 37 SSLSocketAdapter::~SSLSocketAdapter() {
37 } 38 }
38 39
39 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) { 40 int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
40 DCHECK(!restartable); 41 DCHECK(!restartable);
41 hostname_ = hostname; 42 hostname_ = hostname;
42 43
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 77
77 if (result == net::ERR_IO_PENDING || result == net::OK) { 78 if (result == net::ERR_IO_PENDING || result == net::OK) {
78 return 0; 79 return 0;
79 } else { 80 } else {
80 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result); 81 LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result);
81 return result; 82 return result;
82 } 83 }
83 } 84 }
84 85
85 int SSLSocketAdapter::Send(const void* buf, size_t len) { 86 int SSLSocketAdapter::Send(const void* buf, size_t len) {
86 if (ssl_state_ != SSLSTATE_CONNECTED) { 87 if (ssl_state_ == SSLSTATE_ERROR) {
88 SetError(EINVAL);
Wez 2012/06/11 21:21:35 You're avoiding just returning whatever error caus
Sergey Ulanov 2012/06/11 23:06:39 Correct. Send() returns one of the error codes def
89 return -1;
90 } else if (ssl_state_ != SSLSTATE_CONNECTED) {
Wez 2012/06/11 21:21:35 nit: Using "else" here makes this harder to read.
Sergey Ulanov 2012/06/11 23:06:39 Done.
87 return AsyncSocketAdapter::Send(buf, len); 91 return AsyncSocketAdapter::Send(buf, len);
Wez 2012/06/11 21:21:35 Add a comment to explain why we propagate the Send
Sergey Ulanov 2012/06/11 23:06:39 Done.
88 } else { 92 }
89 scoped_refptr<net::IOBuffer> transport_buf(new net::IOBuffer(len));
90 memcpy(transport_buf->data(), buf, len);
91 93
92 int result = ssl_socket_->Write(transport_buf, len, 94 if (write_state_ == IOSTATE_PENDING) {
93 net::CompletionCallback()); 95 SetError(EWOULDBLOCK);
94 if (result == net::ERR_IO_PENDING) { 96 return -1;
95 SetError(EWOULDBLOCK);
96 }
97 transport_buf = NULL;
98 return result;
99 } 97 }
98
99 write_buffer_ = new net::DrainableIOBuffer(new net::IOBuffer(len), len);
100 memcpy(write_buffer_->data(), buf, len);
101
102 DoWrite();
103
104 return len;
100 } 105 }
101 106
102 int SSLSocketAdapter::Recv(void* buf, size_t len) { 107 int SSLSocketAdapter::Recv(void* buf, size_t len) {
103 switch (ssl_state_) { 108 switch (ssl_state_) {
104 case SSLSTATE_NONE: 109 case SSLSTATE_NONE:
105 return AsyncSocketAdapter::Recv(buf, len); 110 return AsyncSocketAdapter::Recv(buf, len);
106 111
107 case SSLSTATE_WAIT: 112 case SSLSTATE_WAIT:
108 SetError(EWOULDBLOCK); 113 SetError(EWOULDBLOCK);
109 return -1; 114 return -1;
110 115
111 case SSLSTATE_CONNECTED: 116 case SSLSTATE_CONNECTED:
112 switch (read_state_) { 117 switch (read_state_) {
113 case IOSTATE_NONE: { 118 case IOSTATE_NONE: {
114 transport_buf_ = new net::IOBuffer(len); 119 read_buffer_ = new net::IOBuffer(len);
115 int result = ssl_socket_->Read( 120 int result = ssl_socket_->Read(
116 transport_buf_, len, 121 read_buffer_, len,
117 base::Bind(&SSLSocketAdapter::OnRead, base::Unretained(this))); 122 base::Bind(&SSLSocketAdapter::OnRead, base::Unretained(this)));
118 if (result >= 0) { 123 if (result >= 0) {
119 memcpy(buf, transport_buf_->data(), len); 124 memcpy(buf, read_buffer_->data(), len);
120 } 125 }
121 126
122 if (result == net::ERR_IO_PENDING) { 127 if (result == net::ERR_IO_PENDING) {
123 read_state_ = IOSTATE_PENDING; 128 read_state_ = IOSTATE_PENDING;
124 SetError(EWOULDBLOCK); 129 SetError(EWOULDBLOCK);
125 } else { 130 } else {
126 if (result < 0) { 131 if (result < 0) {
127 SetError(result); 132 SetError(EINVAL);
128 VLOG(1) << "Socket error " << result; 133 ssl_state_ = SSLSTATE_ERROR;
134 LOG(ERROR) << "Error when reading from SSL socket " << result;
Wez 2012/06/11 21:21:35 nit: not need for "when" here
Sergey Ulanov 2012/06/11 23:06:39 Done.
129 } 135 }
130 transport_buf_ = NULL; 136 read_buffer_ = NULL;
131 } 137 }
132 return result; 138 return result;
133 } 139 }
134 case IOSTATE_PENDING: 140 case IOSTATE_PENDING:
135 SetError(EWOULDBLOCK); 141 SetError(EWOULDBLOCK);
136 return -1; 142 return -1;
137 143
138 case IOSTATE_COMPLETE: 144 case IOSTATE_COMPLETE:
139 memcpy(buf, transport_buf_->data(), len); 145 int size = std::min(read_buffer_size_ - read_buffer_position_,
140 transport_buf_ = NULL; 146 static_cast<int>(len));
Wez 2012/06/11 21:21:35 You'll need {} in this case, since you're declarin
Wez 2012/06/11 21:21:35 nit: If len > read_buffer_size_ - read_buffer_posi
Sergey Ulanov 2012/06/11 23:06:39 Done.
141 read_state_ = IOSTATE_NONE; 147 memcpy(buf, read_buffer_->data() + read_buffer_position_, size);
142 return data_transferred_; 148 read_buffer_position_ += size;
Wez 2012/06/11 21:21:35 Why use a buffer position rather than creating a D
Sergey Ulanov 2012/06/11 23:06:39 Drainable buffer doesn't allow truncating it. Repl
149 if (read_buffer_position_ == read_buffer_size_) {
150 read_buffer_ = NULL;
151 read_state_ = IOSTATE_NONE;
152 }
153 return size;
143 } 154 }
155
156 case SSLSTATE_ERROR:
157 SetError(EINVAL);
158 return -1;
144 } 159 }
145 160
146 NOTREACHED(); 161 NOTREACHED();
147 return -1; 162 return -1;
148 } 163 }
149 164
150 void SSLSocketAdapter::OnConnected(int result) { 165 void SSLSocketAdapter::OnConnected(int result) {
151 if (result == net::OK) { 166 if (result == net::OK) {
152 ssl_state_ = SSLSTATE_CONNECTED; 167 ssl_state_ = SSLSTATE_CONNECTED;
153 OnConnectEvent(this); 168 OnConnectEvent(this);
154 } else { 169 } else {
155 LOG(WARNING) << "OnConnected failed with error " << result; 170 LOG(WARNING) << "OnConnected failed with error " << result;
156 } 171 }
157 } 172 }
158 173
159 void SSLSocketAdapter::OnRead(int result) { 174 void SSLSocketAdapter::OnRead(int result) {
160 DCHECK(read_state_ == IOSTATE_PENDING); 175 DCHECK(read_state_ == IOSTATE_PENDING);
161 read_state_ = IOSTATE_COMPLETE; 176 if (result > 0) {
162 data_transferred_ = result; 177 read_state_ = IOSTATE_COMPLETE;
178 read_buffer_size_ = result;
179 read_buffer_position_ = 0;
180 } else {
181 read_state_ = IOSTATE_NONE;
182 if (result < 0) {
183 ssl_state_ = SSLSTATE_ERROR;
Wez 2012/06/11 21:21:35 nit: It's confusing that you have read_state_, wri
Sergey Ulanov 2012/06/11 23:06:39 Repalaced write_state_ and read_state_ with write_
184 }
185 }
163 AsyncSocketAdapter::OnReadEvent(this); 186 AsyncSocketAdapter::OnReadEvent(this);
164 } 187 }
165 188
166 void SSLSocketAdapter::OnWrite(int result) { 189 void SSLSocketAdapter::OnWritten(int result) {
167 DCHECK(write_state_ == IOSTATE_PENDING); 190 DCHECK(write_state_ == IOSTATE_PENDING);
168 write_state_ = IOSTATE_COMPLETE; 191 write_state_ = IOSTATE_COMPLETE;
169 data_transferred_ = result; 192 if (result >= 0) {
193 write_buffer_->DidConsume(result);
194 if (!write_buffer_->BytesRemaining()) {
195 write_buffer_ = NULL;
196 } else {
197 DoWrite();
198 }
199 } else {
200 ssl_state_ = SSLSTATE_ERROR;
201 }
170 AsyncSocketAdapter::OnWriteEvent(this); 202 AsyncSocketAdapter::OnWriteEvent(this);
171 } 203 }
172 204
205 void SSLSocketAdapter::DoWrite() {
206 DCHECK_GT(write_buffer_->BytesRemaining(), 0);
Wez 2012/06/11 21:21:35 nit: DCHECK |write_state_| is not IO_PENDING?
Sergey Ulanov 2012/06/11 23:06:39 Done.
207 int result = ssl_socket_->Write(
208 write_buffer_, write_buffer_->BytesRemaining(),
209 base::Bind(&SSLSocketAdapter::OnWritten, base::Unretained(this)));
210
211 if (result == net::ERR_IO_PENDING) {
212 write_state_ = IOSTATE_PENDING;
213 } else if (result < 0) {
214 SetError(EINVAL);
215 ssl_state_ = SSLSTATE_ERROR;
216 } else {
217 write_buffer_ = NULL;
218 }
219 }
220
173 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) { 221 void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) {
174 if (ssl_state_ != SSLSTATE_WAIT) { 222 if (ssl_state_ != SSLSTATE_WAIT) {
175 AsyncSocketAdapter::OnConnectEvent(socket); 223 AsyncSocketAdapter::OnConnectEvent(socket);
176 } else { 224 } else {
177 ssl_state_ = SSLSTATE_NONE; 225 ssl_state_ = SSLSTATE_NONE;
178 int result = BeginSSL(); 226 int result = BeginSSL();
179 if (0 != result) { 227 if (0 != result) {
180 // TODO(zork): Handle this case gracefully. 228 // TODO(zork): Handle this case gracefully.
181 LOG(WARNING) << "BeginSSL() failed with " << result; 229 LOG(WARNING) << "BeginSSL() failed with " << result;
182 } 230 }
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 write_buffer_len_ = buffer_len; 416 write_buffer_len_ = buffer_len;
369 return; 417 return;
370 } 418 }
371 } 419 }
372 was_used_to_convey_data_ = true; 420 was_used_to_convey_data_ = true;
373 callback.Run(result); 421 callback.Run(result);
374 } 422 }
375 } 423 }
376 424
377 } // namespace remoting 425 } // 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