The main data transmission protocol used in embeNET is UDP. Most application level communication is done using this protocol. In order to transmit and receive UDP data, the Nodes as well as the Border Router are expected to register UDP sockets, through which the communication will be carried. A socket is a logical endpoint in the networked device, that allows to easily dispatch network traffic to various services running in the device. We may think of the socket as a filter that selects only particular network traffic and feeds it into a software component (service) that owns the socket. Typically various services running in the node will use different ports and thus will register their own sockets. Such sockets will be used for transmitting and receiving data. In embeNET each socket is associated with a port number and may have three types of behavior concerning the way the receiving (destination) device is addressed.
In order to understand types of sockets in embeNET we first need to understand the IPv6 addressing principles employed in embeNET. There are basically two types of network traffic supported:
Apart from that, the traffic is directed to a given port number in the destination device. Thus the destination IPv6 address (unicast or multicast) and destination port identify the actual data recipient.
In embeNET we can register sockets that:
This type of socket behavior is defined during socket registration (see EMBENET_UDP_RegisterSocket). There is no way to change that behavior other than unregister the given socket and register another one.
Let's assume that we have a network with the network prefix set to 2001:0db8:0000:0000. Within that network there is a node with UID = 0000:0000:1234:5678 This node belongs to two groups number 12 and 15
In order to address this node using unicast addressing we should use an address constructed in the following way:
In order to address this node as a member of the group number 12 we should use an address constructed in the following way:
Let's register three sockets in this node - all of them on the same port number = 2222, so that:
So now:
Now let's explore some corner cases:
Before using a socket we must register it through a call to EMBENET_UDP_RegisterSocket. This call takes a pointer to a EMBENET_UDP_SocketDescriptor structure that describes the socket. The following example shows how to register a socket that accepts all types of traffic.
In the above example the socket is created with a data reception function called 'receptionHandler'. This function may look like this:
This function will be called every time a UDP packet through a given socket.
In order to send some data through a registered socket a call to EMBENET_UDP_Send has to be made. The following example illustrates the data sending mechanism by sending 5 bytes ('Hello') through a registered socket to a destination port 2000 in the destination node described by an IPv6 address.
The EMBENET_UDP_Send schedules a single UDP datagram to be sent. This call does not provide any fragmentation capabilities. The maximum amount of data that can be sent by a single call to EMBENET_UDP_Send can be determined using EMBENET_UDP_GetMaxDataSize function:
Once the socket is not needed anymore it can be unregistered by a call to EMBENET_UDP_UnregisterSocket. The following code illustrates this idea:
Each socket can be assigned with a user defined pointer called userContext. This variable can point to any user-defined data to you want to bind with the socket. The intended use case is to pass a user context to the data reception handler. Below is an example. Let's assume that we want the reception handler to store the received value in a buffer, that will be set during socket registration:
We can register the socket with a user context pointing to that buffer
Now, when the receptionHandler is called, we can retrieve the buffer and use it: