NoTA Core Overview

 


Introduction

This document specifies the operation of the NoTA High Interconnect (H_IN) and its interfaces. H_IN is a part of NoTA Interconnect stack. The Interconnect stack consists of H_IN and L_IN. The H_IN handles service registration, discovery, access and security. The L_IN is responsible for conencting the subsystems together.

 

Each subsystem has one H_IN and one L_IN. L_IN is divided to L_INup and L_INdown. One L_INdown is responsible for one network technology and there can be multiple L_INdowns. H_IN uses the L_IN with L_IF interface. The L_IN provides address resolution, H_IN to H_IN message transport and number of sockets that can be connected. The sockets are used to transfer data between nodes (ANs and SNs).

Components and H_IN related interfaces.

The nodes (ANs and SNs) use the H interface (H_IF) to use the H_IN. The H_IN interface can be different in different kind of subsystems. There is a reference H_IF that is the BSD Socket API, that can be used as such or slighly modified. The modified BSD Socket API prefixes each function with capital H and adds instance. For example connect(args) function call is modified to be Hconnect(h_in_t* h_in, args) function call. The arguments, return values and semantics are exactly same as in BSD Socket API. There is also an API extension that adds some functions to BSD Socket API. Usage of the API Extension is never compulsory.

 

The service repository in H_IN is centralized. One of the H_INs act as a HManager (old term H-level Resource Manager). The special node is responsible for having a list of the services in the network and acting as authorization authority. There is also a higher level Resource Manager (also called RMSN) that can be connected by other NoTA nodes with normal H_IN level connection. For implementing service connection authentication there is a special H_IN to RM interface. The usage of that interface is optional and as the interface is local, it can be also modified.

 

The H_INs communicate between each other with H_IN peer protocols. Those protocols are defined and conforming the H_IN peer protocols is mandatory. The peer protocols are the only mandatory part of the specification.

 

Socket Types

 

H_IN provides streaming type and message based sockets. The streaming type socket does not preserve message boundaries whereas the packet type socket preserves the boundaries. Otherwise there is no differences in sockets.

 

The services can have multiple ports when they register. Port 0 refers to standard port that typically accepts service requests. The SN may allocate other ports to whatever purposes. Any port can support either message based or streaming based sockets.

 

H_IN Interface (H_IF)

 

The H_IN Interface will be as default the BSD Socket Interface. There can be also other interfaces and the interface can be freely decided by subsystem vendor. The reference implementation will provide the standard H_IN interface. The BSD Socket Interface does not have all functionalities and therefore it need to be extended. Below is a list of extensions.

 

  • New address family AF_NOTA for socket() function
  • New address type (notaaddr_t) to contain Service Identifier and Port for connect() and bind() functions.
  • New socket option for setting certificate (setsockopt() and getsockopt())
  • New API call for checking incoming connection
  • New API call for ping

 

Data types and constants

 

New definitions, additions to BSD socket API, the BSD Socket API extension.

 

#define AF_NOTA 34
#define PF_NOTA 34
typedef unsigned int sid_t;
typedef unsigned int vdid_t;
struct _nota_addr_t {
  sid_t sid;         /* service identifier */
  unsigned int port; /* port of the sid */
  vdid_t device;     /* virtual device id */
};
typedef struct _nota_addr_t nota_addr_t;

 

Functions

 

The functions presented are the H variants, meaning that they are BSD socket API calls except that they have been prefixed with capital H and instance reference is added.

 


h_in_t* Hgetinstance()

Returns instance to H_IN.

Return value Description
non-NULL Successfull
NULL Error

 


int Hsocket(h_in_t* h_in, int domain, int type, int protocol)

Creates a new socket.

Parameter Description
h_in H_IN Instance
domain Domain of the socket. The AF_NOTA is the NoTA socket
type NoTA supports SOCK_STREAM & SOCK_SEQPACKET
protocol Protocol to use, use 0
Return value Description
>=0 Descriptor of socket that was created (success)
-1 Error, check errno

Available error codes: EINVAL, EAFNOSUPPORT, EMFILE, ENFILE, EPROTONOSUPPORT, EPROTOTYPE, EACCES, ENOMEM, ENOBUFS, ENONET

 


int Hbind(h_in_t* h_in, int sockfd, struct sockaddr* my_addr, socklen_t addrlen)


Binds a created socket for given SID and port.

Parameter Description
h_in H_IN Instance
my_addr Address to use in binding
addrlen Length of the address struct
Return value Description
0 Success
-1 Error (see errno)

Available error codes: EBADF, EINVAL, EACCES, ENOTSOCK

 


int Hlisten(h_in_t* h_in, int socket, int backlog)
Sets bound socket to listening mode for incoming connections.

Parameter Description
h_in H_IN Instance
socket Socket descriptor
backlog Number of connections to keep in the backlog for accepting
Return value Description
0 Success
-1 Error (see errno)

Available error codes: EBADF, EDESTADDRREQ, EINVAL, ENOTSOCK, EOPNOTSUPP, EACCESS, EFAULT, ENOBUFS

 


int Haccept(h_in_t* h_in, int socket, struct sockaddr* addr, socklen_t* addrlen)
Accepts an incoming connection.

Parameter Description
h_in H_IN Instance
addr Address of the remote. The function will fill up if not NULL
addrlen Length of target address struct. The function will fill up if not NULL

Return value Description
>=0 Success. Returns a socket descriptor.
-1 Error (see errno)

Available error codes: EAGAIN, EBADF, ENOTSOCK, EOPNOTSUPP, EINTR, ECONNABORTED, EINVAL, EMFILE, ENFILE, EFAULT, ENOBUFS, ENOMEM, EPROTO

 


int Hconnect(h_in_t* h_in, int socket, const struct sockaddr* address, socklen_t address_len)

Connects a socket to the given address.

Parameter Description
h_in H_IN Instance
address Target address
address_len Length of target address struct

Return value Description
0 Success
-1 Error (see errno)

Available error codes: EADDRNOTAVAIL, EAFNOSUPPORT, EALREADY, EBADF, ECONNREFUSED, EINPROGRESS, EINTR, EISCONN, ENETUNREACH, ENOTSOCK, EPROTOTYPE, ETIMEDOUT, EACCES, EADDRINUSE, ECONNRESET, EHOSTUNREACH, EINVAL, ENETDOWN, ENOBUFS, EOPNOTSUPP, EFAULT, EBUSY

 


ssize_t Hsend(h_in_t* h_in, int socket, const void* buffer, size_t length, int flags)
Sends data through socket. The send shall block until all data is sent unless MSG_DONTWAIT flag has been set.

The function sendmsg behaves same way.

Parameter Description
h_in H_IN Instance
buffer The send buffer to be sent
length Length of the data to be sent
flags Send flags

Return value Description
0>= Success, returns number of bytes sent
-1 Error (see errno)

Available error codes: EAGAIN, EBADF, ECONNRESET, EDESTADDRREQ, ENOTCONN, ENOTSOCK, EOPNOTSUPP, EACCESS, ENETDOWN, ENETUNREACH, ENOBUFS

 


ssize_t Hrecv(h_in_t* h_in, int socket, void* buffer, size_t length, int flags)
Receives data from the socket. The recv shall block until some data is received unless MSG_DONTWAIT has been set. If the MSG_DONTWAIT has been set and the socket is stream based, the function will return some data if there is any data to be received. If the socket is message based, the function will return with contents of a message if there is any available. If the socket is message based, the function will discard the remaining data of the message that does not fit into the buffer. The MSG_PEEK option can be used to check the message size.

The function recvmsg behaves same way.

Parameter Description
h_in H_IN Instance
buffer The receive buffer
length Length of the receive buffer
flags Receive flags (flags can be OR'd)

Flag name Description
MSG_WAITALL Blocks untill whole buffer is filled up
MSG_PEEK Peeks on the received data. Same data will be returned again. In case of message based socket the return value will be the size of the message (can be higher than buffer length).

Return value Description
>=0 Success, number of bytes received to the buffer
-1 Error (see errno)

Available error codes: EAGAIN, EBADF, ECONNRESET, EINTR, EINVAL, ENOTCONN, ENOTSOCK, EOPNOTSUPP, ETIMEDOUT, ENOBUFS, ENOMEM

 


int Hselect(h_in_t* h_in, int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, const struct timespec* timeout)

Monitors a given set of sockets for state changes. The sockets can be monitored when there is a data available for reading, when data can be sent and when socket state becomes to an error state. The socket sets should be manipulated with macros. The same function is used to implement Hpselect and Hpoll.

Parameter Description
h_in H_IN Instance
nfds Highest socket descriptor number
readfds Sockets to be monitored for reading
writefds Sockets to be monitored for writing
errorfds Sockets to be monitored for errors
timeout Timeout value

Macro Description
FD_ZERO(fd_set* fdset) Initialize fd_set
FD_CLR(int fd, fd_set* fdset) Clear socket active flag
FD_ISSET(int fd, fd_set* fdset) Check whether socket is active
FD_SET(int fd, fd_set* fdset) Mark socket active

Return value Description
>=0 Success, number of sockets active (0 means timeouted)
-1 Error (see errno)

Available error codes: EBADF, EINTR, EINVAL

 


int Hclose(h_in_t* h_in, int socket)

Close a socket connection.

Parameter Description
h_in H_IN Instance
socket Socket descriptor

Return value Description
0 Success
-1 Error (see errno)

Available error codes: EBADF, EINTR, EINVAL, EFAULT, ENOTSOCK, EBUSY

 


int Hsetsockopt(h_in_t* h_in, int socket, int level, int option_name, const void* option_value, socklen_t option_len)

Sets socket option.

Parameter Description
h_in H_IN Instance
socket Which socket to modify
level Which level option to set (SOL_SOCKET)
option_name Which option to set
option_value New value of the option
option_len Length of the value

Socket option Parameter type
SO_PASSCRED bytearray

Return value Description
0 Success
-1 Error (see errno)

Available error codes: EBADF, EDOM, EINVAL, EISCONN, ENOPROTOOPT, ENOTSOCK, ENOMEM, ENOBUFS, EFAULT

 


int Hgetsockopt(h_in_t* h_in, int socket, int level, int option_name, void* option_value, socklen_t* option_len)

Gets socket option.

Parameter Description
h_in H_IN Instance
socket Which socket
option_name Name of the option (see SO_*)
option_value Pointer to memory where value will be saved
option_len Pointer to a variable that shows the memory length. Will be updated to match the real length

Return value Description
0 Success
-1 Error (see errno)

Available error codes: EBADF, EINVAL, ENOPROTOOPT, ENOTSOCK, EACCES, EINVAL, ENOBUFS

 

Code examples

 

Service activation

 

#define SID 1
int sock, err;
nota_addr_t addr = { SID, DEFAULT_PORT };
sock = Hsocket(AF_NOTA, SOCK_STREAM, 0); /* create a socket */
if(sock < 0)
return ERROR;
/* the certificate is optional */
err = Hsetsockopt(sock, SOL_SOCKET, SO_PASSCRED, ptr_to_certificate, certificate_length); 
if(err != 0) {
Hclose(sock);
return ERROR;
}
err = Hbind(sock, &addr, sizeof(addr)); /* bind to service id 1 */
if(err != 0) {
Hclose(sock);
return ERROR;
}
err = Hlisten(sock, 1); /* start listening with backlog = 1 */
if(err != 0) {
Hclose(sock);
return ERROR;
}
return sock;

 

Connecting to a service

 

#define SID 1
int sock, err;
nota_addr_t addr = { SID, DEFAULT_PORT };
sock = Hsocket(AF_NOTA, SOCK_STREAM, 0); /* create a socket */
if(sock < 0)
return ERROR;
/* the certificate is optional */
err = Hsetsockopt(sock, SOL_SOCKET, SO_PASSCRED, ptr_to_certificate, certificate_length); 
if(err != 0) {
Hclose(sock);
return ERROR;
}
err = Hconnect(sock, &addr, sizeof(addr)); /* connect to a service */
if(err != 0) {
Hclose(sock);
return ERROR;
}
return sock;

 

Sending & receiving data

 

int fd;
int err;
char data[4] = "abcd";
char buffer[4];
/* connect to a service first */
fd = connect_to_a_service();
if(fd < 0)
return ERROR;
/* send the data */
err = Hsend(fd, data, 4, 0);
if(err != 4) {
Hclose(fd);
return ERROR;
}
/* receive some data */
err = Hrecv(fd, buffer, 4, MSG_WAITALL);
if (err != 4) {
Hclose(fd);
return ERROR;
}
/* done */
Hclose(fd);

 

Accepting incoming connection

 

int serverfd, new_connection;
/* the connection can be accepted after a service is activated */
serverfd = activate_service();
if(new_connection < 0)
return ERROR;
/* the accept call blocks, normally the peer information is not usefull */
new_connection = Haccept(serverfd, NULL, NULL);
if(new_connection < 0) {
Hclose(serverfd);
return ERROR;
}
/* now we can send / receive data */
err = Hsend(new_connection, "abcd", 4, 0);
if(err != 4) {
Hclose(serverfd);
return ERROR;
}

 

Monitoring sockets

 

/* Sockets can be monitored with select function call
* In this example we are monitoring one socket for incoming
* connections and one when there is a data or when data can
* be sent and all for error conditions.
*/
int serverfd, connection, maxfd;
struct timeval tv, err;
fd_set readlist, writelist, errorlist;
/* Connect to a service */
connection = connect_to_a_service();
/* Activate a service */
serverfd = activate_service();
/* set timeout to 10 sec */
tv.m_sec = 10;
tv.m_usec = 0;
maxfd = serverfd > connection ? serverfd : connection;
while(serverfd >= 0 || connection >= 0) {
/* zero current lists */
FD_ZERO(&readlist);
FD_ZERO(&writelist);
FD_ZERO(&errorlist);
/* set sockets to be monitored */
if(connection >= 0) { 
FD_SET(connection, &readlist); 
FD_SET(connection, &writelist); 
FD_SET(connection, &errorlist); 
}
if(serverfd >= 0) {
FD_SET(connection, &readlist); }
/* do the select */
err = Hselect(maxfd, &readlist, &writelist, &errorlist, &tv);
if(err == -1) 
break; /* error */
else if(err == 0)
continue; /* timeout */
if(FD_ISSET(serverfd, &readlist))
accept_new_connection(serverfd);
if(FD_ISSET(connection, &readlist))
read_data(connection);
if(FD_ISSET(connection, &writelist))
send_data(connection);
if(FD_ISSET(connection, &errorlist))
close_connection(connection);
}
    
Bookmark and Share