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

Side by Side Diff: webrtc/base/openssladapter.cc

Issue 2915243002: Fixing SSL error that occurs when underlying socket is blocked. (Closed)
Patch Set: Created 3 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
OLDNEW
1 /* 1 /*
2 * Copyright 2008 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2008 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 327
328 ssl_ = SSL_new(ssl_ctx_); 328 ssl_ = SSL_new(ssl_ctx_);
329 if (!ssl_) { 329 if (!ssl_) {
330 err = -1; 330 err = -1;
331 goto ssl_error; 331 goto ssl_error;
332 } 332 }
333 333
334 SSL_set_app_data(ssl_, this); 334 SSL_set_app_data(ssl_, this);
335 335
336 SSL_set_bio(ssl_, bio, bio); 336 SSL_set_bio(ssl_, bio, bio);
337 // SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER allows different buffers to be passed
338 // into SSL_write when a record could only be partially transmitted (and thus
339 // requires another call to SSL_write to finish transmission). This allows us
340 // to copy the data into our own buffer when this occurs, since the original
341 // buffer can't safely be accessed after control exits Send.
337 SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE | 342 SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE |
338 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); 343 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
juberti1 2017/06/02 05:35:44 From the chat with davidben, I'm not sure we want
Taylor Brandstetter 2017/06/02 06:49:13 Probably. But it's unrelated to this CL so I'll le
339 344
340 // the SSL object owns the bio now 345 // the SSL object owns the bio now
341 bio = nullptr; 346 bio = nullptr;
342 347
343 // Do the connect 348 // Do the connect
344 err = ContinueSSL(); 349 err = ContinueSSL();
345 if (err != 0) 350 if (err != 0)
346 goto ssl_error; 351 goto ssl_error;
347 352
348 return err; 353 return err;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 if (signal) 422 if (signal)
418 AsyncSocketAdapter::OnCloseEvent(this, err); 423 AsyncSocketAdapter::OnCloseEvent(this, err);
419 } 424 }
420 425
421 void 426 void
422 OpenSSLAdapter::Cleanup() { 427 OpenSSLAdapter::Cleanup() {
423 LOG(LS_INFO) << "Cleanup"; 428 LOG(LS_INFO) << "Cleanup";
424 429
425 state_ = SSL_NONE; 430 state_ = SSL_NONE;
426 ssl_read_needs_write_ = false; 431 ssl_read_needs_write_ = false;
427 ssl_write_needs_read_ = false; 432 ssl_write_needs_read_ = false;
pthatcher1 2017/06/02 04:58:21 Should this also clear pending_write_ and pending_
Taylor Brandstetter 2017/06/02 06:49:13 I'll do it for consistency, but I don't see a way
428 custom_verification_succeeded_ = false; 433 custom_verification_succeeded_ = false;
429 434
430 if (ssl_) { 435 if (ssl_) {
431 SSL_free(ssl_); 436 SSL_free(ssl_);
432 ssl_ = nullptr; 437 ssl_ = nullptr;
433 } 438 }
434 439
435 if (ssl_ctx_) { 440 if (ssl_ctx_) {
436 SSL_CTX_free(ssl_ctx_); 441 SSL_CTX_free(ssl_ctx_);
437 ssl_ctx_ = nullptr; 442 ssl_ctx_ = nullptr;
438 } 443 }
439 444
440 // Clear the DTLS timer 445 // Clear the DTLS timer
441 Thread::Current()->Clear(this, MSG_TIMEOUT); 446 Thread::Current()->Clear(this, MSG_TIMEOUT);
442 } 447 }
443 448
449 int OpenSSLAdapter::DoSslWrite(const void* pv, size_t cb) {
450 // If we're in "pending write" mode, we should only be calling SSL_write with
451 // the pending data.
452 RTC_DCHECK(!pending_write_ || pv == pending_data_.data());
453
454 ssl_write_needs_read_ = false;
455 int ret = SSL_write(ssl_, pv, checked_cast<int>(cb));
456 int error = SSL_get_error(ssl_, ret);
457 switch (error) {
458 case SSL_ERROR_SSL:
459 // Walk down the error stack to find the SSL error.
460 uint32_t error_code;
juberti1 2017/06/02 05:35:44 This feels like it should be factored into a funct
Taylor Brandstetter 2017/06/02 06:49:13 Done.
461 const char* file;
462 int line;
463 do {
464 error_code = ERR_get_error_line(&file, &line);
465 if (ERR_GET_LIB(error_code) == ERR_LIB_SSL) {
466 LOG(LS_ERROR) << "ERR_LIB_SSL: " << error_code << ", " << file << ":"
467 << line;
468 break;
469 }
470 } while (error_code != 0);
471 Error("SSL_write", ret ? ret : -1, false);
472 break;
473 case SSL_ERROR_NONE:
474 // Success!
juberti1 2017/06/02 05:35:44 Maybe this case should come first?
Taylor Brandstetter 2017/06/02 06:49:13 Done.
475 return ret;
476 case SSL_ERROR_WANT_READ:
477 LOG(LS_INFO) << " -- error want read";
478 ssl_write_needs_read_ = true;
479 SetError(EWOULDBLOCK);
480 break;
481 case SSL_ERROR_WANT_WRITE:
482 LOG(LS_INFO) << " -- error want write";
483 SetError(EWOULDBLOCK);
484 break;
485 case SSL_ERROR_ZERO_RETURN:
486 // LOG(LS_INFO) << " -- remote side closed";
487 SetError(EWOULDBLOCK);
488 // do we need to signal closure?
489 break;
490 default:
491 LOG(LS_WARNING) << "Unknown error from SSL_write: " << error;
492 Error("SSL_write", ret ? ret : -1, false);
493 break;
494 }
495
496 // If SSL_write fails with SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, this
497 // means the underlying socket is blocked on reading or (more typically)
498 // writing. When this happens, OpenSSL requires that the next call to
499 // SSL_write uses the same arguments (though, with
500 // SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, the actual buffer pointer may be
501 // different).
502 //
503 // However, after Send exits, we will have lost access to data the user of
504 // this class is trying to send, and there's no guarantee that the user of
505 // this class will call Send with the same arguements when it fails. So, we
506 // buffer the data ourselves. When we know the underlying socket is writable
507 // again from OnWriteEvent (or if Send is called again before that happens),
508 // we'll retry sending this buffered data.
509 if ((error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) &&
juberti1 2017/06/02 05:35:43 It seems like this should be a low-level routine -
Taylor Brandstetter 2017/06/02 06:49:13 Ok. Somehow the fact that the write failed due to
510 !pending_write_) {
511 LOG(LS_WARNING)
512 << "SSL_write couldn't write to the underlying socket; buffering data.";
513 pending_write_ = true;
514 pending_data_.SetData(static_cast<const uint8_t*>(pv), cb);
515 // Since we're taking responsibility for sending this data, return its full
516 // size. The user of this class can consider it sent.
517 return cb;
518 }
519
520 return SOCKET_ERROR;
521 }
522
444 // 523 //
445 // AsyncSocket Implementation 524 // AsyncSocket Implementation
446 // 525 //
447 526
448 int 527 int
449 OpenSSLAdapter::Send(const void* pv, size_t cb) { 528 OpenSSLAdapter::Send(const void* pv, size_t cb) {
450 //LOG(LS_INFO) << "OpenSSLAdapter::Send(" << cb << ")"; 529 //LOG(LS_INFO) << "OpenSSLAdapter::Send(" << cb << ")";
451 530
452 switch (state_) { 531 switch (state_) {
453 case SSL_NONE: 532 case SSL_NONE:
454 return AsyncSocketAdapter::Send(pv, cb); 533 return AsyncSocketAdapter::Send(pv, cb);
455 534
456 case SSL_WAIT: 535 case SSL_WAIT:
457 case SSL_CONNECTING: 536 case SSL_CONNECTING:
458 SetError(ENOTCONN); 537 SetError(ENOTCONN);
459 return SOCKET_ERROR; 538 return SOCKET_ERROR;
460 539
461 case SSL_CONNECTED: 540 case SSL_CONNECTED:
462 break; 541 break;
463 542
464 case SSL_ERROR: 543 case SSL_ERROR:
465 default: 544 default:
466 return SOCKET_ERROR; 545 return SOCKET_ERROR;
467 } 546 }
468 547
548 if (pending_write_) {
549 int ret = DoSslWrite(pending_data_.data(), pending_data_.size());
550 if (ret == static_cast<int>(pending_data_.size())) {
551 // We completed sending the data previously passed into SSL_write! Now
552 // we're allowed to send more data.
553 pending_write_ = false;
554 } else {
555 // We couldn't finish sending the pending data, so we definitely can't
556 // send any more data. Return with an EWOULDBLOCK error.
557 SetError(EWOULDBLOCK);
558 return -1;
pthatcher1 2017/06/02 04:58:21 return SOCKET_ERROR or just: return ret;
Taylor Brandstetter 2017/06/02 06:49:13 Done.
559 }
pthatcher1 2017/06/02 04:58:21 Might be more clear with an early return: if (pen
Taylor Brandstetter 2017/06/02 06:49:13 I don't like "MaybeRetrySslWrite" because it's not
560 }
561
469 // OpenSSL will return an error if we try to write zero bytes 562 // OpenSSL will return an error if we try to write zero bytes
470 if (cb == 0) 563 if (cb == 0)
471 return 0; 564 return 0;
472 565
473 ssl_write_needs_read_ = false; 566 return DoSslWrite(pv, cb);
474
475 int code = SSL_write(ssl_, pv, checked_cast<int>(cb));
476 switch (SSL_get_error(ssl_, code)) {
477 case SSL_ERROR_NONE:
478 //LOG(LS_INFO) << " -- success";
479 return code;
480 case SSL_ERROR_WANT_READ:
481 //LOG(LS_INFO) << " -- error want read";
482 ssl_write_needs_read_ = true;
483 SetError(EWOULDBLOCK);
484 break;
485 case SSL_ERROR_WANT_WRITE:
486 //LOG(LS_INFO) << " -- error want write";
487 SetError(EWOULDBLOCK);
488 break;
489 case SSL_ERROR_ZERO_RETURN:
490 //LOG(LS_INFO) << " -- remote side closed";
491 SetError(EWOULDBLOCK);
492 // do we need to signal closure?
493 break;
494 default:
495 //LOG(LS_INFO) << " -- error " << code;
496 Error("SSL_write", (code ? code : -1), false);
497 break;
498 }
499
500 return SOCKET_ERROR;
501 } 567 }
502 568
503 int 569 int
504 OpenSSLAdapter::SendTo(const void* pv, size_t cb, const SocketAddress& addr) { 570 OpenSSLAdapter::SendTo(const void* pv, size_t cb, const SocketAddress& addr) {
505 if (socket_->GetState() == Socket::CS_CONNECTED && 571 if (socket_->GetState() == Socket::CS_CONNECTED &&
506 addr == socket_->GetRemoteAddress()) { 572 addr == socket_->GetRemoteAddress()) {
507 return Send(pv, cb); 573 return Send(pv, cb);
508 } 574 }
509 575
510 SetError(ENOTCONN); 576 SetError(ENOTCONN);
(...skipping 24 matching lines...) Expand all
535 // Don't trust OpenSSL with zero byte reads 601 // Don't trust OpenSSL with zero byte reads
536 if (cb == 0) 602 if (cb == 0)
537 return 0; 603 return 0;
538 604
539 ssl_read_needs_write_ = false; 605 ssl_read_needs_write_ = false;
540 606
541 int code = SSL_read(ssl_, pv, checked_cast<int>(cb)); 607 int code = SSL_read(ssl_, pv, checked_cast<int>(cb));
542 switch (SSL_get_error(ssl_, code)) { 608 switch (SSL_get_error(ssl_, code)) {
543 case SSL_ERROR_NONE: 609 case SSL_ERROR_NONE:
544 //LOG(LS_INFO) << " -- success"; 610 //LOG(LS_INFO) << " -- success";
545 return code; 611 return code;
pthatcher1 2017/06/02 04:58:21 Should we check for SSL_ERROR_SSL here as well?
Taylor Brandstetter 2017/06/02 06:49:13 Done.
546 case SSL_ERROR_WANT_READ: 612 case SSL_ERROR_WANT_READ:
547 //LOG(LS_INFO) << " -- error want read"; 613 //LOG(LS_INFO) << " -- error want read";
548 SetError(EWOULDBLOCK); 614 SetError(EWOULDBLOCK);
549 break; 615 break;
550 case SSL_ERROR_WANT_WRITE: 616 case SSL_ERROR_WANT_WRITE:
551 //LOG(LS_INFO) << " -- error want write"; 617 //LOG(LS_INFO) << " -- error want write";
552 ssl_read_needs_write_ = true; 618 ssl_read_needs_write_ = true;
553 SetError(EWOULDBLOCK); 619 SetError(EWOULDBLOCK);
554 break; 620 break;
555 case SSL_ERROR_ZERO_RETURN: 621 case SSL_ERROR_ZERO_RETURN:
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 return; 741 return;
676 742
677 // Don't let ourselves go away during the callbacks 743 // Don't let ourselves go away during the callbacks
678 //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this 744 //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this
679 745
680 if (ssl_read_needs_write_) { 746 if (ssl_read_needs_write_) {
681 //LOG(LS_INFO) << " -- onStreamReadable"; 747 //LOG(LS_INFO) << " -- onStreamReadable";
682 AsyncSocketAdapter::OnReadEvent(socket); 748 AsyncSocketAdapter::OnReadEvent(socket);
683 } 749 }
684 750
751 // If a previous SSL_write failed due to the underlying socket being blocked,
752 // this will attempt finishing the write operation.
753 if (pending_write_) {
754 if (DoSslWrite(pending_data_.data(), pending_data_.size()) ==
755 static_cast<int>(pending_data_.size())) {
756 pending_write_ = false;
pthatcher1 2017/06/02 04:58:21 Shouldn't we clear the pending_data_?
Taylor Brandstetter 2017/06/02 06:49:13 Would have been pointless before, but since I got
757 }
758 }
pthatcher1 2017/06/02 04:58:21 With the helper method, this could just be: Maybe
759
685 //LOG(LS_INFO) << " -- onStreamWriteable"; 760 //LOG(LS_INFO) << " -- onStreamWriteable";
686 AsyncSocketAdapter::OnWriteEvent(socket); 761 AsyncSocketAdapter::OnWriteEvent(socket);
687 } 762 }
688 763
689 void 764 void
690 OpenSSLAdapter::OnCloseEvent(AsyncSocket* socket, int err) { 765 OpenSSLAdapter::OnCloseEvent(AsyncSocket* socket, int err) {
691 LOG(LS_INFO) << "OpenSSLAdapter::OnCloseEvent(" << err << ")"; 766 LOG(LS_INFO) << "OpenSSLAdapter::OnCloseEvent(" << err << ")";
692 AsyncSocketAdapter::OnCloseEvent(socket, err); 767 AsyncSocketAdapter::OnCloseEvent(socket, err);
693 } 768 }
694 769
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); 981 SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
907 982
908 if (ssl_mode_ == SSL_MODE_DTLS) { 983 if (ssl_mode_ == SSL_MODE_DTLS) {
909 SSL_CTX_set_read_ahead(ctx, 1); 984 SSL_CTX_set_read_ahead(ctx, 1);
910 } 985 }
911 986
912 return ctx; 987 return ctx;
913 } 988 }
914 989
915 } // namespace rtc 990 } // namespace rtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698