grpc / grpc

The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)

Home Page:https://grpc.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Not able to set certain message field of protocol buffers of type ENUM

samrajput1143 opened this issue · comments

Iam using Proto 3, cmake_minimum_required(VERSION 3.14), and a c++ Standard 11.

Below Iam attaching Proto file content

syntax = "proto3";
package api;

enum RICControlCellTypeEnum {

RIC_CONTROL_CELL_UNKWON = 0;
RIC_CONTROL_NR_CELL = 1; 		// Indicates RIC Controls should be set for NR CELL
RIC_CONTROL_EUTRAN_CELL = 2;    // Indicates RIC Controls should be set for E_UTRAN CELL

}

enum RICControlAckEnum {

RIC_CONTROL_ACK_UNKWON = 0;
RIC_CONTROL_NO_ACK = 1; // Optional RIC Control Acknowledgement is not required
RIC_CONTROL_ACK = 2;    // Optional RIC Control Acknowledgement is required
RIC_CONTROL_NACK = 3;   // Optional RIC Control Acknowledgement is only required to report failure

}

message RICE2APHeader {
int64 RanFuncId = 1;
int64 RICRequestorID = 2;
}

message RICControlHeader {
int64 ControlStyle = 1;
int64 ControlActionId = 2;
string UEID = 3;
}

message RICControlMessage {
RICControlCellTypeEnum RICControlCellTypeVal = 1;
string TargetCellID = 2;

}

//RicControl GRPC Req
message RicControlGrpcReq {
string e2NodeID = 1;
string plmnID = 2;
string ranName = 3;
RICE2APHeader RICE2APHeaderData = 4;
RICControlHeader RICControlHeaderData = 5;
RICControlMessage RICControlMessageData = 6;
RICControlAckEnum RICControlAckReqVal = 7; //Currently this Parameter is not Encoded as Part of RIC Control message
}

//RicControlGrpc Rsp
message RicControlGrpcRsp {
int32 rspCode = 1; //Set rspCode to 0. Acknowledging the receipt of GRPC request
string description = 2; //Set despcription.
}

// Services to send gRPC
service MsgComm {
//gRPC call to Send RICControlReqServiceGrpc
rpc SendRICControlReqServiceGrpc(RicControlGrpcReq) returns (RicControlGrpcRsp);
}

This is my Client side code

`shared_ptrgrpc::Channel channel;
std::unique_ptrapi::MsgComm::Stub rc_stub;
channel = grpc::CreateChannel(ts_control_ep, grpc::InsecureChannelCredentials());
rc_stub = api::MsgComm::NewStub(channel, grpc::StubOptions());
grpc::ClientContext context;

api::RicControlGrpcRsp response;
shared_ptrapi::RicControlGrpcReq request = make_sharedapi::RicControlGrpcReq();

api::RICE2APHeader *apHeader = request->mutable_rice2apheaderdata();
apHeader->set_ranfuncid( 300 );
apHeader->set_ricrequestorid( 1001 );

api::RICControlHeader *ctrlHeader = request->mutable_riccontrolheaderdata();
ctrlHeader->set_controlstyle( 3 );
ctrlHeader->set_controlactionid( 1 );
ctrlHeader->set_ueid( ue_id );

api::RICControlMessage *ctrlMsg = request->mutable_riccontrolmessagedata();
ctrlMsg->set_riccontrolcelltypeval( api::RIC_CONTROL_CELL_UNKWON );
ctrlMsg->set_targetcellid( target_cell_id );

request->set_e2nodeid( "unknown_e2nodeid" );
request->set_plmnid( "unknown_plmnid" );
request->set_ranname( "unknown_ranname" );

request->set_riccontrolackreqval( api::RIC_CONTROL_ACK_UNKWON );

grpc::Status status = rc_stub->SendRICControlReqServiceGrpc( &context, *request, &response );
`

This is my basic verison of server side code

`class ControlServiceImpl : public api::MsgComm::Service {
::grpc::Status SendRICControlReqServiceGrpc(::grpc::ServerContext* context, const ::api::RicControlGrpcReq* request,
::api::RicControlGrpcRsp* response) override {

    cout << "[RC] gRPC message received\n==============================\n"
            << request->DebugString() << "==============================\n";

    /*
        TODO check if this is related to RICControlAckEnum
        if yes, then ACK value should be 2 (RIC_CONTROL_ACK)
        api.proto assumes that 0 is an ACK
    */
    response->set_rspcode(0);
    response->set_description("ACK");

    return ::grpc::Status::OK;
}

};

void RunServer() {
string server_address("0.0.0.0:50051");
ControlServiceImpl service;

grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);

unique_ptr<grpc::Server> server(builder.BuildAndStart());

cout << "[RC] Server listening on " << server_address << std::endl;
server->Wait();

}

int main(int argc, char const *argv[]) {
RunServer();

return 0;

}`

Iam expecting see a output of DebugString() on server side something like this
image

But Iam getting an output of DebugString() on server side as below

[RC] gRPC message received

e2NodeID: "unknown_e2nodeid"
plmnID: "unknown_plmnid"
ranName: "unknown_ranname"
RICE2APHeaderData {
RanFuncId: 300
RICRequestorID: 1001
}
RICControlHeaderData {
ControlStyle: 3
ControlActionId: 1
UEID: "Indoor-6"
}
RICControlMessageData {
TargetCellID: "s2/B13"
}

Clearly it can be seen from this message that some of the field in this message is missing (and this missing field is basically of enum type)

I have also captured the packet and analyzed in Wireshark.
In that packet GRPC capture , I also find that these enum field are missing.
I have attached an image as well

image

It seems like you don't have the same proto definition on both client & server. Given that RICControlAckReqVal is not optional for example, I'm guessing the server was compiled against an older definition.

Here is my server side proto file and it is exactly matching with the client side

syntax = "proto3";
package api;

enum RICControlCellTypeEnum {

RIC_CONTROL_CELL_UNKWON = 0; 
RIC_CONTROL_NR_CELL = 1; 		// Indicates RIC Controls should be set for NR CELL
RIC_CONTROL_EUTRAN_CELL = 2;    // Indicates RIC Controls should be set for E_UTRAN CELL

}

enum RICControlAckEnum {

RIC_CONTROL_ACK_UNKWON = 0; 
RIC_CONTROL_NO_ACK = 1; // Optional RIC Control Acknowledgement is not required
RIC_CONTROL_ACK = 2;    // Optional RIC Control Acknowledgement is required
RIC_CONTROL_NACK = 3;   // Optional RIC Control Acknowledgement is only required to report failure

}

message RICE2APHeader {
int64 RanFuncId = 1;
int64 RICRequestorID = 2;
}

message RICControlHeader {
int64 ControlStyle = 1;
int64 ControlActionId = 2;
UeId UEID = 3;
}

message UeId {
gNBUEID GnbUEID = 1;
}

message gNBUEID {
int64 amfUENGAPID = 1;
Guami guami = 2;
repeated int64 gNBCUUEF1APID = 3;
repeated int64 gNBCUCPUEE1APID = 4;
}

message Guami {
string pLMNIdentity = 1;
string aMFRegionID = 2;
string aMFSetID = 3;
string aMFPointer = 4;
}

message RICControlMessage {
RICControlCellTypeEnum RICControlCellTypeVal = 1;
string TargetCellID = 2;

}

//RicControl GRPC Req
message RicControlGrpcReq {
string e2NodeID = 1;
string plmnID = 2;
string ranName = 3;
RICE2APHeader RICE2APHeaderData = 4;
RICControlHeader RICControlHeaderData = 5;
RICControlMessage RICControlMessageData = 6;
RICControlAckEnum RICControlAckReqVal = 7; //Currently this Parameter is not Encoded as Part of RIC Control message
}

//RicControlGrpc Rsp
message RicControlGrpcRsp {
int32 rspCode = 1; //Set rspCode to 0. Acknowledging the receipt of GRPC request
string description = 2; //Set despcription.
}

// Services to send gRPC
service MsgComm {
//gRPC call to Send RICControlReqServiceGrpc
rpc SendRICControlReqServiceGrpc(RicControlGrpcReq) returns (RicControlGrpcRsp);
}

I am using ubuntu 20 (Focal Fossa).
and have installed the dev packages of libgrpc++-dev
and libprotobuf-dev

The c++ stubs are generated using protoc comipler protobuf-compiler and code-gen-plugin protobuf-compiler-grpc.

You can check the versions from the link provided

I have also invoked the service on server side by using grpcurl command and it is working fine
./grpcurl -plaintext -d "{ \"e2NodeID\": \"36000000\", \"plmnID\": \"111\", \"ranName\": \"gnb_131_133_36000000\", \"RICE2APHeaderData\": { \"RanFuncId\": 300, \"RICRequestorID\": 2 }, \"RICControlHeaderData\": { \"ControlStyle\": 3, \"ControlActionId\": 1, \"UEID\": \"00006\" }, \"RICControlMessageData\": { \"RICControlCellTypeVal\": 4, \"TargetCellID\": \"1113\" }, \"RICControlAckReqVal\": 0 }" 10.244.0.185:7777 api.MsgComm.SendRICControlReqServiceGrpc

Ah, I think you may be running into proto3 intended behavior. See protocolbuffers/protobuf#5883 (comment)

With proto3 there is no difference between a singular primitive field being empty and being set to its default value (see here). As a result E1 is not printed out because it is just the default value for that field.

You can probably confirm by trying to access that value directly in the server and confirm it is the default value you've set. Or in the client, set it to a non-default value.