From a053f23b1da74ebb238ee97ea86ba0f9b0ecc0b1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 12 Dec 2016 17:40:22 -0800 Subject: [PATCH 1/4] Make Node extension work with slice changes --- binding.gyp | 1 + build.yaml | 2 + grpc.def | 1 + src/core/lib/iomgr/tcp_uv.c | 1 + src/node/ext/byte_buffer.cc | 6 +- src/node/ext/call.cc | 130 +++++++----------- src/node/ext/call.h | 17 +-- src/node/ext/call_credentials.cc | 3 +- src/node/ext/channel.cc | 3 +- src/node/ext/node_grpc.cc | 16 +-- src/node/ext/server.cc | 19 ++- src/node/ext/slice.cc | 102 ++++++++++++++ src/node/ext/slice.h | 52 +++++++ src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 + 15 files changed, 235 insertions(+), 123 deletions(-) create mode 100644 src/node/ext/slice.cc create mode 100644 src/node/ext/slice.h diff --git a/binding.gyp b/binding.gyp index 356d4acaac7..3c7eb98df20 100644 --- a/binding.gyp +++ b/binding.gyp @@ -839,6 +839,7 @@ "src/node/ext/node_grpc.cc", "src/node/ext/server.cc", "src/node/ext/server_credentials.cc", + "src/node/ext/slice.cc", "src/node/ext/timeval.cc", ], "dependencies": [ diff --git a/build.yaml b/build.yaml index 9e6660d513b..25fe4a7f175 100644 --- a/build.yaml +++ b/build.yaml @@ -3818,6 +3818,7 @@ node_modules: - src/node/ext/completion_queue_async_worker.h - src/node/ext/server.h - src/node/ext/server_credentials.h + - src/node/ext/slice.h - src/node/ext/timeval.h js: - src/node/index.js @@ -3839,6 +3840,7 @@ node_modules: - src/node/ext/node_grpc.cc - src/node/ext/server.cc - src/node/ext/server_credentials.cc + - src/node/ext/slice.cc - src/node/ext/timeval.cc openssl_fallback: base_uri: https://openssl.org/source/old/1.0.2/ diff --git a/grpc.def b/grpc.def index 523fa550f2a..5b2b679708a 100644 --- a/grpc.def +++ b/grpc.def @@ -164,6 +164,7 @@ EXPORTS grpc_slice_hash grpc_slice_is_equivalent grpc_slice_dup + grpc_slice_to_c_string grpc_slice_buffer_init grpc_slice_buffer_destroy grpc_slice_buffer_add diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c index f3510bc7803..15c8b3cbee6 100644 --- a/src/core/lib/iomgr/tcp_uv.c +++ b/src/core/lib/iomgr/tcp_uv.c @@ -48,6 +48,7 @@ #include "src/core/lib/iomgr/network_status_tracker.h" #include "src/core/lib/iomgr/resource_quota.h" #include "src/core/lib/iomgr/tcp_uv.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc index fc339fc4629..7d6fb198603 100644 --- a/src/node/ext/byte_buffer.cc +++ b/src/node/ext/byte_buffer.cc @@ -40,6 +40,7 @@ #include "grpc/slice.h" #include "byte_buffer.h" +#include "slice.h" namespace grpc { namespace node { @@ -54,10 +55,7 @@ using v8::Value; grpc_byte_buffer *BufferToByteBuffer(Local buffer) { Nan::HandleScope scope; - int length = ::node::Buffer::Length(buffer); - char *data = ::node::Buffer::Data(buffer); - grpc_slice slice = grpc_slice_malloc(length); - memcpy(GRPC_SLICE_START_PTR(slice), data, length); + grpc_slice slice = CreateSliceFromBuffer(buffer); grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1)); grpc_slice_unref(slice); return byte_buffer; diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 191e763e0e7..9213d5e87d3 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -48,6 +48,7 @@ #include "completion_queue.h" #include "completion_queue_async_worker.h" #include "call_credentials.h" +#include "slice.h" #include "timeval.h" using std::unique_ptr; @@ -96,8 +97,7 @@ Local nanErrorWithCode(const char *msg, grpc_call_error code) { return scope.Escape(err); } -bool CreateMetadataArray(Local metadata, grpc_metadata_array *array, - shared_ptr resources) { +bool CreateMetadataArray(Local metadata, grpc_metadata_array *array) { HandleScope scope; grpc_metadata_array_init(array); Local keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked(); @@ -113,32 +113,25 @@ bool CreateMetadataArray(Local metadata, grpc_metadata_array *array, array->metadata = reinterpret_cast( gpr_malloc(array->capacity * sizeof(grpc_metadata))); for (unsigned int i = 0; i < keys->Length(); i++) { - Local current_key(keys->Get(i)->ToString()); - Utf8String *utf8_key = new Utf8String(current_key); - resources->strings.push_back(unique_ptr(utf8_key)); + Local current_key(Nan::To(keys->Get(i)).ToLocalChecked()); Local values = Local::Cast( Nan::Get(metadata, current_key).ToLocalChecked()); + grpc_slice key_slice = grpc_slice_intern(CreateSliceFromString(current_key)); for (unsigned int j = 0; j < values->Length(); j++) { Local value = Nan::Get(values, j).ToLocalChecked(); grpc_metadata *current = &array->metadata[array->count]; - current->key = **utf8_key; + current->key = key_slice; // Only allow binary headers for "-bin" keys - if (grpc_is_binary_header(current->key, strlen(current->key))) { + if (grpc_is_binary_header(key_slice)) { if (::node::Buffer::HasInstance(value)) { - current->value = ::node::Buffer::Data(value); - current->value_length = ::node::Buffer::Length(value); - PersistentValue *handle = new PersistentValue(value); - resources->handles.push_back(unique_ptr(handle)); + current->value = CreateSliceFromBuffer(value); } else { return false; } } else { if (value->IsString()) { Local string_value = Nan::To(value).ToLocalChecked(); - Utf8String *utf8_value = new Utf8String(string_value); - resources->strings.push_back(unique_ptr(utf8_value)); - current->value = **utf8_value; - current->value_length = string_value->Length(); + current->value = CreateSliceFromString(string_value); } else { return false; } @@ -153,40 +146,25 @@ Local ParseMetadata(const grpc_metadata_array *metadata_array) { EscapableHandleScope scope; grpc_metadata *metadata_elements = metadata_array->metadata; size_t length = metadata_array->count; - std::map size_map; - std::map index_map; - - for (unsigned int i = 0; i < length; i++) { - const char *key = metadata_elements[i].key; - if (size_map.count(key)) { - size_map[key] += 1; - } else { - size_map[key] = 1; - } - index_map[key] = 0; - } Local metadata_object = Nan::New(); for (unsigned int i = 0; i < length; i++) { grpc_metadata* elem = &metadata_elements[i]; - Local key_string = Nan::New(elem->key).ToLocalChecked(); + // TODO(murgatroid99): Use zero-copy string construction instead + Local key_string = CopyStringFromSlice(elem->key); Local array; MaybeLocal maybe_array = Nan::Get(metadata_object, key_string); if (maybe_array.IsEmpty() || !maybe_array.ToLocalChecked()->IsArray()) { - array = Nan::New(size_map[elem->key]); + array = Nan::New(0); Nan::Set(metadata_object, key_string, array); } else { array = Local::Cast(maybe_array.ToLocalChecked()); } - if (grpc_is_binary_header(elem->key, strlen(elem->key))) { - Nan::Set(array, index_map[elem->key], - MakeFastBuffer( - Nan::CopyBuffer(elem->value, - elem->value_length).ToLocalChecked())); + if (grpc_is_binary_header(elem->key)) { + Nan::Set(array, array->Length(), CreateBufferFromSlice(elem->value)); } else { - Nan::Set(array, index_map[elem->key], - Nan::New(elem->value).ToLocalChecked()); + // TODO(murgatroid99): Use zero-copy string construction instead + Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value)); } - index_map[elem->key] += 1; } return scope.Escape(metadata_object); } @@ -205,8 +183,7 @@ class SendMetadataOp : public Op { EscapableHandleScope scope; return scope.Escape(Nan::True()); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { if (!value->IsObject()) { return false; } @@ -216,7 +193,7 @@ class SendMetadataOp : public Op { return false; } if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(), - &array, resources)) { + &array)) { return false; } out->data.send_initial_metadata.count = array.count; @@ -246,8 +223,7 @@ class SendMessageOp : public Op { EscapableHandleScope scope; return scope.Escape(Nan::True()); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { if (!::node::Buffer::HasInstance(value)) { return false; } @@ -263,8 +239,6 @@ class SendMessageOp : public Op { } send_message = BufferToByteBuffer(value); out->data.send_message = send_message; - PersistentValue *handle = new PersistentValue(value); - resources->handles.push_back(unique_ptr(handle)); return true; } bool IsFinalOp() { @@ -284,8 +258,7 @@ class SendClientCloseOp : public Op { EscapableHandleScope scope; return scope.Escape(Nan::True()); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { return true; } bool IsFinalOp() { @@ -299,12 +272,14 @@ class SendClientCloseOp : public Op { class SendServerStatusOp : public Op { public: + ~SendServerStatusOp() { + grpc_slice_unref(details); + } Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::True()); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { if (!value->IsObject()) { return false; } @@ -339,16 +314,15 @@ class SendServerStatusOp : public Op { Local details = Nan::To( maybe_details.ToLocalChecked()).ToLocalChecked(); grpc_metadata_array array; - if (!CreateMetadataArray(metadata, &array, resources)) { + if (!CreateMetadataArray(metadata, &array)) { return false; } out->data.send_status_from_server.trailing_metadata_count = array.count; out->data.send_status_from_server.trailing_metadata = array.metadata; out->data.send_status_from_server.status = static_cast(code); - Utf8String *str = new Utf8String(details); - resources->strings.push_back(unique_ptr(str)); - out->data.send_status_from_server.status_details = **str; + this->details = CreateSliceFromString(details); + out->data.send_status_from_server.status_details = &this->details; return true; } bool IsFinalOp() { @@ -358,6 +332,9 @@ class SendServerStatusOp : public Op { std::string GetTypeString() const { return "send_status"; } + + private: + grpc_slice details; }; class GetMetadataOp : public Op { @@ -375,8 +352,7 @@ class GetMetadataOp : public Op { return scope.Escape(ParseMetadata(&recv_metadata)); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { out->data.recv_initial_metadata = &recv_metadata; return true; } @@ -408,8 +384,7 @@ class ReadMessageOp : public Op { return scope.Escape(ByteBufferToBuffer(recv_message)); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { out->data.recv_message = &recv_message; return true; } @@ -430,21 +405,16 @@ class ClientStatusOp : public Op { public: ClientStatusOp() { grpc_metadata_array_init(&metadata_array); - status_details = NULL; - details_capacity = 0; } ~ClientStatusOp() { grpc_metadata_array_destroy(&metadata_array); - gpr_free(status_details); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { out->data.recv_status_on_client.trailing_metadata = &metadata_array; out->data.recv_status_on_client.status = &status; out->data.recv_status_on_client.status_details = &status_details; - out->data.recv_status_on_client.status_details_capacity = &details_capacity; return true; } @@ -453,10 +423,8 @@ class ClientStatusOp : public Op { Local status_obj = Nan::New(); Nan::Set(status_obj, Nan::New("code").ToLocalChecked(), Nan::New(status)); - if (status_details != NULL) { - Nan::Set(status_obj, Nan::New("details").ToLocalChecked(), - Nan::New(status_details).ToLocalChecked()); - } + Nan::Set(status_obj, Nan::New("details").ToLocalChecked(), + CopyStringFromSlice(status_details)); Nan::Set(status_obj, Nan::New("metadata").ToLocalChecked(), ParseMetadata(&metadata_array)); return scope.Escape(status_obj); @@ -471,8 +439,7 @@ class ClientStatusOp : public Op { private: grpc_metadata_array metadata_array; grpc_status_code status; - char *status_details; - size_t details_capacity; + grpc_slice status_details; }; class ServerCloseResponseOp : public Op { @@ -482,8 +449,7 @@ class ServerCloseResponseOp : public Op { return scope.Escape(Nan::New(cancelled)); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { out->data.recv_close_on_server.cancelled = &cancelled; return true; } @@ -500,9 +466,8 @@ class ServerCloseResponseOp : public Op { int cancelled; }; -tag::tag(Callback *callback, OpVec *ops, - shared_ptr resources, Call *call) : - callback(callback), ops(ops), resources(resources), call(call){ +tag::tag(Callback *callback, OpVec *ops, Call *call) : + callback(callback), ops(ops), call(call){ } tag::~tag() { @@ -650,20 +615,24 @@ NAN_METHOD(Call::New) { if (channel->GetWrappedChannel() == NULL) { return Nan::ThrowError("Call cannot be created from a closed channel"); } - Utf8String method(info[1]); double deadline = Nan::To(info[2]).FromJust(); grpc_channel *wrapped_channel = channel->GetWrappedChannel(); grpc_call *wrapped_call; if (info[3]->IsString()) { - Utf8String host_override(info[3]); + grpc_slice *host = new grpc_slice; + *host = CreateSliceFromString( + Nan::To(info[3]).ToLocalChecked()); wrapped_call = grpc_channel_create_call( wrapped_channel, parent_call, propagate_flags, - GetCompletionQueue(), *method, - *host_override, MillisecondsToTimespec(deadline), NULL); + GetCompletionQueue(), CreateSliceFromString( + Nan::To(info[1]).ToLocalChecked()), + host, MillisecondsToTimespec(deadline), NULL); + delete host; } else if (info[3]->IsUndefined() || info[3]->IsNull()) { wrapped_call = grpc_channel_create_call( wrapped_channel, parent_call, propagate_flags, - GetCompletionQueue(), *method, + GetCompletionQueue(), CreateSliceFromString( + Nan::To(info[1]).ToLocalChecked()), NULL, MillisecondsToTimespec(deadline), NULL); } else { return Nan::ThrowTypeError("Call's fourth argument must be a string"); @@ -700,7 +669,6 @@ NAN_METHOD(Call::StartBatch) { } Local callback_func = info[1].As(); Call *call = ObjectWrap::Unwrap(info.This()); - shared_ptr resources(new Resources); Local obj = Nan::To(info[0]).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked(); size_t nops = keys->Length(); @@ -745,7 +713,7 @@ NAN_METHOD(Call::StartBatch) { default: return Nan::ThrowError("Argument object had an unrecognized key"); } - if (!op->ParseOp(obj->Get(type), &ops[i], resources)) { + if (!op->ParseOp(obj->Get(type), &ops[i])) { return Nan::ThrowTypeError("Incorrectly typed arguments to startBatch"); } op_vector->push_back(std::move(op)); @@ -753,7 +721,7 @@ NAN_METHOD(Call::StartBatch) { Callback *callback = new Callback(callback_func); grpc_call_error error = grpc_call_start_batch( call->wrapped_call, &ops[0], nops, new struct tag( - callback, op_vector.release(), resources, call), NULL); + callback, op_vector.release(), call), NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("startBatch failed", error)); } diff --git a/src/node/ext/call.h b/src/node/ext/call.h index 31c6566d145..cffff00fce4 100644 --- a/src/node/ext/call.h +++ b/src/node/ext/call.h @@ -51,20 +51,12 @@ namespace node { using std::unique_ptr; using std::shared_ptr; -typedef Nan::Persistent> PersistentValue; - v8::Local nanErrorWithCode(const char *msg, grpc_call_error code); v8::Local ParseMetadata(const grpc_metadata_array *metadata_array); -struct Resources { - std::vector > strings; - std::vector > handles; -}; - bool CreateMetadataArray(v8::Local metadata, - grpc_metadata_array *array, - shared_ptr resources); + grpc_metadata_array *array); /* Wrapper class for grpc_call structs. */ class Call : public Nan::ObjectWrap { @@ -106,8 +98,7 @@ class Call : public Nan::ObjectWrap { class Op { public: virtual v8::Local GetNodeValue() const = 0; - virtual bool ParseOp(v8::Local value, grpc_op *out, - shared_ptr resources) = 0; + virtual bool ParseOp(v8::Local value, grpc_op *out) = 0; virtual ~Op(); v8::Local GetOpType() const; virtual bool IsFinalOp() = 0; @@ -118,12 +109,10 @@ class Op { typedef std::vector> OpVec; struct tag { - tag(Nan::Callback *callback, OpVec *ops, - shared_ptr resources, Call *call); + tag(Nan::Callback *callback, OpVec *ops, Call *call); ~tag(); Nan::Callback *callback; OpVec *ops; - shared_ptr resources; Call *call; }; diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc index 81fc552fd10..4d172d4ddfd 100644 --- a/src/node/ext/call_credentials.cc +++ b/src/node/ext/call_credentials.cc @@ -206,7 +206,6 @@ NAN_METHOD(PluginCallback) { return Nan::ThrowTypeError( "The callback's fourth argument must be an object"); } - shared_ptr resources(new Resources); grpc_status_code code = static_cast( Nan::To(info[0]).FromJust()); Utf8String details_utf8_str(info[1]); @@ -214,7 +213,7 @@ NAN_METHOD(PluginCallback) { grpc_metadata_array array; Local callback_data = Nan::To(info[3]).ToLocalChecked(); if (!CreateMetadataArray(Nan::To(info[2]).ToLocalChecked(), - &array, resources)){ + &array)){ return Nan::ThrowError("Failed to parse metadata"); } grpc_credentials_plugin_metadata_cb cb = diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index 5bc58b9b324..c795ff7f42f 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -280,8 +280,7 @@ NAN_METHOD(Channel::WatchConnectivityState) { channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline), GetCompletionQueue(), new struct tag(callback, - ops.release(), - shared_ptr(nullptr), NULL)); + ops.release(), NULL)); CompletionQueueNext(); } diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc index 9b9eee85b79..682af0e5add 100644 --- a/src/node/ext/node_grpc.cc +++ b/src/node/ext/node_grpc.cc @@ -56,9 +56,12 @@ extern "C" { #include "server.h" #include "completion_queue_async_worker.h" #include "server_credentials.h" +#include "slice.h" #include "timeval.h" #include "completion_queue.h" +using grpc::node::CreateSliceFromString; + using v8::FunctionTemplate; using v8::Local; using v8::Value; @@ -283,10 +286,8 @@ NAN_METHOD(MetadataKeyIsLegal) { "headerKeyIsLegal's argument must be a string"); } Local key = Nan::To(info[0]).ToLocalChecked(); - Nan::Utf8String key_utf8_str(key); - char *key_str = *key_utf8_str; info.GetReturnValue().Set(static_cast( - grpc_header_key_is_legal(key_str, static_cast(key->Length())))); + grpc_header_key_is_legal(CreateSliceFromString(key)))); } NAN_METHOD(MetadataNonbinValueIsLegal) { @@ -295,11 +296,8 @@ NAN_METHOD(MetadataNonbinValueIsLegal) { "metadataNonbinValueIsLegal's argument must be a string"); } Local value = Nan::To(info[0]).ToLocalChecked(); - Nan::Utf8String value_utf8_str(value); - char *value_str = *value_utf8_str; info.GetReturnValue().Set(static_cast( - grpc_header_nonbin_value_is_legal( - value_str, static_cast(value->Length())))); + grpc_header_nonbin_value_is_legal(CreateSliceFromString(value)))); } NAN_METHOD(MetadataKeyIsBinary) { @@ -308,10 +306,8 @@ NAN_METHOD(MetadataKeyIsBinary) { "metadataKeyIsLegal's argument must be a string"); } Local key = Nan::To(info[0]).ToLocalChecked(); - Nan::Utf8String key_utf8_str(key); - char *key_str = *key_utf8_str; info.GetReturnValue().Set(static_cast( - grpc_is_binary_header(key_str, static_cast(key->Length())))); + grpc_is_binary_header(CreateSliceFromString(key)))); } static grpc_ssl_roots_override_result get_ssl_roots_override( diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc index 70d5b96f397..4761b2867db 100644 --- a/src/node/ext/server.cc +++ b/src/node/ext/server.cc @@ -46,6 +46,7 @@ #include "grpc/grpc_security.h" #include "grpc/support/log.h" #include "server_credentials.h" +#include "slice.h" #include "timeval.h" namespace grpc { @@ -99,10 +100,11 @@ class NewCallOp : public Op { } Local obj = Nan::New(); Nan::Set(obj, Nan::New("call").ToLocalChecked(), Call::WrapStruct(call)); + // TODO(murgatroid99): Use zero-copy string construction instead Nan::Set(obj, Nan::New("method").ToLocalChecked(), - Nan::New(details.method).ToLocalChecked()); + CopyStringFromSlice(details.method)); Nan::Set(obj, Nan::New("host").ToLocalChecked(), - Nan::New(details.host).ToLocalChecked()); + CopyStringFromSlice(details.host)); Nan::Set(obj, Nan::New("deadline").ToLocalChecked(), Nan::New(TimespecToMilliseconds(details.deadline)) .ToLocalChecked()); @@ -111,8 +113,7 @@ class NewCallOp : public Op { return scope.Escape(obj); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { return true; } bool IsFinalOp() { @@ -139,8 +140,7 @@ class ServerShutdownOp : public Op { return Nan::New(reinterpret_cast(server)); } - bool ParseOp(Local value, grpc_op *out, - shared_ptr resources) { + bool ParseOp(Local value, grpc_op *out) { return true; } bool IsFinalOp() { @@ -207,8 +207,7 @@ void Server::ShutdownServer() { grpc_server_shutdown_and_notify( this->wrapped_server, GetCompletionQueue(), - new struct tag(new Callback(**shutdown_callback), ops.release(), - shared_ptr(nullptr), NULL)); + new struct tag(new Callback(**shutdown_callback), ops.release(), NULL)); grpc_server_cancel_all_calls(this->wrapped_server); CompletionQueueNext(); this->wrapped_server = NULL; @@ -261,7 +260,7 @@ NAN_METHOD(Server::RequestCall) { GetCompletionQueue(), GetCompletionQueue(), new struct tag(new Callback(info[0].As()), ops.release(), - shared_ptr(nullptr), NULL)); + NULL)); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("requestCall failed", error)); } @@ -314,7 +313,7 @@ NAN_METHOD(Server::TryShutdown) { grpc_server_shutdown_and_notify( server->wrapped_server, GetCompletionQueue(), new struct tag(new Nan::Callback(info[0].As()), ops.release(), - shared_ptr(nullptr), NULL)); + NULL)); CompletionQueueNext(); } diff --git a/src/node/ext/slice.cc b/src/node/ext/slice.cc new file mode 100644 index 00000000000..98a80b3d2f9 --- /dev/null +++ b/src/node/ext/slice.cc @@ -0,0 +1,102 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "slice.h" +#include "byte_buffer.h" + +namespace grpc { +namespace node { + +using Nan::Persistent; + +using v8::Local; +using v8::String; +using v8::Value; + +namespace { +void SliceFreeCallback(char *data, void *hint) { + grpc_slice *slice = reinterpret_cast(hint); + grpc_slice_unref(*slice); + delete slice; +} + +void string_destroy_func(void *user_data) { + delete reinterpret_cast(user_data); +} + +void buffer_destroy_func(void *user_data) { + delete reinterpret_cast(user_data); +} +} // namespace + +grpc_slice CreateSliceFromString(const Local source) { + Nan::HandleScope scope; + Nan::Utf8String *utf8_value = new Nan::Utf8String(source); + return grpc_slice_new_with_user_data(**utf8_value, source->Length(), + string_destroy_func, utf8_value); +} + +grpc_slice CreateSliceFromBuffer(const Local source) { + // Prerequisite: ::node::Buffer::HasInstance(source) + Nan::HandleScope scope; + return grpc_slice_new_with_user_data(::node::Buffer::Data(source), + ::node::Buffer::Length(source), + buffer_destroy_func, + new PersistentValue(source)); +} +Local CopyStringFromSlice(const grpc_slice slice) { + Nan::EscapableHandleScope scope; + if (GRPC_SLICE_LENGTH(slice) == 0) { + return scope.Escape(Nan::EmptyString()); + } + return scope.Escape(Nan::New( + const_cast(reinterpret_cast(GRPC_SLICE_START_PTR(slice))), + GRPC_SLICE_LENGTH(slice)).ToLocalChecked()); +} + +Local CreateBufferFromSlice(const grpc_slice slice) { + Nan::EscapableHandleScope scope; + grpc_slice *slice_ptr = new grpc_slice; + *slice_ptr = grpc_slice_ref(slice); + return scope.Escape(MakeFastBuffer(Nan::NewBuffer( + const_cast(reinterpret_cast(GRPC_SLICE_START_PTR(*slice_ptr))), + GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr).ToLocalChecked())); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/slice.h b/src/node/ext/slice.h new file mode 100644 index 00000000000..7dcb1bd45a8 --- /dev/null +++ b/src/node/ext/slice.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +namespace grpc { +namespace node { + +typedef Nan::Persistent> PersistentValue; + +grpc_slice CreateSliceFromString(const v8::Local source); + +grpc_slice CreateSliceFromBuffer(const v8::Local source); + +v8::Local CopyStringFromSlice(const grpc_slice slice); + +v8::Local CreateBufferFromSlice(const grpc_slice slice); + +} // namespace node +} // namespace grpc diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 4759d26da53..230682e72d9 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -202,6 +202,7 @@ grpc_slice_slice_type grpc_slice_slice_import; grpc_slice_hash_type grpc_slice_hash_import; grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import; grpc_slice_dup_type grpc_slice_dup_import; +grpc_slice_to_c_string_type grpc_slice_to_c_string_import; grpc_slice_buffer_init_type grpc_slice_buffer_init_import; grpc_slice_buffer_destroy_type grpc_slice_buffer_destroy_import; grpc_slice_buffer_add_type grpc_slice_buffer_add_import; @@ -490,6 +491,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_slice_hash_import = (grpc_slice_hash_type) GetProcAddress(library, "grpc_slice_hash"); grpc_slice_is_equivalent_import = (grpc_slice_is_equivalent_type) GetProcAddress(library, "grpc_slice_is_equivalent"); grpc_slice_dup_import = (grpc_slice_dup_type) GetProcAddress(library, "grpc_slice_dup"); + grpc_slice_to_c_string_import = (grpc_slice_to_c_string_type) GetProcAddress(library, "grpc_slice_to_c_string"); grpc_slice_buffer_init_import = (grpc_slice_buffer_init_type) GetProcAddress(library, "grpc_slice_buffer_init"); grpc_slice_buffer_destroy_import = (grpc_slice_buffer_destroy_type) GetProcAddress(library, "grpc_slice_buffer_destroy"); grpc_slice_buffer_add_import = (grpc_slice_buffer_add_type) GetProcAddress(library, "grpc_slice_buffer_add"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 32386e81315..4c4f655b861 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -557,6 +557,9 @@ extern grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import; typedef grpc_slice(*grpc_slice_dup_type)(grpc_slice a); extern grpc_slice_dup_type grpc_slice_dup_import; #define grpc_slice_dup grpc_slice_dup_import +typedef char *(*grpc_slice_to_c_string_type)(grpc_slice s); +extern grpc_slice_to_c_string_type grpc_slice_to_c_string_import; +#define grpc_slice_to_c_string grpc_slice_to_c_string_import typedef void(*grpc_slice_buffer_init_type)(grpc_slice_buffer *sb); extern grpc_slice_buffer_init_type grpc_slice_buffer_init_import; #define grpc_slice_buffer_init grpc_slice_buffer_init_import From 70f4d26e0f164c2ccf5d9530681d25913a2c4509 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 9 Dec 2016 17:39:33 -0800 Subject: [PATCH 2/4] convert char* to grpc_slice in ruby --- src/ruby/ext/grpc/rb_byte_buffer.c | 7 ++ src/ruby/ext/grpc/rb_byte_buffer.h | 3 + src/ruby/ext/grpc/rb_call.c | 93 +++++++++++----------- src/ruby/ext/grpc/rb_channel.c | 27 +++++-- src/ruby/ext/grpc/rb_compression_options.c | 15 ++-- src/ruby/ext/grpc/rb_server.c | 10 ++- 6 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c index f97890e4a2e..0f15f70a28d 100644 --- a/src/ruby/ext/grpc/rb_byte_buffer.c +++ b/src/ruby/ext/grpc/rb_byte_buffer.c @@ -67,3 +67,10 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) { } return rb_string; } + +VALUE grpc_rb_slice_to_ruby_string(grpc_slice slice) { + if (GRPC_SLICE_START_PTR(slice) == NULL) { + rb_raise(rb_eRuntimeError, "attempt to convert uninitialized grpc_slice to ruby string"); + } + return rb_str_new((char*)GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice)); +} diff --git a/src/ruby/ext/grpc/rb_byte_buffer.h b/src/ruby/ext/grpc/rb_byte_buffer.h index c7ddd764890..fac68fe6a00 100644 --- a/src/ruby/ext/grpc/rb_byte_buffer.h +++ b/src/ruby/ext/grpc/rb_byte_buffer.h @@ -44,4 +44,7 @@ grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length); /* Converts a grpc_byte_buffer to a ruby string */ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer); +/* Converts a grpc_slice to a ruby string */ +VALUE grpc_rb_slice_to_ruby_string(grpc_slice slice); + #endif /* GRPC_RB_BYTE_BUFFER_H_ */ diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 67a42af619b..0179bd9e9b2 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -121,8 +121,8 @@ static size_t md_ary_datasize(const void *p) { size_t i, datasize = sizeof(grpc_metadata_array); for (i = 0; i < ary->count; ++i) { const grpc_metadata *const md = &ary->metadata[i]; - datasize += strlen(md->key); - datasize += md->value_length; + datasize += GRPC_SLICE_LENGTH(md->key); + datasize += GRPC_SLICE_LENGTH(md->value); } datasize += ary->capacity * sizeof(grpc_metadata); return datasize; @@ -386,23 +386,23 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { grpc_metadata_array *md_ary = NULL; long array_length; long i; - char *key_str; - size_t key_len; - char *value_str; - size_t value_len; + grpc_slice key_slice; + grpc_slice value_slice; + char* tmp_str; if (TYPE(key) == T_SYMBOL) { - key_str = (char *)rb_id2name(SYM2ID(key)); - key_len = strlen(key_str); - } else { /* StringValueCStr does all other type exclusions for us */ - key_str = StringValueCStr(key); - key_len = RSTRING_LEN(key); + key_slice = grpc_slice_from_static_string(rb_id2name(SYM2ID(key))); + } else if (TYPE(key) == T_STRING) { + key_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(key), RSTRING_LEN(key)); + } else { + rb_raise(rb_eTypeError, "grpc_rb_md_ary_fill_hash_cb: bad type for key parameter"); } - if (!grpc_header_key_is_legal(key_str, key_len)) { + if (!grpc_header_key_is_legal(key_slice)) { + tmp_str = grpc_slice_to_c_string(key_slice); rb_raise(rb_eArgError, "'%s' is an invalid header key, must match [a-z0-9-_.]+", - key_str); + tmp_str); return ST_STOP; } @@ -414,33 +414,31 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { array_length = RARRAY_LEN(val); /* If the value is an array, add capacity for each value in the array */ for (i = 0; i < array_length; i++) { - value_str = RSTRING_PTR(rb_ary_entry(val, i)); - value_len = RSTRING_LEN(rb_ary_entry(val, i)); - if (!grpc_is_binary_header(key_str, key_len) && - !grpc_header_nonbin_value_is_legal(value_str, value_len)) { + value_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(rb_ary_entry(val, i)), RSTRING_LEN(rb_ary_entry(val, i))); + if (!grpc_is_binary_header(key_slice) && + !grpc_header_nonbin_value_is_legal(value_slice)) { // The value has invalid characters + tmp_str = grpc_slice_to_c_string(value_slice); rb_raise(rb_eArgError, - "Header value '%s' has invalid characters", value_str); + "Header value '%s' has invalid characters", tmp_str); return ST_STOP; } - md_ary->metadata[md_ary->count].key = key_str; - md_ary->metadata[md_ary->count].value = value_str; - md_ary->metadata[md_ary->count].value_length = value_len; + md_ary->metadata[md_ary->count].key = key_slice; + md_ary->metadata[md_ary->count].value = value_slice; md_ary->count += 1; } } else if (TYPE(val) == T_STRING) { - value_str = RSTRING_PTR(val); - value_len = RSTRING_LEN(val); - if (!grpc_is_binary_header(key_str, key_len) && - !grpc_header_nonbin_value_is_legal(value_str, value_len)) { + value_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(val), RSTRING_LEN(val)); + if (!grpc_is_binary_header(key_slice) && + !grpc_header_nonbin_value_is_legal(value_slice)) { // The value has invalid characters + tmp_str = grpc_slice_to_c_string(value_slice); rb_raise(rb_eArgError, - "Header value '%s' has invalid characters", value_str); + "Header value '%s' has invalid characters", tmp_str); return ST_STOP; } - md_ary->metadata[md_ary->count].key = key_str; - md_ary->metadata[md_ary->count].value = value_str; - md_ary->metadata[md_ary->count].value_length = value_len; + md_ary->metadata[md_ary->count].key = key_slice; + md_ary->metadata[md_ary->count].value = value_slice; md_ary->count += 1; } else { rb_raise(rb_eArgError, @@ -506,22 +504,19 @@ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) { size_t i; for (i = 0; i < md_ary->count; i++) { - key = rb_str_new2(md_ary->metadata[i].key); + key = grpc_rb_slice_to_ruby_string(md_ary->metadata[i].key); value = rb_hash_aref(result, key); if (value == Qnil) { - value = rb_str_new(md_ary->metadata[i].value, - md_ary->metadata[i].value_length); + value = grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value); rb_hash_aset(result, key, value); } else if (TYPE(value) == T_ARRAY) { /* Add the string to the returned array */ - rb_ary_push(value, rb_str_new(md_ary->metadata[i].value, - md_ary->metadata[i].value_length)); + rb_ary_push(value, grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value)); } else { /* Add the current value with this key and the new one to an array */ new_ary = rb_ary_new(); rb_ary_push(new_ary, value); - rb_ary_push(new_ary, rb_str_new(md_ary->metadata[i].value, - md_ary->metadata[i].value_length)); + rb_ary_push(new_ary, grpc_rb_slice_to_ruby_string(md_ary->metadata[i].value)); rb_hash_aset(result, key, new_ary); } } @@ -563,6 +558,7 @@ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, */ static void grpc_rb_op_update_status_from_server(grpc_op *op, grpc_metadata_array *md_ary, + grpc_slice *send_status_details, VALUE status) { VALUE code = rb_struct_aref(status, sym_code); VALUE details = rb_struct_aref(status, sym_details); @@ -579,8 +575,11 @@ static void grpc_rb_op_update_status_from_server(grpc_op *op, rb_obj_classname(code)); return; } + + *send_status_details = grpc_slice_from_copied_buffer(RSTRING_PTR(details), RSTRING_LEN(details)); + op->data.send_status_from_server.status = NUM2INT(code); - op->data.send_status_from_server.status_details = StringValueCStr(details); + op->data.send_status_from_server.status_details = send_status_details; grpc_rb_md_ary_convert(metadata_hash, md_ary); op->data.send_status_from_server.trailing_metadata_count = md_ary->count; op->data.send_status_from_server.trailing_metadata = md_ary->metadata; @@ -603,9 +602,9 @@ typedef struct run_batch_stack { grpc_metadata_array recv_trailing_metadata; int recv_cancelled; grpc_status_code recv_status; - char *recv_status_details; - size_t recv_status_details_capacity; + grpc_slice recv_status_details; unsigned write_flag; + grpc_slice send_status_details; } run_batch_stack; /* grpc_run_batch_stack_init ensures the run_batch_stack is properly @@ -631,8 +630,12 @@ static void grpc_run_batch_stack_cleanup(run_batch_stack *st) { grpc_metadata_array_destroy(&st->recv_metadata); grpc_metadata_array_destroy(&st->recv_trailing_metadata); - if (st->recv_status_details != NULL) { - gpr_free(st->recv_status_details); + if (GRPC_SLICE_START_PTR(st->send_status_details) != NULL) { + grpc_slice_unref(st->send_status_details); + } + + if (GRPC_SLICE_START_PTR(st->recv_status_details) != NULL) { + grpc_slice_unref(st->recv_status_details); } if (st->recv_message != NULL) { @@ -683,7 +686,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { /* N.B. later there is no need to explicitly delete the metadata keys * and values, they are references to data in ruby objects. */ grpc_rb_op_update_status_from_server( - &st->ops[st->op_num], &st->send_trailing_metadata, this_value); + &st->ops[st->op_num], &st->send_trailing_metadata, &st->send_status_details, this_value); break; case GRPC_OP_RECV_INITIAL_METADATA: st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata; @@ -698,8 +701,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { &st->recv_status; st->ops[st->op_num].data.recv_status_on_client.status_details = &st->recv_status_details; - st->ops[st->op_num].data.recv_status_on_client.status_details_capacity = - &st->recv_status_details_capacity; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: st->ops[st->op_num].data.recv_close_on_server.cancelled = @@ -747,9 +748,9 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) { rb_struct_aset( result, sym_status, rb_struct_new(grpc_rb_sStatus, UINT2NUM(st->recv_status), - (st->recv_status_details == NULL + (GRPC_SLICE_START_PTR(st->recv_status_details) == NULL ? Qnil - : rb_str_new2(st->recv_status_details)), + : grpc_rb_slice_to_ruby_string(st->recv_status_details)), grpc_rb_md_ary_to_h(&st->recv_trailing_metadata), NULL)); break; diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 3b2b88eb774..84e43d3f7bf 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -35,6 +35,7 @@ #include "rb_grpc_imports.generated.h" #include "rb_channel.h" +#include "rb_byte_buffer.h" #include #include @@ -252,10 +253,14 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; int flags = GRPC_PROPAGATE_DEFAULTS; - char *method_chars = StringValueCStr(method); - char *host_chars = NULL; + grpc_slice method_slice; + grpc_slice host_slice; + grpc_slice *host_slice_ptr = NULL; + char* tmp_str = NULL; + if (host != Qnil) { - host_chars = StringValueCStr(host); + host_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host)); + host_slice_ptr = &host_slice; } if (mask != Qnil) { flags = NUM2UINT(mask); @@ -272,15 +277,25 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, return Qnil; } - call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars, - host_chars, grpc_rb_time_timeval( + method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method)); + + call = grpc_channel_create_call(ch, parent_call, flags, cq, method_slice, + host_slice_ptr, grpc_rb_time_timeval( deadline, /* absolute time */ 0), NULL); + if (call == NULL) { + tmp_str = grpc_slice_to_c_string(method_slice); rb_raise(rb_eRuntimeError, "cannot create call with method %s", - method_chars); + tmp_str); return Qnil; } + + grpc_slice_unref(method_slice); + if (host_slice_ptr != NULL) { + grpc_slice_unref(host_slice); + } + res = grpc_rb_wrap_call(call, cq); /* Make this channel an instance attribute of the call so that it is not GCed diff --git a/src/ruby/ext/grpc/rb_compression_options.c b/src/ruby/ext/grpc/rb_compression_options.c index 6200dbafeb8..6b2467ee461 100644 --- a/src/ruby/ext/grpc/rb_compression_options.c +++ b/src/ruby/ext/grpc/rb_compression_options.c @@ -34,6 +34,7 @@ #include #include "rb_compression_options.h" +#include "rb_byte_buffer.h" #include "rb_grpc_imports.generated.h" #include @@ -168,9 +169,9 @@ void grpc_rb_compression_options_set_default_level( * Raises an error if the name of the algorithm passed in is invalid. */ void grpc_rb_compression_options_algorithm_name_to_value_internal( grpc_compression_algorithm *algorithm_value, VALUE algorithm_name) { - char *name_str = NULL; - long name_len = 0; + grpc_slice name_slice; VALUE algorithm_name_as_string = Qnil; + char *tmp_str = NULL; Check_Type(algorithm_name, T_SYMBOL); @@ -178,16 +179,18 @@ void grpc_rb_compression_options_algorithm_name_to_value_internal( * correct C string out of it. */ algorithm_name_as_string = rb_funcall(algorithm_name, rb_intern("to_s"), 0); - name_str = RSTRING_PTR(algorithm_name_as_string); - name_len = RSTRING_LEN(algorithm_name_as_string); + name_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(algorithm_name_as_string), RSTRING_LEN(algorithm_name_as_string)); /* Raise an error if the name isn't recognized as a compression algorithm by * the algorithm parse function * in GRPC core. */ - if (!grpc_compression_algorithm_parse(name_str, name_len, algorithm_value)) { + if(!grpc_compression_algorithm_parse(name_slice, algorithm_value)) { + tmp_str = grpc_slice_to_c_string(name_slice); rb_raise(rb_eNameError, "Invalid compression algorithm name: %s", - StringValueCStr(algorithm_name_as_string)); + tmp_str); } + + grpc_slice_unref(name_slice); } /* Indicates whether a given algorithm is enabled on this instance, given the diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 2a6a246e677..7caafe7b8de 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -43,6 +43,7 @@ #include "rb_channel_args.h" #include "rb_completion_queue.h" #include "rb_server_credentials.h" +#include "rb_byte_buffer.h" #include "rb_grpc.h" /* grpc_rb_cServer is the ruby class that proxies grpc_server. */ @@ -160,8 +161,6 @@ static void grpc_request_call_stack_init(request_call_stack* st) { MEMZERO(st, request_call_stack, 1); grpc_metadata_array_init(&st->md_ary); grpc_call_details_init(&st->details); - st->details.method = NULL; - st->details.host = NULL; } /* grpc_request_call_stack_cleanup ensures the request_call_stack is properly @@ -185,6 +184,7 @@ static VALUE grpc_rb_server_request_call(VALUE self) { void *tag = (void*)&st; grpc_completion_queue *call_queue = grpc_completion_queue_create(NULL); gpr_timespec deadline; + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); @@ -212,11 +212,13 @@ static VALUE grpc_rb_server_request_call(VALUE self) { return Qnil; } + + /* build the NewServerRpc struct result */ deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME); result = rb_struct_new( - grpc_rb_sNewServerRpc, rb_str_new2(st.details.method), - rb_str_new2(st.details.host), + grpc_rb_sNewServerRpc, grpc_rb_slice_to_ruby_string(st.details.method), + grpc_rb_slice_to_ruby_string(st.details.host), rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec), INT2NUM(deadline.tv_nsec / 1000)), grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call, call_queue), From 4038cbff1a3a98ae8c7ea422e22a9da55e46f313 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 12 Dec 2016 20:36:48 +0100 Subject: [PATCH 3/4] make grpc_csharp_ext compile --- .../Internal/BatchContextSafeHandle.cs | 4 +- .../Internal/MetadataArraySafeHandle.cs | 10 ++- .../Grpc.Core/Internal/NativeMethods.cs | 13 ++-- .../Internal/RequestCallContextSafeHandle.cs | 10 ++- src/csharp/ext/grpc_csharp_ext.c | 65 ++++++++----------- 5 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs index 26449ee5393..0e4a77be81a 100644 --- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs @@ -71,7 +71,9 @@ namespace Grpc.Core.Internal // Gets data of recv_status_on_client completion. public ClientSideStatus GetReceivedStatusOnClient() { - string details = Marshal.PtrToStringAnsi(Native.grpcsharp_batch_context_recv_status_on_client_details(this)); + UIntPtr detailsLength; + IntPtr detailsPtr = Native.grpcsharp_batch_context_recv_status_on_client_details(this, out detailsLength); + string details = Marshal.PtrToStringAnsi(detailsPtr, (int) detailsLength.ToUInt32()); var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details); IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this); diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs index 05dda5b1486..d5b87a6c945 100644 --- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs @@ -79,9 +79,13 @@ namespace Grpc.Core.Internal for (ulong i = 0; i < count; i++) { var index = new UIntPtr(i); - string key = Marshal.PtrToStringAnsi(Native.grpcsharp_metadata_array_get_key(metadataArray, index)); - var bytes = new byte[Native.grpcsharp_metadata_array_get_value_length(metadataArray, index).ToUInt64()]; - Marshal.Copy(Native.grpcsharp_metadata_array_get_value(metadataArray, index), bytes, 0, bytes.Length); + UIntPtr keyLen; + IntPtr keyPtr = Native.grpcsharp_metadata_array_get_key(metadataArray, index, out keyLen); + string key = Marshal.PtrToStringAnsi(keyPtr, (int)keyLen.ToUInt32()); + UIntPtr valueLen; + IntPtr valuePtr = Native.grpcsharp_metadata_array_get_value(metadataArray, index, out valueLen); + var bytes = new byte[valueLen.ToUInt64()]; + Marshal.Copy(valuePtr, bytes, 0, bytes.Length); metadata.Add(Metadata.Entry.CreateUnsafe(key, bytes)); } return metadata; diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs index ce38e370936..2f377071f79 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs @@ -128,7 +128,6 @@ namespace Grpc.Core.Internal public readonly Delegates.grpcsharp_metadata_array_count_delegate grpcsharp_metadata_array_count; public readonly Delegates.grpcsharp_metadata_array_get_key_delegate grpcsharp_metadata_array_get_key; public readonly Delegates.grpcsharp_metadata_array_get_value_delegate grpcsharp_metadata_array_get_value; - public readonly Delegates.grpcsharp_metadata_array_get_value_length_delegate grpcsharp_metadata_array_get_value_length; public readonly Delegates.grpcsharp_metadata_array_destroy_full_delegate grpcsharp_metadata_array_destroy_full; public readonly Delegates.grpcsharp_redirect_log_delegate grpcsharp_redirect_log; @@ -237,7 +236,6 @@ namespace Grpc.Core.Internal this.grpcsharp_metadata_array_count = GetMethodDelegate(library); this.grpcsharp_metadata_array_get_key = GetMethodDelegate(library); this.grpcsharp_metadata_array_get_value = GetMethodDelegate(library); - this.grpcsharp_metadata_array_get_value_length = GetMethodDelegate(library); this.grpcsharp_metadata_array_destroy_full = GetMethodDelegate(library); this.grpcsharp_redirect_log = GetMethodDelegate(library); @@ -306,15 +304,15 @@ namespace Grpc.Core.Internal public delegate IntPtr grpcsharp_batch_context_recv_message_length_delegate(BatchContextSafeHandle ctx); public delegate void grpcsharp_batch_context_recv_message_to_buffer_delegate(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen); public delegate StatusCode grpcsharp_batch_context_recv_status_on_client_status_delegate(BatchContextSafeHandle ctx); - public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx); // returns const char* + public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength); public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx); public delegate int grpcsharp_batch_context_recv_close_on_server_cancelled_delegate(BatchContextSafeHandle ctx); public delegate void grpcsharp_batch_context_destroy_delegate(IntPtr ctx); public delegate RequestCallContextSafeHandle grpcsharp_request_call_context_create_delegate(); public delegate CallSafeHandle grpcsharp_request_call_context_call_delegate(RequestCallContextSafeHandle ctx); - public delegate IntPtr grpcsharp_request_call_context_method_delegate(RequestCallContextSafeHandle ctx); // returns const char* - public delegate IntPtr grpcsharp_request_call_context_host_delegate(RequestCallContextSafeHandle ctx); // returns const char* + public delegate IntPtr grpcsharp_request_call_context_method_delegate(RequestCallContextSafeHandle ctx, out UIntPtr methodLength); + public delegate IntPtr grpcsharp_request_call_context_host_delegate(RequestCallContextSafeHandle ctx, out UIntPtr hostLength); public delegate Timespec grpcsharp_request_call_context_deadline_delegate(RequestCallContextSafeHandle ctx); public delegate IntPtr grpcsharp_request_call_context_request_metadata_delegate(RequestCallContextSafeHandle ctx); public delegate void grpcsharp_request_call_context_destroy_delegate(IntPtr ctx); @@ -384,9 +382,8 @@ namespace Grpc.Core.Internal public delegate MetadataArraySafeHandle grpcsharp_metadata_array_create_delegate(UIntPtr capacity); public delegate void grpcsharp_metadata_array_add_delegate(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength); public delegate UIntPtr grpcsharp_metadata_array_count_delegate(IntPtr metadataArray); - public delegate IntPtr grpcsharp_metadata_array_get_key_delegate(IntPtr metadataArray, UIntPtr index); - public delegate IntPtr grpcsharp_metadata_array_get_value_delegate(IntPtr metadataArray, UIntPtr index); - public delegate UIntPtr grpcsharp_metadata_array_get_value_length_delegate(IntPtr metadataArray, UIntPtr index); + public delegate IntPtr grpcsharp_metadata_array_get_key_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength); + public delegate IntPtr grpcsharp_metadata_array_get_value_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength); public delegate void grpcsharp_metadata_array_destroy_full_delegate(IntPtr array); public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback); diff --git a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs index ea7819d7b1f..c1560bc8bf4 100644 --- a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs @@ -66,8 +66,14 @@ namespace Grpc.Core.Internal { var call = Native.grpcsharp_request_call_context_call(this); - var method = Marshal.PtrToStringAnsi(Native.grpcsharp_request_call_context_method(this)); - var host = Marshal.PtrToStringAnsi(Native.grpcsharp_request_call_context_host(this)); + UIntPtr methodLen; + IntPtr methodPtr = Native.grpcsharp_request_call_context_method(this, out methodLen); + var method = Marshal.PtrToStringAnsi(methodPtr, (int) methodLen.ToUInt32()); + + UIntPtr hostLen; + IntPtr hostPtr = Native.grpcsharp_request_call_context_host(this, out hostLen); + var host = Marshal.PtrToStringAnsi(hostPtr, (int) hostLen.ToUInt32()); + var deadline = Native.grpcsharp_request_call_context_deadline(this); IntPtr metadataArrayPtr = Native.grpcsharp_request_call_context_request_metadata(this); diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 618522a3b50..12c747b8008 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -73,15 +73,13 @@ typedef struct grpcsharp_batch_context { grpc_byte_buffer *send_message; struct { grpc_metadata_array trailing_metadata; - char *status_details; } send_status_from_server; grpc_metadata_array recv_initial_metadata; grpc_byte_buffer *recv_message; struct { grpc_metadata_array trailing_metadata; grpc_status_code status; - char *status_details; - size_t status_details_capacity; + grpc_slice status_details; } recv_status_on_client; int recv_close_on_server_cancelled; } grpcsharp_batch_context; @@ -178,21 +176,17 @@ grpcsharp_metadata_array_count(grpc_metadata_array *array) { } GPR_EXPORT const char *GPR_CALLTYPE -grpcsharp_metadata_array_get_key(grpc_metadata_array *array, size_t index) { +grpcsharp_metadata_array_get_key(grpc_metadata_array *array, size_t index, size_t *key_length) { GPR_ASSERT(index < array->count); - return array->metadata[index].key; + *key_length = GRPC_SLICE_LENGTH(array->metadata[index].key); + return (char *)GRPC_SLICE_START_PTR(array->metadata[index].key); } GPR_EXPORT const char *GPR_CALLTYPE -grpcsharp_metadata_array_get_value(grpc_metadata_array *array, size_t index) { +grpcsharp_metadata_array_get_value(grpc_metadata_array *array, size_t index, size_t *value_length) { GPR_ASSERT(index < array->count); - return array->metadata[index].value; -} - -GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_metadata_array_get_value_length( - grpc_metadata_array *array, size_t index) { - GPR_ASSERT(index < array->count); - return (intptr_t)array->metadata[index].value_length; + *value_length = GRPC_SLICE_LENGTH(array->metadata[index].value); + return (char *)GRPC_SLICE_START_PTR(array->metadata[index].value); } /* Move contents of metadata array */ @@ -225,7 +219,6 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_destroy(grpcsharp_batch_con grpcsharp_metadata_array_destroy_metadata_including_entries( &(ctx->send_status_from_server.trailing_metadata)); - gpr_free(ctx->send_status_from_server.status_details); grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata)); @@ -233,7 +226,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_destroy(grpcsharp_batch_con grpcsharp_metadata_array_destroy_metadata_only( &(ctx->recv_status_on_client.trailing_metadata)); - gpr_free((void *)ctx->recv_status_on_client.status_details); + grpc_slice_unref(ctx->recv_status_on_client.status_details); gpr_free(ctx); } @@ -305,8 +298,9 @@ grpcsharp_batch_context_recv_status_on_client_status( GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_recv_status_on_client_details( - const grpcsharp_batch_context *ctx) { - return ctx->recv_status_on_client.status_details; + const grpcsharp_batch_context *ctx, size_t *details_length) { + *details_length = GRPC_SLICE_LENGTH(ctx->recv_status_on_client.status_details); + return (char *)GRPC_SLICE_START_PTR(ctx->recv_status_on_client.status_details); } GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE @@ -322,13 +316,15 @@ GPR_EXPORT grpc_call *GPR_CALLTYPE grpcsharp_request_call_context_call( GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_request_call_context_method( - const grpcsharp_request_call_context *ctx) { - return ctx->call_details.method; + const grpcsharp_request_call_context *ctx, size_t *method_length) { + *method_length = GRPC_SLICE_LENGTH(ctx->call_details.method); + return (char *)GRPC_SLICE_START_PTR(ctx->call_details.method); } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_request_call_context_host( - const grpcsharp_request_call_context *ctx) { - return ctx->call_details.host; + const grpcsharp_request_call_context *ctx, size_t *host_length) { + *host_length = GRPC_SLICE_LENGTH(ctx->call_details.host); + return (char *)GRPC_SLICE_START_PTR(ctx->call_details.host); } GPR_EXPORT gpr_timespec GPR_CALLTYPE @@ -403,9 +399,14 @@ grpcsharp_channel_create_call(grpc_channel *channel, grpc_call *parent_call, const char *method, const char *host, gpr_timespec deadline) { grpc_slice method_slice = grpc_slice_from_copied_string(method); - grpc_slice host_slice = host == NULL ? grpc_empty_string() : grpc_slice_from_copied_string(host); - grpc_call *grpc_channel_create_call(channel, parent_call, propagation_mask, cq, - method_slice, host_slice, deadline, NULL); + grpc_slice *host_slice_ptr = NULL; + grpc_slice host_slice; + if (host != NULL) { + host_slice = grpc_slice_from_copied_string(host); + host_slice_ptr = &host_slice; + } + return grpc_channel_create_call(channel, parent_call, propagation_mask, cq, + method_slice, host_slice_ptr, deadline, NULL); } GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE @@ -560,11 +561,8 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, &(ctx->recv_status_on_client.trailing_metadata); ops[5].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); - /* not using preallocation for status_details */ ops[5].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); - ops[5].data.recv_status_on_client.status_details_capacity = - &(ctx->recv_status_on_client.status_details_capacity); ops[5].flags = 0; ops[5].reserved = NULL; @@ -604,11 +602,8 @@ grpcsharp_call_start_client_streaming(grpc_call *call, &(ctx->recv_status_on_client.trailing_metadata); ops[3].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); - /* not using preallocation for status_details */ ops[3].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); - ops[3].data.recv_status_on_client.status_details_capacity = - &(ctx->recv_status_on_client.status_details_capacity); ops[3].flags = 0; ops[3].reserved = NULL; @@ -647,11 +642,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( &(ctx->recv_status_on_client.trailing_metadata); ops[3].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); - /* not using preallocation for status_details */ ops[3].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); - ops[3].data.recv_status_on_client.status_details_capacity = - &(ctx->recv_status_on_client.status_details_capacity); ops[3].flags = 0; ops[3].reserved = NULL; @@ -681,11 +673,8 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, &(ctx->recv_status_on_client.trailing_metadata); ops[1].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); - /* not using preallocation for status_details */ ops[1].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); - ops[1].data.recv_status_on_client.status_details_capacity = - &(ctx->recv_status_on_client.status_details_capacity); ops[1].flags = 0; ops[1].reserved = NULL; @@ -749,10 +738,10 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( grpc_op ops[3]; memset(ops, 0, sizeof(ops)); size_t nops = 1; + grpc_slice status_details_slice = grpc_slice_from_copied_string(status_details); ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER; ops[0].data.send_status_from_server.status = status_code; - ops[0].data.send_status_from_server.status_details = - gpr_strdup(status_details); + ops[0].data.send_status_from_server.status_details = &status_details_slice; grpcsharp_metadata_array_move( &(ctx->send_status_from_server.trailing_metadata), trailing_metadata); ops[0].data.send_status_from_server.trailing_metadata_count = From 5b7c5f52163a23b06bb0d329b2544e6c5fb1d521 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 13 Dec 2016 10:48:21 +0100 Subject: [PATCH 4/4] fix compiler warning in hpack_parser.c --- src/core/ext/transport/chttp2/transport/hpack_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c index 3c7d5e83104..5dabe272d39 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_parser.c +++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c @@ -1511,7 +1511,7 @@ static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end, uint8_t binary, grpc_chttp2_hpack_parser_string *str) { - if (!p->huff && binary == NOT_BINARY && (end - cur) >= p->strlen && + if (!p->huff && binary == NOT_BINARY && (end - cur) >= (intptr_t)p->strlen && p->current_slice_refcount != NULL) { str->copied = false; str->data.referenced.refcount = p->current_slice_refcount;