Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NSAPI_ERROR_NO_CONNECTION when connected to a socket via IP #30

Open
martinbydefault opened this issue Nov 5, 2020 · 3 comments
Open

Comments

@martinbydefault
Copy link

martinbydefault commented Nov 5, 2020

I'm having this following problem:
When I connect to a socket using a hostname, the call to MQTTClient::connect works correctly.
But if I connect to the socket using the IP, MQTTClient::connect gives me NSAPI_ERROR_NO_CONNECTION.

Here is my code:
Note that iface configuration is not included.

NetworkInterface *iface;
...
nsapi_size_or_error_t rc;
const char *hostname = "broker.hivemq.com";
const char *ip = "18.158.154.65";
const int port = 1883;

const char* topic = "topic/subject";
TCPSocket socket;
SocketAddress a;
MQTTClient client(&socket);
socket.open(iface);
// iface->gethostbyname(hostname, &a);
a.set_ip_address(ip);
a.set_port(port);
socket.connect(a);

MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.MQTTVersion = 3;
data.clientID.cstring = (char *) "mbed-sample";

if ((rc = client.connect(data)) != 0)
    print_function("rc from MQTT connect is %d\r\n", rc);

When I comment a.set_ip_address(ip); and uncomment iface->gethostbyname(hostname, &a); I get no error when doing the MQTT connection, and I can correctly subscribe to a topic for example.

But if I run the code as it is, i get the error: rc from MQTT connect is -3004 where -3004 is NSAPI_ERROR_NO_CONNECTION.

I also checked the logs when connecting to my own MQTT server and got this:

1604583169: New connection from 167.116.30.185 on port 1883.
1604583169: Socket error on client <unknown>, disconnecting

So the connection is created but then some socket error occurs client side.

I even added some debug code to check the socket connection:

rc = socket.open(iface);
if (rc != NSAPI_ERROR_OK) {
    print_function("TCPSocket.open() fails, code: %d\n", rc);
    return -1;
}
...
rc = socket.connect(a);
if (rc < 0) {
    print_function("TCPSocket.connect() fails, code: %d\n", rc);
    return -1;
} else {
    print_function("TCP: connected with %s server\n", socket.get_ip_address());
}

And I got this log:

TCP: connected with <MY-IP> server
Connecting to MQTT...rc from MQTT connect is -3004
@nuertey
Copy link

nuertey commented May 27, 2022

I am running into this issue currently myself @martinbydefault . And I am digging into my particular network stack's Mbed OS implementation of gethostbyname() to see what else they do to SocketAddress that our just setting the raw IP address and port on it does not suffice for.

I think that on the surface of it, our issue is not so much that we are using the raw IP instead of the FQDN, I think it is because SocketAddress expects something else besides the IP and port, some something else which it stored within itself when the FQDN was resolved. Hence why they passed a pointer of SocketAddress down during the resolution... I guess...

I will report back with what I find; and any mitigations that I come up with. Let me know if you find some other way to make it work with the raw IP yourself.

@nuertey
Copy link

nuertey commented May 27, 2022

Hi @martinbydefault ,

Okay I have a simple solution that works. Here is how I was able to get it to work for me in my 2-tiered application:

                // Assume that we are already dealing with an IP address. i.e.,
                // as the designer of this application, I am mandating that the
                // user can choose to specify IP addresses directly in the mbed_app.json
                // echo-server-hostname field. This will facilitate testing with
                // locally hosted Echo Servers, which by necessity, do not have 
                // DNS names. 
                
                // In which case the following is how we can ensure that the requisite 
                // SocketAddress object that is normally created during FQDN resolution,
                // is manually constructed and propagated back to the User:
                SocketAddress tempSockAddress(address.c_str(), 0);
                *pTheSocketAddress = tempSockAddress;

                ipAddress.emplace(address.c_str()); 

So in your case, I think that if you simply do the below, it should work and the socket connection will succeed:

SocketAddress a(ip, port);

// No need to do these any longer. They are now superfluous:
//a.set_ip_address(ip);
//a.set_port(port);

// Simply carry on connecting right after construction of the SocketAddress:
socket.connect(a);

Enjoy
Nuertey

nuertey added a commit to nuertey/Nuertey-Dragonfly-Cellular-LightControl that referenced this issue May 27, 2022
…hen I would be doing MQTT testing. Also see this thread below on me instructing other folks on how to solve it on their setups.

ARMmbed/mbed-mqtt#30

Nuertey-Dragonfly-Cellular-LightControl Application - Beginning...

Mbed OS version: 6.15.1

Built: May 27 2022, 07:58:10

Running LEDLightControl::Setup() ...
[00000179ms][INFO][STE1]: power_up: PHY Addr 0 AutoNeg 1
[00000254ms][DBG ][STE1]: MAC Addr 00:80:e1:37:00:25
[00000325ms][INFO][STE1]: ETH buffers : 4 Rx 4 Tx
[00001871ms][INFO][STE1]: PHY ID 7C130
[00001939ms][INFO][STE1]: low_level_init_successful
Connecting to network ...
[00002207ms][INFO][STE1]: emac_link_state_cb set to true
Global IP address set!
Running LEDLightControl::ConnectToSocket() ...
Particular Network Interface IP address: 10.42.0.58
Particular Network Interface Netmask: 255.255.255.0
Particular Network Interface Gateway: 10.42.0.1
Particular Network Interface MAC Address: 00:80:e1:37:00:25
Connecting to "10.42.0.1" as resolved to: "10.42.0.1:7" ...
Error! TCPSocket.connect() to EchoServer returned:                    [-3004] -> "not connected to a network"
@nuertey
Copy link

nuertey commented Jun 9, 2022

@martinbydefault note also that I think you need to change the order of your socket.connect() and the MQTTClient instantiation. i.e. I think that the MQTTClient on being created expects the socket to ALREADY be connected by then; like so:

...
socket.open(iface);
// iface->gethostbyname(hostname, &a);
SocketAddress a(ip, port);
socket.connect(a);
MQTTClient client(&socket); // New MQTT API expects client to already be connected... I think.

Regards
Nuertey

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants