Skip to content

Notes about ReturnValue inconsistencies during NWS/NWC communication failures #3280

@randaz81

Description

@randaz81

Return value is supposed to be: return_value_error_nws_nwc_communication_error when NWS/NWC communication fails.

However, let's consider the following code (1):

yarp::dev::ReturnValue RobotDescription_nwc_yarp::getAllDevices(std::vector<DeviceDescription>& dev_list)
{
    std::lock_guard<std::mutex> lg(m_mutex);
    return_getAllDevices ret = m_RPC.getAllDevicesRPC();
    if (!ret.ret) {
        yCError(ROBOTDESCRIPTION_NWC_YARP, "Unable to getAllDevices");
        return ret.ret;
    }
    dev_list = ret.devices;
    return ReturnValue_ok;
}

the ReturnValue is propagated from getAllDevicesRPC(), which is generated by Thrift (2):

return_getAllDevices IRobotDescriptionMsgs::getAllDevicesRPC()
{
    if (!yarp().canWrite()) {
        yError("Missing server method '%s'?", IRobotDescriptionMsgs_getAllDevicesRPC_helper::s_prototype);
    }
    IRobotDescriptionMsgs_getAllDevicesRPC_helper helper{};
    bool ok = yarp().write(helper, helper);
    return ok ? helper.reply.return_helper : return_getAllDevices{};
}

If the write() function fails, it returns the dafault value of: return_getAllDevices which is also generated (3):

class return_getAllDevices :
        public yarp::os::idl::WirePortable
{
public:
    // Fields
    yarp::dev::ReturnValue ret{};
    std::vector<yarp::dev::DeviceDescription> devices{};

    // Default constructor
    return_getAllDevices() = default;

    // Constructor with field values
    return_getAllDevices(const yarp::dev::ReturnValue& ret,
                         const std::vector<yarp::dev::DeviceDescription>& devices);
   ///...

In the end, yarp::dev::ReturnValue ret{} is return_value_uninitialized and not return_value_error_nws_nwc_communication_error.

This is not a big issue, because both values can be casted to false, but in the future we might consider fixing this.


The following considerations have been made:

Fixing this in 1) can be done in the following hacky way:

    if (!ret.ret) {
        yCError(ROBOTDESCRIPTION_NWC_YARP, "Unable to getAllDevices");
     if (ret.ret == return_value_uninitialized) ret.ret = return_value_error_nws_nwc_communication_error;
        return ret.ret;
    }

From a theoretical standpoint, this is acceptable, as we are indeed assigning return_value_error_nws_nwc_communication_error in the relevant section of the code within the NWC.
It would also be beneficial to create a common method or base class for all NWCs to handle this uniformly.

Another possibility is to fix this (option 2). However, this is not ideal from a theoretical point of view, as the generated Thrift code is agnostic to the existence of the NWS/NWC—it could represent a generic communication protocol.

Additionally, it's difficult to implement because it would require assigning a value within a nested data structure, which makes it challenging to support in a generic code generator.

This issue is being kept as a reminder, but there is currently no ongoing activity to resolve it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions