Chromium Code Reviews| Index: runtime/bin/secure_socket.cc |
| diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc |
| index 4310aec44fc46eae40591b3963836fb30206703f..0d2a76330c47acef983a80ceb9b5bfd0db259836 100644 |
| --- a/runtime/bin/secure_socket.cc |
| +++ b/runtime/bin/secure_socket.cc |
| @@ -40,6 +40,13 @@ dart::Mutex SSLFilter::mutex_; // To protect library initialization. |
| // be null if only secure client sockets are used. |
| const char* SSLFilter::password_ = NULL; |
| +// Forward declaration. |
| +static void ProcessFilter(Dart_Port dest_port_id, |
| + Dart_Port reply_port_id, |
| + Dart_CObject* message); |
| + |
| +NativeService SSLFilter::filter_service_("FilterService", ProcessFilter, 16); |
| + |
| static const int kSSLFilterNativeFieldIndex = 0; |
| static SSLFilter* GetFilter(Dart_NativeArguments args) { |
| @@ -161,22 +168,6 @@ void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)( |
| } |
| -void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) { |
| - Dart_EnterScope(); |
| - Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| - int64_t buffer_id = DartUtils::GetIntegerValue(buffer_id_object); |
| - if (buffer_id < 0 || buffer_id >= SSLFilter::kNumBuffers) { |
| - Dart_ThrowException(DartUtils::NewDartArgumentError( |
| - "Illegal argument to ProcessBuffer")); |
| - } |
| - |
| - intptr_t bytes_read = |
| - GetFilter(args)->ProcessBuffer(static_cast<int>(buffer_id)); |
| - Dart_SetReturnValue(args, Dart_NewInteger(bytes_read)); |
| - Dart_ExitScope(); |
| -} |
| - |
| - |
| void FUNCTION_NAME(SecureSocket_InitializeLibrary) |
| (Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| @@ -231,6 +222,110 @@ void FUNCTION_NAME(SecureSocket_PeerCertificate) |
| } |
| +void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
| + Dart_EnterScope(); |
| + intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); |
| + Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); |
| + Dart_ExitScope(); |
| +} |
| + |
| + |
| +/** |
|
Søren Gjesse
2013/06/17 07:31:07
Nice comment
Bill Hesse
2013/06/20 14:56:26
Thanks a lot
|
| + * Pushes data through the SSL filter, reading and writing from circular |
| + * buffers shared with Dart. |
| + * |
| + * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to |
| + * pass encrypted and plaintext data to and from the C++ SSLFilter object. |
| + * |
| + * ProcessFilter is called with a CObject array containing the pointer to |
| + * the SSLFilter, encoded as an int, and the start and end positions of the |
| + * valid data in the four circular buffers. The function only reads from |
| + * the valid data area of the input buffers, and only writes to the free |
| + * area of the output buffers. The function returns the new start and end |
| + * positions in the buffers, but it only updates start for input buffers, and |
| + * end for output buffers. Therefore, the Dart thread can simultaneously |
| + * write to the free space and end pointer of input buffers, and read from |
| + * the data space of output buffers, and modify the start pointer. |
| + * |
| + * When ProcessFilter returns, the Dart thread is responsible for combining |
| + * the updated pointers from Dart and C++, to make the new valid state of |
| + * the circular buffer. |
| + */ |
| +static void ProcessFilter(Dart_Port dest_port_id, |
| + Dart_Port reply_port_id, |
| + Dart_CObject* message) { |
| + CObjectArray args(message); |
| + CObjectIntptr filter_object(args[0]); |
| + SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value()); |
| + bool in_handshake = CObjectBool(args[1]).Value(); |
| + int starts[SSLFilter::kNumBuffers]; |
| + int ends[SSLFilter::kNumBuffers]; |
| + for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
| + starts[i] = CObjectInt32(args[2*i + 2]).Value(); |
|
Søren Gjesse
2013/06/17 07:31:07
We normally have space around all binary operators
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + ends[i] = CObjectInt32(args[2*i + 3]).Value(); |
| + } |
| + |
| + filter->ProcessAllBuffers(starts, ends, in_handshake); |
| + |
| + for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
|
Søren Gjesse
2013/06/17 07:31:07
You could "cheat" here and just update the int val
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + args.SetAt(2*i + 2, new CObjectInt32(CObject::NewInt32(starts[i]))); |
| + args.SetAt(2*i + 3, new CObjectInt32(CObject::NewInt32(ends[i]))); |
| + } |
| + Dart_PostCObject(reply_port_id, args.AsApiCObject()); |
| +} |
| + |
| + |
| +void SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], |
| + int ends[kNumBuffers], |
| + bool in_handshake) { |
| + for (int i = 0; i < kNumBuffers; ++i) { |
| + if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; |
| + int start = starts[i]; |
| + int end = ends[i]; |
| + int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| + switch (i) { |
| + case kReadPlaintext: |
| + case kWriteEncrypted: |
|
Søren Gjesse
2013/06/17 07:31:07
Maybe add an overall comment here: "Write data to
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + if (start <= end) { |
|
Søren Gjesse
2013/06/17 07:31:07
If start == 0 this is not two segments after all.
Bill Hesse
2013/06/20 14:56:26
Or if it equals 1. I think the comments are enoug
|
| + // Free space is split into two segments. |
|
Søren Gjesse
2013/06/17 07:31:07
Please explain the "or" (when is the last element
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + // The first is [end, size - 1) or [end, size). |
| + int buffer_end = (start == 0) ? size - 1 : size; |
| + int bytes = ProcessBuffer(i, end, buffer_end); |
| + end += bytes; |
| + ASSERT(end <= size); |
| + if (end == size) end = 0; |
| + } |
| + if (start > end + 1) { |
| + int bytes = ProcessBuffer(i, end, start - 1); |
| + end += bytes; |
| + ASSERT(end < start); |
| + } |
| + ends[i] = end; |
| + break; |
| + case kReadEncrypted: |
| + case kWritePlaintext: |
|
Søren Gjesse
2013/06/17 07:31:07
Overall comment here: "Read data from buffer"
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + if (end < start) { |
| + // Data is split into two segments. |
| + // The first is [start, size). |
| + int bytes = ProcessBuffer(i, start, size); |
| + start += bytes; |
| + ASSERT(start <= size); |
| + if (start == size) start = 0; |
| + } |
| + if (start < end) { |
| + int bytes = ProcessBuffer(i, start, end); |
| + start += bytes; |
| + ASSERT(start <= end); |
| + } |
| + starts[i] = start; |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| +} |
| + |
| + |
| static Dart_Handle X509FromCertificate(CERTCertificate* certificate) { |
| PRTime start_validity; |
| PRTime end_validity; |
| @@ -291,15 +386,13 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| // Create SSLFilter buffers as ExternalUint8Array objects. |
| Dart_Handle dart_buffers_object = ThrowIfError( |
| Dart_GetField(dart_this, DartUtils::NewString("buffers"))); |
| - Dart_Handle dart_buffer_object = |
| - Dart_ListGetAt(dart_buffers_object, kReadPlaintext); |
| - Dart_Handle external_buffer_class = |
| - Dart_InstanceGetClass(dart_buffer_object); |
| + Dart_Handle secure_filter_impl_class = |
| + Dart_InstanceGetClass(dart_this); |
| Dart_Handle dart_buffer_size = ThrowIfError( |
| - Dart_GetField(external_buffer_class, DartUtils::NewString("SIZE"))); |
| + Dart_GetField(secure_filter_impl_class, DartUtils::NewString("SIZE"))); |
| int64_t buffer_size = DartUtils::GetIntegerValue(dart_buffer_size); |
| Dart_Handle dart_encrypted_buffer_size = ThrowIfError( |
| - Dart_GetField(external_buffer_class, |
| + Dart_GetField(secure_filter_impl_class, |
| DartUtils::NewString("ENCRYPTED_SIZE"))); |
| int64_t encrypted_buffer_size = |
| DartUtils::GetIntegerValue(dart_encrypted_buffer_size); |
| @@ -317,7 +410,7 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| Dart_Handle data_identifier = DartUtils::NewString("data"); |
| for (int i = 0; i < kNumBuffers; ++i) { |
| - int size = isEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| + int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| dart_buffer_objects_[i] = |
| Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)); |
| ASSERT(dart_buffer_objects_[i] != NULL); |
| @@ -626,106 +719,102 @@ void SSLFilter::Destroy() { |
| } |
| -intptr_t SSLFilter::ProcessBuffer(int buffer_index) { |
| - int size = isEncrypted(buffer_index) ? encrypted_buffer_size_ : buffer_size_; |
| - Dart_Handle buffer_object = |
| - Dart_HandleFromPersistent(dart_buffer_objects_[buffer_index]); |
| - Dart_Handle start_object = ThrowIfError( |
| - Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_start_))); |
| - Dart_Handle length_object = ThrowIfError( |
| - Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_length_))); |
| - int64_t unsafe_start = DartUtils::GetIntegerValue(start_object); |
| - int64_t unsafe_length = DartUtils::GetIntegerValue(length_object); |
| - ASSERT(unsafe_start >= 0); |
| - ASSERT(unsafe_start < size); |
| - ASSERT(unsafe_length >= 0); |
| - ASSERT(unsafe_length <= size); |
| - int start = static_cast<int>(unsafe_start); |
| - int length = static_cast<int>(unsafe_length); |
| - uint8_t* buffer = buffers_[buffer_index]; |
| - |
| +intptr_t SSLFilter::ProcessBuffer(int buffer_index, int start, int end) { |
|
Søren Gjesse
2013/06/17 07:31:07
You don't need for this CL, but how about just spl
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + int length = end - start; |
| int bytes_processed = 0; |
| - switch (buffer_index) { |
| - case kReadPlaintext: { |
| - int bytes_free = size - start - length; |
| - bytes_processed = PR_Read(filter_, |
| - buffer + start + length, |
| - bytes_free); |
| - if (bytes_processed < 0) { |
| - ASSERT(bytes_processed == -1); |
| - // TODO(whesse): Handle unexpected errors here. |
| - PRErrorCode pr_error = PR_GetError(); |
| - if (PR_WOULD_BLOCK_ERROR != pr_error) { |
| - ThrowPRException("Error reading plaintext from SSLFilter"); |
| + // The kWritePlaintext case must be called to push data through the filter. |
| + if (length > 0 || buffer_index == kWritePlaintext) { |
| + uint8_t* buffer = buffers_[buffer_index]; |
| + switch (buffer_index) { |
| + case kReadPlaintext: { |
| + bytes_processed = PR_Read(filter_, |
| + buffer + start, |
| + length); |
| + if (bytes_processed < 0) { |
| + ASSERT(bytes_processed == -1); |
| + // TODO(whesse): Handle unexpected errors here. |
| + PRErrorCode pr_error = PR_GetError(); |
| + if (PR_WOULD_BLOCK_ERROR != pr_error) { |
| + // TODO(whesse): Handle errors |
|
Søren Gjesse
2013/06/17 07:31:07
Please open an issue on this.
Bill Hesse
2013/06/20 14:56:26
Done.
|
| + FATAL("Error reading plaintext from SSLFilter"); |
| + } |
| + bytes_processed = 0; |
| } |
| - bytes_processed = 0; |
| + break; |
| } |
| - break; |
| - } |
| - case kWriteEncrypted: { |
| - const uint8_t* buf1; |
| - const uint8_t* buf2; |
| - unsigned int len1; |
| - unsigned int len2; |
| - int bytes_free = size - start - length; |
| - memio_Private* secret = memio_GetSecret(filter_); |
| - memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2); |
| - int bytes_to_send = |
| - dart::Utils::Minimum(len1, static_cast<unsigned>(bytes_free)); |
| - if (bytes_to_send > 0) { |
| - memmove(buffer + start + length, buf1, bytes_to_send); |
| - bytes_processed = bytes_to_send; |
| - } |
| - bytes_to_send = dart::Utils::Minimum(len2, |
| - static_cast<unsigned>(bytes_free - bytes_processed)); |
| - if (bytes_to_send > 0) { |
| - memmove(buffer + start + length + bytes_processed, buf2, |
| - bytes_to_send); |
| - bytes_processed += bytes_to_send; |
| - } |
| - if (bytes_processed > 0) { |
| - memio_PutWriteResult(secret, bytes_processed); |
| + case kWriteEncrypted: { |
| + const uint8_t* buf1; |
| + const uint8_t* buf2; |
| + unsigned int len1; |
| + unsigned int len2; |
| + memio_Private* secret = memio_GetSecret(filter_); |
| + memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2); |
| + int bytes_to_send = |
| + dart::Utils::Minimum(len1, static_cast<unsigned>(length)); |
| + if (bytes_to_send > 0) { |
| + memmove(buffer + start, buf1, bytes_to_send); |
| + bytes_processed = bytes_to_send; |
| + } |
| + bytes_to_send = dart::Utils::Minimum(len2, |
| + static_cast<unsigned>(length - bytes_processed)); |
| + if (bytes_to_send > 0) { |
| + memmove(buffer + start + bytes_processed, buf2, bytes_to_send); |
| + bytes_processed += bytes_to_send; |
| + } |
| + if (bytes_processed > 0) { |
| + memio_PutWriteResult(secret, bytes_processed); |
| + } |
| + break; |
| } |
| - break; |
| - } |
| - case kReadEncrypted: { |
| - if (length > 0) { |
| - bytes_processed = length; |
| + case kReadEncrypted: { |
| memio_Private* secret = memio_GetSecret(filter_); |
| uint8_t* filter_buf; |
| int free_bytes = memio_GetReadParams(secret, &filter_buf); |
| - if (free_bytes < bytes_processed) bytes_processed = free_bytes; |
| - memmove(filter_buf, |
| - buffer + start, |
| - bytes_processed); |
| + bytes_processed = dart::Utils::Minimum(length, free_bytes); |
| + memmove(filter_buf, buffer + start, bytes_processed); |
| memio_PutReadResult(secret, bytes_processed); |
| - } |
| - break; |
| - } |
| - |
| - case kWritePlaintext: { |
| - if (length > 0) { |
| - bytes_processed = PR_Write(filter_, |
| - buffer + start, |
| - length); |
| + break; |
| } |
| - if (bytes_processed < 0) { |
| - ASSERT(bytes_processed == -1); |
| - // TODO(whesse): Handle unexpected errors here. |
| - PRErrorCode pr_error = PR_GetError(); |
| - if (PR_WOULD_BLOCK_ERROR != pr_error) { |
| - ThrowPRException("Error reading plaintext from SSLFilter"); |
| + case kWritePlaintext: { |
| + bytes_processed = PR_Write(filter_, buffer + start, length); |
| + if (bytes_processed < 0) { |
| + ASSERT(bytes_processed == -1); |
| + // TODO(whesse): Handle unexpected errors here. |
| + PRErrorCode pr_error = PR_GetError(); |
| + if (PR_WOULD_BLOCK_ERROR != pr_error) { |
| + // TODO(whesse): Handle errors |
| + FATAL("Error reading plaintext from SSLFilter"); |
| + } |
| + bytes_processed = 0; |
| } |
| - bytes_processed = 0; |
| + break; |
| } |
| - break; |
| } |
| } |
| return bytes_processed; |
| } |
| + |
| +Dart_Port SSLFilter::GetServicePort() { |
| + return filter_service_.GetServicePort(); |
| +} |
| + |
| + |
| +void FUNCTION_NAME(SecureSocket_NewServicePort)(Dart_NativeArguments args) { |
| + Dart_EnterScope(); |
| + Dart_SetReturnValue(args, Dart_Null()); |
| + Dart_Port service_port = SSLFilter::GetServicePort(); |
| + if (service_port != ILLEGAL_PORT) { |
| + // Return a send port for the service port. |
| + Dart_Handle send_port = Dart_NewSendPort(service_port); |
| + Dart_SetReturnValue(args, send_port); |
| + } |
| + Dart_ExitScope(); |
| +} |
| + |
| + |
| } // namespace bin |
| } // namespace dart |