How to convert an IP address array to SocketAddress

I have a given IP address as an array like uint8_t ip[4] = {10, 101, 1, 1};
How to use in SocketAddress?
Is there a way to convert to a string ?

Hello Stefan,

I’m afraid there in such Mbed function but you can try this:

char str[4 * 3 + 3 + 1]; // 4 * 3 digits + 3 dots + 1 terminating NULL char

const char* ipToString(char* str, uint8_t ip[4])
{
    uint8_t i = 0;
    uint8_t j = 0;

    for (i = 0; i < 3; i++) {
        j += sprintf(&str[j], "%d", ip[i]);
        str[j++] = '.';
    }

    j += sprintf(&str[j], "%d", ip[i]);
    str[j] = '\0';
    return str;
}

If you’re using sprintf, why not just write:

char str[16];

sprintf(&str, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

SocketAddress ip_addr(str);

SocketAddress has a constructor that takes the address bytes and address type:
https://os.mbed.com/docs/mbed-os/v5.15/mbed-os-api-doxy/class_socket_address.html#a799e9df7fd000b33efebad45a9cb513f

So, what does it actually mean: “Raw IP address in big-endian order”

There are several variations, of which the binary types seem to be: nsapi_addr_t and const void *

The nsapi_addr_t contains an array of 16 bytes (I guess to cater for IPv6?), so are the octets just represented in binary fashion eg: 0xFF, 0xFF, 0xFF, 0xFF => 255 255 255 255? (dots are assumed?).

Can the const void * version be declared simply as: 0xFFFFFFFF for the above example?

Of course Chris, your sprintf is much simpler :slight_smile: Thank you for that! And I was wrong also about the missing Mbed built-in function. Thank you Johannes for the info! So it seems that Stefan can create a SocketAddress by passing his IP address to the constructor:

uint8_t ip[4] = {10, 101, 1, 1};
SocketAddress sockAddr(ip, NSAPI_IPv4); // optional third parameter 'port' defaults to 0

This does not work when using set_network(). I get an error message
no suitable conversion function from “SocketAddress” to “const char *” exists

#include <mbed.h>
#include "EthernetInterface.h"

EthernetInterface eth;

uint8_t ip[4] = {10, 101, 1, 201};
uint8_t subnet[4] = {255, 255, 0, 0};
uint8_t gateway[4] = {0, 0, 0, 0};

SocketAddress IP(ip, NSAPI_IPv4);
SocketAddress SUBNET(subnet, NSAPI_IPv4);
SocketAddress GATEWAY(gateway, NSAPI_IPv4);

int main() {
  eth.set_network(IP, SUBNET, GATEWAY);
  eth.connect();

  while(1) {
  }
}

with mbed-os 5.15 it works. There is a constructor that takes ‘const &SocketAddress’ as arguments.
And a

printf("IP: %s\nsubnet: %s\ngateway: %s\n", IP.get_ip_address(), SUBNET.get_ip_address(), GATEWAY.get_ip_address());

is also printing the correct addresses.

And using get_default_instance() is more versatile for different network interfaces:
(using DHCP, but can be set also to fixed IP):

    // Connect to the network with the default networking interface
    // if you use WiFi: see mbed_app.json for the credentials
    NetworkInterface* network = NetworkInterface::get_default_instance();
    if (!network) {
        printf("Cannot connect to the network, see serial output\n");
        return 1;
    } 
    nsapi_error_t connect_status = network->connect();

    if (connect_status != NSAPI_ERROR_OK) {
        printf("Failed to connect to network (%d)\n", connect_status);
        return 2;
    } else {
        SocketAddress socketAddress;
        network->get_ip_address(&socketAddress);
        printf("my IP is: %s\n", socketAddress.get_ip_address());
    } 

tried with sprintf, also an error message:
no suitable conversion function from “SocketAddress” to “const char *” exists

#include <mbed.h>
#include "EthernetInterface.h"

EthernetInterface eth;

const uint8_t ip[4] = {10, 101, 1, 201};
const uint8_t subnet[4] = {255, 255, 0, 0};
const uint8_t gateway[4] = {0, 0, 0, 0};

//SocketAddress IP(ip, NSAPI_IPv4);
//SocketAddress SUBNET(subnet, NSAPI_IPv4);
//SocketAddress GATEWAY(gateway, NSAPI_IPv4);

int main() {
  char ipAddress[16];
  sprintf(ipAddress, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
  SocketAddress IP(ipAddress);
  char subnetMask[16];
  sprintf(subnetMask, "%d.%d.%d.%d", subnet[0], subnet[1], subnet[2], subnet[3]);
  SocketAddress SUBNET(subnetMask);
  char gatewayAddress[16];
  sprintf(gatewayAddress, "%d.%d.%d.%d", gateway[0], gateway[1], gateway[2], gateway[3]);
  SocketAddress GATEWAY(gatewayAddress);

  eth.set_network(IP, SUBNET, GATEWAY);
  eth.connect();

  while(1) {

  }
}

set_network takes const SocketAddress& arguments.
Try either this :

#include <mbed.h>
#include "EthernetInterface.h"

EthernetInterface eth;

uint8_t ip[4] = {10, 101, 1, 201};
uint8_t subnet[4] = {255, 255, 0, 0};
uint8_t gateway[4] = {0, 0, 0, 0};

const SocketAddress IP(ip, NSAPI_IPv4);
const SocketAddress SUBNET(subnet, NSAPI_IPv4);
const SocketAddress GATEWAY(gateway, NSAPI_IPv4);

int main() {
  eth.set_network(IP, SUBNET, GATEWAY);
  eth.connect();

  while(1) {
  }
}

or this:

#include <mbed.h>
#include "EthernetInterface.h"

EthernetInterface eth;

uint8_t ip[4] = {10, 101, 1, 201};
uint8_t subnet[4] = {255, 255, 0, 0};
uint8_t gateway[4] = {0, 0, 0, 0};

SocketAddress IP(ip, NSAPI_IPv4);
SocketAddress SUBNET(subnet, NSAPI_IPv4);
SocketAddress GATEWAY(gateway, NSAPI_IPv4);

int main() {
  eth.set_network((const SocketAddress&)IP, (const SocketAddress&)SUBNET, (const SocketAddress&)GATEWAY);
  eth.connect();

  while(1) {
  }
}

yes, it looks like the SocketAddress arguments are introduced with mbed-os 5.15. The string based functions are deprecated, so I would upgrade the mbed-os.
The typecast is not necessary.

that was the same, only a different way to construct the SocketAddress.

eth.set_network("10.101.1.201", "255.255.0.0", "0.0.0.0");

should work also, but again, this is depracted and not recommended with newer mbed-os versions. The SocketAddress is a better abstraction for handling IPv4/IPv6.

In the moment I work with platformIO and they use the mbed version 5.14, so I have to wait because online compiler doesn’t work in the moment (macOS Catalina with Safari).

ok, so half-way to the future is still to use SocketAddress with the string based ip address, then it can be changed later by simply removing the ‘.get_ip_address()’:

eth.set_network(IP.get_ip_address(), SUBNET.get_ip_address(), GATEWAY.get_ip_address())

or maybe try using Mbed-studio, should run also on a MacOS.