OpenThread COAP Client to a public server over Internet

Hello,

I am trying to make a Thread COAP Client on nRF52840 DK work with coap.me public server. I have created a Border Router with a Raspberry Pi and a nRF52 dongle and I am sure that it works as I can ping and run COAP CLI commands successfully with the OpenThread CLI sample. I can COAP GET and PUT to coap.me.

The coap.me IPv6 address was converted by me with the well known 64:ff9b::/96 prefix. The path was added to the border router as I can see with ot netdata show. 

The problem is with the COAP Client sample provided. I modified the destination IPv6 address to be the same I use with the CLI sample and the URI path to "coap://coap.me:5683/hello". I have also tried just "hello". No luck so far. 

As I said the CLI sample works fine: I get a response which is "world". Here the CLI commands I use after having joined the Thread network:

ot coap start

ot coap get 64:ff9b:0:0:0:0:8666:da12 hello 

NOTE: in my COAP client program the Thread network is joined automatically as I have added the following options:

CONFIG_OPENTHREAD_JOINER=y
CONFIG_OPENTHREAD_JOINER_AUTOSTART=y
CONFIG_OPENTHREAD_JOINER_PSKD="J01NME"

Indeed I can ping the Border router IPV6 address from my board running the modified COAP Client and vice-versa so they see each other. 

Can you please help to understand why my program directly derived from your COAP client sample does not work while CLI works fine?

Thank you.

Marco

  • Hi Marco,

    Sorry for the late reply. I can repeat your issue, need a bit more time to debug the issue plus traveling.

    I will try to give you a reply next week. Is this OK for you?

    Best regards,

    Charlie

  • Ah OK, no problem, I just wanted to know if it was my problem only or not. Let me know if I can help you on this by trying something...

    Thank you very much for your help!

    Marco

  • Hi  I just want to let you know that I have the same problem with the OT APIs directly. I can't even ping a remote server. 

    I have attached my new source code.

    Cheers.

    /*
     * Copyright (c) 2022 Marco Russi
     *
     */
    
    #include <zephyr/kernel.h>
    #include <net/coap_utils.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/net/openthread.h>
    #include <zephyr/net/socket.h>
    #include <openthread/coap.h>
    #include <openthread/ip6.h>
    #include <openthread/message.h>
    #include <openthread/ping_sender.h>
    #include <openthread/thread.h>
    #include "coap_client_utils.h"
    
    
    LOG_MODULE_REGISTER(coap_client_utils, CONFIG_COAP_CLIENT_UTILS_LOG_LEVEL);
    
    
    #define COAP_PORT 5683
    #define PEER_SERVER_IPV4_ADDRESS			  "64.227.117.8"
    //#define PERR_SERVER_IPV6_ADDRESS        "fe80:0:0:0:c8f1:d752:f4fc:2865"
    #define PEER_SERVER_IPV6_ADDRESS        "64:ff9b:0:0:0:0:40e3:7508"
    #define TEST_URI_PATH 						      "ping"
    
    
    static bool is_connected;
    static struct k_work test_ping;
    static struct k_work test_msg_work;
    static struct k_work on_connect_work;
    static struct k_work on_disconnect_work;
    static struct openthread_context *ot_context;
    static struct otNetifAddress *netif;
    static uint8_t buf[32];
    
    
    static void send_test_msg(struct k_work *item);
    static void ping_dest(struct k_work *item);
    static void on_thread_state_changed(uint32_t flags, void *context);
    static void submit_work_if_connected(struct k_work *work);
    static void coap_default_handler(void *context, otMessage *message,
                                     const otMessageInfo *message_info);
    static void print_unicast_addresses(struct openthread_context *ot);
    static void print_ipv6_address(const otIp6Address addr);
    static bool init_coap(struct otInstance *ot);
    static void response_handler(void *aContext,
                                 otMessage *aMessage,
                                 const otMessageInfo *aMessageInfo,
                                 otError aResult);
    static bool send_test_message(struct otInstance *ot);
    static void reply_callback (const otPingSenderReply *aReply, void *aContext);
    static bool ping_send( struct otInstance *ot );
    
    
    static void send_test_msg(struct k_work *item)
    {
      bool ret;
    
      ret = send_test_message(ot_context->instance);
    
      LOG_INF("Send test message -> %s", (true == ret ? "Success" : "FAIL"));
    }
    
    
    static void ping_dest(struct k_work *item)
    {
      bool ret;
    
      ret = ping_send(ot_context->instance);
    
      LOG_INF("PING test -> %s", (true == ret ? "Success" : "FAIL"));
    }
    
    
    static void on_thread_state_changed(uint32_t flags, void *context)
    {
      bool ret;
    	struct openthread_context *ot = context;
    	
    	LOG_INF("Thread state changed: %x", flags);
    
    	if (flags & OT_CHANGED_THREAD_ROLE) {
    		switch (otThreadGetDeviceRole(ot->instance)) {
    		case OT_DEVICE_ROLE_CHILD:
    		case OT_DEVICE_ROLE_ROUTER:
    		case OT_DEVICE_ROLE_LEADER:
    		{
    			k_work_submit(&on_connect_work);
    			is_connected = true;
    			print_unicast_addresses(ot);
    			
    			if (OT_DEVICE_ROLE_ROUTER == otThreadGetDeviceRole(ot->instance))
          {
            ret = init_coap(ot->instance);
    
            LOG_INF("INIT COAP -> %s", (true == ret ? "Success" : "FAIL"));
          }
    			break;
    		}
    
    		case OT_DEVICE_ROLE_DISABLED:
    		case OT_DEVICE_ROLE_DETACHED:
    		default:
    			k_work_submit(&on_disconnect_work);
    			is_connected = false;
    			break;
    		}
    	} 
    	else if (flags & OT_CHANGED_JOINER_STATE) {
    		LOG_INF("Joiner state changed");
    	}
    }
    
    
    static void submit_work_if_connected(struct k_work *work)
    {
    	if (is_connected) {
    		k_work_submit(work);
    	} else {
    		LOG_INF("Connection is broken");
    	}
    }
    
    
    static void coap_default_handler(void *context, otMessage *message,
                                     const otMessageInfo *message_info)
    {
      ARG_UNUSED(context);
      ARG_UNUSED(message);
      ARG_UNUSED(message_info);
    
      LOG_INF("Received CoAP message that does not match any request "
        "or resource");
    }
    
    
    static void print_unicast_addresses(struct openthread_context *ot)
    {
    	netif = otIp6GetUnicastAddresses(ot->instance);
    	while (netif != NULL)
    	{
    		print_ipv6_address((const otIp6Address)netif->mAddress);
    		netif = netif->mNext;
    	};
    }
    
    
    static void print_ipv6_address(const otIp6Address addr)
    {
    	LOG_INF("Mesh Local EID Address: %02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x",
    				addr.mFields.m8[0],
    				addr.mFields.m8[1],
    				addr.mFields.m8[2],
    				addr.mFields.m8[3],
    				addr.mFields.m8[4],
    				addr.mFields.m8[5],
    				addr.mFields.m8[6],
    				addr.mFields.m8[7],
    				addr.mFields.m8[8],
    				addr.mFields.m8[9],
    				addr.mFields.m8[10],
    				addr.mFields.m8[11],
    				addr.mFields.m8[12],
    				addr.mFields.m8[13],
    				addr.mFields.m8[14],
    				addr.mFields.m8[15]);
    }
    
    
    static bool init_coap( struct otInstance *ot )
    {
      otError error;
    
      if (!ot) {
        LOG_ERR("There is no valid OpenThread instance");
        error = OT_ERROR_FAILED;
        goto end;
      }
    
      otCoapSetDefaultHandler(ot, coap_default_handler, NULL);
    
      error = otCoapStart(ot, COAP_PORT);
      if (error != OT_ERROR_NONE) {
        LOG_ERR("Failed to start OT CoAP. Error: %d", error);
        goto end;
      }
    
    end:
      return error == OT_ERROR_NONE ? 1 : 0;
    }
    
    
    static void response_handler(void *aContext,
                                 otMessage *aMessage,
                                 const otMessageInfo *aMessageInfo,
                                 otError aResult)
    {
      uint16_t len, offset;
    
      (void)aContext;
      (void)aMessageInfo;
    
      LOG_INF("I GOT SOMETHING!!!!!");
    
      if (OT_ERROR_ABORT == aResult)
      {
        LOG_INF("ERROR: ABORT");
      }
      else if (OT_ERROR_RESPONSE_TIMEOUT == aResult)
      {
        LOG_INF("ERROR TIMEOUT");
      }
      else
      {
        LOG_INF("ALL GOOD");
      }
    
      len = otMessageGetLength(aMessage);
      LOG_INF("MESSAGE LENGTH: %d", len);
    
      offset = otMessageGetOffset(aMessage);
      LOG_INF("MESSAGE OFFSET: %d", offset);
    
      len = otMessageRead(aMessage, offset, (void *)buf, len);
      LOG_INF("MESSAGE: %s", buf);
    }
    
    
    static bool send_test_message( struct otInstance *ot )
    {
      otError error = OT_ERROR_NO_BUFS;
      otMessage *msg = NULL;
      otMessageInfo msg_info;
    
      memset(&msg_info, 0, sizeof(msg_info));
    
      msg = otCoapNewMessage(ot, NULL);
      if (msg == NULL) {
        goto end;
      }
    
      otCoapMessageInit(msg, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_GET);
    
      otCoapMessageGenerateToken(msg, OT_COAP_DEFAULT_TOKEN_LENGTH);
    
      error = otCoapMessageAppendUriPathOptions(msg, TEST_URI_PATH);
      if (error != OT_ERROR_NONE) {
        goto end;
      }
    
      //otThreadGetMeshLocalEid(ot);
    
      //bool TRUE to allow IPv6 Hop Limit 0 in mHopLimit, FALSE otherwise.
      //msg_info.mAllowZeroHopLimit = false;
      //uint8_t The ECN status of the packet, represented as in the IPv6 header.
      //mEcn
      //uint8_t The IPv6 Hop Limit value.
      //mHopLimit
      //bool TRUE if packets sent/received via host interface, FALSE otherwise.
      //mIsHostInterface
      //const void *A pointer to link-specific information.
      //mLinkInfo
      //bool  TRUE to allow looping back multicast, FALSE otherwise.
      //mMulticastLoop
      //otIp6Address The peer IPv6 address.
      //msg_info.mPeerAddr = peer_addr;
      otIp6AddressFromString(PEER_SERVER_IPV6_ADDRESS, &msg_info.mPeerAddr);
      //uint16_t The peer transport-layer port.
      msg_info.mPeerPort = COAP_PORT;
      //otIp6Address The local IPv6 address.
      //mSockAddr
      //uint16_t The local transport-layer port.
      //mSockPort = COAP_PORT;
      LOG_INF("GOING TO COAP ADDRESS:");
      print_ipv6_address(msg_info.mPeerAddr);
    
      error = otCoapSendRequest(ot, msg, &msg_info, response_handler, NULL);
    
    end:
      if (error != OT_ERROR_NONE && msg != NULL) {
        otMessageFree(msg);
      }
    
      return error == OT_ERROR_NONE ? 1 : 0;
    }
    
    
    static void reply_callback (const otPingSenderReply *aReply, void *aContext)
    {
      (void)aContext;
    
      LOG_INF("GOT A PING REPLY!!!!!!");
    
      print_ipv6_address(aReply->mSenderAddress);
    }
    
    
    static bool ping_send( struct otInstance *ot )
    {
      otError error = OT_ERROR_NONE;
      otPingSenderConfig config;
    
      memset(&config, 0, sizeof(config));
    
      otIp6AddressFromString(PEER_SERVER_IPV6_ADDRESS, &config.mDestination);
      LOG_INF("GOING TO PING ADDRESS:");
      print_ipv6_address(config.mDestination);
    
      config.mCallbackContext = NULL;
      config.mReplyCallback = reply_callback;
    
      error = otPingSenderPing(ot, &config);
    
      return (error == OT_ERROR_NONE ? 1 : 0);
    }
    
    
    void coap_client_utils_init(ot_connection_cb_t on_connect,
              ot_disconnection_cb_t on_disconnect)
    {
      ot_context = openthread_get_default_context();
    
      k_work_init(&on_connect_work, on_connect);
      k_work_init(&on_disconnect_work, on_disconnect);
      k_work_init(&test_msg_work, send_test_msg);
      k_work_init(&test_ping, ping_dest);
    
      openthread_set_state_changed_cb(on_thread_state_changed);
    }
    
    
    void coap_client_join_network(void)
    {
      openthread_start(ot_context);
    }
    
    
    void coap_client_send_test_msg(void)
    {
      submit_work_if_connected(&test_msg_work);
    }
    
    
    void coap_client_ping_dest(void)
    {
      submit_work_if_connected(&test_ping);
    }
    
    
    

  • Hi Marco,

    Thanks for the update, I have tested with the NCS2.2.0 OT sample and experienced a similar issue as you now, not able to find the cause.

    I have requested our development team to debug this issue together and will give you feedback if we find something.

    We may request a sniffer recording for your test later, please prepare to set up Sniffer for 802.15.4.

    Best regards,

    Charlie

Related