IPN examples
This page contains some quick notes on how to use IPN sockets. (all the examples require
#include <net/af_ipn>
Contents |
Communication among peers
Each process execute the same code to join the network:
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); /* or a different protocol */ err=bind(s,(struct sockaddr *)&sun,sizeof(sun)); err=connect(s,NULL,0);
Note: here and throughout all the examples of this page, the error management has been skipped for the sake of clearness. In the code here above the values s and err when negative should activate error management actions.
Using IPN_BROADCAST each process receives all the messages sent by the others. The socket is closed by close. When the last process leaves the network, the network itself is terminated (the socket in the file system must be removed using unlink).
Broadcast IPN, one sender, many receivers
The sender runs the following code:
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); /* or a different protocol */ err=shutdown(s,SHUT_RD); err=bind(s,(struct sockaddr *)&sun,sizeof(sun)); err=connect(s,NULL,0);
The receivers do not need to manage the network, thus they skip the bind and execute:
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); /* or a different protocol */ err=shutdown(s,SHUT_WR); err=connect(s,(struct sockaddr *)&sun,sizeof(sun));
For a protected service it is possible to create a user or a group and apply appropriate access mode.
if the sender add this statement (e.g. just after the SHUT_RD shutdown):
int mode=0744; err=setsockopt(s,0,IPN_SO_MODE,&mode,sizeof(mode));
the receivers belonging to other users cannot send anything to the IPN network. The shutdown statement for those receivers is useless and can be deleted. (the actual access mode takes into account umask in the usual way, all the bits set in the mask will be cleared in the access mode).
Lossless service
To create a lossless service add these statements before bind:
int flags=IPN_FLAG_LOSSLESS; int size=64; /* standard size is 8, it is too small for LOSSLESS */ err=setsockopt(s,0,IPN_SO_FLAGS,&flags,sizeof(flags)); err=setsockopt(s,0,IPN_SO_MSGPOOLSIZE,&size,sizeof(size));
The value of IPN_SO_MSGPOOLSIZE must be increased. While for LOSSY service it is the number of pending message per node, for LOSSLESS service this is the overall number of pending messages in the network.
IPN network connected to a TAP interface
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); struct ifreq ifr; err=bind(s,(struct sockaddr *)&sun,sizeof(sun)); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "test", IFNAMSIZ); ifr.ifr_flags=IPN_NODEFLAG_TAP; err=ioctl(s, IPN_CONN_NETDEV, (void *) &ifr);
Using IPN_BROADCAST all the packets sent on the IPN networks will appear as incoming packets on the TAP interface and viceversa: all the packets sent by the TAP interface will be received by all the nodes connected to the IPN network.
IPN network connected to a GRAB interface
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); struct ifreq ifr; err=bind(s,(struct sockaddr *)&sun,sizeof(sun)); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "eth1", IFNAMSIZ); ifr.ifr_flags=IPN_NODEFLAG_GRAB; err=ioctl(s, IPN_CONN_NETDEV, (void *) &ifr);
The code is very similar to the one used for the TAP interface. In this case the interface must already exist. All the packets received by the interface (in this case from the real ethernet eth1) will be sent over the IPN network, and all the packets sent on the GRABBED port by the IPN network will be sent also an the real ethernet. In this way it is possible to extend an Ethernet with an IPN network.
OOB notification of the number of senders/receivers
struct sockaddr_un sun={.sun_family=AF_IPN,.sun_path="/tmp/sockipn"}; int s=socket(AF_IPN,SOCK_RAW,IPN_BROADCAST); int want=1; int nreaders; struct pollfd pfd[...]={{0,POLLPRI,0},...}; err=setsockopt(s,0,IPN_SO_HANDLE_OOB,&want,sizeof(want)); err=setsockopt(s,0,IPN_SO_WANT_OOB_NUMNODES,&want,sizeof(want)); err=shutdown(s,SHUT_RD); err=connect(s,(struct sockaddr *)&sun,sizeof(sun)); pfd[0].fd=s; while (poll(pfd,...,...) >= 0) { if (pfd[0].revents & POLLPRI) { struct numnode_oob *nn = (struct numnode_oob *) buf; len=read(s,buf,256); nreaders= nn->numreaders; } /* the code here can decide different behavior depending on nreaders. maybe the program stops sending data on the ipn net when there are no receivers */ }
IPN sends notifications from protocols as OOB messages. OOB messages are delivered first (preempting all waiting normal messages) together with normal messages, if necessary they can be recognized using recvmsg system call: MSG_OOB is set on msg_flags. The example above is a sender (maybe a broadcasting daemon) stopping to send data when no receivers are registered on the network, and resuming its service as soon as a new receiver join the net.