Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changes between Initial Version and Version 1 of NetworkAPITutorial


Ignore:
Timestamp:
2016-03-11T16:10:43Z (7 years ago)
Author:
Jiri Svoboda
Comment:

Start tutorial on networking API

Legend:

Unmodified
Added
Removed
Modified
  • NetworkAPITutorial

    v1 v1  
     1= HelenOS Network Transport API tutorial =
     2
     3This tutorial is a set of step by step guide to creating a simple network application in HelenOS that communicates over TCP or UDP.
     4
     5== Introduction ==
     6
     7HelenOS network stack was designed and written from scratch. Its APIs do not mimic any existing preexisting interfaces (such as BSD sockets). This allows us the freedom to design more sleek and modern APIs compared to just sticking with the legacy APIs.
     8
     9This means the programmer needs to learn new APIs. However the learning curve is not steep and somebody who knows BSD sockets should be able to learn them quickly. In synchronous modes the mapping from one API to another is not too complicated.
     10
     11== TCP client ==
     12
     13Here we describe how to create an application that connects to a remote server via TCP.
     14
     15We'll need to include the following headers:
     16
     17{{{
     18#include <inet/endpoint.h>
     19#include <inet/hostport.h>
     20#include <inet/tcp.h>
     21}}}
     22
     23Suppose we want the user to specify the host name (or address) and port to connect to. The user will supply it as a host:port string in the 'hostport' variable.
     24
     25We need to declare and initialize an endpoint pair - a data type which can hold both a remote and local endpoint (address:port pair).
     26
     27{{{
     28inet_ep2_t epp;
     29inet_ep2_init(&epp);
     30}}}
     31
     32After calling inet_ep2_init() the endpoint is fully unspecified. Now we'll parse the hostport string and save the result to the 'remote' endpoint. Thus we'll have specified to which host and port we want to connect to:
     33
     34{{{
     35char *errmsg;
     36rc = inet_hostport_plookup_one(hostport, ip_any, &epp.remote, NULL, &errmsg);
     37if (rc = EOK) {
     38        printf("Error: %s (host:port %s).\n", errmsg, hostport);
     39        goto error;
     40}}}
     41
     42Note that the 'hostport' string can contain either a host name or a literal IP address. Here are some examples of valid host:port strings:
     43
     44 * {{{example.com:1234}}} (with a host name)
     45 * {{{192.0.2.3:1234}}} (with an IPv4 address literal)
     46 * {{{[2001:db8::23]:1234}}} (with a literal IPv6 address)
     47
     48The argument ip_any means that we're willing to work with any IP protocol version (and the system should select an appropriate one).
     49
     50We need to create an object representing the TCP service.
     51
     52{{{
     53tcp_t *tcp;
     54rc = tcp_create(&tcp);
     55if (rc != EOK)
     56        goto error;
     57}}}
     58
     59We can now initiate the connection:
     60
     61{{{
     62tcp_conn_t *conn;
     63rc = tcp_conn_create(tcp, &epp, &conn_cb, NULL, &conn);
     64if (rc != EOK)
     65        goto error;
     66}}}
     67
     68Here {{{&epp}}} is the endpoint pair which specifies the local and remote endpoints. Note that if a local address is not provided, it is automatically selected. If a local port is not provided, it is allocated from the set of ephemeral ports.
     69
     70{{{&conn_cb}}} is a pointer to the structure of type {{{tcp_cb_t}}} containing callbacks to be used with the connection. {{{NULL}}} is a user argument that can be used by the user's callback functions. The callback structure is defined as:
     71
     72{{{
     73/** TCP connection callbacks */
     74typedef struct tcp_cb {
     75        void (*connected)(tcp_conn_t *);
     76        void (*conn_failed)(tcp_conn_t *);
     77        void (*conn_reset)(tcp_conn_t *);
     78        void (*data_avail)(tcp_conn_t *);
     79        void (*urg_data)(tcp_conn_t *);
     80} tcp_cb_t;
     81}}}
     82
     83All the callbacks are optional, i.e. the user only needs to specify handlers for the events he is interested in.
     84
     85The function {{{tcp_conn_create()}}} returns immediately and does not wait for the connection to be established. If we want to block until the connection is established, we can call:
     86
     87{{{
     88rc = tcp_conn_wait_connected(conn);
     89if (rc != EOK)
     90        goto error;
     91}}}
     92
     93Alternatively, we can use callbacks to determine connection progress.
     94 * {{{void (*connected)(tcp_conn_t *)}}} when connection was established
     95 * {{{void (*conn_failed)(tcp_conn_t *)}}} when the attempt to connect is given up
     96
     97To send data we can simply use:
     98
     99{{{
     100int rc = tcp_conn_send(conn, data, size);
     101}}}
     102
     103
     104note that the function may block until space is available in the connection's outbound buffer. If we don't want to send data anymore, we can close the outbound half of the connection with:
     105
     106{{{
     107rc = tcp_conn_send_fin(conn);
     108}}}
     109
     110Note that we can still continue to receive data on the connection after that.
     111
     112To receive data:
     113
     114{{{
     115rc = tcp_conn_recv(conn, recv_buf, RECV_BUF_SIZE, &nrecv);
     116}}}
     117
     118The function {{{tcp_conn_recv()}}} blocks until some data is available. On success it returns {{{EOK}}} and places the number of received bytes in {{{nrecv}}}.
     119
     120To receive data in an asynchronous manner, we can register for the callback
     121 * {{{void (*data_avail)(tcp_conn_t *)}}}
     122
     123This callback is invoked when new data is received on the connection. The user's callback handler should then pick up all available data.
     124
     125Here's an example how the callback handler might look like:
     126
     127{{{
     128static void example_data_avail(tcp_conn_t *conn)
     129{
     130        int rc;
     131        size_t nrecv;
     132       
     133        while (true) {
     134                rc = tcp_conn_recv(conn, recv_buf, RECV_BUF_SIZE, &nrecv);
     135                if (rc != EOK) {
     136                        printf("Receive error %d\n", rc);
     137                        break;
     138                }
     139       
     140                example_data_received(recv_buf, nrecv);
     141
     142                if (nrecv != RECV_BUF_SIZE)
     143                        break;
     144        }
     145}
     146}}}
     147
     148Another callback that can be registered is
     149 * {{{void (*conn_reset)(tcp_conn_t *)}}}
     150which informs us that the connection was reset by the peer. No more data can be sent or received afterwards and the only option is to destroy the connection.
     151
     152When we are done with a connection we want to destroy it. When we are done with all TCP communications we want to destroy the TCP service object.
     153
     154{{{
     155tcp_conn_destroy(conn);
     156tcp_destroy(tcp);
     157}}}
     158
     159
     160= TCP server =
     161
     162TODO
     163
     164= UDP client =
     165
     166TODO
     167
     168= UDP server =
     169
     170TODO