Example #1
0
bool Port::open(const Contact& contact, bool registerName,
                const char *fakeName)
{
    Contact contact2 = contact;

    if (!NetworkBase::initialized()) {
        YARP_ERROR(Logger::get(), "YARP not initialized; create a yarp::os::Network object before using ports");
        return false;
    }

    std::string n = contact2.getName();

    NameConfig conf;
    std::string nenv = std::string("YARP_RENAME") + conf.getSafeString(n);
    std::string rename = NetworkBase::getEnvironment(nenv.c_str());
    if (rename!="") {
        n = rename;
        contact2.setName(n);
    }

    bool local = false;
    if (n == "" && contact2.getPort()<=0) {
        local = true;
        registerName = false;
        n = "...";
    }

    NestedContact nc(n);
    if (nc.getNestedName()!="") {
        if (nc.getNodeName() == "") {
            Nodes& nodes = NameClient::getNameClient().getNodes();
            nodes.requireActiveName();
            std::string node_name = nodes.getActiveName();
            if (node_name!="") {
                n = n + node_name;
            }
        }
    }

    PortCoreAdapter *currentCore = &(IMPL());
    if (currentCore!=nullptr) {
        currentCore->active = false;
        if (n!="" && (n[0]!='/'||currentCore->includeNode) && n[0]!='=' && n!="..." && n.substr(0, 3)!="...") {
            if (fakeName==nullptr) {
                Nodes& nodes = NameClient::getNameClient().getNodes();
                std::string node_name = nodes.getActiveName();
                if (node_name!="") {
                    n = (n[0]=='/'?"":"/") + n + "@" + node_name;
                }
            }
        }
    }
    if (n!="" && n[0]!='/'  && n[0]!='=' && n!="..." && n.substr(0, 3)!="...") {
        if (fakeName==nullptr) {
            YARP_SPRINTF1(Logger::get(), error,
                          "Port name '%s' needs to start with a '/' character",
                          n.c_str());
            return false;
        }
    }
    if (n!="" && n!="..." && n[0]!='=' && n.substr(0, 3)!="...") {
        if (fakeName==nullptr) {
            std::string prefix = NetworkBase::getEnvironment("YARP_PORT_PREFIX");
            if (prefix!="") {
                n = prefix + n;
                contact2.setName(n);
            }
        }
    }
    if (currentCore!=nullptr) {
        NestedContact nc;
        nc.fromString(n);
        if (nc.getNestedName()!="") {
            if (nc.getCategory()=="") {
                // we need to add in a category
                std::string cat;
                if (currentCore->commitToRead) {
                    cat = "-";
                } else if (currentCore->commitToWrite) {
                    cat = "+";
                }
                if (cat!="") {
                    if (currentCore->commitToRpc) {
                        cat += "1";
                    }
                    contact2.setName(nc.getNestedName() +
                                     cat +
                                     "@" +
                                     nc.getNodeName());
                } else {
                    YARP_SPRINTF1(Logger::get(), error,
                                  "Error: Port '%s' is not committed to being either an input or output port.",
                                  n.c_str());
                    YARP_SPRINTF0(Logger::get(), error,
                                  "YARP does not mind, but we are trying to register with a name server that does.");
                    YARP_SPRINTF0(Logger::get(), error,
                                  "You can call Port::setWriteOnly() or Port::setReadOnly(), OR rename the port.");
                    NestedContact nc2 = nc;
                    nc2.setCategoryWrite();
                    YARP_SPRINTF1(Logger::get(), error,
                                  "For an output port, call it: %s (+ adds data)",
                                  nc2.toString().c_str());
                    nc2.setCategoryRead();
                    YARP_SPRINTF1(Logger::get(), error,
                                  "For an input port, call it: %s (- takes data)",
                                  nc2.toString().c_str());
                    return false;
                }
            }
        }
    }

    // Allow for open() to be called safely many times on the same Port
    if (currentCore && currentCore->isOpened()) {
        auto* newCore = new PortCoreAdapter(*this);
        yAssert(newCore != nullptr);
        // copy state that should survive in a new open()
        if (currentCore->checkPortReader() != nullptr) {
            newCore->configReader(*(currentCore->checkPortReader()));
        }
        if (currentCore->checkAdminPortReader() != nullptr) {
            newCore->configAdminReader(*(currentCore->checkAdminPortReader()));
        }
        if (currentCore->checkReadCreator() != nullptr) {
            newCore->configReadCreator(*(currentCore->checkReadCreator()));
        }
        if (currentCore->checkWaitAfterSend() >= 0) {
            newCore->configWaitAfterSend(currentCore->checkWaitAfterSend());
        }
        if (currentCore->haveCallbackLock) {
            newCore->configCallbackLock(currentCore->recCallbackLock);
        }
        close();
        if (owned) delete ((PortCoreAdapter*)implementation);
        implementation = newCore;
        owned = true;
        currentCore = newCore;
        currentCore->active = false;
    }

    PortCoreAdapter& core = IMPL();

    core.openable();

    if (NetworkBase::localNetworkAllocation()&&contact2.getPort()<=0) {
        YARP_DEBUG(Logger::get(), "local network allocation needed");
        local = true;
    }

    bool success = true;
    Contact address(contact2.getName(),
                    contact2.getCarrier(),
                    contact2.getHost(),
                    contact2.getPort());
    address.setNestedContact(contact2.getNested());

    core.setReadHandler(core);
    if (contact2.getPort()>0 && contact2.getHost()!="") {
        registerName = false;
    }

    std::string ntyp = getType().getNameOnWire();
    if (ntyp=="") {
        NestedContact nc;
        nc.fromString(n);
        if (nc.getTypeName()!="") ntyp = nc.getTypeName();
    }
    if (ntyp=="") {
        ntyp = getType().getName();
    }
    if (ntyp!="") {
        NestedContact nc;
        nc.fromString(contact2.getName());
        nc.setTypeName(ntyp);
        contact2.setNestedContact(nc);
        if (getType().getNameOnWire()!=ntyp) {
            core.promiseType(Type::byNameOnWire(ntyp.c_str()));
        }
    }

    if (registerName&&!local) {
        address = NetworkBase::registerContact(contact2);
    }

    core.setControlRegistration(registerName);
    success = (address.isValid()||local)&&(fakeName==nullptr);

    if (success) {
        // create a node if needed
        Nodes& nodes = NameClient::getNameClient().getNodes();
        nodes.prepare(address.getRegName());
    }

    // If we are a service client, go ahead and connect
    if (success) {
        NestedContact nc;
        nc.fromString(address.getName());
        if (nc.getNestedName()!="") {
            if (nc.getCategory() == "+1") {
                addOutput(nc.getNestedName());
            }
        }
    }

    std::string blame = "invalid address";
    if (success) {
        success = core.listen(address, registerName);
        blame = "address conflict";
        if (success) {
            success = core.start();
            blame = "manager did not start";
        }
    }
    if (success) {
        address = core.getAddress();
        if (registerName&&local) {
            contact2.setSocket(address.getCarrier(),
                               address.getHost(),
                               address.getPort());
            contact2.setName(address.getRegName());
            Contact newName = NetworkBase::registerContact(contact2);
            core.resetPortName(newName.getName());
            address = core.getAddress();
        } else if (core.getAddress().getRegName()=="" && !registerName) {
            core.resetPortName(core.getAddress().toURI(false));
            core.setName(core.getAddress().getRegName());
        }

        if (core.getVerbosity()>=1) {
            if (address.getRegName()=="") {
                YARP_INFO(Logger::get(),
                          std::string("Anonymous port active at ") +
                          address.toURI());
            } else {
                YARP_INFO(Logger::get(),
                          std::string("Port ") +
                          address.getRegName() +
                          " active at " +
                          address.toURI());
            }
        }
    }

    if (fakeName!=nullptr) {
        success = core.manualStart(fakeName);
        blame = "unmanaged port failed to start";
    }

    if (!success) {
        YARP_ERROR(Logger::get(),
                   std::string("Port ") +
                   (address.isValid()?(address.getRegName().c_str()):(contact2.getName().c_str())) +
                   " failed to activate" +
                   (address.isValid()?" at ":"") +
                   (address.isValid()?address.toURI():std::string("")) +
                   " (" +
                   blame +
                   ")");
    }

    if (success) {
        // create a node if needed
        Nodes& nodes = NameClient::getNameClient().getNodes();
        nodes.add(*this);
    }

    if (success && currentCore!=nullptr) currentCore->active = true;
    return success;
}