TCP/IP Stack System Description

Software Architecture

The following Figure shows the architecture of the TCP/IP stack when attaching to an independent Ethernet stack through XC channel:

XTCP software architecture
_images/xtcp_arch-crop.png

The server runs in a single thread and connects to the XMOS Ethernet MAC component (see [XEth10]). It can then connect to several client threads over XC channels.

Alternatively, the TCP/IP server and Ethernet server can be run as an integrated system of two threads. To enable this, the header file uip_single_server.h should be included, and the function uipSingleServer() used in place of the uip_server() and ethernet_server function from the ethernet repository. In addition, the module_mii_singlethread should be used instead of module_ethernet and module_locks in the Makefile. Finally, define the constant UIP_USE_SINGLE_THREADED_ETHERNET in your application’s xtcp_client_config.h file.

IP Configuration

The server will determine its IP configuration based on the arguments passed into the uip_server() or uipSingleServer() function. If an address is supplied then that address will be used (a static IP address configuration).

If no address is supplied then the server will first try to find a DHCP server on the network to obtain an address automatically. If it cannot obtain an address from DHCP, it will determine a link local address (in the range 169.254/16) automatically using the Zeroconf IPV4LL protocol.

To use dynamic address, the uip_server() can be passed a null to the ip configuration parameter. The uipSingleServer() must be passed a structure with 0 for all fields of the addresses.

Events and Connections

The TCP/IP stack client interface is a low-level event based interface. This is to allow applications to manage buffering and connection management in the most efficient way possible for the application.

Example event sequence
_images/events-crop.png

Each client will receive events from the server. These events usually have an associated connection. In addition to receiving these events the client can send commands to the server to initiate new connections and so on.

Figure 2 shows an example event/command sequence of a client making a connection, sending some data, receiving some data and then closing the connection. Note that sending and receiving may be split into several events/commands since the server itself performs no buffering.

If the client is handling multiple connections then the server may interleave events for each connection so the client has to hold a persistent state for each connection.

The connection and event model is the same from both TCP connections and UDP connections. Full details of both the possible events and possible commands can be found in Section API.

TCP and UDP

The XTCP API treats UDP and TCP connections in the same way. The only difference is when the protocol is specified on initializing connections with xtcp_connect() or xtcp_listen().

New Connections

New connections are made in two different ways. Either the xtcp_connect() function is used to initiate a connection with a remote host as a client or the xtcp_listen() function is used to listen on a port for other hosts to connect to the application . In either case once a connection is established then the XTCP_NEW_CONNECTION event is triggered.

In the Berkley sockets API, a listening UDP connection merely reports data received on the socket, indepedent of the source IP address. In XTCP, a XTCP_NEW_CONNECTION event is sent each time data arrives from a new source. The API function xtcp_close() should be called after the connection is no longer needed.

Receiving Data

When data is received by a connection, the XTCP_RECV_DATA event is triggered and communicated to the client. At this point the client must call the xtcp_recv() function to receive the data.

Data is sent from host to client as the UDP or TCP packets come in. There is no buffering in the server so it will wait for the client to handle the event before processing new incoming packets.

As an alternative to the low level interface, a higher level buffered interface is available. See section Buffered API.

Sending Data

When sending data, the client is responsible for dividing the data into chunks for the server and re-transmitting the previous chunk if a transmission error occurs.

Note that re-transmission may be needed on both TCP and UDP connections. On UDP connections, the transmission may fail if the server has not yet established a connection between the destination IP address and layer 2 MAC address.

The client can initiate a send transaction with the xtcp_init_send() function. At this point no sending has been done but the server is notified of a wish to send. The client must then wait for a XTCP_REQUEST_DATA event at which point it must respond with a call to xtcp_send().

After this data is sent to the server, two things can happen: Either the server will respond with an XTCP_SENT_DATA event, in which case the next chunk of data can be sent or with an XTCP_RESEND_DATA event in which case the client must re-transmit the previous chunk of data.

The command/event exchange continues until the client calls the xtcp_complete_send() function to finish the send transaction. After this the server will not trigger any more XTCP_SENT_DATA events.

As well as events related to connections. The server may also send link status events to the client. The events XTCP_IFUP and XTCP_IFDOWN indicate to a client when the link goes up or down.

Configuration

The server is configured via arguments passed to the uip_server() function and the defines described in Section Configuration Defines.

Client connections are configured via the client API described in Section Configuration Defines.

Buffered API

As an alternative to the low level interface, a buffered interface is available as a utility layer.

To set up the buffered interface, the application must receive or make a new connection. As part of the new connection processing a buffer must be associated with it, by calling xtcp_buffered_set_rx_buffer() and xtcp_buffered_set_tx_buffer().

When sending using the buffered interface, a call to xtcp_buffered_send() is all that is required. When processing the XTCP_SENT_DATA, XTCP_REQUEST_DATA and XTCP_RESEND_DATA, the function xtcp_buffered_send_handler() should be called.

When processing a XTCP_RECV_DATA event, either the function xtcp_buffered_recv() or xtcp_buffered_recv_upto() can be called. These either return the data requested, or zero. If some data is returned, indicated by a non-zero return value, then the application should process the data, and call the receive function again. Only when the function returns zero can the application stop trying to receive and process the data.

Two example applications are provided. app_buffered_protocol_demo shows the use of the buffered API used with fixed length packets, and app_buffered_protocol_demo_2 shows the use of the delimited token mechanism.