Index: runtime/bin/secure_socket.cc |
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc |
index 4310aec44fc46eae40591b3963836fb30206703f..2df872a249bb8ffde3a429bee397e8c16d3210bd 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(); |
+} |
+ |
+ |
+/** |
+ * 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(); |
+ ends[i] = CObjectInt32(args[2*i + 3]).Value(); |
+ } |
+ |
+ filter->ProcessAllBuffers(starts, ends, in_handshake); |
+ |
+ for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
+ 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 = isEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
+ switch (i) { |
+ case kReadPlaintext: |
+ case kWriteEncrypted: |
+ if (start <= end) { |
+ // Free space is split into two segments. |
+ // 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: |
+ 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); |
@@ -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) { |
+ 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 |
+ 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 |