Skip to Content
CTech Digital
  • Home
  • Odoo services
  • AI services
  • Contact us
  • 0
  • Nederlands (BE) English (UK) Français
CTech Digital
  • 0
    • Home
    • Odoo services
    • AI services
    • Contact us
  • Nederlands (BE) English (UK) Français

30/5/25

Continued on message based communication
  • All Blogs
  • Daily blog
  • 30/5/25
  • 30 May 2025 by
    CTech Metrology, Luc Wens

    First tests in CTrack

    We already did a small test setting a responder to an alarm coming from the template proxy. That worked fine.

    To test the request handling, we used the proxy handshake.

    This initially failed because both CCommunicationObject and CCommunicationThread are derived from CCommunicationInterface, and thus had both their own responders.

    This is now fixed in CCommunicationObject::SetCommunicationThread where we make sure that the communication thread uses the same message responder.

    Another change was to set the promise of a request in the communication thread.

    One thing to check now is why our handshake is failing, it may be possible that some of the characters were changed by JSON, so we need to check that the JSON conversion does not alter the contents of the handshake parameters.

    By the way, this is what our handshake looks like now

    bool CProxyDevice::HandShake()
    {
    #if !defined(CTRACK_UI) // && !defined(_DEBUG)
        std::vector<char> challenge = GenerateRandomCharVector(120);
        std::string       challengeStr(challenge.begin(), challenge.end());
        std::string       challengeBase64 = Botan::base64_encode(reinterpret_cast<const uint8_t *>(challenge.data()), challenge.size());

        CTrack::Message message;
        message.SetID(TAG_HANDSHAKE);
        message.SetParams({{ATTRIB_CHALLENGE, challengeBase64}});
        std::future<CTrack::Message> future;
        m_CommunicationObject.GetMessageResponder()->SendRequest(message, future);


        int timeoutSecs = 5;
        #ifdef _DEBUG
        timeoutSecs = INT_MAX;
        #endif
        if (future.wait_for(std::chrono::seconds(timeoutSecs)) == std::future_status::timeout)
        {
            PrintError("Timeout waiting for handshake response on port {}", m_TCP_Port);
            return false;
        }
        std::string     ChallengeReturnBase64;
        CTrack::Message response = future.get();

        if (response.GetID() != TAG_HANDSHAKE)
            THROW_ERROR(fmt::format("Handshake failed : invalid message ID {} expected {}", message.GetID(), TAG_HANDSHAKE));
        if (response.GetParams().contains(ATTRIB_CHALLENGE))
            ChallengeReturnBase64 = response.GetParams()[ATTRIB_CHALLENGE].get<std::string>();
        else
            THROW_ERROR(fmt::format("Handshake failed : missing attribute {}", ATTRIB_CHALLENGE));

        // check the challenge return
        Botan::secure_vector<uint8_t> ChallengeReturn = Botan::base64_decode(ChallengeReturnBase64);

        std::unique_ptr<Botan::Public_Key> PublicKey  = LoadPublicKeyFromString(proxy_public_key_pem);
        if (PublicKey)
        {
            std::string challengeReturnStr(ChallengeReturn.begin(), ChallengeReturn.end());
            if (VerifySignature(challengeStr, challengeReturnStr, PublicKey))
                return true;
        }
        return false;
    #else
        return true;
    #endif
    }

    Looking at the highlighted blocks:

    • First we send a message with ID TAG_HANDSHAKE and as parameter the challenge, we send it as a request in the future form, which means we will use this future to wait for the result to come back, rather then setting a callback which is called in the main thread, not the communication thread, and that will use the message returned by the future
    • future.wait will block until the promise is set, this is done by the communication thread of TCPCommunication.cpp

      while (pCurrentSocket->ReadExtractTelegram(TCPGram))
      {
          if (TCPGram->GetCode() == TCPGRAM_CODE_MESSAGE)
          {
              CTrack::Message message;
              if (TCPGram->GetMessage(message))
                  m_pMessageResponder->RequestSetPromiseThread(message);

          }

          if (TCPGram->GetCode() == TCPGRAM_CODE_INTERRUPT)
              InterruptSet(true);
          else
              PushReceivePackage(TCPGram);


    The proxy handshake is working in 1f1a85b230e70771375a90358b46c31fffcc9ecc 

    So this means we can not go ahead and start reworking all commands and states.

    That is for later.

    in Daily blog
    27/7/25
    Working on a message based proxy design
    Copyright © CTech
    Nederlands (BE) | English (UK) | Français
    Powered by Odoo - The #1 Open Source eCommerce