containerd / ttrpc-rust

Rust implementation of ttrpc (GRPC for low-memory environments)
Apache License 2.0
195 stars 45 forks source link

client block when server return something with mh.length = 0 #49

Closed windniw closed 4 years ago

windniw commented 4 years ago

Description of problem

https://github.com/containerd/ttrpc/blob/master/example/example.proto

Rust-client will block when calling go-ttrpc-server in method2

client code

        let resp = protocols::example_ttrpc::ExampleClient::new(self.conn.clone()).method2(&req, 0);
        print!("Get response from server {:?}", resp);

client log

$ RUST_LOG=trace cargo run client
    ...
    Finished dev [unoptimized + debuginfo] target(s) in 7.29s
     Running `target/debug/ttrpc-in-rust client`
[TRACE ttrpc::channel] Got Message header MessageHeader { length: 0, stream_id: 1, type_: 2, flags: 0 }

Bug

for method which return an empty like

rpc Method2(Method1Request) returns (google.protobuf.Empty);

rust server

    fn method2(
        &self,
        _ctx: &::ttrpc::TtrpcContext,
        req: protocolsx::example::Method1Request,
    ) -> ::ttrpc::Result<protocolsx::empty::Empty> {
        Ok(protocolsx::empty::Empty::new());
    }

// server send response like 
// MessageHeader { length: 2, stream_id: 1, type_: 2, flags: 0 }
// Message body [10, 0]

go server

func (s *exampleServer) Method2(ctx context.Context, r *example.Method1Request) (*types.Empty, error) {
    return &types.Empty{}, nil
}

// server send response like 
// MessageHeader { length: 0, stream_id: 1, type_: 2, flags: 0 }
// Message body []

https://github.com/containerd/ttrpc-rust/blob/2873753befd530fa4f5cee6f94e1e4b67d417aed/src/sync/channel.rs#L99-L113 https://github.com/containerd/ttrpc-rust/blob/2873753befd530fa4f5cee6f94e1e4b67d417aed/src/sync/channel.rs#L24-L30

That's why it looks good in rust but die in go. When mh.length == 0, client still try to read something from the socket with MsgFlags::empty() instead of MsgFlags::MSG_DONTWAIT which cause this block.

windniw commented 4 years ago

I add a check if mh.length == 0, skip read_count. It looks working well in this kind of response. Could I fix it in this way ?