Network Operations

The basic tasks involved in network operations are connecting to the
network, downloading HTTP content, and parsing data in XML and JSON
formats. The following sections provide you with the fundamental
building blocks for creating Tizen applications that download content
and parse data efficiently.

Connecting to the Network

You can write applications that create a network connection and check
the connection status over that connection. The connected application
can access connection details, such as the IP address, proxy
information, gateway information, and connection statistics.

Required Privileges and Features

Applications that use the Network (in
mobile
and
wearable
applications) and Telephony (in
mobile
and
wearable
applications) APIs must declare the required privileges in the
tizen-manifest.xml file. For more information on the Tizen privileges,
see Security and API Privileges.

To perform the network operations, the application manifest must include
the following privileges:

<privileges>
   <privilege>http://tizen.org/privilege/network.get</privilege>
</privileges>

To perform the network operations, the device must support the following
features:

  • http://tizen.org/feature/network.wifi
  • http://tizen.org/feature/network.telephony

Network Selection

The supported network connections vary depending on the device. If Wi-Fi
is available on your device, the device tries first to use a Wi-Fi
network to connect to the Internet, and only selects the mobile
(cellular) network if a Wi-Fi network is not available. If the device
does not support Wi-Fi, you must check whether it supports the mobile
network and whether mobile data is switched on.

Checking the Network Connection

The Connection Manager API (in
mobile
and
wearable
applications) provides functions for managing data connections. It
allows you to get a state of the connection interface, such as
Bluetooth, mobile network, and Wi-Fi. It also contains functions for
getting the IP address, proxy information, and gateway information.

Before your application attempts to connect to a network, it must check
whether a network connection is available, by using the
connection_get_type() function. This is necessary, because the device
can be out of range of a network, or the user may have disabled both
Wi-Fi and mobile data access.

The following example demonstrates how to create a connection handle and
check the currently used connection type with the Connection API:

#include <tizen.h>
#include <service_app.h>
#include "service.h" /* Auto-generated header file by Tizen Studio */
#include <net_connection.h>

static connection_h connection;

bool
service_app_create(void *data)
{
    int error_code;

    /* Create a connection handle */
    error_code = connection_create(&connection);
    if (error_code != CONNECTION_ERROR_NONE)
        return;

    /*
       Get the type of the current profile for data connection
       net_state is the network type defined in the connection_type_e enumerator
    */
    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);
    }

    return true;
}

void
service_app_terminate(void *data)
{
    /* Destroy the created connection handle */
    error_code = connection_destroy(connection);

    return;
}

/* Assume that auto-generated functions from Tizen Studio are here */

int
main(int argc, char* argv[])
{
    char ad[50] = {0,};
    service_app_lifecycle_callback_s event_callback;
    app_event_handler_h handlers[5] = {NULL,};

    event_callback.create = service_app_create;
    event_callback.terminate = service_app_terminate;
    event_callback.app_control = service_app_control;

    service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY,
                                  service_app_low_battery, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY,
                                  service_app_low_memory, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED,
                                  service_app_lang_changed, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED,
                                  service_app_region_changed, &ad);

    return service_app_main(argc, argv, &event_callback, ad);
}

Downloading HTTP Content

After a network connection is established, the application can download
HTTP content from the Internet. There are 2 ways to download HTTP
content:

  • With libcurl, which is an open
    source library.
  • With the
    Download
    API, which is one of Tizen framework APIs.

Required Privileges

To download HTTP content, the application must declare the required
privileges in the tizen-manifest.xml file. The files that the
application downloads from the Internet are stored in the device
storage. The privileges are required to access the resources for
downloading content and to save them to the media storage. For more
information on the Tizen privileges, see Security and API
Privileges
.

To perform the HTTP download operations, the application manifest must
include the following privileges:

<privileges>
   <privilege>http://tizen.org/privilege/download</privilege>
   <privilege>http://tizen.org/privilege/mediastorage</privilege>
</privileges>

Downloading HTTP Content with libcurl

The Curl API (in
mobile
and
wearable
applications) is a client-side URL transfer library supporting various
protocols, such as HTTP, HTTPS, FTP, and file URIs. It allows
applications to perform URL-related activities without having to involve
a Web browser.

The following example demonstrates how to perform an HTTP download with
libcurl:

#include <tizen.h>
#include <service_app.h>
#include "service.h" /* Auto-generated header file by Tizen Studio */
#include <curl/curl.h>

/*
   start_downloading() function utilizes the ecore_thread_feedback_run() function
   to allow the download_thread_run_cb() function to call the
   download_feedback_cb function
*/
static void
start_downloading(void *data)
{
    appdata_s *ad = data;
    Ecore_Thread *thread;

    /* Create a thread that communicates with the main thread */
    thread = ecore_thread_feedback_run(download_thread_run_cb, download_feedback_cb,
                                       download_thread_end_cb, download_thread_cancel_cb,
                                       ad, EINA_FALSE);
}

bool
service_app_create(void *data)
{
    start_downloading(data);

    return true;
}

/* Assume that auto-generated functions from Tizen Studio are here */

int
main(int argc, char* argv[])
{
    char ad[50] = {0,};
    service_app_lifecycle_callback_s event_callback;
    app_event_handler_h handlers[5] = {NULL,};

    event_callback.create = service_app_create;
    event_callback.terminate = service_app_terminate;
    event_callback.app_control = service_app_control;

    service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY,
                                  service_app_low_battery, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY,
                                  service_app_low_memory, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED,
                                  service_app_lang_changed, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED,
                                  service_app_region_changed, &ad);

    return service_app_main(argc, argv, &event_callback, ad);
}

The ecore_thread_feedback() function allows the
download_thread_run_cb() callback to call the download_feedback_cb()
callback:

static void
download_thread_run_cb(void *data, Ecore_Thread *thread)
{
    download_contents(data);

    /*
       ecore_thread_feedback() invokes download_feedback_cb()
       registered by ecore_thread_feedback_run()
    */
    ecore_thread_feedback(thread, data);
}

static void
download_contents(void *data)
{
    if (data == NULL) {
        dlog_print(DLOG_ERROR, LOG_TAG, "data is NULL");

        return;
    }

    appdata_s *ad = data;
    CURL *curl;

    const char error_message[BUFFER_SIZE];

    /* Initialize the curl session */
    curl = curl_easy_init();
    dlog_print(DLOG_DEBUG, LOG_TAG, "curl_easy_init()");

    /* Download the header */
    if (curl) {
        /* Set URL to get */
        CURLcode error_code = curl_easy_setopt(curl, CURLOPT_URL, "http://developer.tizen.org");

        /* Verify the SSL certificate */
        curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);

        /* Verify the host name in the SSL certificate */
        curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);

        /* Follow HTTP 3xx redirects */
        curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);

        /* Callback for writing data */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCb);

        /* Data pointer to pass to the write callback */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

        /* User-Agent: header */
        curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "TizenMaps/1.0");

        /* Provide a buffer for storing errors */
        curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errbuf);

        /* Timeout for the entire request */
        curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, TIZEN_CFG_CURL_TIMEOUT);

        /* Callback to progress meter function */
        curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, XferInfoCb);

        /* Switch off the progress meter */
        curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L);

        /* Perform a blocking file transfer */
        error_code = curl_easy_perform(curl);
        dlog_print(DLOG_DEBUG, LOG_TAG, "curl_easy_perform(curl): %s (%d)",
                   curl_easy_strerror(error_code), error_code);
        if (error_code == CURLE_ABORTED_BY_CALLBACK)
            /* Clean up and display cancel message */
        else if (error_code != CURLE_OK)
            /* Display failure message */

        curl_easy_cleanup(curl);
        dlog_print(DLOG_DEBUG, LOG_TAG, "curl_easy_cleanup(ad->curl)");
    } else {
        /* Display failure message */
    }
}

/*
   This function is called in the main thread whenever ecore_thread_feedback()
   is called in the download thread
*/
static void
download_feedback_cb(void *data, Ecore_Thread *thread, void *msg_data)
{
    /* TODO: Something that you want here */
    if (msg_data == NULL) {
        dlog_print(DLOG_ERROR, LOG_TAG, "msg_data is NULL");

        return;
    }
}

static void
download_thread_end_cb(void *data, Ecore_Thread *thread)
{
    dlog_print(DLOG_ERROR, LOG_TAG, "thread end!");
}

static void
download_thread_cancel_cb(void *data, Ecore_Thread *thread)
{
    dlog_print(DLOG_ERROR, LOG_TAG, "thread cancel!");
}

Downloading HTTP Content with the Download API

You can download content asynchronously from a given URL into the device
storage. The
Download
API provides functions to create and manage 1 or more download requests.

This feature is supported in mobile applications only.

The following figure illustrates the download states:

Figure: Download states

Download states

The Start step begins to download content. If the queue is empty,
the state is transited to downloading (DOWNLOAD_STATE_COMPLETED).
Otherwise, the request is queued. The application can pause, cancel, or
resume the download based on user interaction. Whenever the user makes a
request, the state of the download is transited accordingly to paused,
canceled, or downloading.

The following example demonstrates how to perform an HTTP download:

#include <tizen.h>
#include <service_app.h>
#include "service.h" /* Auto-generated header file by Tizen Studio */
#include <download.h>

download_error_e error;
int download_id;
/* Callback to be triggered by download_set_state_changed_cb() */
void
state_changed_cb(int download_id, download_state_e state, void *user_data)
{
    /* Download state is completed, failed, or canceled, destroy the handle */
    if (state >= DOWNLOAD_STATE_COMPLETED) {
        dlog_print(DLOG_INFO, LOG_TAG, "Download completed!");
        if (download_destroy(download_id) == DOWNLOAD_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "Successfully released the memory of a download request!");
        }
    }
}

/* Callback to be triggered by download_set_progress_cb() */
static void
progress_cb(int download_id, unsigned long long received, void *user_data)
{
    dlog_print(DLOG_INFO, LOG_TAG, "received: %llu of %llu", received, *((unsigned long long*)user_data));
}

/* Download the file with notification to default file name and location */
int
start_downloading()
{
    /* Create a download handle */
    error = download_create(&download_id);

    /* Set a callback to get the state */
    error = download_set_state_changed_cb(download_id, state_changed_cb, NULL);
    error = download_set_progress_cb(download_id, progress_cb, &content_size);

    /* Set the URL for downloading content */
    error = download_set_url(download_id, "http://developer.tizen.org");

    /*
       Set the destination path and file name
       If the values are not given,
       the default storage and an auto-generated file name are used
    */
    char *data_path = app_get_data_path();
    error = download_set_destination(download_id, data_path);
    free(data_path);
    error = download_set_file_name(download_id, "downloaded_file.bin");

    /*
       Set auto download
       If you set the second parameter to true, the download manager continues downloading
       even after the client process is terminated
    */
    error = download_set_auto_download(download_id, true);

    /* Start content download */
    error = download_start(download_id);

    return error;
}

int
end_downloading()
{
    /* Release callbacks */
    download_unset_progress_cb(download_id);
    download_unset_state_changed_cb(download_id);

    /* Destroy the download handle */
    error = download_destroy(download_id);

    return error;
}

bool
service_app_create(void *data)
{
    start_downloading(data);

    return true;
}

void
service_app_terminate(void *data)
{
    end_downloading();

    return;
}

/* Assume that auto-generated functions from Tizen Studio are here */

int
main(int argc, char* argv[])
{
    char ad[50] = {0,};
    service_app_lifecycle_callback_s event_callback;
    app_event_handler_h handlers[5] = {NULL,};

    event_callback.create = service_app_create;
    event_callback.terminate = service_app_terminate;
    event_callback.app_control = service_app_control;

    service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY,
                                  service_app_low_battery, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY,
                                  service_app_low_memory, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED,
                                  service_app_lang_changed, &ad);
    service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED,
                                  service_app_region_changed, &ad);

    return service_app_main(argc, argv, &event_callback, ad);
}

Parsing XML and JSON

The responses of many open APIs are composed of XML or JSON data. Tizen
provides the JSON-GLIB library
for parsing JSON and libxml2 for parsing XML.

Required Privileges

Applications that read and write to a device file system must declare
the required privileges in the tizen-manifest.xml file. For more
information on the Tizen privileges, see Security and API
Privileges
.

To perform the download operations and read and write to a file system,
the application manifest must include the following privileges:

<privileges>
   <privilege>http://tizen.org/privilege/filesystem.read</privilege>
   <privilege>http://tizen.org/privilege/filesystem.write</privilege>
</privileges>

Parsing JSON

JSON-GLib is a library
aimed at providing an API for efficient parsing and writing of JSON
(JavaScript Object Notation) streams, using GLib data types and API. As
Tizen supports JSON-GLIB natively, you do not need to manually download
this library and install it on your project.

The following example demonstrates how to parse a JSON file:

#include <json-glib/json-glib.h>

/* Called a moment after downloading */
static void
parse_downloaded(void *data)
{
    char *file_name = NULL;
    download_get_downloaded_file_path((int)data, &file_name);
    dlog_print(DLOG_DEBUG, LOG_TAG, "got file %s", file_name);

    /* Parse a file */
    call_parser(file_name);

    /* Remove the file when no longer used */
    remove(file_name);
}

static void
call_parser(char *file_name)
{
    int parse_reply = json_parse(file_name, ad_);
    if (parse_reply == -1) {
        elm_object_text_set(ad_->popup_label, "<align=center>This file is not in JSON format</align>");
    } else if (parse_reply == 1) {
        elm_object_text_set(ad_->popup_label, "<align=center>File parsed, however some nodes "
                            "weren't imported due to the limit of nesting level</align>");
    } else {
        elm_object_text_set(ad_->popup_label, "<align=center>File parsed</align>");
    }
}

/* Parse a given JSON file */
int
json_parse(char *file_name, void *data)
{
    appdata_s *ad = (appdata_s *)data;
    GError *error = NULL;
    JsonParser *parser = json_parser_new();

    /* Load a file to parse */
    json_parser_load_from_file(parser, file_name, &error);

    dlog_print(DLOG_DEBUG, LOG_TAG, "parsing %s", file_name);

    if (error) {
        dlog_print(DLOG_DEBUG, LOG_TAG, "parsing failed");
        g_object_unref(parser);
        g_error_free(error);

        return -1;
    }

    /* Iterate through root members */
    JsonNode *root = json_parser_get_root(parser);

    if (json_node_get_node_type(root) == JSON_NODE_NULL
        || json_node_get_node_type(root) == JSON_NODE_VALUE) {
        dlog_print(DLOG_DEBUG, LOG_TAG, "not supported root");
        g_object_unref(parser);

        return -1;
    }

    ad->parsing_in_progress = true;

    /* Show editor item */
    create_editor_view(data, NULL, NULL);

    switch (json_node_get_node_type(root)) {
    case JSON_NODE_OBJECT:
        ;
        JsonObject *object;
        object = json_node_get_object(root);
        json_object_foreach_member(object, object_member_cb, (gpointer)root_associated);
        break;
    case JSON_NODE_ARRAY:
        ;
        JsonArray *array;
        array = json_node_get_array(root);
        json_array_foreach_element(array, array_element_cb, (gpointer)root_associated);
        break;
    default:
        ;
    }

    root_associated->type = json_node_get_node_type(root);

    ad->parsing_in_progress = false;

    g_object_unref(parser);

    if (nodes_omitted)
        return 1;

    return 0;
}

Parsing XML

Libxml2 is the XML C parser and toolkit developed for the Gnome project
(but usable outside the Gnome platform). It is free software available
under the MIT License. XML itself is a metalanguage to design markup
languages: it is a text language where semantics and structure are added
to the content using extra markup information enclosed between angle
brackets. HTML is the most well-known markup language. Though the
library is written in C, a variety of language bindings make it
available in other environments.

Note
For more examples and tutorials, see libxml
Tutorial
.

The following example comes from the libxml Tutorial. It demonstrates
how to parse and validate an XML file to a tree and free the result:

/*
   section: Parsing
   synopsis: Parse and validate an XML file to a tree and free the result
   purpose: Create a parser context for an XML file, then parse and validate
            the file, creating a tree, check the validation result
            and xmlFreeDoc() to free the resulting tree
   usage: parse2 test2.xml
   test: parse2 test2.xml
   author: Daniel Veillard
   copy: see Copyright for the status of this software
*/

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

/*
   exampleFunc:
   @filename: a filename or an URL

   Parse and validate the resource and free the resulting tree
*/
static void
exampleFunc(const char *filename)
{
    xmlParserCtxtPtr ctxt; /* Parser context */
    xmlDocPtr doc; /* Resulting document tree */

    /* Create a parser context */
    ctxt = xmlNewParserCtxt();
    if (ctxt == NULL) {
        fprintf(stderr, "Failed to allocate parser context\n");

        return;
    }
    /* Parse the file, activating the DTD validation option */
    doc = xmlCtxtReadFile(ctxt, filename, NULL, XML_PARSE_DTDVALID);
    /* Check whether parsing succeeds */
    if (doc == NULL) {
        fprintf(stderr, "Failed to parse %s\n", filename);
    } else {
        /* Check whether validation succeeds */
        if (ctxt->valid == 0)
            fprintf(stderr, "Failed to validate %s\n", filename);
        /* Free up the resulting document */
        xmlFreeDoc(doc);
    }
    /* Free up the parser context */
    xmlFreeParserCtxt(ctxt);
}

int
main(int argc, char **argv)
{
    if (argc != 2)
        return(1);

    /*
       Initialize the library and check potential ABI mismatches
       between the version it was compiled for and the actual shared
       library used
    */
    LIBXML_TEST_VERSION

    exampleFunc(argv[1]);

    /* Cleanup function for the XML library */
    xmlCleanupParser();
    /* This is to debug memory for regression tests */
    xmlMemoryDump();

    return(0);
}