예제 #1
0
static MetaObject extractReturnedMetaObject(const Message& msg, TransportSocketPtr sock)
{
  static const std::string retSig =
      "({I(Issss[(ss)<MetaMethodParameter,name,description>]s)<MetaMethod,uid,returnSignature,name,"
      "parametersSignature,description,parameters,returnDescription>}{I(Iss)<MetaSignal,uid,name,signature>}{I(Iss)<"
      "MetaProperty,uid,name,signature>}s)<MetaObject,methods,signals,properties,description>";

  AnyReference ref = msg.value((msg.flags() & Message::TypeFlag_DynamicPayload) ? "m" : retSig, sock);
  MetaObject obj = ref.to<MetaObject>();
  ref.destroy();
  return obj;
}
예제 #2
0
void GwObjectHost::assignClientMessageObjectsGwIds(const Signature& signature, Message& msg, TransportSocketPtr sender)
{
  // if there's no chance of any object being in the call we're done.
  if (!hasObjectsSomewhere(signature))
    return;

  AnyReference callParameters = msg.value(signature, sender);

  // re-serialize the arguments so that the objects can receive a GW-specific objectId
  // ObjectHost uses a static int for its objectId so we're OK instantiating multiple
  // ones.
  Message forward;
  MockObjectHost host(Message::Service_Server);

  forward.setFlags(msg.flags());
  forward.setValue(callParameters, signature, &host, sender.get());
  msg.setBuffer(forward.buffer());

  // The message will store all the objects it serializes in the host.
  const ObjectHost::ObjectMap& objects = host.objects();
  std::map<GwObjectId, MetaObject> newObjectsMetaObjects;
  std::map<GwObjectId, std::pair<TransportSocketPtr, ObjectAddress> > newObjectsOrigin;
  std::map<ObjectAddress, GwObjectId> newHostObjectBank;
  for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it)
  {
    GwObjectId oid = it->first;
    ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get());
    RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value);
    ObjectAddress addr;
    addr.service = ro->service();
    addr.object = ro->object();
    ro->setTransportSocket(TransportSocketPtr());

    newObjectsMetaObjects[oid] = ro->metaObject();
    newObjectsOrigin[oid] = std::make_pair(sender, addr);
    newHostObjectBank[addr] = oid;
    // We set an empty transportsocket.
    // Otherwise when we destroy `passed` below, the remoteobject
    // will attempt to send back home a `terminate` message, which we don't want.
    // By setting a null socket the object will stay alive on the remote end.

    qiLogDebug() << "Message " << msg.address() << ", Object connection: {" << addr.service << "," << addr.object
                 << "} <=> {0," << oid << "}";
  }
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
    _objectsMetaObjects.insert(newObjectsMetaObjects.begin(), newObjectsMetaObjects.end());
    _objectsOrigin.insert(newObjectsOrigin.begin(), newObjectsOrigin.end());
    _hostObjectBank[sender].insert(newHostObjectBank.begin(), newHostObjectBank.end());
  }
  callParameters.destroy();
}
예제 #3
0
  static bool isIntegerOrDouble(AnyReference value)
  {

    Signature signature(value.signature());
    return signature.isConvertibleTo(Signature("i")) != 0.0 ||
           signature.isConvertibleTo(Signature("d")) != 0.0;
  }
예제 #4
0
TEST(Value, DefaultMap)
{ // this one has tricky code and deserves a test)
  TypeInterface* dmt = TypeInterface::fromSignature(qi::Signature("{si}"));
  AnyValue val = AnyValue(AnyReference(dmt), false, true);
  ASSERT_EQ(0u, val.size());
  val["foo"].update(12);
  ASSERT_EQ(1u, val.size());
  ASSERT_EQ(12, val.find("foo").toInt());
  ASSERT_EQ(0, val.find("bar").type());
  val.insert(std::string("bar"), 13);
  ASSERT_EQ(13, val.element<int>("bar"));
  val.element<int>("foo") = 10;
  ASSERT_EQ(10, val.find("foo").toInt());
  AnyIterator b = val.begin();
  AnyIterator end = val.end();
  qi::int64_t sum = 0;
  while (b != end)
  {
    AnyReference deref = *b;
    sum += deref[1].toInt();
    ++b;
  }
  ASSERT_EQ(23, sum);

  AnyIterator b2 = val.begin();
  AnyIterator end2 = val.end();
  sum = 0;
  while (b2 != end2)
  {
    AnyReference deref = *b2;
    AnyIterator it = b2;
    sum += deref[1].toInt();
    ASSERT_EQ(b2++, it);
  }
  ASSERT_EQ(23, sum);

  AnyReference valCopy = val.clone();
  ASSERT_EQ(13, valCopy.element<int>("bar"));
  ASSERT_EQ(2u, valCopy.size());
  // reset val, checks valCopy still works
  val.reset();
  val = AnyValue::from(5);
  ASSERT_EQ(13, valCopy.element<int>("bar"));
  ASSERT_EQ(2u, valCopy.size());
  valCopy.destroy();
}
예제 #5
0
TEST(Value, Basic)
{
  AnyReference v;
  int twelve = 12;
  v = AutoAnyReference(twelve);
  ASSERT_TRUE(v.type() != 0);
  ASSERT_TRUE(v.rawValue() != 0);
  ASSERT_EQ(v.toInt(), 12);
  ASSERT_EQ(v.toFloat(), 12.0f);
  ASSERT_EQ(v.toDouble(), 12.0);
  double five = 5.0;
  v = AutoAnyReference(five);
  ASSERT_EQ(v.toInt(), 5);
  ASSERT_EQ(v.toFloat(), 5.0f);
  ASSERT_EQ(v.toDouble(), 5.0);
  v = AutoAnyReference("foo");
  ASSERT_EQ("foo", v.toString());
}
예제 #6
0
TEST(Value, AnyObject)
{
  {
    // GenericObject uses intrusive refcount and must be valid
    // Also object does some typechecking
    qi::DynamicObjectBuilder dynBuild;
    qi::AnyObject ori = dynBuild.object(&nothing);
    qi::GenericObject& go = *ori.asGenericObject();

    AnyReference v = AnyReference::from(ori);
    qi::detail::ManagedObjectPtr mo = v.to<qi::detail::ManagedObjectPtr>();
    ASSERT_TRUE(!!mo);
    ASSERT_EQ(mo.get(), &go);
    qi::AnyObject out = v.to<AnyObject>();
    ASSERT_TRUE(out);
    ASSERT_TRUE(out == ori);
    out = v.toObject();
    ASSERT_TRUE(out);
    ASSERT_EQ(out.asGenericObject(), mo.get());
  }
  ASSERT_TRUE(triggered);
}
예제 #7
0
  bool ParameterModelPrivate::inInterval(AnyReference value, AnyReference min, AnyReference max) const
  {
    Signature signature(value.signature());
    qiLogDebug() << "Enter in inInterval";
    qiLogDebug() << "Signature of value is : " << signature.toString();

    //if value is bool string or Resource return true
    if(signature.isConvertibleTo(Signature::fromType(Signature::Type_Bool)) == 1.0f ||
       signature.isConvertibleTo(Signature::fromType(Signature::Type_String)) == 1.0f ||
       signature.isConvertibleTo(ParameterModel::signatureRessource()) == 1.0f)
      return true;

    qiLogDebug() << "Type of value is double or integer";

    //if value is not in [min, max] return false
    if(value < min || max < value)
      return false;

    return true;
  }
예제 #8
0
TEST(Value, list)
{
  int one = 1;
  AnyReference v = AnyReference::from(one);
  v.set(5);
  ASSERT_ANY_THROW(v.set("foo"));
  ASSERT_ANY_THROW(v.set(std::vector<int>()));
  std::vector<int> vint;
  vint.push_back(12);
  v = AnyReference::from(vint);
  v.append(7);
  ASSERT_EQ(7, v[1].toInt());
  ASSERT_EQ(7, v[1].toFloat());
  ASSERT_EQ(7, v.element<int>(1));
  v[1].setInt(8);
  ASSERT_EQ(8, v[1].toInt());
  v.element<int>(1) = 9;
  ASSERT_EQ(9, v[1].toInt());
  ASSERT_ANY_THROW(v.element<double>(1)); // wrong type
  ASSERT_ANY_THROW(v.element<int>(17));   // out of bound
  EXPECT_EQ(v.as<std::vector<int> >().size(), v.size());
}
예제 #9
0
  void Session_Service::onAuthentication(const TransportSocket::SocketEventData& data, long requestId, TransportSocketPtr socket, ClientAuthenticatorPtr auth, SignalSubscriberPtr old)
  {
    static const std::string cmsig = typeOf<CapabilityMap>()->signature().toString();
    boost::recursive_mutex::scoped_lock sl(_requestsMutex);
    ServiceRequest *sr = serviceRequest(requestId);
    if (!sr)
      return;
    if (data.which() == TransportSocket::Event_Error)
    {
      if (old)
        socket->socketEvent.disconnect(*old);
      sr->promise.setError(boost::get<std::string>(data));
      removeRequest(requestId);
      return;
    }

#if BOOST_VERSION < 105800
    const Message& msg = boost::get<const Message&>(data);
#else
    const Message& msg = boost::relaxed_get<const Message&>(data);
#endif
    int function = msg.function();
    bool failure = msg.type() == Message::Type_Error
        || msg.service() != Message::Service_Server
        || function != Message::ServerFunction_Authenticate;

    if (failure)
    {
      if (old)
        socket->socketEvent.disconnect(*old);
      if (_enforceAuth)
      {
        std::stringstream error;
        if (msg.type() == Message::Type_Error)
          error << "Error while authenticating: " << msg.value("s", socket).to<std::string>();
        else
          error << "Expected a message for function #" << Message::ServerFunction_Authenticate << " (authentication), received a message for function " << function;
        sr->promise.setError(error.str());
        removeRequest(requestId);
      }
      else
      {
        session_service_private::sendCapabilities(socket);
        qi::Future<void> metaObjFut;
        sr->remoteObject = new qi::RemoteObject(sr->serviceId, socket);
        metaObjFut = sr->remoteObject->fetchMetaObject();
        metaObjFut.connect(&Session_Service::onRemoteObjectComplete, this, _1, requestId);
      }
      return;
    }

    AnyReference cmref = msg.value(typeOf<CapabilityMap>()->signature(), socket);
    CapabilityMap authData = cmref.to<CapabilityMap>();
    CapabilityMap::iterator authStateIt = authData.find(AuthProvider::State_Key);
    cmref.destroy();

    if (authStateIt == authData.end() || authStateIt->second.to<unsigned int>() < AuthProvider::State_Error
        || authStateIt->second.to<unsigned int>() > AuthProvider::State_Done)
    {
      if (old)
        socket->socketEvent.disconnect(*old);
      std::string error = "Invalid authentication state token.";
      sr->promise.setError(error);
      removeRequest(requestId);
      qiLogInfo() << error;
      return;
    }
    if (authData[AuthProvider::State_Key].to<unsigned int>() == AuthProvider::State_Done)
    {
      qi::Future<void> metaObjFut;
      if (old)
        socket->socketEvent.disconnect(*old);
      sr->remoteObject = new qi::RemoteObject(sr->serviceId, socket);
      //ask the remoteObject to fetch the metaObject
      metaObjFut = sr->remoteObject->fetchMetaObject();
      metaObjFut.connect(&Session_Service::onRemoteObjectComplete, this, _1, requestId);
      return;
    }

    CapabilityMap nextData = auth->processAuth(authData);
    Message authMsg;
    authMsg.setService(Message::Service_Server);
    authMsg.setType(Message::Type_Call);
    authMsg.setValue(nextData, cmsig);
    authMsg.setFunction(Message::ServerFunction_Authenticate);
    socket->send(authMsg);
  }
예제 #10
0
void GwObjectHost::harvestServiceOriginatingObjects(Message& msg, TransportSocketPtr sender)
{
  Signature signature;
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    MetaObject* metaObject = NULL;
    const Signature& (MetaMethod::*signatureGetter)() const = NULL;
    if (msg.type() == Message::Type_Reply || msg.type() == Message::Type_Error)
    {
      std::map<ServiceId, std::map<ObjectId, MetaObject> >::iterator sit = _servicesMetaObjects.find(msg.service());
      if (msg.function() == Message::BoundObjectFunction_MetaObject &&
          sit->second.find(msg.object()) == sit->second.end())
      {
        boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
        _servicesMetaObjects[msg.service()][Message::GenericObject_Main] = extractReturnedMetaObject(msg, sender);
        return;
      }
      metaObject = &_servicesMetaObjects[msg.service()][msg.object()];
      signatureGetter = &MetaMethod::returnSignature;
    }
    else if (msg.type() == Message::Type_Call || msg.type() == Message::Type_Post)
    {
      // if a service does a CALL, he does so on a user-supplied object.
      std::map<GwObjectId, MetaObject>::iterator mit = _objectsMetaObjects.find(msg.object());
      assert(mit != _objectsMetaObjects.end());
      metaObject = &mit->second;
      signatureGetter = &MetaMethod::parametersSignature;
    }
    const MetaMethod* method = metaObject->method(msg.function());
    if (!method)
      return;
    signature = (method->*signatureGetter)();
  }
  if (!hasObjectsSomewhere(signature))
  {
    // no object can be here
    return;
  }

  AnyReference passed = msg.value(signature, sender);
  StreamContext filler;
  MockObjectHost host(Message::Service_Server);
  Message dummy;

  // we don't want to pollute the original message and potentially change valid id
  // of contained objects, so we do it in an unrelated message.
  dummy.setValue(passed, signature, &host, &filler);

  const ObjectHost::ObjectMap& objects = host.objects();
  std::map<ObjectId, MetaObject> newServicesMetaObject;
  for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it)
  {
    ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get());
    RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value);

    // We set an empty transportsocket.
    // Otherwise when we destroy `passed` below, the remoteobject
    // will attempt to send back home a `terminate` message, which we don't want.
    // By setting a null socket the object will stay alive on the remote end.
    ro->setTransportSocket(TransportSocketPtr());
    newServicesMetaObject[ro->object()] = ro->metaObject();
  }
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
    _servicesMetaObjects[msg.service()].insert(newServicesMetaObject.begin(), newServicesMetaObject.end());
  }
  passed.destroy();
}
예제 #11
0
TEST(Value, list_at)
{
  std::vector<int> v{2, 5, 7};
  AnyReference list = AnyReference::from(v);
  const AnyReference listc = AnyReference::from(v);

  // at(T)
  {
    AnyReference val = list.at(1);
    EXPECT_EQ(5, val.toInt());
    AnyReference valInvalid = list.at(4);
    EXPECT_EQ(nullptr, valInvalid.type());
  }
  // at(T) const
  {
    const AnyReference val = listc.at(1);
    EXPECT_EQ(5, val.toInt());
    const AnyReference valInvalid = listc.at(4);
    EXPECT_EQ(nullptr, valInvalid.type());
  }
}
예제 #12
0
TEST(Value, Map_at)
{
  std::map<std::string, double> map;
  map["foo"] = 1;
  map["bar"] = 2;
  AutoAnyReference v(map);
  const AutoAnyReference vc(map);

  // at(T)
  {
    AnyReference val1 = v.at("foo");
    EXPECT_EQ(1, val1.toInt());
    AnyReference valInvalid = v.at("nokey");
    EXPECT_EQ(nullptr, valInvalid.type());
  }
  // at(T) const
  {
    const AnyReference val1 = vc.at("bar");
    EXPECT_EQ(2, val1.toInt());
    const AnyReference valInvalid = vc.at("nokey");
    EXPECT_EQ(nullptr, valInvalid.type());
  }
  // at(AnyReference)
  {
    AnyReference val1 = v.at(AnyReference::from("foo"));
    EXPECT_EQ(1, val1.toInt());
    AnyReference valInvalid = v.at(AnyReference::from("nokey"));
    EXPECT_EQ(nullptr, valInvalid.type());
  }
  // at(AnyReference) const
  {
    const AnyReference val1 = vc.at(AnyReference::from("bar"));
    EXPECT_EQ(2, val1.toInt());
    const AnyReference valInvalid = vc.at(AnyReference::from("nokey"));
    EXPECT_EQ(nullptr, valInvalid.type());
  }
}
예제 #13
0
  void Server::onMessageReadyNotAuthenticated(const Message &msg, TransportSocketPtr socket, AuthProviderPtr auth,
                                              boost::shared_ptr<bool> first, SignalSubscriberPtr oldSignal)
  {
    qiLogVerbose() << "Starting auth message" << msg.address();
    int id = msg.id();
    int service = msg.service();
    int function = msg.action();
    int type = msg.type();
    Message reply;

    reply.setId(id);
    reply.setService(service);
    if (service != Message::Service_Server
        || type != Message::Type_Call
        || function != Message::ServerFunction_Authenticate)
    {
      socket->messageReady.disconnect(*oldSignal);
      if (_enforceAuth)
      {
        std::stringstream err;

        err << "Expected authentication (service #" << Message::Service_Server <<
               ", type #" << Message::Type_Call <<
               ", action #" << Message::ServerFunction_Authenticate <<
               "), received service #" << service << ", type #" << type << ", action #" << function;
        reply.setType(Message::Type_Error);
        reply.setError(err.str());
        socket->send(reply);
        socket->disconnect();
        qiLogVerbose() << err.str();
      }
      else
      {
        server_private::sendCapabilities(socket);
        qiLogVerbose() << "Authentication is not enforced. Skipping...";

        connectMessageReady(socket);
        onMessageReady(msg, socket);
      }
      return;
    }
    // the socket now contains the remote capabilities in socket->remoteCapabilities()
    qiLogVerbose() << "Authenticating client " << socket->remoteEndpoint().str() << "...";

    AnyReference cmref = msg.value(typeOf<CapabilityMap>()->signature(), socket);
    CapabilityMap authData = cmref.to<CapabilityMap>();
    cmref.destroy();
    CapabilityMap authResult = auth->processAuth(authData);
    unsigned int state = authResult[AuthProvider::State_Key].to<unsigned int>();
    std::string cmsig = typeOf<CapabilityMap>()->signature().toString();
    reply.setFunction(function);
    switch (state)
    {
    case AuthProvider::State_Done:
      qiLogVerbose() << "Client " << socket->remoteEndpoint().str() << " successfully authenticated.";
      socket->messageReady.disconnect(*oldSignal);
      connectMessageReady(socket);
      // no break, we know that authentication is done, send the response to the remote end
    case AuthProvider::State_Cont:
      if (*first)
      {
        authResult.insert(socket->localCapabilities().begin(), socket->localCapabilities().end());
        *first = false;
      }
      reply.setValue(authResult, cmsig);
      reply.setType(Message::Type_Reply);
      socket->send(reply);
      break;
    case AuthProvider::State_Error:
    default:{
      std::stringstream builder;
      builder << "Authentication failed";
      if (authResult.find(AuthProvider::Error_Reason_Key) != authResult.end())
      {
        builder << ": " << authResult[AuthProvider::Error_Reason_Key].to<std::string>();
        builder << " [" << _authProviderFactory->authVersionMajor() << "." << _authProviderFactory->authVersionMinor() << "]";
      }
      reply.setType(Message::Type_Error);
      reply.setError(builder.str());
      qiLogVerbose() << builder.str();
      socket->send(reply);
      socket->disconnect();
      }
    }
    qiLogVerbose() << "Auth ends";
  }
예제 #14
0
  //should be done in the object thread
  void RemoteObject::onMessagePending(const qi::Message &msg)
  {
    qiLogDebug() << this << "(" << _service << '/' << _object << ") msg " << msg.address() << " " << msg.buffer().size();
    if (msg.object() != _object)
    {
      qiLogDebug() << "Passing message " << msg.address() << " to host " ;
      {
        boost::mutex::scoped_lock lock(_socketMutex);
        if(_socket)
          ObjectHost::onMessage(msg, _socket);
        return;
      }
    }


    if (msg.type() == qi::Message::Type_Event) {
      SignalBase* sb = signal(msg.event());
      if (sb)
      {
        try {
          // Signal associated with properties have incorrect signature,
          // Trust MetaObject.
          //std::string sig = sb->signature();
          const MetaSignal* ms  = _self.metaObject().signal(msg.event());
          qi::Signature sig = ms->parametersSignature();

          // Remove top-level tuple
          //sig = sig.substr(1, sig.length()-2);
          //TODO: Optimise
          AnyReference value = msg.value((msg.flags()&Message::TypeFlag_DynamicPayload)? "m":sig, _socket);

          {
            GenericFunctionParameters args;
            if (sig == "m")
              args = value.content().asTupleValuePtr();
            else
              args = value.asTupleValuePtr();
            qiLogDebug() << "Triggering local event listeners with args : " << args.size();
            sb->trigger(args);
          }
          value.destroy();
        }
        catch (const std::exception& e)
        {
          qiLogWarning() << "Deserialize error on event: " << e.what();
        }
      }
      else
      {
        qiLogWarning() << "Event message on unknown signal " << msg.event();
        qiLogDebug() << metaObject().signalMap().size();
      }
      return;
    }


    if (msg.type() != qi::Message::Type_Reply
      && msg.type() != qi::Message::Type_Error
      && msg.type() != qi::Message::Type_Canceled) {
      qiLogError() << "Message " << msg.address() << " type not handled: " << msg.type();
      return;
    }

    qi::Promise<AnyReference> promise;
    {
      boost::mutex::scoped_lock lock(_promisesMutex);
      std::map<int, qi::Promise<AnyReference> >::iterator it;
      it = _promises.find(msg.id());
      if (it != _promises.end()) {
        promise = _promises[msg.id()];
        _promises.erase(it);
        qiLogDebug() << "Handling promise id:" << msg.id();
      } else  {
        qiLogError() << "no promise found for req id:" << msg.id()
                     << "  obj: " << msg.service() << "  func: " << msg.function() << " type: " << Message::typeToString(msg.type());
        return;
      }
    }

    switch (msg.type()) {
      case qi::Message::Type_Canceled: {
        qiLogDebug() << "Message " << msg.address() << " has been cancelled.";
        promise.setCanceled();
        return;
      }
      case qi::Message::Type_Reply: {
        // Get call signature
        MetaMethod* mm =  metaObject().method(msg.function());
        if (!mm)
        {
          qiLogError() << "Result for unknown function "
           << msg.function();
           promise.setError("Result for unknown function");
           return;
        }
        try {
          qi::AnyReference val = msg.value(
            (msg.flags() & Message::TypeFlag_DynamicPayload) ?
              "m" : mm->returnSignature(),
            _socket);
          promise.setValue(val);
        } catch (std::runtime_error &err) {
          promise.setError(err.what());
        }

        qiLogDebug() << "Message " << msg.address() << " passed to promise";
        return;
      }

      case qi::Message::Type_Error: {
        try {
          static std::string sigerr("m");
          qi::AnyReference gvp = msg.value(sigerr, _socket).content();
          std::string err = gvp.asString();
          qiLogVerbose() << "Received error message"  << msg.address() << ":" << err;
          promise.setError(err);
        } catch (std::runtime_error &e) {
          //houston we have an error about the error..
          promise.setError(e.what());
        }
        return;
      }
      default:
        //not possible
        return;
    }
  }
예제 #15
0
 void visitDynamic(AnyReference pointee)
 {
   if (pointee.isValid()) {
     serialize(pointee, out);
   }
 }
예제 #16
0
 void visitUnknown(AnyReference v)
 {
   qiLogError() << "JSON Error: Type " << v.type()->infoString() <<" not serializable";
   out << "\"Error: no serialization for unknown type:" << v.type()->infoString() << "\"";
 }