Provided by: libossp-sa-dev_1.2.6-3_amd64 bug

NAME

       OSSP sa - Socket Abstraction

VERSION

       OSSP sa 1.2.5 (02-Oct-2005)

SYNOPSIS

       Abstract Data Types:
           sa_rc_t, sa_addr_t, sa_t.

       Address Object Operations:
           sa_addr_create, sa_addr_destroy.

       Address Operations:
           sa_addr_u2a, sa_addr_s2a, sa_addr_a2u, sa_addr_a2s, sa_addr_match.

       Socket Object Operations:
           sa_create, sa_destroy.

       Socket Parameter Operations:
           sa_type, sa_timeout, sa_buffer, sa_option, sa_syscall.

       Socket Connection Operations:
           sa_bind, sa_connect, sa_listen, sa_accept, sa_getremote, sa_getlocal, sa_shutdown.

       Socket Input/Output Operations (Stream Communication):
           sa_getfd, sa_read, sa_readln, sa_write, sa_writef, sa_flush.

       Socket Input/Output Operations (Datagram Communication):
           sa_recv, sa_send, sa_sendf.

       Socket Error Handling:
           sa_error.

DESCRIPTION

       OSSP sa is an abstraction library for the Unix Socket networking application programming
       interface (API), featuring stream and datagram oriented communication over Unix Domain and
       Internet Domain (TCP and UDP) sockets.

       It provides the following key features:

       Stand-Alone, Self-Contained, Embeddable
           Although there are various Open Source libraries available which provide a similar
           abstraction approach, they all either lack important features or unfortunately depend
           on other companion libraries. OSSP sa fills this gap by providing all important
           features (see following points) as a stand-alone and fully self-contained library.
           This way OSSP sa can be trivially embedded as a sub-library into other libraries. It
           especially provides additional support for namespace-safe embedding of its API in
           order to avoid symbol conflicts (see SA_PREFIX in sa.h).

       Address Abstraction
           Most of the ugliness in the Unix Socket API is the necessity to have to deal with the
           various address structures (struct sockaddr_xx) which exist because of both the
           different communication types and addressing schemes. OSSP sa fully hides this by
           providing an abstract and opaque address type (sa_addr_t) together with utility
           functions which allow one to convert from the traditional struct sockaddr or URI
           specification to the sa_addr_t and vice versa without having to deal with special
           cases related to the underlying particular struct sockaddr_xx. OSSP sa support Unix
           Domain and both IPv4 and IPv6 Internet Domain addressing.

       Type Abstraction
           Some other subtle details in the Unix Socket API make the life hard in practice:
           socklen_t and ssize_t. These two types originally were (and on some platforms still
           are) plain integers or unsigned integers while POSIX later introduced own types for
           them (and even revised these types after some time again). This is nasty, because for
           100% type-correct API usage (especially important on 64-bit machines where pointers to
           different integer types make trouble), every application has to check whether the
           newer types exists, and if not provide own definitions which map to the still actually
           used integer type on the underlying platform. OSSP sa hides most of this in its API
           and for socklen_t provides a backward-compatibility definition.  Instead of ssize_t it
           can use size_t because OSSP sa does not use traditional Unix return code semantics.

       I/O Timeouts
           Each I/O function in OSSP sa is aware of timeouts (set by sa_timeout(3)), i.e., all
           I/O operations return SA_ERR_TMT if the timeout expired before the I/O operation was
           able to succeed.  This allows one to easily program less-blocking network services.
           OSSP sa internally implements these timeouts either through the SO_{SND,RCV}TIMEO
           feature on more modern Socket implementations or through traditional select(2). This
           way high performance is achieved on modern platforms while the full functionality
           still is available on older platforms.

       I/O Stream Buffering
           If OSSP sa is used for stream communication, internally all I/O operations can be
           performed through input and/or output buffers (set by sa_buffer(3)) for achieving
           higher I/O performance by doing I/O operations on larger aggregated messages and with
           less required system calls. Additionally if OSSP sa is used for stream communication,
           for convenience reasons line-oriented reading (sa_readln(3)) and formatted writing
           (see sa_writef(3)) is provided, modelled after STDIO's fgets(3) and fprintf(3). Both
           features fully leverage from the I/O buffering.

DATA TYPES

       OSSP sa uses three data types in its API:

       sa_rc_t (Return Code Type)
           This is an exported enumerated integer type with the following possible values:

            SA_OK       Everything Ok
            SA_ERR_ARG  Invalid Argument
            SA_ERR_USE  Invalid Use Or Context
            SA_ERR_MEM  Not Enough Memory
            SA_ERR_MTC  Matching Failed
            SA_ERR_EOF  End Of Communication
            SA_ERR_TMT  Communication Timeout
            SA_ERR_SYS  Operating System Error (see errno)
            SA_ERR_IMP  Implementation Not Available
            SA_ERR_INT  Internal Error

       sa_addr_t (Socket Address Abstraction Type)
           This is an opaque data type representing a socket address.  Only pointers to this
           abstract data type are used in the API.

       sa_t (Socket Abstraction Type)
           This is an opaque data type representing a socket.  Only pointers to this abstract
           data type are used in the API.

FUNCTIONS

       OSSP sa provides a bunch of API functions, all modelled after the same prototype:

       sa_rc_t sa_name(sa_[addr_]_t *, ...)

       This means, every function returns sa_rc_t to indicate its success (SA_OK) or failure
       (SA_ERR_XXX) by returning a return code (the corresponding describing text can be
       determined by passing this return code to sa_error(3)). Each function name starts with the
       common prefix sa_ and receives a sa_t (or sa_addr_t) object handle on which it operates as
       its first argument.

       Address Object Operations

       This API part provides operations for the creation and destruction of address abstraction
       sa_addr_t.

       sa_rc_t sa_addr_create(sa_addr_t **saa);
           Create a socket address abstraction object.  The object is stored in saa on success.

           Example: sa_addr_t *saa; sa_addr_create(&saa);

       sa_rc_t sa_addr_destroy(sa_addr_t *saa);
           Destroy a socket address abstraction object.  The object saa is invalid after this
           call succeeded.

           Example: sa_addr_destroy(saa);

       Address Operations

       This API part provides operations for working with the address abstraction sa_addr_t.

       sa_rc_t sa_addr_u2a(sa_addr_t *saa, const char *uri, ...);
           Import an address into by converting from an URI specification to the corresponding
           address abstraction.

           The supported syntax for uri is: "unix:path" for Unix Domain addresses and
           "inet://addr:port[#protocol]" for Internet Domain addresses.

           In the URI, path can be an absolute or relative filesystem path to an existing or not-
           existing file. addr can be an IPv4 address in dotted decimal notation ("127.0.0.1"),
           an IPv6 address in colon-separated (optionally abbreviated) hexadecimal notation
           ("::1") or a to-be-resolved hostname ("localhost.example.com"). port has to be either
           a decimal port in the range 1...65535 or a port name ("smtp"). If port is specified as
           a name, it is resolved as a TCP port by default. To force resolving a port name via a
           particular protocol, protocol can be specified as either "tcp" or "udp".

           The result is stored in saa on success.

           Example: sa_addr_u2a(saa, "inet://192.168.0.1:smtp");

       sa_rc_t sa_addr_s2a(sa_addr_t *saa, const struct sockaddr *sabuf, socklen_t salen);
           Import an address by converting from a traditional struct sockaddr object to the
           corresponding address abstraction.

           The accepted addresses for sabuf are: struct sockaddr_un (AF_LOCAL), struct
           sockaddr_in (AF_INET) and struct sockaddr_in6 (AF_INET6). The salen is the
           corresponding sizeof(...) of the particular underyling structure.

           The result is stored in saa on success.

           Example: sockaddr_in in; sa_addr_s2a(saa, (struct sockaddr *)&in,
           (socklen_t)sizeof(in));

       sa_rc_t sa_addr_a2u(sa_addr_t *saa, char **uri);
           Export an address by converting from the address abstraction to the corresponding URI
           specification.

           The result is a string of the form "unix:path" for Unix Domain addresses and
           "inet://addr:port" for Internet Domain addresses. Notice that addr and port are
           returned in numerical (unresolved) way. Additionally, because usually one cannot map
           bidirectionally between TCP or UDP port names and the numerical value, there is no
           distinction between TCP and UDP here.

           The result is stored in uri on success.  The caller has to free(3) the uri buffer
           later.

           Example: char *uri; sa_addr_a2u(saa, &uri);

       sa_rc_t sa_addr_a2s(sa_addr_t *saa, struct sockaddr **sabuf, socklen_t *salen);
           Export an address by converting from the address abstraction to the corresponding
           traditional struct sockaddr object.

           The result is one of the following particular underlying address structures: struct
           sockaddr_un (AF_LOCAL), struct sockaddr_in (AF_INET) and struct sockaddr_in6
           (AF_INET6).

           The result is stored in sabuf and salen on success.  The caller has to free(3) the
           sabuf buffer later.

           Example: struct sockaddr sabuf, socklen_t salen; sa_addr_a2s(saa, &sa, &salen);

       sa_rc_t sa_addr_match(sa_addr_t *saa1, sa_addr_t *saa2, size_t prefixlen);
           Match two address abstractions up to a specified prefix.

           This compares the addresses saa1 and saa2 by only taking the prefix part of length
           prefixlen into account. prefixlen is number of filesystem path characters for Unix
           Domain addresses and number of bits for Internet Domain addresses. In case of Internet
           Domain addresses, the addresses are matched in network byte order and the port
           (counting as an additional bit/item of length 1) is virtually appended to the address
           for matching. Specifying prefixlen as -1 means matching the whole address (but without
           the virtually appended port) without having to know how long the underlying address
           representation (length of path for Unix Domain addresses, 32+1 [IPv4] or 128+1 [IPv6]
           for Internet Domain addresses) is. Specifying prefixlen as -2 is equal to -1 but
           additionally the port is matched, too.

           This especially can be used to implement Access Control Lists (ACL) without having to
           fiddle around with the underlying representation.  For this, make saa1 the to be
           checked address and saa2 plus prefixlen the ACL pattern as shown in the following
           example.

           Example:

            sa_addr_t *srv_sa;
            sa_addr_t *clt_saa;
            sa_t      *clt_sa;
            sa_addr_t *acl_saa;
            char      *acl_addr = "192.168.0.0";
            int        acl_len  = 24;
            ...
            sa_addr_u2a(&acl_saa, "inet://%s:0", acl_addr);
            ...
            while (sa_accept(srv_sa, &clt_saa, &clt_sa) == SA_OK) {
                if (sa_addr_match(clt_saa, acl_saa, acl_len) != SA_OK) {
                    /* connection refused */
                    ...
                    sa_addr_destroy(clt_saa);
                    sa_destroy(clt_sa);
                    continue;
                }
                ...
            }
            ...

       Socket Object Operations

       This API part provides operations for the creation and destruction of socket abstraction
       sa_t.

       sa_rc_t sa_create(sa_t **sa);
           Create a socket abstraction object.  The object is stored in sa on success.

           Example: sa_t *sa; sa_create(&sa);

       sa_rc_t sa_destroy(sa_t *sa);
           Destroy a socket abstraction object.  The object sa is invalid after this call
           succeeded.

           Example: sa_destroy(sa);

       Socket Parameter Operations

       This API part provides operations for parameterizing the socket abstraction sa_t.

       sa_rc_t sa_type(sa_t *sa, sa_type_t type);
           Assign a particular communication protocol type to the socket abstraction object.

           A socket can only be assigned a single protocol type at any time.  Nevertheless one
           can switch the type of a socket abstraction object at any time in order to reuse it
           for a different communication. Just keep in mind that switching the type will stop a
           still ongoing communication by closing the underlying socket.

           Possible values for type are SA_TYPE_STREAM (stream communication) and
           SA_TYPE_DATAGRAM (datagram communication). The default communication protocol type is
           SA_TYPE_STREAM.

           Example: sa_type(sa, SA_TYPE_STREAM);

       sa_rc_t sa_timeout(sa_t *sa, sa_timeout_t id, long sec, long usec);
           Assign one or more communication timeouts to the socket abstraction object.

           Possible values for id are: SA_TIMEOUT_ACCEPT (affecting sa_accept(3)),
           SA_TIMEOUT_CONNECT (affecting sa_connect(3)), SA_TIMEOUT_READ (affecting sa_read(3),
           sa_readln(3) and sa_recv(3)) and SA_TIMEOUT_WRITE (affecting sa_write(3),
           sa_writef(3), sa_send(3), and sa_sendf(3)). Additionally you can set all four timeouts
           at once by using SA_TIMEOUT_ALL. The default is that no communication timeouts are
           used which is equal to sec=0/usec=0.

           Example: sa_timeout(sa, SA_TIMEOUT_ALL, 30, 0);

       sa_rc_t sa_buffer(sa_t *sa, sa_buffer_t id, size_t size);
           Assign I/O communication buffers to the socket abstraction object.

           Possible values for id are: SA_BUFFER_READ (affecting sa_read(3) and sa_readln(3)) and
           SA_BUFFER_WRITE (affecting sa_write(3) and sa_writef(3)). The default is that no
           communication buffers are used which is equal to size=0.

           Example: sa_buffer(sa, SA_BUFFER_READ, 16384);

       sa_rc_t sa_option(sa_t *sa, sa_option_t id, ...);
           Adjust various options of the socket abstraction object.

           The adjusted option is controlled by id. The number and type of the expected following
           argument(s) are dependent on the particular option.  Currently the following options
           are implemented (option arguments in parenthesis):

           SA_OPTION_NAGLE (int yesno) for enabling (yesno=1) or disabling (yesno == 0) Nagle's
           Algorithm (see RFC898 and TCP_NODELAY of setsockopt(2)).

           SA_OPTION_LINGER (int amount) for enabling (amount == seconds != 0) or disabling
           (amount == 0) lingering on close (see SO_LINGER of setsockopt(2)). Notice: using
           seconds > 0 results in a regular (maximum of seconds lasting) lingering on close while
           using seconds < 0 results in the special case of a TCP RST based connection
           termination on close.

           SA_OPTION_REUSEADDR (int yesno) for enabling (yesno == 1) or disabling (yesno == 0)
           the reusability of the address on binding via sa_bind(3) (see SO_REUSEADDR of
           setsockopt(2)).

           SA_OPTION_REUSEPORT (int yesno) for enabling (yesno == 1) or disabling (yesno == 0)
           the reusability of the port on binding via sa_bind(3) (see SO_REUSEPORT of
           setsockopt(2)).

           SA_OPTION_NONBLOCK (int yesno) for enabling (yesno == 1) or disabling (yesno == 0)
           non-blocking I/O mode (see O_NONBLOCK of fcntl(2)).

           Example: sa_option(sa, SA_OPTION_NONBLOCK, 1);

       sa_rc_t sa_syscall(sa_t *sa, sa_syscall_t id, void (*fptr)(), void *fctx);
           Divert I/O communication related system calls to user supplied callback functions.

           This allows you to override mostly all I/O related system calls OSSP sa internally
           performs while communicating. This can be used to adapt OSSP sa to different run-time
           environments and requirements without having to change the source code. Usually this
           is used to divert the system calls to the variants of a user-land multithreading
           facility like GNU Pth.

           The function supplied as fptr is required to fulfill the API of the replaced system
           call, i.e., it has to have the same prototype (if fctx is NULL). If fctx is not NULL,
           this prototype has to be extended to accept an additional first argument of type void
           * which receives the value of fctx. It is up to the callback function whether to pass
           the call through to the replaced actual system call or not.

           Possible values for id are (expected prototypes behind fptr are given in parenthesis):

           SA_SYSCALL_CONNECT: "int (*)([void *,] int, const struct sockaddr *, socklen_t)", see
           connect(2).

           SA_SYSCALL_ACCEPT: "int (*)([void *,] int, struct sockaddr *, socklen_t *)", see
           accept(2).

           SA_SYSCALL_SELECT: "int (*)([void *,] int, fd_set *, fd_set *, fd_set *, struct
           timeval *)", see select(2).

           SA_SYSCALL_READ: "ssize_t (*)([void *,] int, void *, size_t)", see read(2).

           SA_SYSCALL_WRITE: "ssize_t (*)([void *,] int, const void *, size_t)", see write(2).

           SA_SYSCALL_RECVFROM: "ssize_t (*)([void *,] int, void *, size_t, int, struct sockaddr
           *, socklen_t *)", see recvfrom(2).

           SA_SYSCALL_SENDTO: "ssize_t (*)([void *,] int, const void *, size_t, int, const struct
           sockaddr *, socklen_t)", see sendto(2).

           Example:

            ssize_t
            trace_read(void *ctx, int fd, void *buf, size_t len)
            {
                FILE *fp = (FILE *)ctx;
                ssize_t rv;
                int errno_saved;

                rv = read(fd, buf, len);
                errno_saved = errno;
                fprintf(fp, "read(%d, %lx, %d) = %d\n",
                        fd, (long)buf, len, rv);
                errno = errno_saved;
                return rv;
            }

            ...
            FILE *trace_fp = ...;
            sa_syscall(sa, SA_SC_READ, trace_read, trace_fp);
            ...

       Socket Connection Operations

       This API part provides connection operations for stream-oriented data communication
       through the socket abstraction sa_t.

       sa_rc_t sa_bind(sa_t *sa, sa_addr_t *laddr);
           Bind socket abstraction object to a local protocol address.

           This assigns the local protocol address laddr. When a socket is created, it exists in
           an address family space but has no protocol address assigned. This call requests that
           laddr be used as the local address. For servers this is the address they later listen
           on (see sa_listen(3)) for incoming connections, for clients this is the address used
           for outgoing connections (see sa_connect(3)). Internally this directly maps to
           bind(2).

           Example: sa_bind(sa, laddr);

       sa_rc_t sa_connect(sa_t *sa, sa_addr_t *raddr);
           Initiate an outgoing connection on a socket abstraction object.

           This performs a connect to the remote address raddr. If the socket is of type
           SA_TYPE_DATAGRAM, this call specifies the peer with which the socket is to be
           associated; this address is that to which datagrams are to be sent, and the only
           address from which datagrams are to be received. If the socket is of type
           SA_TYPE_STREAM, this call attempts to make a connection to the remote socket.
           Internally this directly maps to connect(2).

           Example: sa_connect(sa, raddr);

       sa_rc_t sa_listen(sa_t *sa, int backlog);
           Listen for incoming connections on a socket abstraction object.

           A willingness to accept incoming connections and a queue limit for incoming
           connections are specified by this call. The backlog argument defines the maximum
           length the queue of pending connections may grow to.  Internally this directly maps to
           listen(2).

           Example: sa_listen(sa, 128);

       sa_rc_t sa_accept(sa_t *sa, sa_addr_t **caddr, sa_t **csa);
           Accept incoming connection on a socket abstraction object.

           This accepts an incoming connection by extracting the first connection request on the
           queue of pending connections. It creates a new socket abstraction object (returned in
           csa) and a new socket address abstraction object (returned in caddr) describing the
           connection. The caller has to destroy these objects later. If no pending connections
           are present on the queue, it blocks the caller until a connection is present.

           Example:

            sa_addr_t *clt_saa;
            sa_t      *clt_sa;
            ...
            while (sa_accept(srv_sa, &clt_saa, &clt_sa) == SA_OK) {
                ...
            }

       sa_rc_t sa_getremote(sa_t *sa, sa_addr_t **raddr);
           Get address abstraction of remote side of communication.

           This determines the address of the communication peer and creates a new socket address
           abstraction object (returned in raddr) describing the peer address. The application
           has to destroy raddr later with sa_addr_destroy(3). Internally this maps to
           getpeername(2).

           Example: sa_addr_t *raddr; sa_getremote(sa, &raddr);

       sa_rc_t sa_getlocal(sa_t *sa, sa_addr_t **laddr);
           Get address abstraction of local side of communication.

           This determines the address of the local communication side and creates a new socket
           address abstraction object (returned in laddr) describing the local address. The
           application has to destroy laddr later with sa_addr_destroy(3). Internally this maps
           to getsockname(2).

           Example: sa_addr_t *laddr; sa_getlocal(sa, &laddr);

       sa_rc_t sa_shutdown(sa_t *sa, char *flags);
           Shut down part of the full-duplex connection.

           This performs a shut down of the connection described in sa. The flags string can be
           either "r" (indicating the read channel of the communication is shut down only), "w"
           (indicating the write channel of the communication is shut down only), or "rw"
           (indicating both the read and write channels of the communication are shut down).
           Internally this directly maps to shutdown(2).

           Example: sa_shutdown(sa, "w");

       Socket Input/Output Operations (Stream Communication)

       This API part provides I/O operations for stream-oriented data communication through the
       socket abstraction sa_t.

       sa_rc_t sa_getfd(sa_t *sa, int *fd);
           Get underlying socket filedescriptor.

           This peeks into the underlying socket filedescriptor OSSP sa allocated internally for
           the communication. This can be used for adjusting the socket communication (via
           fcntl(2), setsockopt(2), etc) directly.

           Think twice before using this, then think once more. After all that, think again. With
           enough thought, the need for directly manipulating the underlying socket can often be
           eliminated. At least remember that all your direct socket operations fully by-pass
           OSSP sa and this way can leads to nasty side-effects.

           Example: int fd; sa_getfd(sa, &fd);

       sa_rc_t sa_read(sa_t *sa, char *buf, size_t buflen, size_t *bufdone);
           Read a chunk of data from socket into own buffer.

           This reads from the socket (optionally through the internal read buffer) up to a
           maximum of buflen bytes into buffer buf. The actual number of read bytes is stored in
           bufdone. This internally maps to read(2).

           Example: char buf[1024]; size_t n; sa_read(sa, buf, sizeof(buf), &n);

       sa_rc_t sa_readln(sa_t *sa, char *buf, size_t buflen, size_t *bufdone);
           Read a line of data from socket into own buffer.

           This reads from the socket (optionally through the internal read buffer) up to a
           maximum of buflen bytes into buffer buf, but only as long as no line terminating
           newline character (0x0a) was found. The line terminating newline character is stored
           in the buffer plus a (not counted) terminating NUL character ('\0'), too. The actual
           number of read bytes is stored in bufdone. This internally maps to sa_read(3).

           Keep in mind that for efficiency reasons, line-oriented I/O usually always should be
           performed with read buffer (see sa_option(3) and SA_BUFFER_READ). Without such a read
           buffer, the performance is cruel, because single character read(2) operations would be
           performed on the underlying socket.

           Example: char buf[1024]; size_t n; sa_readln(sa, buf, sizeof(buf), &n);

       sa_rc_t sa_write(sa_t *sa, const char *buf, size_t buflen, size_t *bufdone);
           Write a chunk of data to socket from own buffer.

           This writes to the socket (optionally through the internal write buffer) buflen bytes
           from buffer buf. In case of a partial write, the actual number of written bytes is
           stored in bufdone. This internally maps to write(2).

           Example: sa_write(sa, cp, strlen(cp), NULL);

       sa_rc_t sa_writef(sa_t *sa, const char *fmt, ...);
           Write formatted data data to socket.

           This formats a string according to the printf(3)-style format specification fmt and
           sends the result to the socket (optionally through the internal write buffer). In case
           of a partial socket write, the not written data of the formatted string is internally
           discarded. Hence using a write buffer is strongly recommended here (see sa_option(3)
           and SA_BUFFER_WRITE). This internally maps to sa_write(3).

           The underlying string formatting engine is just a minimal one and for security and
           independence reasons intentionally not directly based on s[n]printf(3). It understands
           only the following format specifications: "%%", "%c" (char), "%s" (char *) and "%d"
           (int) without any precision and padding possibilities. It is intended for minimal
           formatting only. If you need more sophisticated formatting, you have to format first
           into an own buffer via s[n]printf(3) and then write this to the socket via sa_write(3)
           instead.

           Example: sa_writef(sa, "%s=%d\n", cp, i);

       sa_rc_t sa_flush(sa_t *sa);
           Flush still pending outgoing data to socket.

           This writes all still pending outgoing data for the internal write buffer (see
           sa_option(3) and SA_BUFFER_WRITE) to the socket. This internally maps to write(2).

           Example: sa_flush(sa);

       Socket Input/Output Operations (Datagram Communication)

       This API part provides I/O operations for datagram-oriented data communication through the
       socket abstraction sa_t.

       sa_rc_t sa_recv(sa_t *sa, sa_addr_t **raddr, char *buf, size_t buflen, size_t *bufdone);
           Receive a chunk of data from remote address via socket into own buffer.

           This receives from the remote address specified in raddr via the socket up to a
           maximum of buflen bytes into buffer buf. The actual number of received bytes is stored
           in bufdone. This internally maps to recvfrom(2).

           Example: char buf[1024]; size_t n; sa_recv(sa, buf, sizeof(buf), &n, saa);

       sa_rc_t sa_send(sa_t *sa, sa_addr_t *raddr, const char *buf, size_t buflen, size_t
       *bufdone);
           Send a chunk of data to remote address via socket from own buffer.

           This sends to the remote address specified in raddr via the socket buflen bytes from
           buffer buf. The actual number of sent bytes is stored in bufdone. This internally maps
           to sendto(2).

           Example: sa_send(sa, buf, strlen(buf), NULL, saa);

       sa_rc_t sa_sendf(sa_t *sa, sa_addr_t *raddr, const char *fmt, ...);
           Send formatted data data to remote address via socket.

           This formats a string according to the printf(3)-style format specification fmt and
           sends the result to the socket as a single piece of data chunk. In case of a partial
           socket write, the not written data of the formatted string is internally discarded.

           The underlying string formatting engine is just a minimal one and for security and
           independence reasons intentionally not directly based on s[n]printf(3). It understands
           only the following format specifications: "%%", "%c" (char), "%s" (char *) and "%d"
           (int) without any precision and padding possibilities. It is intended for minimal
           formatting only. If you need more sophisticated formatting, you have to format first
           into an own buffer via s[n]printf(3) and then send this to the remote address via
           sa_send(3) instead.

           Example: sa_sendf(sa, saa, "%s=%d\n", cp, i);

       Socket Error Handling

       This API part provides error handling operations only.

       char *sa_error(sa_rc_t rv);
           Return the string representation corresponding to the return code value rv. The
           returned string has to be treated read-only by the application and is not required to
           be deallocated.

SEE ALSO

       Standards

       R. Gilligan, S. Thomson, J. Bound, W. Stevens: "Basic Socket Interface Extensions for
       IPv6", RFC 2553, March 1999.

       W. Stevens: "Advanced Sockets API for IPv6", RFC 2292, February 1998.

       R. Fielding, L. Masinter, T. Berners-Lee: "Uniform Resource Identifiers: Generic Syntax",
       RFC 2396, August 1998.

       R. Hinden, S. Deering: "IP Version 6 Addressing Architecture", RFC 2373, July 1998.

       R. Hinden, B. Carpenter, L. Masinter: "Format for Literal IPv6 Addresses in URL's", RFC
       2732, December 1999.

       Papers

       Stuart Sechrest: "An Introductory 4.4BSD Interprocess Communication Tutorial", FreeBSD 4.4
       (/usr/share/doc/psd/20.ipctut/).

       Samuel J. Leffler, Robert S. Fabry, William N. Joy, Phil Lapsley: "An Advanced 4.4BSD
       Interprocess Communication Tutorial", FreeBSD 4.4 (/usr/share/doc/psd/21.ipc/).

       Craig Metz: "Protocol Independence Using the Sockets API",
       http://www.usenix.org/publications/library/proceedings/usenix2000/freenix/metzprotocol.html,
       USENIX Annual Technical Conference, June 2000.

       Manual Pages

       socket(2), accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2),
       ioctl(2), listen(2), read(2), recv(2), select(2), send(2), shutdown(2), socketpair(2),
       write(2), getprotoent(3), protocols(4).

HISTORY

       OSSP sa was invented in August 2001 by Ralf S. Engelschall <rse@engelschall.com> under
       contract with Cable & Wireless <http://www.cw.com/> for use inside the OSSP project. Its
       creation was prompted by the requirement to implement an SMTP logging channel for the OSSP
       l2 library. Its initial code was derived from a predecessor sub-library originally written
       for socket address abstraction inside the OSSP lmtp2nntp tool.

AUTHOR

        Ralf S. Engelschall
        rse@engelschall.com
        www.engelschall.com