Skip to content

Stream terminated by RST_STREAM with PROTOCOL_ERROR when listening on unix domain socket #742

Closed
@BogdanIonesq

Description

@BogdanIonesq

Bug Report

Version

tonic v0.5.2
tonic-build v0.5.2

Platform

Linux 5.13.9-arch1-1 x86_64 GNU/Linux

Description

I tried to keep the example as small as possible:
proto/hello.proto

syntax = "proto3";

package hello;

service HelloService {
  rpc SayHello(HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string first_name = 1;
  string middle_name = 2;
  string last_name = 3;
}

Cargo.toml

...
[[bin]]
name = "server"
path = "src/server.rs"

[dependencies]
tonic = "0.5"
prost = "0.8"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
futures = "0.3.16"
async-stream = "0.3.2"

[build-dependencies]
tonic-build = "0.5"

src/server.rs

use tonic::{transport::Server, Request, Response, Status};
use hello::{HelloRequest, HelloResponse};
use hello::hello_service_server::{HelloService, HelloServiceServer};
use std::path::Path;
use tokio::net::{UnixListener};
use futures::TryFutureExt;
mod unix;

pub mod hello {
    tonic::include_proto!("hello");
}

#[derive(Debug, Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl HelloService for MyGreeter {
    async fn say_hello(
        &self,
        request: Request<HelloRequest>,
    ) -> Result<Response<HelloResponse>, Status> {
        println!("Got a request: {:?}", request);

        let reply = HelloResponse {
            first_name: format!("first").into(),
            middle_name: format!("middle").into(),
            last_name: format!("last").into(),
        };

        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Starting Greeter ...");

    let sock_path = Path::new("/tmp/example.sock");
    let greeter = MyGreeter::default();

    let incoming = {
        let uds = UnixListener::bind(sock_path)?;

        async_stream::stream! {
            while let item = uds.accept().map_ok(|(st, _)| unix::UnixStream(st)).await {
                yield item;
            }
        }
    };

    Server::builder()
        .add_service(HelloServiceServer::new(greeter))
        .serve_with_incoming(incoming)
        .await?;

    Ok(())
}

Along with the straightforward build.rs (compiling the proto/hello.proto) and the mod unix found in the uds example.

Running cargo run --bin server successfully starts the server. However, when executing a grpcurl call from the proto/ directory, the following error is encountered:

$ grpcurl -plaintext -proto hello.proto -d '{"greeting": "hello"}' -unix /tmp/example.sock hello.HelloService/SayHello
ERROR:
  Code: Internal
  Message: stream terminated by RST_STREAM with error code: PROTOCOL_ERROR

I have first encountered this error when executing a gRPC call from a Go client, so I do not think that it is an issue from grpcurl. It seems to be related to the unix domain socket listener, since listening on a random TCP port works:

$ grpcurl -plaintext -proto hello.proto -d '{"greeting": "hello"}' 127.0.0.1:4444 hello.HelloService/SayHello
{
  "firstName": "first",
  "middleName": "middle",
  "lastName": "last"
}

Any ideas how this can be fixed or what the root cause is?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions