This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF9160 MQTT Client error -12 (ENOMEM) when Host url is very long

Hello, 

I'm using the mqtt_simple example with the following changes to add WebSockets Secure Support:

# Networking
CONFIG_NET_NATIVE=y

# MQTT
CONFIG_MQTT_LIB_TLS=y
CONFIG_MQTT_LIB_WEBSOCKET=y
CONFIG_WEBSOCKET_CLIENT=y

# Logs
CONFIG_NET_LOG=y
CONFIG_MQTT_LOG_LEVEL_DBG=y

Also I set the Application MQTT topics, clientId, host, port and everything using the CONFIG.

The only change I made in the code was this:

client->transport.type = MQTT_TRANSPORT_SECURE_WEBSOCKET;

The issue is that our Amazon AWS IoT broker url is very long, exactly 1.681 bytes, this is because Amazon give us a url with the token and all the credentials embedded in the url. When I run the code I'm seeing a ENOMEM (-12) when calling the mqtt_connect function.

This is the log:

*** Booting Zephyr OS build v2.4.0-ncs1  ***
The MQTT simple sample started
Provisioning certificates
LTE Link Connecting ...<CR><LF>
+CEREG: 2,"3174","02D71604",7,0,0,"11100000","11100000"
+CSCON: 1
+CEREG: 1,"3174","02D71604",7,,,"11100000","11100000"
LTE Link Connected!
IPv4 Address found 3.211.121.218
ERROR: mqtt_connect -12
[00:00:03.320,220] <ESC><dbg> net_mqtt.client_connect: (0x20020e08): Using transport type 3<ESC>
[00:00:03.320,587] <ESC><dbg> net_mqtt_sock_tls.mqtt_client_tls_connect: (0x20020e08): Created socket 1<ESC>[0
[00:00:03.321,044] <ESC><dbg> net_mqtt_websocket.mqtt_client_websocket_connect: (0x20020e08): mqtt_client_tls_connect: -12<ESC>
[00:00:03.321,075] <ESC><dbg> net_mqtt.mqtt_connect: (0x20020e08): client_connect: -12<ESC>

I was able to debug the error to the following function in mqtt_transport_socket_tls.c

int mqtt_client_tls_connect(struct mqtt_client *client)
{
    .
    .
    .
    
    if (tls_config->hostname) {
		ret = setsockopt(client->transport.tls.sock, SOL_TLS,
				 TLS_HOSTNAME, tls_config->hostname,
				 strlen(tls_config->hostname));
		if (ret < 0) {
			goto error;
		}
	}
	
	.
	.
	.
	
}

So my question is how I can somehow increase the memory that the setsockopt function uses when setting the hostname on the socket.

I already tested increasing the main stack and heap memory using the CONFIG with no luck.

# Memory
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_HEAP_MEM_POOL_SIZE=16384

Btw I'm using NCS v1.4.0 and modem fw 1.2.3.

Any help will be appreciated.

Thanks! 

Parents
  • Hi, 

    Is the URL still valid (it has not expired)? Is the signature correct?

    I dont know why I cant reply to your last comment but I'm happy to tell you that I already was able to connect to the broker successfully. The issue was a bad certificate that was giving me that 403 forbidden error. 

    Also, out of curiosity, why do you want to use websockets instead of "pure" MQTT, and how do you generate the URL?

    We generate the url requesting an Amazon Signature v4 url to authenticate on our broker. That url is generated on our server and the device requests it using a http GET.

    The only thing that is happening right now (and I'm not sure if it's a bug or not, because it only happens with this aws broker) is that I wasn't able to publish to any topic. I was able to subscribe, receive data and send the keep alive, but when I tried to publish something the broker kicked me for some reason.

    Searching on other implementation that we have on other microcontroller I found that the library we use does not splits the publish message in header and payload but sends it in a single packet, so I checked the mqtt library code and found and mofified the following code in the mqtt.c file:

    int mqtt_publish(struct mqtt_client *client, const struct mqtt_publish_param *param) {
    
        int err_code;
    	struct buf_ctx packet;
    	struct iovec io_vector[1];      // Modified size to 1 to sent in a single packet
    	struct msghdr msg;
    
    	NULL_PARAM_CHECK(client);
    	NULL_PARAM_CHECK(param);
    
    	MQTT_TRC("[CID %p]:[State 0x%02x]: >> Topic size 0x%08x, "
    		 "Data size 0x%08x", client, client->internal.state,
    		 param->message.topic.topic.size,
    		 param->message.payload.len);
    
    	mqtt_mutex_lock(client);
    
    	tx_buf_init(client, &packet);
    
    	err_code = verify_tx_state(client);
    	if (err_code < 0) {
    		goto error;
    	}
        
        // Internally modified this function to add the payload inside the packet buffer
    	err_code = publish_encode(param, &packet);
    	if (err_code < 0) {
    		goto error;
    	}
    
    	io_vector[0].iov_base = packet.cur;
    	io_vector[0].iov_len = packet.end - packet.cur;
    	
    	// removed this to send in a single packet
    	//io_vector[1].iov_base = param->message.payload.data;
    	//io_vector[1].iov_len = param->message.payload.len;
    
    	memset(&msg, 0, sizeof(msg));
    
    	msg.msg_iov = io_vector;
    	msg.msg_iovlen = ARRAY_SIZE(io_vector);
    
    	err_code = client_write_msg(client, &msg);
    
    error:
    	MQTT_TRC("[CID %p]:[State 0x%02x]: << result 0x%08x",
    			 client, client->internal.state, err_code);
    
    	mqtt_mutex_unlock(client);
    
    	return err_code;
    }

    If I send the publish in a single packet it works, if not, it doesn't. I tried with another wss broker and the original code worked so I'm not sure what could be wrong in the multi packet publish with this aws broker.

    I dont know if you know something about that,

    Thanks in advance

Reply
  • Hi, 

    Is the URL still valid (it has not expired)? Is the signature correct?

    I dont know why I cant reply to your last comment but I'm happy to tell you that I already was able to connect to the broker successfully. The issue was a bad certificate that was giving me that 403 forbidden error. 

    Also, out of curiosity, why do you want to use websockets instead of "pure" MQTT, and how do you generate the URL?

    We generate the url requesting an Amazon Signature v4 url to authenticate on our broker. That url is generated on our server and the device requests it using a http GET.

    The only thing that is happening right now (and I'm not sure if it's a bug or not, because it only happens with this aws broker) is that I wasn't able to publish to any topic. I was able to subscribe, receive data and send the keep alive, but when I tried to publish something the broker kicked me for some reason.

    Searching on other implementation that we have on other microcontroller I found that the library we use does not splits the publish message in header and payload but sends it in a single packet, so I checked the mqtt library code and found and mofified the following code in the mqtt.c file:

    int mqtt_publish(struct mqtt_client *client, const struct mqtt_publish_param *param) {
    
        int err_code;
    	struct buf_ctx packet;
    	struct iovec io_vector[1];      // Modified size to 1 to sent in a single packet
    	struct msghdr msg;
    
    	NULL_PARAM_CHECK(client);
    	NULL_PARAM_CHECK(param);
    
    	MQTT_TRC("[CID %p]:[State 0x%02x]: >> Topic size 0x%08x, "
    		 "Data size 0x%08x", client, client->internal.state,
    		 param->message.topic.topic.size,
    		 param->message.payload.len);
    
    	mqtt_mutex_lock(client);
    
    	tx_buf_init(client, &packet);
    
    	err_code = verify_tx_state(client);
    	if (err_code < 0) {
    		goto error;
    	}
        
        // Internally modified this function to add the payload inside the packet buffer
    	err_code = publish_encode(param, &packet);
    	if (err_code < 0) {
    		goto error;
    	}
    
    	io_vector[0].iov_base = packet.cur;
    	io_vector[0].iov_len = packet.end - packet.cur;
    	
    	// removed this to send in a single packet
    	//io_vector[1].iov_base = param->message.payload.data;
    	//io_vector[1].iov_len = param->message.payload.len;
    
    	memset(&msg, 0, sizeof(msg));
    
    	msg.msg_iov = io_vector;
    	msg.msg_iovlen = ARRAY_SIZE(io_vector);
    
    	err_code = client_write_msg(client, &msg);
    
    error:
    	MQTT_TRC("[CID %p]:[State 0x%02x]: << result 0x%08x",
    			 client, client->internal.state, err_code);
    
    	mqtt_mutex_unlock(client);
    
    	return err_code;
    }

    If I send the publish in a single packet it works, if not, it doesn't. I tried with another wss broker and the original code worked so I'm not sure what could be wrong in the multi packet publish with this aws broker.

    I dont know if you know something about that,

    Thanks in advance

Children
  • Hi, it's good to hear you got it working.

    I discussed your publish problems with some of our experts.

    To us, it looks like a bug/limitation in the AWS broker.

    According to the MQTT specification, it should be okay to split the MQTT message accross multiple WebSocket and TCP packets.

    "A single WebSocket data frame can contain multiple or partial MQTT Control Packets. The receiver MUST NOT assume that MQTT Control Packets are aligned on WebSocket frame boundaries [MQTT-6.0.0-2]."

    But, we know that the AWS broker isn't following the specification on all points, this might be another point where they brake it. You might want to discuss this with AWS support.

    Best regards,

    Didrik

Related