Mobile native Wearable native

Connection: Managing Modem Data Connections

This tutorial demonstrates how you can get the network connection information, such as default gateway and proxy configuration, IPv4 and IPv6 addresses, cellular connection state, and data transfer statistics.

Warm-up

Become familiar with the Connection API basics by learning about:

Initializing Connections

To use the functions and data types of the Connection API (in mobile and wearable applications), include the <net_connection.h> header file in your application:

#include <net_connection.h>

To be able to use all connection functions, you must create a handle that contains information about the connection. Use the connection static variable that stores the connection handle.

static connection_h connection;

Create the connection handle using the connection_create() function that allows you to obtain the connection state and data transfer information.

int error_code;
 
error_code = connection_create(&connection);
if (error_code != CONNECTION_ERROR_NONE)
   return;

Destroy the created connection handle when you do not need it anymore.

connection_destroy(connection);

Getting the Network Connection Details

To get the type of the current connection, IP address, and proxy information, the Connection API supports the following network types:

  • CONNECTION_TYPE_DISCONNECTED
  • CONNECTION_TYPE_WIFI
  • CONNECTION_TYPE_CELLULAR
  • CONNECTION_TYPE_ETHERNET
  • CONNECTION_TYPE_BT

The Connection API supports both IPv4 and IPv6 with the following address types:

  • CONNECTION_ADDRESS_FAMILY_IPV4
  • CONNECTION_ADDRESS_FAMILY_IPV6

In this tutorial, an IPv4 address is retrieved.

  1. To get the type of the current profile for data connection, use the connection_get_type() function:
    int error_code;
    connection_type_e net_state;
    error_code = connection_get_type(connection, &net_state);
    if (error_code == CONNECTION_ERROR_NONE)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Network connection type : %d", net_state);
    }

    You can also use the connection_set_type_changed_cb() function to register a callback function that is called when the connection type changes.

    connection_set_type_changed_cb(connection, __connection_changed_cb, NULL);
    

    When the connection type changes, the __connection_changed_cb() function is invoked.

    static void __connection_changed_cb(connection_type_e type, void* user_data)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Type changed callback, connection type : %d", type);
    }
  2. To get the connection IPv4 address, use the connection_get_ip_address() function. The IP address is printed using dlog util, or shown to the user in another way.

    Finally, free the memory allocated for the ip_addr temporary variable.

    char *ip_addr = NULL;
    error_code = connection_get_ip_address(connection, CONNECTION_ADDRESS_FAMILY_IPV4, &ip_addr);
    if (error_code == CONNECTION_ERROR_NONE)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "IP address : %s", ip_addr);
       free(ip_addr);
    }
  3. To get the connection proxy information, use the connection_get_proxy() function. The proxy address is printed.

    Finally, free the memory allocated for the proxy_addr variable.

    error_code = connection_get_proxy(connection, address_family, &proxy_addr);
    if (error_code == CONNECTION_ERROR_NONE) 
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Proxy address : %s", proxy_addr);
       free(proxy_addr); 
    }

Getting the Connection Information

To obtain cellular and Wi-Fi connection information with data transfer statistics, such as the amount of total sent or received data and last sent or received data (only Wi-Fi and cellular statistics information is supported):

  1. To get the cellular connection state, use the connection_get_cellular_state() function. There are 6 states in which the network connection can be:
    • CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE
    • CONNECTION_CELLULAR_STATE_FLIGHT_MODE
    • CONNECTION_CELLULAR_STATE_ROAMING_OFF
    • CONNECTION_CELLULAR_STATE_CALL_ONLY_AVAILABLE
    • CONNECTION_CELLULAR_STATE_AVAILABLE
    • CONNECTION_CELLULAR_STATE_CONNECTED

    In the example, using a switch statement, the cellular state is shown.

    connection_cellular_state_e cellular_state;
    connection_get_cellular_state(connection, &cellular_state);
    switch (cellular_state) 
    {
       case CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE: 
          dlog_print(DLOG_INFO, LOG_TAG, "Out of service"); 
          break;
       case CONNECTION_CELLULAR_STATE_FLIGHT_MODE: 
          dlog_print(DLOG_INFO, LOG_TAG, "Flight mode");   
          break;
       case CONNECTION_CELLULAR_STATE_ROAMING_OFF: 
          dlog_print(DLOG_INFO, LOG_TAG, "Roaming is turned off"); 
          break;
       case CONNECTION_CELLULAR_STATE_CALL_ONLY_AVAILABLE: 
          dlog_print(DLOG_INFO, LOG_TAG, "Call only"); 
          break;
       case CONNECTION_CELLULAR_STATE_AVAILABLE: 
          dlog_print(DLOG_INFO, LOG_TAG, "Available"); 
          break;
       case CONNECTION_CELLULAR_STATE_CONNECTED: 
          dlog_print(DLOG_INFO, LOG_TAG, "Connected"); 
          break;
       default: 
          dlog_print(DLOG_INFO, LOG_TAG, "error");
          break;
    }
    
  2. To get the Wi-Fi connection state, use the connection_get_wifi_state() function. There are 3 states in which the Wi-Fi connection can be:
    • CONNECTION_WIFI_STATE_DEACTIVATED
    • CONNECTION_WIFI_STATE_DISCONNECTED
    • CONNECTION_WIFI_STATE_CONNECTED

    In the example, using a switch statement, the wifi_state enumeration variable is shown.

    connection_wifi_state_e wifi_state;
    connection_get_wifi_state(connection, &wifi_state);
    switch (wifi_state) 
    {
       case CONNECTION_WIFI_STATE_DEACTIVATED:
          dlog_print(DLOG_INFO, LOG_TAG, "Deactivated state");
          break;
       case CONNECTION_WIFI_STATE_DISCONNECTED:
          dlog_print(DLOG_INFO, LOG_TAG, "Disconnected state");
          break;
       case CONNECTION_WIFI_STATE_CONNECTED:
          dlog_print(DLOG_INFO, LOG_TAG, "Connected state");
          break;
       default:
          dlog_print(DLOG_INFO, LOG_TAG, "error"); 
          break;
    }
    
  3. Get connection statistics.

    Connection statistics include the amount of total sent and received data and the last sent and received data. To read the statistics, use the connection_get_statistics() function. The function arguments determine which statistics are received, and for which connection type.

    Statistics are identified by the following constants:

    • CONNECTION_STATISTICS_TYPE_LAST_RECEIVED_DATA
    • CONNECTION_STATISTICS_TYPE_LAST_SENT_DATA
    • CONNECTION_STATISTICS_TYPE_TOTAL_RECEIVED_DATA
    • CONNECTION_STATISTICS_TYPE_TOTAL_SENT_DATA

    Use the following constants to set the connection type:

    • CONNECTION_TYPE_WIFI
    • CONNECTION_TYPE_CELLULAR

    The code below reads all statistics for cellular and WiFi connections.

    long long last_received_size;
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_CELLULAR, CONNECTION_STATISTICS_TYPE_LAST_RECEIVED_DATA, & last_received_size);
    // Handle statistics
     
    long long last_sent_size;
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_CELLULAR, CONNECTION_STATISTICS_TYPE_LAST_SENT_DATA, & last_sent_size);
    // Handle statistics
     
    long long total_received_size;
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_CELLULAR, CONNECTION_STATISTICS_TYPE_TOTAL_RECEIVED_DATA, & total_received_size);
    // Handle statistics
     
    long long total_sent_size;
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_CELLULAR, CONNECTION_STATISTICS_TYPE_TOTAL_SENT_DATA, & total_sent_size);
    // Handle statistics
     
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_WIFI, CONNECTION_STATISTICS_TYPE_LAST_RECEIVED_DATA, & last_received_size);
    // Handle statistics
     
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_WIFI, CONNECTION_STATISTICS_TYPE_LAST_SENT_DATA, & last_sent_size);
    // Handle statistics
     
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_WIFI, CONNECTION_STATISTICS_TYPE_TOTAL_RECEIVED_DATA, & total_received_size);
    // Handle statistics
     
    error_code = connection_get_statistics(connection, CONNECTION_TYPE_WIFI, CONNECTION_STATISTICS_TYPE_TOTAL_SENT_DATA, & total_sent_size);
    // Handle statistics

Registering the Property Change Callback

To register callback functions that are called when information changes:

  1. Define callback functions.

    In this tutorial, the callbacks registered are the __ip_changed_cb() and __proxy_changed_cb() functions, used for address changes. In case of an address change, an information message is printed in the file (or shown to the user in another way). The message contains information on which address has been changed and what the new value is.

    static void __ip_changed_cb(const char* ipv4_address, const char* ipv6_address, void* user_data) 
    {
       dlog_print(DLOG_INFO, LOG_TAG, "%s callback, IPv4 address : %s, IPv6 address : %s", (char *)user_data, ipv4_address, (ipv6_address ? ipv6_address : "NULL"));
    }
     
    static void __proxy_changed_cb(const char* ipv4_address, const char* ipv6_address, void* user_data) 
    {
       dlog_print(DLOG_INFO, LOG_TAG, "%s callback, IPv4 address : %s, IPv6 address : %s", (char *)user_data, ipv4_address, (ipv6_address ? ipv6_address : "NULL"));
    }
    
  2. Register the defined callback functions.

    You have to register the previously defined callback functions. The connection_set_ip_address_changed_cb() and connection_set_proxy_address_changed_cb() functions are used to register the __ip_changed_cb() and __proxy_changed_cb() functions called when the IP address or the proxy address is changed, respectively. The last parameter (user_data) is set to a message which is printed in the callback.

    error_code = connection_set_ip_address_changed_cb(connection, __ip_changed_cb, "IP addr changed:");
    if (error_code != CONNECTION_ERROR_NONE) 
    {
       // Error handling
    }
    error_code = connection_set_proxy_address_changed_cb(connection, __proxy_changed_cb, "Proxy IP addr changed:");
    if (error_code != CONNECTION_ERROR_NONE) 
    {
       // Error handling
    }
    
  3. Unregister the callback functions.

    When the callback functions are not needed any more, unregister them using the connection_unset_network_state_changed_cb() function.

    error_code = connection_unset_ip_address_changed_cb(connection);
    if (error_code != CONNECTION_ERROR_NONE) 
    {
       // Error handling
    }
      
    error_code = connection_unset_proxy_address_changed_cb(connection);
    if (error_code != CONNECTION_ERROR_NONE) 
    {
       // Error handling
    }
    

Initializing a Socket

To initialize a socket for use:

  1. To use the functions and data types of the Socket API, include the following header files:
    #include <sys/stat.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <net/if.h>
    
  2. Declare the necessary variables:
    int main(int argc, char **argv)
    {
       int rv = 0;
       int ip_type = -1;
       char user_url[100] = {0,};
       char user_port[10] = {0,};
       char user_msg[200] = {0,};
       char *local_ipv4 = NULL;
       char *local_ipv6 = NULL;
       char *interface_name = NULL;
    
       connection_type_e net_state;
       connection_h connection = NULL;
       connection_profile_h profile_h = NULL;
    
       // Input the URL and message to be sent
    
  3. Include the required header files and create a connection handle.
  4. Check whether the default connection is available:
       connection_type_e net_state;
    
       rv = connection_get_type(connection, &net_state);
       if (rv != CONNECTION_ERROR_NONE || net_state == CONNECTION_TYPE_DISCONNECTED) 
       {
          dlog_print(DLOG_INFO, LOG_TAG, "Not connected %d\n", rv);
          connection_destroy(connection);
    
          return -1;
       }
    
  5. Check the address type of the default connection.

    The address type can be IPv4 or IPv6.

       int ip_type = -1;
       char *local_ipv4 = NULL;
       char *local_ipv6 = NULL;
       connection_profile_h profile_h = NULL;
    
       rv = connection_get_current_profile(connection, &profile_h);
       if (rv != CONNECTION_ERROR_NONE) 
       {
          dlog_print(DLOG_INFO, LOG_TAG, "Fail to get profile handle %d\n", rv);
          connection_destroy(connection);
    
          return -1;
       }
    
       rv = connection_profile_get_ip_address(profile_h, CONNECTION_ADDRESS_FAMILY_IPV6, &local_ipv6);
       if (rv == CONNECTION_ERROR_NONE && g_strcmp0(local_ipv6, "::") != 0) 
       {
          ip_type = CONNECTION_ADDRESS_FAMILY_IPV6;
          dlog_print(DLOG_INFO, LOG_TAG, "IPv6 address : %s\n", local_ipv6);
       }
    
       // If both IPv4 and IPv6 types are set, the IPv4 type is used as default here
       rv = connection_profile_get_ip_address(profile_h, CONNECTION_ADDRESS_FAMILY_IPV4, &local_ipv4);
       if (rv == CONNECTION_ERROR_NONE && g_strcmp0(local_ipv4, &0.0.0.0&) != 0) 
       {
          ip_type = CONNECTION_ADDRESS_FAMILY_IPV4;
          dlog_print(DLOG_INFO, LOG_TAG, "IPv4 address : %s\n", local_ipv4);
       }
    
       if (ip_type != CONNECTION_ADDRESS_FAMILY_IPV6 && ip_type != CONNECTION_ADDRESS_FAMILY_IPV4) 
       {
          dlog_print(DLOG_INFO, LOG_TAG, "No IP address!\n");
          // Error handling
       }
    
       connection_profile_get_network_interface_name(profile_h, &interface_name);
       dlog_print(DLOG_INFO, LOG_TAG, "Interface Name:%s\n", interface_name);
    }
    

Retrieving the Address Family

To get the IP addresses for the hostname to connect:

  1. Define the user URL and message to be sent.
  2. Retrieve the IP addresses:
       struct sockaddr_in6 *addr6;
       struct addrinfo hints;
       struct addrinfo *result;
       char user_url[100] = {0,};
       char user_port[10] = {0,};
    
       memset(&hints, 0x00, sizeof(struct addrinfo));
    
       hints.ai_family = PF_UNSPEC;
       hints.ai_socktype = SOCK_STREAM;
       hints.ai_protocol = IPPROTO_TCP;
    
       if (getaddrinfo(user_url, user_port, &hints, &result) != 0) 
       {
          dlog_print(DLOG_INFO, LOG_TAG, "getaddrinfo() error\n");
          // Error handling
       }
    }
    

Creating the Socket and Managing the Remote Host Connection

To create the socket and connect to a remote host:

  1. Find the proper address family and create the socket:
    int sockfd = -1;
    struct addrinfo *rp;
    
    rp = result;
    
    for (rp = result; rp != NULL; rp = rp->ai_next) 
    {
       if (rp->ai_family == AF_INET && ip_type == CONNECTION_ADDRESS_FAMILY_IPV4) 
       {
          if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) > 0) 
          {
             dlog_print(DLOG_INFO, LOG_TAG, "socket error\n");
             freeaddrinfo(result);
          }
          dlog_print(DLOG_INFO, LOG_TAG, "IPv4\n");
    
       } 
       else if (rp->ai_family == AF_INET6 && ip_type == CONNECTION_ADDRESS_FAMILY_IPV6) 
       {
          if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) 
          {
             dlog_print(DLOG_INFO, LOG_TAG, "socket error\n");
             freeaddrinfo(result);
          }
          dlog_print(DLOG_INFO, LOG_TAG, "IPv6\n");
       }
    }
    
  2. Connect to the remote host:
    • Use the IPv4 socket:
      if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) < 0) 
      {
         dlog_print(DLOG_INFO, LOG_TAG, "connect() error: %s\n", strerror(errno));
         freeaddrinfo(result);
         close(sockfd);
      }
      
    • Use the IPv6 socket.

      The interface index is needed for the IPv6 connection.

      char *interface_name = NULL;
      
      connection_profile_get_network_interface_name(profile_h, &interface_name);
      dlog_print(DLOG_INFO, LOG_TAG, "Interface Name:%s\n", interface_name);
      
      addr6 = (struct sockaddr_in6 *)rp->ai_addr;
      addr6->sin6_scope_id = if_nametoindex(interface_name);
      
      if ((sockfd = connect(sockfd, (struct sockaddr *)addr6, rp->ai_addrlen)) < 0) 
      {
         dlog_print(DLOG_INFO, LOG_TAG, "connect() error: %s\n", strerror(errno));
         freeaddrinfo(result);
         close(sockfd);
      }
      
  3. Manage messages:
    • Send a message to the remote host:
      if ((count = write(sockfd, user_msg, 200)) < 0) 
      {
         dlog_print(DLOG_INFO, LOG_TAG, "write() error: %s\n", strerror(errno));
      
         freeaddrinfo(result);
         close(sockfd);
      }
      dlog_print(DLOG_INFO, LOG_TAG, "Sent count: %d, msg: %s\n", count, user_msg);
      
    • Read a message from the remote host:
      char buf[257];
      memset(buf, 0x00, 257);
      
      if ((count = read(sockfd, buf, 256)) < 0) 
      {
         dlog_print(DLOG_INFO, LOG_TAG, "read() error: %s\n", strerror(errno));
      
         freeaddrinfo(result);
         close(sockfd);
      }
      buf[count] = '\0';
      dlog_print(DLOG_INFO, LOG_TAG, "\nRead: %s\n", buf);
      
  4. Close the socket and release the resources:
    freeaddrinfo(result);
    close(sockfd);
    
    done:
       connection_profile_destroy(profile_h);
       connection_destroy(connection);
    
       free(local_ipv6);
       free(local_ipv4);
       free(interface_name);
    
       return 0;
    
Go to top