Documentation for libsocket

Introduction/Explanations

libsocket is a library written in C for the purpose of simplifying the usage of AF_INET/AF_INET6 (internet domain) and AF_UNIX (unix domain) sockets. With many specialized functions in the API, it's hard to do things really wrong. And with the excellent error processing with optional verbosity on stderr, it's also quite easy to debug your applications.

libsocket is targeted at advanced/experienced/professional C-on-Linux programmers which don't like the traditional BSD sockets API. libsocket is not targeted at programmers which do their first experiences with C or sockets! To understand the library, you SHALL have experience with the underlying syscalls.

libsocket is the name for the whole project. libinetsocket is the part for INET/INET6 sockets, libunixsocket for UNIX sockets.

If you want to see some examples using the library, take a look at the example programs in examples/. Compile them either together with the C source files in C/inet and C/unix or link them against an already installed copy with -lsocket (or -lsocket_hl on SunOS).

Note: The manpage extracts are from the manpages delivered with Debian (Linux manpages), usually created by the man-pages project. The OpenBSD manpage extracts are taken from the OpenBSD website

Compile time configuration

If the macro VERBOSE is defined, libsocket prints verbose error messages on STDERR device. The error messages come from functions like strerror or gai_strerror. This is VERY useful when there are problems in your program or the library itself. Typically, you specify it in the CMakeLists file:

ADD_DEFINITIONS(-DVERBOSE)

Another compile-time option is _TRADITIONAL_RDNS. It specifies if the library should use getnameinfo() or gethostbyaddr() for reverse DNS queries. The latter possibility may be needed on FreeBSD or other systems were getnameinfo is not an option.

Usage of flags

The usage of the flags for some functions is described for every function. If you don't need any flags, you may specify 0 for every flag argument.

Errors and return values

If you don't enable the VERBOSE macro, the library knows another way to notify you if there was an error; if anything went wrong, the return value will be -1. Every function behaves this way, so it's strongly recommended to check the return values of the API functions. To obtain more information about what exactly caused an error, check errno; the man pages of the underlying syscalls (described in this document) contain information about possible errno values.

libinetsocket

As the name says, libinetsocket is the part for internet domain sockets. All important features are supported and it's possible to give flags to the system calls, e.g. it's possible to give the flag MSG_DONTROUTE to the wrapper function of sendto().

libinetsocket is adapted for multi-platform usage. It's mainly tested on Linux and FreeBSD, but the client functions work also on SunOS (OpenIndiana).

libunixsocket

libunixsocket is responsible for UNIX domain sockets. The calls are similar to the libinetsocket calls.

libunixsocket works on Linux, but as well on FreeBSD and SunOS.

Usage in your application

Dynamic

Build and install the library following the instructions in README.md and link your application against it using the documentation in LINKAGE.

Static

Static linking is not recommended. That means, copy a checkout of the library files (C/, headers/) to the source tree of your application. Then, simply compile the files together with the other files (as if they were just a part of your application).

Details about dependancies: The actual code is in libinetsocket.c resp. libunixsocket.c. Every file of your application that wants to use these functions has to include the header files, e.g.:

API calls

libinetsocket

create_inet_stream_socket()

int create_inet_stream_socket(const char* host, const char* service, char proto_osi3, int flags)

This function creates, connects and returns a inet stream socket (TCP socket) which is connected to host:service.

Returns the socket file descriptor number, on error -1.

SOCK_NONBLOCK does not let you wait when read()ing or write()ing; instead of blocking (if there's nothing available) read()/write() return -1.

SOCK_CLOEXEC closes the socket if you call a syscall from the exec() family (to execute another program).

The underlying protocol will be TCP.

For sending and receiving data, use read()/write() or send()/recv().

create_inet_dgram_socket()

int create_inet_dgram_socket(char proto_osi3, int flags)

Returns an integer describing a DGRAM (UDP) socket.

Returns the socket file descriptor number, on error -1.

The protocol used for communication is UDP.

To send and receive data on this socket, you may use the functions explained below, sendto_inet_dgram_socket() and recvfrom_inet_dgram_socket().

sendto_inet_dgram_socket()

ssize_t sendto_inet_dgram_socket(int sfd, void* buf, size_t size, char* host, char* service, int sendto_flags)

It returns the number of bytes sent; this number may be lower than size.

Returns the number of bytes sent, on error -1.

Linux specifies the following flags:

   "The flags argument is the bitwise OR of zero or more of the following flags.

   MSG_CONFIRM (Since Linux 2.3.15)
          Tell the link layer that forward progress happened: you got a successful reply from  the  other  side.   If  the  link  layer
          doesn't  get  this  it  will regularly reprobe the neighbor (e.g., via a unicast ARP).  Only valid on SOCK_DGRAM and SOCK_RAW
          sockets and currently only implemented for IPv4 and IPv6.  See arp(7) for details.

   MSG_DONTROUTE
          Don't use a gateway to send out the packet, only send to hosts on directly connected networks.  This is usually used only  by
          diagnostic or routing programs.  This is only defined for protocol families that route; packet sockets don't.

   MSG_DONTWAIT (since Linux 2.2)
          Enables  nonblocking  operation;  if  the  operation would block, EAGAIN or EWOULDBLOCK is returned (this can also be enabled
          using the O_NONBLOCK flag with the F_SETFL fcntl(2)).

   MSG_EOR (since Linux 2.2)
          Terminates a record (when this notion is supported, as for sockets of type SOCK_SEQPACKET).

   MSG_MORE (Since Linux 2.4.4)
          The caller has more data to send.  This flag is used with TCP sockets to obtain the same effect as the TCP_CORK socket option
          (see tcp(7)), with the difference that this flag can be set on a per-call basis.

          Since Linux 2.6, this flag is also supported for UDP sockets, and informs the kernel to package all of the data sent in calls
          with this flag set into a single datagram which is only transmitted when a call is performed that does not specify this flag.
          (See also the UDP_CORK socket option described in udp(7).)

   MSG_NOSIGNAL (since Linux 2.2)
          Requests  not to send SIGPIPE on errors on stream oriented sockets when the other end breaks the connection.  The EPIPE error
          is still returned.

   MSG_OOB
          Sends out-of-band data on sockets that support this notion (e.g., of type SOCK_STREAM); the  underlying  protocol  must  also
          support out-of-band data."

FreeBSD has this flags available (sendto(2)):

The flags argument may include one or more of the following:

 #define MSG_OOB         0x00001 /* process out-of-band data */
 #define MSG_DONTROUTE   0x00004 /* bypass routing, use direct interface */
 #define MSG_EOR         0x00008 /* data completes record */
 #define MSG_EOF         0x00100 /* data completes transaction */
 #define MSG_NOSIGNAL    0x20000 /* do not generate SIGPIPE on EOF */

If it is not possible to send data at the moment, this call blocks excepted you specified SOCK_NONBLOCK when creating the socket. In this case the function will return -1; errno will be set to EAGAIN or EWOULDBLOCK.

recvfrom_inet_dgram_socket()

ssize_t recvfrom_inet_dgram_socket(int sfd, void* buffer, size_t size, char* src_host, size_t src_host_len, char* src_service, size_t src_service_len, int recvfrom_flags, int numeric)

Returns the number of bytes received, or -1 if an error occurred.

Flags for Linux:

       MSG_CMSG_CLOEXEC (recvmsg() only; since Linux 2.6.23)
          Set the close-on-exec flag for the file descriptor received via a UNIX domain file descriptor using the SCM_RIGHTS  operation
          (described in unix(7)).  This flag is useful for the same reasons as the O_CLOEXEC flag of open(2).

       MSG_DONTWAIT (since Linux 2.2)
          Enables  nonblocking  operation;  if the operation would block, the call fails with the error EAGAIN or EWOULDBLOCK (this can
          also be enabled using the O_NONBLOCK flag with the F_SETFL fcntl(2)).

       MSG_ERRQUEUE (since Linux 2.2)
          This flag specifies that queued errors should be received from the socket error queue.  The error is passed in  an  ancillary
          message  with  a  type  dependent on the protocol (for IPv4 IP_RECVERR).  The user should supply a buffer of sufficient size.
          See cmsg(3) and ip(7) for more information.  The payload of the original packet that caused the error  is  passed  as  normal
          data via msg_iovec.  The original destination address of the datagram that caused the error is supplied via msg_name.

          For  local  errors,  no address is passed (this can be checked with the cmsg_len member of the cmsghdr).  For error receives,
          the MSG_ERRQUEUE is set in the msghdr.  After an error has been passed, the pending socket error is regenerated based on  the
          next queued error and will be passed on the next socket operation.

          The error is supplied in a sock_extended_err structure:

          #define SO_EE_ORIGIN_NONE    0
          #define SO_EE_ORIGIN_LOCAL   1
          #define SO_EE_ORIGIN_ICMP    2
          #define SO_EE_ORIGIN_ICMP6   3

          struct sock_extended_err
          {
              uint32_t ee_errno;   /* error number */
              uint8_t  ee_origin;  /* where the error originated */
              uint8_t  ee_type;    /* type */
              uint8_t  ee_code;    /* code */
              uint8_t  ee_pad;     /* padding */
              uint32_t ee_info;    /* additional information */
              uint32_t ee_data;    /* other data */
              /* More data may follow */
          };

          struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);

          ee_errno  contains  the  errno  number of the queued error.  ee_origin is the origin code of where the error originated.  The
          other fields are protocol-specific.  The macro SOCK_EE_OFFENDER returns a pointer to the address of the network object  where
          the  error  originated  from given a pointer to the ancillary message.  If this address is not known, the sa_family member of
          the sockaddr contains AF_UNSPEC and the other fields of the sockaddr are undefined.  The payload of the  packet  that  caused
          the error is passed as normal data.

          For  local  errors,  no address is passed (this can be checked with the cmsg_len member of the cmsghdr).  For error receives,
          the MSG_ERRQUEUE is set in the msghdr.  After an error has been passed, the pending socket error is regenerated based on  the
          next queued error and will be passed on the next socket operation.

       MSG_OOB
          This  flag  requests  receipt of out-of-band data that would not be received in the normal data stream.  Some protocols place
          expedited data at the head of the normal data queue, and thus this flag cannot be used with such protocols.

       MSG_PEEK
          This flag causes the receive operation to return data from the beginning of the receive queue without removing that data from
          the queue.  Thus, a subsequent receive call will return the same data.

       MSG_TRUNC (since Linux 2.2)
          For  raw (AF_PACKET), Internet datagram (since Linux 2.4.27/2.6.8), and netlink (since Linux 2.6.22) sockets: return the real
          length of the packet or datagram, even when it was longer than the passed buffer.  Not implemented for UNIX domain  (unix(7))
          sockets.

          For use with Internet stream sockets, see tcp(7).

       MSG_WAITALL (since Linux 2.2)
          This  flag  requests  that  the operation block until the full request is satisfied.  However, the call may still return less
          data than requested if a signal is caught, an error or disconnect occurs, or the next data to be received is of  a  different
          type than that returned.

Flags on FreeBSD:

The flags argument to a recv() function is formed by or'ing
one or more of the values:

   MSG_OOB     process out-of-band data
   MSG_PEEK    peek at incoming message
   MSG_WAITALL     wait for full request or error
   MSG_DONTWAIT    do not block

connect_inet_dgram_socket()

int connect_inet_dgram_socket(int sfd, char* host, char* service)

Calls to read(2) and write(2) on a connected socket will receive and send data only to/from the host and service you connected to. Sending/receiving to/from other hosts is still possible with {recvfrom,sendto}_inet_dgram_socket(). An example covering this is available at examples/echo_dgram_connected_client.c.

You may call this function multiple times on the same socket to reconnect it.

A socket can be disconnected by calling connect() with the arguments set to 0.

connect_inet_dgram_socket(socket,0,0);

Returns 0 on success, -1 on error.

destroy_inet_socket()

int destroy_inet_socket(int sfd)

Simply calls close(2) on sfd.

Returns 0 on success, -1 on error.

shutdown_inet_stream_socket()

int shutdown_inet_stream_socket(int sfd, int method)

Calls shutdown(2) on sfd.

Calling shutdown_inet_stream_socket() on a socket has the following effects:

Returns 0 upon success, -1 on error.

create_inet_server_socket()

int create_inet_server_socket(const char* bind_addr, const char* bind_port, char proto_osi4, char proto_osi3, int flags)

Creates a server socket, also known as Passive Socket. With such a socket you may accept connections (STREAM) or simply bind a UDP socket; if you use it as UDP "server" socket, it's almost the same as a socket created with create_inet_dgram_socket(), but it's bound (bind(2)) to a specified address.

The arguments:

Internals: The backlog argument of listen(2) when using TCP sockets is set to LIBSOCKET_BACKLOG, defined at the beginning of src/libinetsocket.c. Default is 128, the maximum value on Linux. This may differ on other platforms.

Returns a valid socket file descriptor on success, on error, -1 is returned.

accept_inet_stream_socket()

int accept_inet_stream_socket(int sfd, char* src_host, size_t src_host_len, char* src_service, size_t src_service_len, int flags, int accept_flags)

Accept incoming connections on server sockets created with create_inet_server_socket().

This function will block until there's an incoming connection.

Returns a stream file descriptor connected to the connecting client. On error, -1 is returned.

Other functions

get_address_family()

int get_address_family(const char* host)

Returns the available libsocket address family for the given host. The address family is either LIBSOCKET_IPv4 or LIBSOCKET_IPv6 (defined in libinetsocket header file). If a host is reachable via IPv6, LIBSOCKET_IPv6 will be returned.

This function is very useful when creating a UDP socket for a certain destination (host); without this function it would be impossible to obtain the address family to use for such a socket (UDP sockets do not have the BOTH address family available for the send call)

libunixsocket

As mentioned in the introduction, libunixsocket is Linux-specific. Until now, it did not run on other Unixes than Linux.

create_unix_stream_socket()

int create_unix_stream_socket(const char* path, int flags)

Creates a UNIX STREAM socket and connects it to path.

Returns a valid socket descriptor on success or -1 on error.

create_unix_dgram_socket()

int create_unix_dgram_socket(const char* bind_path, int flags)

Creates a UNIX DGRAM socket and binds it optionally to bind_path.

Returns a valid socket descriptor on success or -1 on error.

connect_unix_dgram_socket()

int connect_unix_dgram_socket(int sfd, const char* path)

Connect a UNIX DGRAM socket.

Returns 0 on success and -1 on error.

destroy_unix_socket()

int destroy_unix_socket(int sfd)

Destroy (close) a socket.

Returns 0 on success and -1 on error.

shutdown_unix_stream_socket()

int shutdown_unix_stream_socket(int sfd, int method)

Calling shutdown_inet_stream_socket() on a socket has the following effects:

Returns 0 upon success, -1 on error.

create_unix_server_socket()

int create_unix_server_socket(const char* path, int socktype, int flags)

Creates a new UNIX server (passive) socket.

Returns a valid passive socket descriptor or -1 on error.

If you specify DGRAM as socktype, you get the same result like with create_unix_dgram_socket("path",0) because there's no difference between server and client when using DGRAM sockets.

accept_unix_stream_socket()

int accept_unix_stream_socket(int sfd, int flags)

Accepts a connection on UNIX stream sockets.

Returns a socket connected to the client, or -1 on error.

recvfrom_unix_dgram_socket()

ssize_t recvfrom_unix_dgram_socket(int sfd, void* buf, size_t size, char* from, size_t from_size, int recvfrom_flags)

Receives a datagram which is sent to the socket sfd which should be bound to somewhere.

Returns the number of received bytes, or -1 on error.

sendto_unix_dgram_socket()

ssize_t sendto_unix_dgram_socket(int sfd, void* buf, size_t size, const char* path, int sendto_flags)

Sends a message to another socket.

Returns number of sent bytes or -1.