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

Side by Side Diff: sdk/lib/io/secure_socket.dart

Issue 16858011: dart:io | Enable multithreaded secure networking encryption. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove unrelated changes to tests and carryOver parameter. Created 7 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.io; 5 part of dart.io;
6 6
7 /** 7 /**
8 * A high-level class for communicating securely over a TCP socket, using 8 * A high-level class for communicating securely over a TCP socket, using
9 * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an 9 * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
10 * [IOSink] interface, making it ideal for using together with 10 * [IOSink] interface, making it ideal for using together with
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 final String subject; 336 final String subject;
337 final String issuer; 337 final String issuer;
338 final DateTime startValidity; 338 final DateTime startValidity;
339 final DateTime endValidity; 339 final DateTime endValidity;
340 } 340 }
341 341
342 342
343 class _RawSecureSocket extends Stream<RawSocketEvent> 343 class _RawSecureSocket extends Stream<RawSocketEvent>
344 implements RawSecureSocket { 344 implements RawSecureSocket {
345 // Status states 345 // Status states
346 static final int NOT_CONNECTED = 200;
347 static final int HANDSHAKE = 201; 346 static final int HANDSHAKE = 201;
348 static final int CONNECTED = 202; 347 static final int CONNECTED = 202;
349 static final int CLOSED = 203; 348 static final int CLOSED = 203;
350 349
351 // Buffer identifiers. 350 // Buffer identifiers.
352 // These must agree with those in the native C++ implementation. 351 // These must agree with those in the native C++ implementation.
353 static final int READ_PLAINTEXT = 0; 352 static final int READ_PLAINTEXT = 0;
354 static final int WRITE_PLAINTEXT = 1; 353 static final int WRITE_PLAINTEXT = 1;
355 static final int READ_ENCRYPTED = 2; 354 static final int READ_ENCRYPTED = 2;
356 static final int WRITE_ENCRYPTED = 3; 355 static final int WRITE_ENCRYPTED = 3;
357 static final int NUM_BUFFERS = 4; 356 static final int NUM_BUFFERS = 4;
358 357
358 // Is a buffer identifier for an encrypted buffer?
359 static bool isEncrypted(int identifier) => identifier >= READ_ENCRYPTED;
Anders Johnsen 2013/06/14 06:54:41 isBufferEncrypted
Bill Hesse 2013/06/14 08:55:02 Changed to _isBufferEncrypted
360
359 RawSocket _socket; 361 RawSocket _socket;
360 final Completer<_RawSecureSocket> _handshakeComplete = 362 final Completer<_RawSecureSocket> _handshakeComplete =
361 new Completer<_RawSecureSocket>(); 363 new Completer<_RawSecureSocket>();
362 StreamController<RawSocketEvent> _controller; 364 StreamController<RawSocketEvent> _controller;
363 Stream<RawSocketEvent> _stream; 365 Stream<RawSocketEvent> _stream;
364 StreamSubscription<RawSocketEvent> _socketSubscription; 366 StreamSubscription<RawSocketEvent> _socketSubscription;
365 List<int> _carryOverData; 367 List<int> _carryOverData;
366 int _carryOverDataIndex = 0; 368 int _carryOverDataIndex = 0;
367 final InternetAddress address; 369 final InternetAddress address;
368 final bool is_server; 370 final bool is_server;
369 final String certificateName; 371 final String certificateName;
370 final bool requestClientCertificate; 372 final bool requestClientCertificate;
371 final bool requireClientCertificate; 373 final bool requireClientCertificate;
372 final bool sendClientCertificate; 374 final bool sendClientCertificate;
373 final Function onBadCertificate; 375 final Function onBadCertificate;
374 376
375 var _status = NOT_CONNECTED; 377 var _status = HANDSHAKE;
376 bool _writeEventsEnabled = true; 378 bool _writeEventsEnabled = true;
377 bool _readEventsEnabled = true; 379 bool _readEventsEnabled = true;
380 int _pauseCount = 0;
381 bool _pendingReadEvent = false;
378 bool _socketClosedRead = false; // The network socket is closed for reading. 382 bool _socketClosedRead = false; // The network socket is closed for reading.
379 bool _socketClosedWrite = false; // The network socket is closed for writing. 383 bool _socketClosedWrite = false; // The network socket is closed for writing.
380 bool _closedRead = false; // The secure socket has fired an onClosed event. 384 bool _closedRead = false; // The secure socket has fired an onClosed event.
381 bool _closedWrite = false; // The secure socket has been closed for writing. 385 bool _closedWrite = false; // The secure socket has been closed for writing.
382 bool _filterReadEmpty = true; // There is no buffered data to read. 386 bool _readEmpty = true; // There is no buffered data to read.
383 bool _filterWriteEmpty = true; // There is no buffered data to be written. 387 bool _writeEmpty = true; // There is no buffered data to be written.
384 bool _connectPending = false; 388 bool _connectPending = false;
389 bool _filterPending = false;
390 bool _filterActive = false;
391
385 _SecureFilter _secureFilter = new _SecureFilter(); 392 _SecureFilter _secureFilter = new _SecureFilter();
393 int _filterPointer;
394 SendPort _filterService;
386 395
387 static Future<_RawSecureSocket> connect( 396 static Future<_RawSecureSocket> connect(
388 host, 397 host,
389 int requestedPort, 398 int requestedPort,
390 String certificateName, 399 String certificateName,
391 {bool is_server, 400 {bool is_server,
392 RawSocket socket, 401 RawSocket socket,
393 StreamSubscription subscription, 402 StreamSubscription subscription,
394 List<int> carryOverData, 403 List<int> carryOverData,
395 bool requestClientCertificate: false, 404 bool requestClientCertificate: false,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 sync: true, 443 sync: true,
435 onListen: _onSubscriptionStateChange, 444 onListen: _onSubscriptionStateChange,
436 onPause: _onPauseStateChange, 445 onPause: _onPauseStateChange,
437 onResume: _onPauseStateChange, 446 onResume: _onPauseStateChange,
438 onCancel: _onSubscriptionStateChange); 447 onCancel: _onSubscriptionStateChange);
439 _stream = _controller.stream; 448 _stream = _controller.stream;
440 // Throw an ArgumentError if any field is invalid. After this, all 449 // Throw an ArgumentError if any field is invalid. After this, all
441 // errors will be reported through the future or the stream. 450 // errors will be reported through the future or the stream.
442 _verifyFields(); 451 _verifyFields();
443 _secureFilter.init(); 452 _secureFilter.init();
444 if (_carryOverData != null) _readFromCarryOver(); 453 _filterPointer = _secureFilter._pointer();
445 _secureFilter.registerHandshakeCompleteCallback( 454 _secureFilter.registerHandshakeCompleteCallback(
446 _secureHandshakeCompleteHandler); 455 _secureHandshakeCompleteHandler);
447 if (onBadCertificate != null) { 456 if (onBadCertificate != null) {
448 _secureFilter.registerBadCertificateCallback(onBadCertificate); 457 _secureFilter.registerBadCertificateCallback(onBadCertificate);
449 } 458 }
450 var futureSocket; 459 var futureSocket;
451 if (socket == null) { 460 if (socket == null) {
452 futureSocket = RawSocket.connect(address, requestedPort); 461 futureSocket = RawSocket.connect(address, requestedPort);
453 } else { 462 } else {
454 futureSocket = new Future.value(socket); 463 futureSocket = new Future.value(socket);
(...skipping 15 matching lines...) Expand all
470 } 479 }
471 _connectPending = true; 480 _connectPending = true;
472 _secureFilter.connect(address.host, 481 _secureFilter.connect(address.host,
473 port, 482 port,
474 is_server, 483 is_server,
475 certificateName, 484 certificateName,
476 requestClientCertificate || 485 requestClientCertificate ||
477 requireClientCertificate, 486 requireClientCertificate,
478 requireClientCertificate, 487 requireClientCertificate,
479 sendClientCertificate); 488 sendClientCertificate);
480 _status = HANDSHAKE;
481 _secureHandshake(); 489 _secureHandshake();
482 }) 490 })
483 .catchError((error) { 491 .catchError((error) {
484 _handshakeComplete.completeError(error); 492 _handshakeComplete.completeError(error);
485 _close(); 493 _close();
486 }); 494 });
487 } 495 }
488 496
489 StreamSubscription listen(void onData(RawSocketEvent data), 497 StreamSubscription listen(void onData(RawSocketEvent data),
490 {void onError(error), 498 {void onError(error),
491 void onDone(), 499 void onDone(),
492 bool cancelOnError}) { 500 bool cancelOnError}) {
493 if (_writeEventsEnabled) { 501 _sendWriteEvent();
494 _writeEventsEnabled = false;
495 _controller.add(RawSocketEvent.WRITE);
496 }
497 return _stream.listen(onData, 502 return _stream.listen(onData,
498 onError: onError, 503 onError: onError,
499 onDone: onDone, 504 onDone: onDone,
500 cancelOnError: cancelOnError); 505 cancelOnError: cancelOnError);
501 } 506 }
502 507
503 void _verifyFields() { 508 void _verifyFields() {
504 assert(is_server is bool); 509 assert(is_server is bool);
505 assert(_socket == null || _socket is RawSocket); 510 assert(_socket == null || _socket is RawSocket);
506 if (address is! InternetAddress) { 511 if (address is! InternetAddress) {
(...skipping 21 matching lines...) Expand all
528 } 533 }
529 534
530 int get port => _socket.port; 535 int get port => _socket.port;
531 536
532 String get remoteHost => _socket.remoteHost; 537 String get remoteHost => _socket.remoteHost;
533 538
534 int get remotePort => _socket.remotePort; 539 int get remotePort => _socket.remotePort;
535 540
536 int available() { 541 int available() {
537 if (_status != CONNECTED) return 0; 542 if (_status != CONNECTED) return 0;
538 _readEncryptedData();
539 return _secureFilter.buffers[READ_PLAINTEXT].length; 543 return _secureFilter.buffers[READ_PLAINTEXT].length;
540 } 544 }
541 545
542 void close() { 546 void close() {
543 shutdown(SocketDirection.BOTH); 547 shutdown(SocketDirection.BOTH);
544 } 548 }
545 549
546 void _close() { 550 void _close() {
547 _closedWrite = true; 551 _closedWrite = true;
548 _closedRead = true; 552 _closedRead = true;
549 if (_socket != null) { 553 if (_socket != null) {
550 _socket.close(); 554 _socket.close();
551 } 555 }
552 _socketClosedWrite = true; 556 _socketClosedWrite = true;
553 _socketClosedRead = true; 557 _socketClosedRead = true;
554 if (_secureFilter != null) { 558 if (!_filterActive && _secureFilter != null) {
555 _secureFilter.destroy(); 559 _secureFilter.destroy();
556 _secureFilter = null; 560 _secureFilter = null;
557 } 561 }
558 if (_socketSubscription != null) { 562 if (_socketSubscription != null) {
559 _socketSubscription.cancel(); 563 _socketSubscription.cancel();
560 } 564 }
561 _controller.close(); 565 _controller.close();
562 _status = CLOSED; 566 _status = CLOSED;
563 } 567 }
564 568
565 void shutdown(SocketDirection direction) { 569 void shutdown(SocketDirection direction) {
566 if (direction == SocketDirection.SEND || 570 if (direction == SocketDirection.SEND ||
567 direction == SocketDirection.BOTH) { 571 direction == SocketDirection.BOTH) {
568 _closedWrite = true; 572 _closedWrite = true;
569 _writeEncryptedData(); 573 if (_writeEmpty) {
570 if (_filterWriteEmpty) {
571 _socket.shutdown(SocketDirection.SEND); 574 _socket.shutdown(SocketDirection.SEND);
572 _socketClosedWrite = true; 575 _socketClosedWrite = true;
573 if (_closedRead) { 576 if (_closedRead) {
574 _close(); 577 _close();
575 } 578 }
576 } 579 }
577 } 580 }
578 if (direction == SocketDirection.RECEIVE || 581 if (direction == SocketDirection.RECEIVE ||
579 direction == SocketDirection.BOTH) { 582 direction == SocketDirection.BOTH) {
580 _closedRead = true; 583 _closedRead = true;
581 _socketClosedRead = true; 584 _socketClosedRead = true;
582 _socket.shutdown(SocketDirection.RECEIVE); 585 _socket.shutdown(SocketDirection.RECEIVE);
583 if (_socketClosedWrite) { 586 if (_socketClosedWrite) {
584 _close(); 587 _close();
585 } 588 }
586 } 589 }
587 } 590 }
588 591
589 bool get writeEventsEnabled => _writeEventsEnabled; 592 bool get writeEventsEnabled => _writeEventsEnabled;
590 593
591 void set writeEventsEnabled(bool value) { 594 void set writeEventsEnabled(bool value) {
592 if (value && 595 _writeEventsEnabled = value;
593 _controller.hasListener && 596 if (value) {
594 _secureFilter != null && 597 Timer.run(() => _sendWriteEvent());
595 _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
596 Timer.run(() => _controller.add(RawSocketEvent.WRITE));
597 } else {
598 _writeEventsEnabled = value;
599 } 598 }
600 } 599 }
601 600
602 bool get readEventsEnabled => _readEventsEnabled; 601 bool get readEventsEnabled => _readEventsEnabled;
603 602
604 void set readEventsEnabled(bool value) { 603 void set readEventsEnabled(bool value) {
605 _readEventsEnabled = value; 604 _readEventsEnabled = value;
606 if (value && 605 _scheduleReadEvent();
607 ((_secureFilter != null &&
608 _secureFilter.buffers[READ_PLAINTEXT].length > 0) ||
609 _socketClosedRead)) {
610 // We might not have no underlying socket to set off read events.
611 Timer.run(_readHandler);
612 }
613 } 606 }
614 607
615 List<int> read([int len]) { 608 List<int> read([int length]) {
616 if (_closedRead) { 609 if (_closedRead) {
617 throw new SocketException("Reading from a closed socket"); 610 throw new SocketException("Reading from a closed socket");
618 } 611 }
619 if (_status != CONNECTED) { 612 if (_status != CONNECTED) {
620 return null; 613 return null;
621 } 614 }
622 var buffer = _secureFilter.buffers[READ_PLAINTEXT]; 615 var buffer = _secureFilter.buffers[READ_PLAINTEXT];
623 _readEncryptedData(); 616 if (length == null) {
624 int toRead = buffer.length; 617 length = buffer.length;
625 if (len != null) { 618 } else if (length is! int || length < 0) {
626 if (len is! int || len < 0) {
627 throw new ArgumentError( 619 throw new ArgumentError(
628 "Invalid len parameter in SecureSocket.read (len: $len)"); 620 "Invalid length parameter in SecureSocket.read (length: $length)");
629 } 621 } else {
630 if (len < toRead) { 622 length = min(length, buffer.length);
631 toRead = len;
632 }
633 } 623 }
634 List<int> result = (toRead == 0) ? null : 624 if (length == 0) return null;
Søren Gjesse 2013/06/14 09:27:44 Move this code into the buffer in a method called
635 buffer.data.sublist(buffer.start, buffer.start + toRead); 625 List<int> result = new Uint8List(length);
636 buffer.advanceStart(toRead); 626 int bytesRead = 0;
637 627 while (bytesRead < length) { // Loop over 2 data ranges in circular buffer.
638 // Set up a read event if the filter still has data. 628 int toRead = buffer.linearLength;
639 if (!_filterReadEmpty) { 629 result.setRange(bytesRead,
640 Timer.run(_readHandler); 630 bytesRead + toRead,
631 buffer.data,
632 buffer.start);
633 buffer.advanceStart(toRead);
634 bytesRead += toRead;
641 } 635 }
642 636 _runFilter();
Anders Johnsen 2013/06/14 06:54:41 Don't you mean to _runFilter inside the loop? Othe
Bill Hesse 2013/06/14 08:55:02 No. The loop runs at most twice, for the two exis
643 if (_socketClosedRead) { // An onClose event is pending.
644 // _closedRead is false, since we are in a read call.
645 if (!_filterReadEmpty) {
646 // _filterReadEmpty may be out of date since read empties
647 // the plaintext buffer after calling _readEncryptedData.
648 // TODO(whesse): Fix this as part of fixing read.
649 _readEncryptedData();
650 }
651 if (_filterReadEmpty) {
652 // This can't be an else clause: the value of _filterReadEmpty changes.
653 // This must be asynchronous, because we are in a read call.
654 Timer.run(_closeHandler);
655 }
656 }
657
658 return result; 637 return result;
659 } 638 }
660 639
661 // Write the data to the socket, and flush it as much as possible 640 // Write the data to the socket, and schedule the filter to encrypt it.
662 // until it would block. If the write would block, _writeEncryptedData sets
663 // up handlers to flush the pipeline when possible.
664 int write(List<int> data, [int offset, int bytes]) { 641 int write(List<int> data, [int offset, int bytes]) {
665 if (_closedWrite) { 642 if (_closedWrite) {
666 _controller.addError(new SocketException("Writing to a closed socket")); 643 _controller.addError(new SocketException("Writing to a closed socket"));
667 return 0; 644 return 0;
668 } 645 }
669 if (_status != CONNECTED) return 0; 646 if (_status != CONNECTED) return 0;
670 647
671 if (offset == null) offset = 0; 648 if (offset == null) offset = 0;
672 if (bytes == null) bytes = data.length - offset; 649 if (bytes == null) bytes = data.length - offset;
673 650
674 var buffer = _secureFilter.buffers[WRITE_PLAINTEXT]; 651 var buffer = _secureFilter.buffers[WRITE_PLAINTEXT];
675 if (bytes > buffer.free) { 652 if (bytes > buffer.free) {
676 bytes = buffer.free; 653 bytes = buffer.free;
677 } 654 }
678 if (bytes > 0) { 655 int written = 0;
Søren Gjesse 2013/06/14 09:27:44 Move this code into the buffer in a method called
679 int startIndex = buffer.start + buffer.length; 656 int toWrite = min(bytes, buffer.linearFree);
680 buffer.data.setRange(startIndex, startIndex + bytes, data, offset); 657 while (toWrite > 0) { // The buffer may contain two linear free ranges.
681 buffer.length += bytes; 658 _writeEmpty = false;
659 buffer.data.setRange(buffer.end, buffer.end + toWrite, data, offset);
660 buffer.advanceEnd(toWrite);
661 offset += toWrite;
662 written += toWrite;
663 toWrite = min(bytes - written, buffer.linearFree);
682 } 664 }
683 _writeEncryptedData(); // Tries to flush all pipeline stages. 665 _runFilter();
Anders Johnsen 2013/06/14 06:54:41 Ditto.
Bill Hesse 2013/06/14 08:55:02 Done.
684 return bytes; 666 return written;
685 } 667 }
686 668
687 X509Certificate get peerCertificate => _secureFilter.peerCertificate; 669 X509Certificate get peerCertificate => _secureFilter.peerCertificate;
688 670
689 bool setOption(SocketOption option, bool enabled) { 671 bool setOption(SocketOption option, bool enabled) {
690 if (_socket == null) return false; 672 if (_socket == null) return false;
691 return _socket.setOption(option, enabled); 673 return _socket.setOption(option, enabled);
692 } 674 }
693 675
694 void _writeHandler() {
695 if (_status == CLOSED) return;
696 _writeEncryptedData();
697 if (_filterWriteEmpty && _closedWrite && !_socketClosedWrite) {
698 // Close _socket for write, by calling shutdown(), to avoid cloning the
699 // socket closing code in shutdown().
700 shutdown(SocketDirection.SEND);
701 }
702 if (_status == HANDSHAKE) {
703 try {
704 _secureHandshake();
705 } catch (e) { _reportError(e, "RawSecureSocket error"); }
706 } else if (_status == CONNECTED &&
707 _controller.hasListener &&
708 _writeEventsEnabled &&
709 _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
710 // Reset the one-shot handler.
711 _writeEventsEnabled = false;
712 _controller.add(RawSocketEvent.WRITE);
713 }
714 }
715
716 void _eventDispatcher(RawSocketEvent event) { 676 void _eventDispatcher(RawSocketEvent event) {
717 if (event == RawSocketEvent.READ) { 677 if (event == RawSocketEvent.READ) {
718 _readHandler(); 678 _readHandler();
719 } else if (event == RawSocketEvent.WRITE) { 679 } else if (event == RawSocketEvent.WRITE) {
720 _writeHandler(); 680 _writeHandler();
721 } else if (event == RawSocketEvent.READ_CLOSED) { 681 } else if (event == RawSocketEvent.READ_CLOSED) {
722 _closeHandler(); 682 _closeHandler();
723 } 683 }
724 } 684 }
725 685
726 void _readFromCarryOver() {
727 assert(_carryOverData != null);
728 var encrypted = _secureFilter.buffers[READ_ENCRYPTED];
729 var bytes = _carryOverData.length - _carryOverDataIndex;
730 int startIndex = encrypted.start + encrypted.length;
731 encrypted.data.setRange(startIndex,
732 startIndex + bytes,
733 _carryOverData,
734 _carryOverDataIndex);
735 encrypted.length += bytes;
736 _carryOverDataIndex += bytes;
737 if (_carryOverData.length == _carryOverDataIndex) {
738 _carryOverData = null;
739 }
740 }
741
742 void _readHandler() { 686 void _readHandler() {
743 if (_status == CLOSED) { 687 _readSocket();
744 return; 688 _runFilter();
745 } else if (_status == HANDSHAKE) { 689 }
746 try { 690
747 _secureHandshake(); 691 void _writeHandler() {
748 if (_status != HANDSHAKE) _readHandler(); 692 _writeSocket();
749 } catch (e) { _reportError(e, "RawSecureSocket error"); } 693 _runFilter();
750 } else {
751 if (_status != CONNECTED) {
752 // Cannot happen.
753 throw new SocketException("Internal SocketIO Error");
754 }
755 try {
756 _readEncryptedData();
757 } catch (e) { _reportError(e, "RawSecureSocket error"); }
758 if (!_filterReadEmpty) {
759 if (_readEventsEnabled) {
760 if (_secureFilter.buffers[READ_PLAINTEXT].length > 0) {
761 _controller.add(RawSocketEvent.READ);
762 }
763 if (_socketClosedRead) {
764 // Keep firing read events until we are paused or buffer is empty.
765 Timer.run(_readHandler);
766 }
767 }
768 } else if (_socketClosedRead) {
769 _closeHandler();
770 }
771 }
772 } 694 }
773 695
774 void _doneHandler() { 696 void _doneHandler() {
775 if (_filterReadEmpty) { 697 if (_readEmpty) {
776 _close(); 698 _close();
777 } 699 }
778 } 700 }
779 701
780 void _errorHandler(e) { 702 void _errorHandler(e) {
781 _reportError(e, 'Error on underlying RawSocket'); 703 _reportError(e, 'Error on underlying RawSocket');
782 } 704 }
783 705
784 void _reportError(e, String message) { 706 void _reportError(e, String message) {
785 // TODO(whesse): Call _reportError from all internal functions that throw. 707 // TODO(whesse): Call _reportError from all internal functions that throw.
786 if (e is SocketException) { 708 if (e is SocketException) {
787 e = new SocketException('$message (${e.message})', e.osError); 709 e = new SocketException('$message (${e.message})', e.osError);
788 } else if (e is OSError) { 710 } else if (e is OSError) {
789 e = new SocketException(message, e); 711 e = new SocketException(message, e);
790 } else { 712 } else {
791 e = new SocketException('$message (${e.toString()})', null); 713 e = new SocketException('$message (${e.toString()})', null);
792 } 714 }
793 if (_connectPending) { 715 if (_connectPending) {
794 _handshakeComplete.completeError(e); 716 _handshakeComplete.completeError(e);
795 } else { 717 } else {
796 _controller.addError(e); 718 _controller.addError(e);
797 } 719 }
798 _close(); 720 _close();
799 } 721 }
800 722
801 void _closeHandler() { 723 void _closeHandler() {
802 if (_status == CONNECTED) { 724 if (_status == CONNECTED) {
803 if (_closedRead) return; 725 if (_closedRead) return;
804 _socketClosedRead = true; 726 _socketClosedRead = true;
805 if (_filterReadEmpty) { 727 if (_readEmpty) {
806 _closedRead = true; 728 _closedRead = true;
807 _controller.add(RawSocketEvent.READ_CLOSED); 729 _controller.add(RawSocketEvent.READ_CLOSED);
808 if (_socketClosedWrite) { 730 if (_socketClosedWrite) {
809 _close(); 731 _close();
810 } 732 }
733 } else {
734 _runFilter();
811 } 735 }
812 } else if (_status == HANDSHAKE) { 736 } else if (_status == HANDSHAKE) {
737 _socketClosedRead = true;
738 if (_readEmpty) {
813 _reportError( 739 _reportError(
814 new SocketException('Connection terminated during handshake'), 740 new SocketException('Connection terminated during handshake'),
815 'handshake error'); 741 'RawSecureSocket error');
742 } else {
743 _secureHandshake();
744 }
816 } 745 }
817 } 746 }
818 747
819 void _secureHandshake() { 748 void _secureHandshake() {
820 _readEncryptedData(); 749 try {
821 _secureFilter.handshake(); 750 _secureFilter.handshake();
822 _writeEncryptedData(); 751 _writeEmpty = false;
752 _readSocket();
753 _writeSocket();
754 _runFilter();
755 } catch (e) {
Anders Johnsen 2013/06/14 06:54:41 what errors are you expecting to catch here?
Bill Hesse 2013/06/14 08:55:02 All handshake errors are caught here - we used to
756 _reportError(e, "RawSecureSocket error");
757 }
823 } 758 }
824 759
825 void _secureHandshakeCompleteHandler() { 760 void _secureHandshakeCompleteHandler() {
826 _status = CONNECTED; 761 _status = CONNECTED;
827 if (_connectPending) { 762 if (_connectPending) {
828 _connectPending = false; 763 _connectPending = false;
829 // If we complete the future synchronously, user code will run here, 764 // We don't want user code to run synchronously in this callback.
830 // and modify the state of the RawSecureSocket. For example, it
831 // could close the socket, and set _filter to null.
832 Timer.run(() => _handshakeComplete.complete(this)); 765 Timer.run(() => _handshakeComplete.complete(this));
833 } 766 }
834 } 767 }
835 768
836 void _onPauseStateChange() { 769 void _onPauseStateChange() {
770 if (_controller.isPaused) {
771 _pauseCount++;
772 } else {
773 _pauseCount--;
774 if (_pauseCount == 0) {
775 _scheduleReadEvent();
776 _sendWriteEvent(); // Can send event synchronously.
777 }
778 }
779
837 if (!_socketClosedRead || !_socketClosedWrite) { 780 if (!_socketClosedRead || !_socketClosedWrite) {
838 if (_controller.isPaused) { 781 if (_controller.isPaused) {
839 _socketSubscription.pause(); 782 _socketSubscription.pause();
840 } else { 783 } else {
841 _socketSubscription.resume(); 784 _socketSubscription.resume();
842 } 785 }
843 } 786 }
844 } 787 }
845 788
846 void _onSubscriptionStateChange() { 789 void _onSubscriptionStateChange() {
847 if (_controller.hasListener) { 790 if (_controller.hasListener) {
848 // TODO(ajohnsen): Do something here? 791 // TODO(ajohnsen): Do something here?
849 } 792 }
850 } 793 }
851 794
852 void _readEncryptedData() { 795 void _readSocket() {
853 // Read from the socket, and push it through the filter as far as 796 if (_status == CLOSED) return;
854 // possible.
855 var encrypted = _secureFilter.buffers[READ_ENCRYPTED]; 797 var encrypted = _secureFilter.buffers[READ_ENCRYPTED];
856 var plaintext = _secureFilter.buffers[READ_PLAINTEXT]; 798 while (true) { // Loop over both linear segments in the buffer.
857 bool progress = true; 799 var encrypted_free = encrypted.linearFree;
858 while (progress) { 800 if (encrypted_free == 0) break;
859 progress = false; 801 List<int> data = readSocketOrBufferedData(encrypted_free);
860 // Do not try to read plaintext from the filter while handshaking. 802 if (data == null) break;
861 if ((_status == CONNECTED) && plaintext.free > 0) { 803 int bytes = data.length;
862 int bytes = _secureFilter.processBuffer(READ_PLAINTEXT); 804 encrypted.data.setRange(encrypted.end, encrypted.end + bytes, data);
863 if (bytes > 0) { 805 encrypted.advanceEnd(bytes);
864 plaintext.length += bytes; 806 _readEmpty = false;
865 progress = true; 807 }
866 } 808 }
867 } 809
868 if (encrypted.length > 0) { 810 void _runFilter() {
869 int bytes = _secureFilter.processBuffer(READ_ENCRYPTED); 811 _filterPending = true;
870 if (bytes > 0) { 812 _tryFilter();
871 encrypted.advanceStart(bytes); 813 }
872 progress = true; 814
873 } 815 void _tryFilter() {
874 } 816 if (_status == CLOSED) return;
875 if (!_socketClosedRead && encrypted.free > 0) { 817 if (_filterPending && !_filterActive) {
876 if (_carryOverData != null) { 818 _filterActive = true;
877 _readFromCarryOver(); 819 _filterPending = false;
878 progress = true; 820 _pushAllFilterStages().then((progress) {
879 } else { 821 _filterActive = false;
880 List<int> data = _socket.read(encrypted.free); 822 if (_status == CLOSED) {
881 if (data != null) { 823 _secureFilter.destroy();
882 int bytes = data.length; 824 _secureFilter = null;
883 int startIndex = encrypted.start + encrypted.length; 825 return;
884 encrypted.data.setRange(startIndex, startIndex + bytes, data); 826 }
885 encrypted.length += bytes; 827 if (_writeEmpty && _closedWrite && !_socketClosedWrite) {
886 progress = true; 828 // Checks for and handles all cases of partially closed sockets.
829 shutdown(SocketDirection.SEND);
830 if (_status == CLOSED) return;
831 }
832 if (_readEmpty && _socketClosedRead && !_closedRead) {
833 if (_status == HANDSHAKE) {
834 _secureFilter.handshake();
835 if (_status == HANDSHAKE) {
836 _reportError(
837 new SocketException('Connection terminated during handshake'),
838 'RawSecureSocket error');
839 }
887 } 840 }
888 } 841 _closeHandler();
889 } 842 }
890 } 843 if (_status == CLOSED) return;
891 // If there is any data in any stages of the filter, there should 844 if (progress) {
892 // be data in the plaintext buffer after this process. 845 _filterPending = true;
893 // TODO(whesse): Verify that this is true, and there can be no 846 _readSocket();
894 // partial encrypted block stuck in the secureFilter. 847 _writeSocket();
895 _filterReadEmpty = (plaintext.length == 0); 848 if (_status == HANDSHAKE) {
896 } 849 _secureHandshake();
897 850 }
898 void _writeEncryptedData() { 851 }
852 _tryFilter();
853 });
854 }
855 }
856
857 List<int> readSocketOrBufferedData(int bytes) {
Anders Johnsen 2013/06/14 06:54:41 Make private.
Bill Hesse 2013/06/14 08:55:02 Done.
858 if (_carryOverData != null) {
859 if (bytes > _carryOverData.length - _carryOverDataIndex) {
860 bytes = _carryOverData.length - _carryOverDataIndex;
861 }
862 var result = _carryOverData.sublist(_carryOverDataIndex,
863 _carryOverDataIndex + bytes);
864 _carryOverDataIndex += bytes;
865 if (_carryOverData.length == _carryOverDataIndex) {
866 _carryOverData = null;
867 }
868 return result;
869 } else if (!_socketClosedRead) {
870 try {
871 return _socket.read(bytes);
872 } catch (e) {
873 _reportError(e, "RawSecureSocket error reading encrypted socket");
874 return null;
875 }
876 } else {
877 return null;
878 }
879 }
880
881 void _writeSocket() {
899 if (_socketClosedWrite) return; 882 if (_socketClosedWrite) return;
900 var encrypted = _secureFilter.buffers[WRITE_ENCRYPTED]; 883 var encrypted = _secureFilter.buffers[WRITE_ENCRYPTED];
901 var plaintext = _secureFilter.buffers[WRITE_PLAINTEXT]; 884 while (true) { // Loop over both linear ranges in circular buffer.
902 while (true) { 885 // Get the length of the first data segment in circular buffer.
903 if (encrypted.length > 0) { 886 var encrypted = _secureFilter.buffers[WRITE_ENCRYPTED];
904 // Write from the filter to the socket. 887 var encrypted_length = encrypted.linearLength;
905 int bytes = _socket.write(encrypted.data, 888 if (encrypted_length == 0) break;
906 encrypted.start, 889 int bytes = _socket.write(encrypted.data,
907 encrypted.length); 890 encrypted.start,
908 encrypted.advanceStart(bytes); 891 encrypted_length);
909 if (encrypted.length > 0) { 892 encrypted.advanceStart(bytes);
893 if (bytes < encrypted_length) {
910 // The socket has blocked while we have data to write. 894 // The socket has blocked while we have data to write.
911 // We must be notified when it becomes unblocked. 895 // We must be notified when it becomes unblocked.
912 _socket.writeEventsEnabled = true; 896 _socket.writeEventsEnabled = true;
913 _filterWriteEmpty = false;
914 break; 897 break;
915 } 898 }
916 } else { 899 }
917 var plaintext = _secureFilter.buffers[WRITE_PLAINTEXT]; 900 }
918 if (plaintext.length > 0) { 901
919 int plaintext_bytes = _secureFilter.processBuffer(WRITE_PLAINTEXT); 902 // If a read event should be sent, add it to the controller.
920 plaintext.advanceStart(plaintext_bytes); 903 _scheduleReadEvent() {
921 } 904 if (!_pendingReadEvent &&
922 int bytes = _secureFilter.processBuffer(WRITE_ENCRYPTED); 905 _readEventsEnabled &&
923 if (bytes <= 0) { 906 _pauseCount == 0 &&
924 // We know the WRITE_ENCRYPTED buffer is empty, and the 907 _secureFilter != null &&
925 // filter wrote zero bytes to it, so the filter must be empty. 908 !_secureFilter.buffers[READ_PLAINTEXT].isEmpty) {
926 // Also, the WRITE_PLAINTEXT buffer must have been empty, or 909 _pendingReadEvent = true;
927 // it would have written to the filter. 910 Timer.run(_sendReadEvent);
928 // TODO(whesse): Verify that the filter works this way. 911 }
929 _filterWriteEmpty = true; 912 }
930 break; 913
931 } 914 _sendReadEvent() {
932 encrypted.length += bytes; 915 _pendingReadEvent = false;
933 } 916 if (_readEventsEnabled &&
934 } 917 _pauseCount == 0 &&
918 _secureFilter != null &&
919 !_secureFilter.buffers[READ_PLAINTEXT].isEmpty) {
920 _controller.add(RawSocketEvent.READ);
921 _scheduleReadEvent();
922 }
923 }
924
925 // If a write event should be sent, add it to the controller.
926 _sendWriteEvent() {
927 if (!_closedWrite &&
928 _writeEventsEnabled &&
929 _pauseCount == 0 &&
930 _secureFilter != null &&
931 _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
932 _writeEventsEnabled = false;
933 _controller.add(RawSocketEvent.WRITE);
934 }
935 }
936
937 Future<bool> _pushAllFilterStages() {
938 if (_filterService == null) {
939 _filterService = _SecureFilter._newServicePort();
940 }
941 List args = [_filterPointer, _status != CONNECTED];
942 var bufs = _secureFilter.buffers;
943 for (var i = 0; i < NUM_BUFFERS; ++i) {
944 args.add(bufs[i].start);
945 args.add(bufs[i].end);
946 }
947
948 return _filterService.call(args).then((positions) {
949 // Compute writeEmpty as "write plaintext buffer and write encrypted
950 // buffer were empty when we started and are empty now".
951 _writeEmpty = bufs[WRITE_PLAINTEXT].isEmpty &&
952 positions[2 * WRITE_ENCRYPTED + 2] ==
953 positions[2 * WRITE_ENCRYPTED + 3];
954 // If we were in handshake when this started, _writeEmpty may be false
955 // because the handshake wrote data after we checked.
956 if (positions[1]) _writeEmpty = false;
957
958 // Compute readEmpty as "both read buffers were empty when we started
959 // and are empty now".
960 _readEmpty = bufs[READ_ENCRYPTED].isEmpty &&
961 positions[2 * READ_PLAINTEXT + 2] ==
962 positions[2 * READ_PLAINTEXT + 3];
963
964 bool progress = false;
965 _ExternalBuffer buffer = bufs[WRITE_PLAINTEXT];
966 int new_start = positions[2 * WRITE_PLAINTEXT + 2];
967 if (new_start != buffer.start) {
968 progress = true;
969 // If WRITE_PLAINTEXT goes from full to not full:
970 if (buffer.free == 0) {
971 buffer.start = new_start;
972 _sendWriteEvent();
973 } else {
974 buffer.start = new_start;
975 }
976 }
977 buffer = bufs[READ_ENCRYPTED];
978 new_start = positions[2 * READ_ENCRYPTED + 2];
979 if (new_start != buffer.start) {
980 progress = true;
981 // If READ_ENCRYPTED goes from full to not full:
982 if (buffer.free == 0) {
983 buffer.start = new_start;
984 _readSocket();
985 } else {
986 buffer.start = new_start;
987 }
988 }
989 buffer = bufs[WRITE_ENCRYPTED];
990 int new_end = positions[2 * WRITE_ENCRYPTED + 3];
991 if (new_end != buffer.end) {
992 progress = true;
993 // If WRITE_ENCRYPTED goes from empty to non-empty:
994 if (buffer.length == 0) {
995 buffer.end = new_end;
996 _writeSocket();
997 } else {
998 buffer.end = new_end;
999 }
1000 }
1001 buffer = bufs[READ_PLAINTEXT];
1002 new_end = positions[2 * READ_PLAINTEXT + 3];
1003 if (new_end != buffer.end) {
1004 progress = true;
1005 // If READ_PLAINTEXT goes from empty to non-empty:
1006 if (buffer.length == 0) {
1007 buffer.end = new_end;
1008 _scheduleReadEvent();
1009 } else {
1010 buffer.end = new_end;
1011 }
1012 }
1013 return progress;
1014 });
935 } 1015 }
936 } 1016 }
937 1017
938 1018
1019 /**
1020 * A circular buffer backed by an external byte array. Accessed from
1021 * both C++ and Dart code in an unsynchronized way, with one reading
1022 * and one writing. All updates to start and end are done by Dart code.
1023 */
939 class _ExternalBuffer { 1024 class _ExternalBuffer {
Søren Gjesse 2013/06/14 09:27:44 I think adding more methods to this class would ma
940 // Performance is improved if a full buffer of plaintext fits 1025 _ExternalBuffer(this.size) : start = 0, end = 0;
941 // in the encrypted buffer, when encrypted. 1026
942 static final int SIZE = 8 * 1024; 1027 void advanceStart(int bytes) {
943 static final int ENCRYPTED_SIZE = 10 * 1024; 1028 assert(start > end || start + bytes <= end);
944 _ExternalBuffer() : start = 0, length = 0; 1029 start += bytes;
945 1030 if (start >= size) {
946 // TODO(whesse): Consider making this a circular buffer. Only if it helps. 1031 start -= size;
947 void advanceStart(int numBytes) { 1032 assert(start <= end);
948 start += numBytes; 1033 assert(start < size);
949 length -= numBytes; 1034 }
950 if (length == 0) { 1035 }
951 start = 0; 1036
952 } 1037 void advanceEnd(int bytes) {
953 } 1038 assert(start <= end || start > end + bytes);
954 1039 end += bytes;
955 int get free => data.length - (start + length); 1040 if (end >= size) {
1041 end -= size;
1042 assert(end < start);
1043 assert(end < size);
1044 }
1045 }
1046
1047 bool get isEmpty => end == start;
1048
1049 int get length {
1050 if (start > end) return size + end - start;
1051 return end - start;
1052 }
1053
1054 int get linearLength {
1055 if (start > end) return size - start;
1056 return end - start;
1057 }
1058
1059 int get free {
1060 if (start > end) return start - end - 1;
1061 return size + start - end - 1;
1062 }
1063
1064 int get linearFree {
1065 if (start > end) return start - end - 1;
1066 if (start == 0) return size - end - 1;
1067 return size - end;
1068 }
1069
956 1070
957 List data; // This will be a ExternalByteArray, backed by C allocated data. 1071 List data; // This will be a ExternalByteArray, backed by C allocated data.
958 int start; 1072 int start;
959 int length; 1073 int end;
1074 int size;
960 } 1075 }
961 1076
962 1077
963 abstract class _SecureFilter { 1078 abstract class _SecureFilter {
964 external factory _SecureFilter(); 1079 external factory _SecureFilter();
965 1080
1081 external static SendPort _newServicePort();
1082
966 void connect(String hostName, 1083 void connect(String hostName,
967 int port, 1084 int port,
968 bool is_server, 1085 bool is_server,
969 String certificateName, 1086 String certificateName,
970 bool requestClientCertificate, 1087 bool requestClientCertificate,
971 bool requireClientCertificate, 1088 bool requireClientCertificate,
972 bool sendClientCertificate); 1089 bool sendClientCertificate);
973 void destroy(); 1090 void destroy();
974 void handshake(); 1091 void handshake();
975 void init(); 1092 void init();
976 X509Certificate get peerCertificate; 1093 X509Certificate get peerCertificate;
977 int processBuffer(int bufferIndex); 1094 int processBuffer(int bufferIndex);
978 void registerBadCertificateCallback(Function callback); 1095 void registerBadCertificateCallback(Function callback);
979 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); 1096 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
1097 int _pointer();
980 1098
981 List<_ExternalBuffer> get buffers; 1099 List<_ExternalBuffer> get buffers;
982 } 1100 }
OLDNEW
« runtime/bin/secure_socket_patch.dart ('K') | « runtime/bin/secure_socket_patch.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698