Emulating type-independent service method call on server side, C++

53 views
Skip to first unread message

Alexovsky

unread,
Nov 14, 2023, 1:10:53 PM11/14/23
to grpc.io
Hello, I’m exploring the possibility of calling service methods and passing existing data to it.
That is, starting the server to function without an explicit connection to the client and receiving data from the client. This is something like a transport, should work over UDP and is suitable for *unary* requests and responses.
Based on *helloworld*.
Used: hack of contract violation and access to private fields; custom types for mirroring inaccessible types from *.cc.
Everything works, `GreeterServiceImpl::SayHello` is called with the necessary data, and there are the following problems.
I’m struggling with resource leaks now and the thread `ThreadInternalsWindows::thread_body` hangs forever in the function
`grpc::internal::UnaryRunHandlerHelper()` on call
`param.call->cq()->Pluck(&ops);`
Any ideas on how to fix it? Or perhaps try a different approach to calling service methods?
Here are some of the steps:
```
// client data, from gRPC helloworld, done as SerializeToArray()
std::vector< unsigned char > fromUdp = { 0x0a, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64 };
// get grpc_core server
::grpc_core::Server *servC = ::grpc_core::Server::FromC( server ->c_server( ) );
// 'unprivate' hack to get access to '&grpc_core::Server::registered_methods_'
typedef std::vector<std::unique_ptr<grpc_core::Server::RegisteredMethod>> &rm_t;
rm_t vecRm2 = (servC) ->*get(B_member());
// at index 0 is "/helloworld.Greeter/SayHello"
grpc_core_Server_RegisteredMethod *srm0 =
(grpc_core_Server_RegisteredMethod *)vecRm2[ 0 ].get( );
// main method
auto matcher = srm0 ->matcher.get( );
// main call object
grpc_call_create_args args_call_create = {};
// emulate grpc_core::Server::ChannelData::AcceptStream and Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone
...
// create channel
...
absl::StatusOr<grpc_core::RefCountedPtr<grpc_core::Channel>> channel0 =
grpc_core::Channel::CreateWithBuilder( &builder );
grpc_core::RefCountedPtr<grpc_core::Channel> channelX = channel0.value( );
...
// filling main call object
args_call_create.channel = channelX;
args_call_create.server = servC;
args_call_create.server_transport_data = reinterpret_cast<void* >( id ); // for !is_client
args_call_create.send_deadline = grpc_core::Timestamp::InfFuture( );
// prepare to filling client data
grpc_call* call;
grpc_error_handle error = grpc_call_create( &args_call_create, &call );
grpc_call_stack* call_stack = grpc_call_get_call_stack( call );
grpc_call_element* elem = grpc_call_stack_element(call_stack, 0);
auto* calld = static_cast<grpc_core::Server::CallData*>(elem->call_data);
calld ->Start( elem );
// filling client data
calld ->payload_ = grpc_raw_byte_buffer_create( nullptr, 0 );
grpc_byte_buffer* buffer = calld ->payload_;
grpc_core::SliceBuffer buf;
grpc_core::Slice single = grpc_core::Slice::FromCopiedBuffer( fromUdp.data( ), fromUdp.size( ) );
buf.Append( std::move( single ) );
grpc_slice_buffer_move_into( buf.c_slice_buffer( ), &calld ->payload_ ->data.raw.slice_buffer );
// call main method
matcher ->MatchOrQueue( 0, calld );
// something to wait execution in other thread
std::this_thread::sleep_for( std::chrono::seconds( 3 ) );
```
I think I need to emulate a call to some kind of `grpc_closure` in `ExecCtx::Flush`, I can’t find it yet.
This is my first post. While searching, I couldn't find anyone posting links to their repo here. Can I post a GitHub link here as an add-on?

Alexovsky

unread,
Nov 16, 2023, 9:37:40 AM11/16/23
to grpc.io
A solution has been found.
```
while ( true ) {
grpc_core_FilterStackCall *filterStackCall = (grpc_core_FilterStackCall *)calld ->call_;
grpc_completion_queue *call_cq_pluck = filterStackCall ->cq_;
int num_polls = call_cq_pluck ->num_polls; // no thread safe
if ( num_polls > 0 ) {
cqd_pluck ->shutdown = true; // atomic
break;
}
std::this_thread::sleep_for( std::chrono::milliseconds( 300 ) );
}
```
It is better, of course, to use `grpc::internal::BlockingUnaryCall`, which can accept `google::protobuf::Message*`
created via `google::protobuf::DynamicMessageFactory`
The channel `server ->InProcessChannel( grpc::ChannelArguments{ } );` is suitable for both reflection and calling.
Reply all
Reply to author
Forward
0 new messages