.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.3 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` . ds C' 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "sa 3" .TH sa 3 "OSSP sa 1.2.5" "02-Oct-2005" "Socket Abstraction" .SH "NAME" \&\fBOSSP sa\fR \- Socket Abstraction .SH "VERSION" .IX Header "VERSION" \&\fB\s-1OSSP\s0 sa \s-11.2.5 (02-Oct-2005)\s0\fR .SH "SYNOPSIS" .IX Header "SYNOPSIS" .IP "\fBAbstract Data Types\fR:" 4 .IX Item "Abstract Data Types:" sa_rc_t, sa_addr_t, sa_t. .IP "\fBAddress Object Operations\fR:" 4 .IX Item "Address Object Operations:" sa_addr_create, sa_addr_destroy. .IP "\fBAddress Operations\fR:" 4 .IX Item "Address Operations:" sa_addr_u2a, sa_addr_s2a, sa_addr_a2u, sa_addr_a2s, sa_addr_match. .IP "\fBSocket Object Operations\fR:" 4 .IX Item "Socket Object Operations:" sa_create, sa_destroy. .IP "\fBSocket Parameter Operations\fR:" 4 .IX Item "Socket Parameter Operations:" sa_type, sa_timeout, sa_buffer, sa_option, sa_syscall. .IP "\fBSocket Connection Operations\fR:" 4 .IX Item "Socket Connection Operations:" sa_bind, sa_connect, sa_listen, sa_accept, sa_getremote, sa_getlocal, sa_shutdown. .IP "\fBSocket Input/Output Operations (Stream Communication)\fR:" 4 .IX Item "Socket Input/Output Operations (Stream Communication):" sa_getfd, sa_read, sa_readln, sa_write, sa_writef, sa_flush. .IP "\fBSocket Input/Output Operations (Datagram Communication)\fR:" 4 .IX Item "Socket Input/Output Operations (Datagram Communication):" sa_recv, sa_send, sa_sendf. .IP "\fBSocket Error Handling\fR:" 4 .IX Item "Socket Error Handling:" sa_error. .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fB\s-1OSSP\s0 sa\fR is an abstraction library for the Unix \fISocket\fR networking application programming interface (\s-1API\s0), featuring stream and datagram oriented communication over \fIUnix Domain\fR and \fIInternet Domain\fR (\s-1TCP\s0 and \s-1UDP\s0) sockets. .PP It provides the following key features: .IP "\fBStand\-Alone, Self\-Contained, Embeddable\fR" 4 .IX Item "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. \fB\s-1OSSP\s0 sa\fR fills this gap by providing all important features (see following points) as a stand-alone and fully self-contained library. This way \fB\s-1OSSP\s0 sa\fR can be trivially embedded as a sub-library into other libraries. It especially provides additional support for namespace-safe embedding of its \s-1API\s0 in order to avoid symbol conflicts (see \f(CW\*(C`SA_PREFIX\*(C'\fR in \fIsa.h\fR). .IP "\fBAddress Abstraction\fR" 4 .IX Item "Address Abstraction" Most of the ugliness in the Unix \fISocket\fR \s-1API\s0 is the necessity to have to deal with the various address structures (\f(CW\*(C`struct sockaddr_xx\*(C'\fR) which exist because of both the different communication types and addressing schemes. \fB\s-1OSSP\s0 sa\fR fully hides this by providing an abstract and opaque address type (\f(CW\*(C`sa_addr_t\*(C'\fR) together with utility functions which allow one to convert from the traditional \f(CW\*(C`struct sockaddr\*(C'\fR or \&\s-1URI\s0 specification to the \f(CW\*(C`sa_addr_t\*(C'\fR and vice versa without having to deal with special cases related to the underlying particular \f(CW\*(C`struct sockaddr_xx\*(C'\fR. \fB\s-1OSSP\s0 sa\fR support \fIUnix Domain\fR and both IPv4 and IPv6 \&\fIInternet Domain\fR addressing. .IP "\fBType Abstraction\fR" 4 .IX Item "Type Abstraction" Some other subtle details in the Unix \fISocket\fR \s-1API\s0 make the life hard in practice: \f(CW\*(C`socklen_t\*(C'\fR and \f(CW\*(C`ssize_t\*(C'\fR. These two types originally were (and on some platforms still are) plain integers or unsigned integers while \s-1POSIX\s0 later introduced own types for them (and even revised these types after some time again). This is nasty, because for 100% type-correct \s-1API\s0 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. \fB\s-1OSSP\s0 sa\fR hides most of this in its \&\s-1API\s0 and for \f(CW\*(C`socklen_t\*(C'\fR provides a backward-compatibility definition. Instead of \f(CW\*(C`ssize_t\*(C'\fR it can use \f(CW\*(C`size_t\*(C'\fR because \fB\s-1OSSP\s0 sa\fR does not use traditional Unix return code semantics. .IP "\fBI/O Timeouts\fR" 4 .IX Item "I/O Timeouts" Each I/O function in \fB\s-1OSSP\s0 sa\fR is aware of timeouts (set by \&\fIsa_timeout\fR\|(3)), i.e., all I/O operations return \f(CW\*(C`SA_ERR_TMT\*(C'\fR if the timeout expired before the I/O operation was able to succeed. This allows one to easily program less-blocking network services. \&\fB\s-1OSSP\s0 sa\fR internally implements these timeouts either through the \&\f(CW\*(C`SO_\*(C'\fR{\f(CW\*(C`SND\*(C'\fR,\f(CW\*(C`RCV\*(C'\fR}\f(CW\*(C`TIMEO\*(C'\fR feature on more modern \fISocket\fR implementations or through traditional \fIselect\fR\|(2). This way high performance is achieved on modern platforms while the full functionality still is available on older platforms. .IP "\fBI/O Stream Buffering\fR" 4 .IX Item "I/O Stream Buffering" If \fB\s-1OSSP\s0 sa\fR is used for stream communication, internally all I/O operations can be performed through input and/or output buffers (set by \fIsa_buffer\fR\|(3)) for achieving higher I/O performance by doing I/O operations on larger aggregated messages and with less required system calls. Additionally if \fB\s-1OSSP\s0 sa\fR is used for stream communication, for convenience reasons line-oriented reading (\fIsa_readln\fR\|(3)) and formatted writing (see \fIsa_writef\fR\|(3)) is provided, modelled after \s-1STDIO\s0's \fIfgets\fR\|(3) and \fIfprintf\fR\|(3). Both features fully leverage from the I/O buffering. .SH "DATA TYPES" .IX Header "DATA TYPES" \&\fB\s-1OSSP\s0 sa\fR uses three data types in its \s-1API:\s0 .IP "\fBsa_rc_t\fR (Return Code Type)" 4 .IX Item "sa_rc_t (Return Code Type)" This is an exported enumerated integer type with the following possible values: .Sp .Vb 10 \& 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 .Ve .IP "\fBsa_addr_t\fR (Socket Address Abstraction Type)" 4 .IX Item "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 \s-1API\s0. .IP "\fBsa_t\fR (Socket Abstraction Type)" 4 .IX Item "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 \s-1API\s0. .SH "FUNCTIONS" .IX Header "FUNCTIONS" \&\fB\s-1OSSP\s0 sa\fR provides a bunch of \s-1API\s0 functions, all modelled after the same prototype: .PP \&\f(CW\*(C`sa_rc_t\*(C'\fR \fBsa_\fR\fIname\fR\f(CW\*(C`(sa_\*(C'\fR[\f(CW\*(C`addr_\*(C'\fR]\f(CW\*(C`_t *,\*(C'\fR ...\f(CW\*(C`)\*(C'\fR .PP This means, every function returns \f(CW\*(C`sa_rc_t\*(C'\fR to indicate its success (\f(CW\*(C`SA_OK\*(C'\fR) or failure (\f(CW\*(C`SA_ERR_\*(C'\fR\fI\s-1XXX\s0\fR) by returning a return code (the corresponding describing text can be determined by passing this return code to \fIsa_error\fR\|(3)). Each function name starts with the common prefix \&\f(CW\*(C`sa_\*(C'\fR and receives a \f(CW\*(C`sa_t\*(C'\fR (or \f(CW\*(C`sa_addr_t\*(C'\fR) object handle on which it operates as its first argument. .Sh "Address Object Operations" .IX Subsection "Address Object Operations" This \s-1API\s0 part provides operations for the creation and destruction of address abstraction \f(CW\*(C`sa_addr_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_create\fR\f(CW\*(C`(sa_addr_t **\*(C'\fR\fIsaa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_create\fR\f(CW\*(C`(sa_addr_t **\*(C'\fR\fIsaa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_addr_create(sa_addr_t **saa);" Create a socket address abstraction object. The object is stored in \fIsaa\fR on success. .Sp Example: \f(CW\*(C`sa_addr_t *saa; sa_addr_create(&saa);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_destroy\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_destroy\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_addr_destroy(sa_addr_t *saa);" Destroy a socket address abstraction object. The object \fIsaa\fR is invalid after this call succeeded. .Sp Example: \f(CW\*(C`sa_addr_destroy(saa);\*(C'\fR .Sh "Address Operations" .IX Subsection "Address Operations" This \s-1API\s0 part provides operations for working with the address abstraction \f(CW\*(C`sa_addr_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_u2a\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, const char *\*(C'\fR\fIuri\fR\f(CW\*(C`, ...);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_u2a\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, const char *\*(C'\fR\fIuri\fR\f(CW\*(C`, ...);\*(C'\fR" 4 .IX Item "sa_rc_t sa_addr_u2a(sa_addr_t *saa, const char *uri, ...);" Import an address into by converting from an \s-1URI\s0 specification to the corresponding address abstraction. .Sp The supported syntax for \fIuri\fR is: "\f(CW\*(C`unix:\*(C'\fR\fIpath\fR" for \fIUnix Domain\fR addresses and "\f(CW\*(C`inet://\*(C'\fR\fIaddr\fR\f(CW\*(C`:\*(C'\fR\fIport\fR[\f(CW\*(C`#\*(C'\fR\fIprotocol\fR]" for \&\fIInternet Domain\fR addresses. .Sp In the \s-1URI\s0, \fIpath\fR can be an absolute or relative filesystem path to an existing or not-existing file. \fIaddr\fR can be an IPv4 address in dotted decimal notation ("\f(CW127.0.0.1\fR\*(L"), an IPv6 address in colon-separated (optionally abbreviated) hexadecimal notation (\*(R"\f(CW\*(C`::1\*(C'\fR\*(L") or a to-be-resolved hostname (\*(R"\f(CW\*(C`localhost.example.com\*(C'\fR"). \fIport\fR has to be either a decimal port in the range \f(CW1\fR...\f(CW65535\fR or a port name ("\f(CW\*(C`smtp\*(C'\fR"). If \fIport\fR is specified as a name, it is resolved as a \s-1TCP\s0 port by default. To force resolving a \fIport\fR name via a particular protocol, \fIprotocol\fR can be specified as either "\f(CW\*(C`tcp\*(C'\fR\*(L" or \*(R"\f(CW\*(C`udp\*(C'\fR". .Sp The result is stored in \fIsaa\fR on success. .Sp Example: \f(CW\*(C`sa_addr_u2a(saa, "inet://192.168.0.1:smtp");\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_s2a\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, const struct sockaddr *\*(C'\fR\fIsabuf\fR\f(CW\*(C`, socklen_t \*(C'\fR\fIsalen\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_s2a\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, const struct sockaddr *\*(C'\fR\fIsabuf\fR\f(CW\*(C`, socklen_t \*(C'\fR\fIsalen\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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 \f(CW\*(C`struct sockaddr\*(C'\fR object to the corresponding address abstraction. .Sp The accepted addresses for \fIsabuf\fR are: \f(CW\*(C`struct sockaddr_un\*(C'\fR (\f(CW\*(C`AF_LOCAL\*(C'\fR), \f(CW\*(C`struct sockaddr_in\*(C'\fR (\f(CW\*(C`AF_INET\*(C'\fR) and \f(CW\*(C`struct sockaddr_in6\*(C'\fR (\f(CW\*(C`AF_INET6\*(C'\fR). The \fIsalen\fR is the corresponding \&\f(CW\*(C`sizeof(...)\*(C'\fR of the particular underyling structure. .Sp The result is stored in \fIsaa\fR on success. .Sp Example: \f(CW\*(C`sockaddr_in in; sa_addr_s2a(saa, (struct sockaddr *)&in, (socklen_t)sizeof(in));\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_a2u\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, char **\*(C'\fR\fIuri\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_a2u\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, char **\*(C'\fR\fIuri\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_addr_a2u(sa_addr_t *saa, char **uri);" Export an address by converting from the address abstraction to the corresponding \s-1URI\s0 specification. .Sp The result is a string of the form "\f(CW\*(C`unix:\*(C'\fR\fIpath\fR" for \fIUnix Domain\fR addresses and "\f(CW\*(C`inet://\*(C'\fR\fIaddr\fR\f(CW\*(C`:\*(C'\fR\fIport\fR" for \fIInternet Domain\fR addresses. Notice that \fIaddr\fR and \fIport\fR are returned in numerical (unresolved) way. Additionally, because usually one cannot map bidirectionally between \s-1TCP\s0 or \s-1UDP\s0 port names and the numerical value, there is no distinction between \s-1TCP\s0 and \s-1UDP\s0 here. .Sp The result is stored in \fIuri\fR on success. The caller has to \fIfree\fR\|(3) the \fIuri\fR buffer later. .Sp Example: \f(CW\*(C`char *uri; sa_addr_a2u(saa, &uri);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_a2s\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, struct sockaddr **\*(C'\fR\fIsabuf\fR\f(CW\*(C`, socklen_t *\*(C'\fR\fIsalen\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_a2s\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa\fR\f(CW\*(C`, struct sockaddr **\*(C'\fR\fIsabuf\fR\f(CW\*(C`, socklen_t *\*(C'\fR\fIsalen\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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 \f(CW\*(C`struct sockaddr\*(C'\fR object. .Sp The result is one of the following particular underlying address structures: \f(CW\*(C`struct sockaddr_un\*(C'\fR (\f(CW\*(C`AF_LOCAL\*(C'\fR), \f(CW\*(C`struct sockaddr_in\*(C'\fR (\f(CW\*(C`AF_INET\*(C'\fR) and \f(CW\*(C`struct sockaddr_in6\*(C'\fR (\f(CW\*(C`AF_INET6\*(C'\fR). .Sp The result is stored in \fIsabuf\fR and \fIsalen\fR on success. The caller has to \fIfree\fR\|(3) the \fIsabuf\fR buffer later. .Sp Example: \f(CW\*(C`struct sockaddr sabuf, socklen_t salen; sa_addr_a2s(saa, &sa, &salen);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_addr_match\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa1\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIsaa2\fR\f(CW\*(C`, size_t \*(C'\fR\fIprefixlen\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_addr_match\fR\f(CW\*(C`(sa_addr_t *\*(C'\fR\fIsaa1\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIsaa2\fR\f(CW\*(C`, size_t \*(C'\fR\fIprefixlen\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This compares the addresses \fIsaa1\fR and \fIsaa2\fR by only taking the prefix part of length \fIprefixlen\fR into account. \fIprefixlen\fR is number of filesystem path characters for \fIUnix Domain\fR addresses and number of bits for \fIInternet Domain\fR addresses. In case of \fIInternet Domain\fR 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 \fIprefixlen\fR as \f(CW\*(C`\-1\*(C'\fR 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 \fIprefixlen\fR as \f(CW\*(C`\-2\*(C'\fR is equal to \f(CW\*(C`\-1\*(C'\fR but additionally the port is matched, too. .Sp This especially can be used to implement Access Control Lists (\s-1ACL\s0) without having to fiddle around with the underlying representation. For this, make \fIsaa1\fR the to be checked address and \fIsaa2\fR plus \&\fIprefixlen\fR the \s-1ACL\s0 pattern as shown in the following example. .Sp Example: .Sp .Vb 20 \& 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; \& } \& ... \& } \& ... .Ve .Sh "Socket Object Operations" .IX Subsection "Socket Object Operations" This \s-1API\s0 part provides operations for the creation and destruction of socket abstraction \f(CW\*(C`sa_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_create\fR\f(CW\*(C`(sa_t **\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_create\fR\f(CW\*(C`(sa_t **\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_create(sa_t **sa);" Create a socket abstraction object. The object is stored in \fIsa\fR on success. .Sp Example: \f(CW\*(C`sa_t *sa; sa_create(&sa);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_destroy\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_destroy\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_destroy(sa_t *sa);" Destroy a socket abstraction object. The object \fIsa\fR is invalid after this call succeeded. .Sp Example: \f(CW\*(C`sa_destroy(sa);\*(C'\fR .Sh "Socket Parameter Operations" .IX Subsection "Socket Parameter Operations" This \s-1API\s0 part provides operations for parameterizing the socket abstraction \f(CW\*(C`sa_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_type\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_type_t \*(C'\fR\fItype\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_type\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_type_t \*(C'\fR\fItype\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_type(sa_t *sa, sa_type_t type);" Assign a particular communication protocol type to the socket abstraction object. .Sp 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. .Sp Possible values for \fItype\fR are \f(CW\*(C`SA_TYPE_STREAM\*(C'\fR (stream communication) and \f(CW\*(C`SA_TYPE_DATAGRAM\*(C'\fR (datagram communication). The default communication protocol type is \f(CW\*(C`SA_TYPE_STREAM\*(C'\fR. .Sp Example: \f(CW\*(C`sa_type(sa, SA_TYPE_STREAM);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_timeout\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_timeout_t \*(C'\fR\fIid\fR\f(CW\*(C`, long \*(C'\fR\fIsec\fR\f(CW\*(C`, long \*(C'\fR\fIusec\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_timeout\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_timeout_t \*(C'\fR\fIid\fR\f(CW\*(C`, long \*(C'\fR\fIsec\fR\f(CW\*(C`, long \*(C'\fR\fIusec\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp Possible values for \fIid\fR are: \f(CW\*(C`SA_TIMEOUT_ACCEPT\*(C'\fR (affecting \&\fIsa_accept\fR\|(3)), \f(CW\*(C`SA_TIMEOUT_CONNECT\*(C'\fR (affecting \fIsa_connect\fR\|(3)), \&\f(CW\*(C`SA_TIMEOUT_READ\*(C'\fR (affecting \fIsa_read\fR\|(3), \fIsa_readln\fR\|(3) and \fIsa_recv\fR\|(3)) and \f(CW\*(C`SA_TIMEOUT_WRITE\*(C'\fR (affecting \fIsa_write\fR\|(3), \fIsa_writef\fR\|(3), \&\fIsa_send\fR\|(3), and \fIsa_sendf\fR\|(3)). Additionally you can set all four timeouts at once by using \f(CW\*(C`SA_TIMEOUT_ALL\*(C'\fR. The default is that no communication timeouts are used which is equal to \fIsec\fR=\f(CW0\fR/\fIusec\fR=\f(CW0\fR. .Sp Example: \f(CW\*(C`sa_timeout(sa, SA_TIMEOUT_ALL, 30, 0);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_buffer\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_buffer_t \*(C'\fR\fIid\fR\f(CW\*(C`, size_t \*(C'\fR\fIsize\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_buffer\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_buffer_t \*(C'\fR\fIid\fR\f(CW\*(C`, size_t \*(C'\fR\fIsize\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp Possible values for \fIid\fR are: \f(CW\*(C`SA_BUFFER_READ\*(C'\fR (affecting \fIsa_read\fR\|(3) and \fIsa_readln\fR\|(3)) and \f(CW\*(C`SA_BUFFER_WRITE\*(C'\fR (affecting \fIsa_write\fR\|(3) and \&\fIsa_writef\fR\|(3)). The default is that no communication buffers are used which is equal to \fIsize\fR=\f(CW0\fR. .Sp Example: \f(CW\*(C`sa_buffer(sa, SA_BUFFER_READ, 16384);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_option\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_option_t \*(C'\fR\fIid\fR\f(CW\*(C`, ...);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_option\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_option_t \*(C'\fR\fIid\fR\f(CW\*(C`, ...);\*(C'\fR" 4 .IX Item "sa_rc_t sa_option(sa_t *sa, sa_option_t id, ...);" Adjust various options of the socket abstraction object. .Sp The adjusted option is controlled by \fIid\fR. 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): .Sp \&\f(CW\*(C`SA_OPTION_NAGLE\*(C'\fR (\f(CW\*(C`int\*(C'\fR \fIyesno\fR) for enabling (\fIyesno\fR=\f(CW1\fR) or disabling (\fIyesno\fR == \f(CW0\fR) Nagle's Algorithm (see \s-1RFC898\s0 and \&\f(CW\*(C`TCP_NODELAY\*(C'\fR of \fIsetsockopt\fR\|(2)). .Sp \&\f(CW\*(C`SA_OPTION_LINGER\*(C'\fR (\f(CW\*(C`int\*(C'\fR \fIamount\fR) for enabling (\fIamount\fR == \&\fIseconds\fR != \f(CW0\fR) or disabling (\fIamount\fR == \f(CW0\fR) lingering on close (see \f(CW\*(C`SO_LINGER\*(C'\fR of \fIsetsockopt\fR\|(2)). Notice: using \fIseconds\fR > \f(CW0\fR results in a regular (maximum of \fIseconds\fR lasting) lingering on close while using \fIseconds\fR < \f(CW0\fR results in the special case of a \s-1TCP\s0 \&\s-1RST\s0 based connection termination on close. .Sp \&\f(CW\*(C`SA_OPTION_REUSEADDR\*(C'\fR (\f(CW\*(C`int\*(C'\fR \fIyesno\fR) for enabling (\fIyesno\fR == \&\f(CW1\fR) or disabling (\fIyesno\fR == \f(CW0\fR) the reusability of the address on binding via \fIsa_bind\fR\|(3) (see \f(CW\*(C`SO_REUSEADDR\*(C'\fR of \fIsetsockopt\fR\|(2)). .Sp \&\f(CW\*(C`SA_OPTION_REUSEPORT\*(C'\fR (\f(CW\*(C`int\*(C'\fR \fIyesno\fR) for enabling (\fIyesno\fR == \f(CW1\fR) or disabling (\fIyesno\fR == \f(CW0\fR) the reusability of the port on binding via \fIsa_bind\fR\|(3) (see \f(CW\*(C`SO_REUSEPORT\*(C'\fR of \fIsetsockopt\fR\|(2)). .Sp \&\f(CW\*(C`SA_OPTION_NONBLOCK\*(C'\fR (\f(CW\*(C`int\*(C'\fR \fIyesno\fR) for enabling (\fIyesno\fR == \f(CW1\fR) or disabling (\fIyesno\fR == \f(CW0\fR) non-blocking I/O mode (see \f(CW\*(C`O_NONBLOCK\*(C'\fR of \fIfcntl\fR\|(2)). .Sp Example: \f(CW\*(C`sa_option(sa, SA_OPTION_NONBLOCK, 1);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_syscall\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_syscall_t \*(C'\fR\fIid\fR\f(CW\*(C`, void (*\*(C'\fR\fIfptr\fR\f(CW\*(C`)(), void *\*(C'\fR\fIfctx\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_syscall\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_syscall_t \*(C'\fR\fIid\fR\f(CW\*(C`, void (*\*(C'\fR\fIfptr\fR\f(CW\*(C`)(), void *\*(C'\fR\fIfctx\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This allows you to override mostly all I/O related system calls \fB\s-1OSSP\s0 sa\fR internally performs while communicating. This can be used to adapt \&\fB\s-1OSSP\s0 sa\fR 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 \&\fB\s-1GNU\s0 Pth\fR. .Sp The function supplied as \fIfptr\fR is required to fulfill the \s-1API\s0 of the replaced system call, i.e., it has to have the same prototype (if \&\fIfctx\fR is \f(CW\*(C`NULL\*(C'\fR). If \fIfctx\fR is not \f(CW\*(C`NULL\*(C'\fR, this prototype has to be extended to accept an additional first argument of type \f(CW\*(C`void *\*(C'\fR which receives the value of \fIfctx\fR. It is up to the callback function whether to pass the call through to the replaced actual system call or not. .Sp Possible values for \fIid\fR are (expected prototypes behind \fIfptr\fR are given in parenthesis): .Sp \&\fB\s-1SA_SYSCALL_CONNECT\s0\fR: "\f(CW\*(C`int (*)([void *,] int, const struct sockaddr *, socklen_t)\*(C'\fR", see \fIconnect\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_ACCEPT\s0\fR: "\f(CW\*(C`int (*)([void *,] int, struct sockaddr *, socklen_t *)\*(C'\fR", see \fIaccept\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_SELECT\s0\fR: "\f(CW\*(C`int (*)([void *,] int, fd_set *, fd_set *, fd_set *, struct timeval *)\*(C'\fR", see \fIselect\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_READ\s0\fR: "\f(CW\*(C`ssize_t (*)([void *,] int, void *, size_t)\*(C'\fR", see \&\fIread\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_WRITE\s0\fR: "\f(CW\*(C`ssize_t (*)([void *,] int, const void *, size_t)\*(C'\fR", see \fIwrite\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_RECVFROM\s0\fR: "\f(CW\*(C`ssize_t (*)([void *,] int, void *, size_t, int, struct sockaddr *, socklen_t *)\*(C'\fR", see \fIrecvfrom\fR\|(2). .Sp \&\fB\s-1SA_SYSCALL_SENDTO\s0\fR: "\f(CW\*(C`ssize_t (*)([void *,] int, const void *, size_t, int, const struct sockaddr *, socklen_t)\*(C'\fR", see \fIsendto\fR\|(2). .Sp Example: .Sp .Vb 6 \& ssize_t \& trace_read(void *ctx, int fd, void *buf, size_t len) \& { \& FILE *fp = (FILE *)ctx; \& ssize_t rv; \& int errno_saved; .Ve .Sp .Vb 7 \& rv = read(fd, buf, len); \& errno_saved = errno; \& fprintf(fp, "read(%d, %lx, %d) = %d\en", \& fd, (long)buf, len, rv); \& errno = errno_saved; \& return rv; \& } .Ve .Sp .Vb 4 \& ... \& FILE *trace_fp = ...; \& sa_syscall(sa, SA_SC_READ, trace_read, trace_fp); \& ... .Ve .Sh "Socket Connection Operations" .IX Subsection "Socket Connection Operations" This \s-1API\s0 part provides connection operations for stream-oriented data communication through the socket abstraction \f(CW\*(C`sa_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_bind\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIladdr\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_bind\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIladdr\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_bind(sa_t *sa, sa_addr_t *laddr);" Bind socket abstraction object to a local protocol address. .Sp This assigns the local protocol address \fIladdr\fR. When a socket is created, it exists in an address family space but has no protocol address assigned. This call requests that \fIladdr\fR be used as the local address. For servers this is the address they later listen on (see \&\fIsa_listen\fR\|(3)) for incoming connections, for clients this is the address used for outgoing connections (see \fIsa_connect\fR\|(3)). Internally this directly maps to \fIbind\fR\|(2). .Sp Example: \f(CW\*(C`sa_bind(sa, laddr);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_connect\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_connect\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_connect(sa_t *sa, sa_addr_t *raddr);" Initiate an outgoing connection on a socket abstraction object. .Sp This performs a connect to the remote address \fIraddr\fR. If the socket is of type \f(CW\*(C`SA_TYPE_DATAGRAM\*(C'\fR, 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 \f(CW\*(C`SA_TYPE_STREAM\*(C'\fR, this call attempts to make a connection to the remote socket. Internally this directly maps to \fIconnect\fR\|(2). .Sp Example: \f(CW\*(C`sa_connect(sa, raddr);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_listen\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, int \*(C'\fR\fIbacklog\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_listen\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, int \*(C'\fR\fIbacklog\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_listen(sa_t *sa, int backlog);" Listen for incoming connections on a socket abstraction object. .Sp A willingness to accept incoming connections and a queue limit for incoming connections are specified by this call. The \fIbacklog\fR argument defines the maximum length the queue of pending connections may grow to. Internally this directly maps to \fIlisten\fR\|(2). .Sp Example: \f(CW\*(C`sa_listen(sa, 128);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_accept\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIcaddr\fR\f(CW\*(C`, sa_t **\*(C'\fR\fIcsa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_accept\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIcaddr\fR\f(CW\*(C`, sa_t **\*(C'\fR\fIcsa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_accept(sa_t *sa, sa_addr_t **caddr, sa_t **csa);" Accept incoming connection on a socket abstraction object. .Sp 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 \fIcsa\fR) and a new socket address abstraction object (returned in \fIcaddr\fR) 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. .Sp Example: .Sp .Vb 6 \& sa_addr_t *clt_saa; \& sa_t *clt_sa; \& ... \& while (sa_accept(srv_sa, &clt_saa, &clt_sa) == SA_OK) { \& ... \& } .Ve .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_getremote\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIraddr\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_getremote\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIraddr\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_getremote(sa_t *sa, sa_addr_t **raddr);" Get address abstraction of remote side of communication. .Sp This determines the address of the communication peer and creates a new socket address abstraction object (returned in \fIraddr\fR) describing the peer address. The application has to destroy \fIraddr\fR later with \&\fIsa_addr_destroy\fR\|(3). Internally this maps to \fIgetpeername\fR\|(2). .Sp Example: \f(CW\*(C`sa_addr_t *raddr; sa_getremote(sa, &raddr);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_getlocal\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIladdr\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_getlocal\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIladdr\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_getlocal(sa_t *sa, sa_addr_t **laddr);" Get address abstraction of local side of communication. .Sp This determines the address of the local communication side and creates a new socket address abstraction object (returned in \fIladdr\fR) describing the local address. The application has to destroy \fIladdr\fR later with \fIsa_addr_destroy\fR\|(3). Internally this maps to \fIgetsockname\fR\|(2). .Sp Example: \f(CW\*(C`sa_addr_t *laddr; sa_getlocal(sa, &laddr);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_shutdown\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIflags\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_shutdown\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIflags\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_shutdown(sa_t *sa, char *flags);" Shut down part of the full-duplex connection. .Sp This performs a shut down of the connection described in \fIsa\fR. The flags string can be either "\f(CW\*(C`r\*(C'\fR\*(L" (indicating the read channel of the communication is shut down only), \*(R"\f(CW\*(C`w\*(C'\fR\*(L" (indicating the write channel of the communication is shut down only), or \*(R"\f(CW\*(C`rw\*(C'\fR" (indicating both the read and write channels of the communication are shut down). Internally this directly maps to \fIshutdown\fR\|(2). .Sp Example: \f(CW\*(C`sa_shutdown(sa, "w");\*(C'\fR .Sh "Socket Input/Output Operations (Stream Communication)" .IX Subsection "Socket Input/Output Operations (Stream Communication)" This \s-1API\s0 part provides I/O operations for stream-oriented data communication through the socket abstraction \f(CW\*(C`sa_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_getfd\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, int *\*(C'\fR\fIfd\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_getfd\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, int *\*(C'\fR\fIfd\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_getfd(sa_t *sa, int *fd);" Get underlying socket filedescriptor. .Sp This peeks into the underlying socket filedescriptor \fB\s-1OSSP\s0 sa\fR allocated internally for the communication. This can be used for adjusting the socket communication (via \fIfcntl\fR\|(2), \fIsetsockopt\fR\|(2), etc) directly. .Sp 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 \fB\s-1OSSP\s0 sa\fR and this way can leads to nasty side\-effects. .Sp Example: \f(CW\*(C`int fd; sa_getfd(sa, &fd);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_read\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_read\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This reads from the socket (optionally through the internal read buffer) up to a maximum of \fIbuflen\fR bytes into buffer \fIbuf\fR. The actual number of read bytes is stored in \fIbufdone\fR. This internally maps to \fIread\fR\|(2). .Sp Example: \f(CW\*(C`char buf[1024]; size_t n; sa_read(sa, buf, sizeof(buf), &n);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_readln\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_readln\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This reads from the socket (optionally through the internal read buffer) up to a maximum of \fIbuflen\fR bytes into buffer \fIbuf\fR, 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 \f(CW\*(C`NUL\*(C'\fR character ('\f(CW\*(C`\e0\*(C'\fR'), too. The actual number of read bytes is stored in \fIbufdone\fR. This internally maps to \&\fIsa_read\fR\|(3). .Sp Keep in mind that for efficiency reasons, line-oriented I/O usually always should be performed with read buffer (see \fIsa_option\fR\|(3) and \&\f(CW\*(C`SA_BUFFER_READ\*(C'\fR). Without such a read buffer, the performance is cruel, because single character \fIread\fR\|(2) operations would be performed on the underlying socket. .Sp Example: \f(CW\*(C`char buf[1024]; size_t n; sa_readln(sa, buf, sizeof(buf), &n);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_write\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, const char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_write\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, const char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This writes to the socket (optionally through the internal write buffer) \&\fIbuflen\fR bytes from buffer \fIbuf\fR. In case of a partial write, the actual number of written bytes is stored in \fIbufdone\fR. This internally maps to \fIwrite\fR\|(2). .Sp Example: \f(CW\*(C`sa_write(sa, cp, strlen(cp), NULL);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_writef\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, const char *\*(C'\fR\fIfmt\fR\f(CW\*(C`, ...);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_writef\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, const char *\*(C'\fR\fIfmt\fR\f(CW\*(C`, ...);\*(C'\fR" 4 .IX Item "sa_rc_t sa_writef(sa_t *sa, const char *fmt, ...);" Write formatted data data to socket. .Sp This formats a string according to the \fIprintf\fR\|(3)\-style format specification \fIfmt\fR 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 \fIsa_option\fR\|(3) and \f(CW\*(C`SA_BUFFER_WRITE\*(C'\fR). This internally maps to \&\fIsa_write\fR\|(3). .Sp The underlying string formatting engine is just a minimal one and for security and independence reasons intentionally not directly based on s[n]\fIprintf\fR\|(3). It understands only the following format specifications: "\f(CW\*(C`%%\*(C'\fR\*(L", \*(R"\f(CW%c\fR" (\f(CW\*(C`char\*(C'\fR), "\f(CW%s\fR" (\f(CW\*(C`char *\*(C'\fR) and "\f(CW%d\fR" (\f(CW\*(C`int\*(C'\fR) 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]\fIprintf\fR\|(3) and then write this to the socket via \fIsa_write\fR\|(3) instead. .Sp Example: \f(CW\*(C`sa_writef(sa, "%s=%d\en", cp, i);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_flush\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_flush\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "sa_rc_t sa_flush(sa_t *sa);" Flush still pending outgoing data to socket. .Sp This writes all still pending outgoing data for the internal write buffer (see \fIsa_option\fR\|(3) and \f(CW\*(C`SA_BUFFER_WRITE\*(C'\fR) to the socket. This internally maps to \fIwrite\fR\|(2). .Sp Example: \f(CW\*(C`sa_flush(sa);\*(C'\fR .Sh "Socket Input/Output Operations (Datagram Communication)" .IX Subsection "Socket Input/Output Operations (Datagram Communication)" This \s-1API\s0 part provides I/O operations for datagram-oriented data communication through the socket abstraction \f(CW\*(C`sa_t\*(C'\fR. .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_recv\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIraddr\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_recv\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t **\*(C'\fR\fIraddr\fR\f(CW\*(C`, char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This receives from the remote address specified in \fIraddr\fR via the socket up to a maximum of \fIbuflen\fR bytes into buffer \fIbuf\fR. The actual number of received bytes is stored in \fIbufdone\fR. This internally maps to \fIrecvfrom\fR\|(2). .Sp Example: \f(CW\*(C`char buf[1024]; size_t n; sa_recv(sa, buf, sizeof(buf), &n, saa);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_send\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`, const char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_send\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`, const char *\*(C'\fR\fIbuf\fR\f(CW\*(C`, size_t \*(C'\fR\fIbuflen\fR\f(CW\*(C`, size_t *\*(C'\fR\fIbufdone\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "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. .Sp This sends to the remote address specified in \fIraddr\fR via the socket \&\fIbuflen\fR bytes from buffer \fIbuf\fR. The actual number of sent bytes is stored in \fIbufdone\fR. This internally maps to \fIsendto\fR\|(2). .Sp Example: \f(CW\*(C`sa_send(sa, buf, strlen(buf), NULL, saa);\*(C'\fR .ie n .IP "\*(C`sa_rc_t \*(C'\fR\fBsa_sendf\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`, const char *\*(C'\fR\fIfmt\fR\f(CW\*(C`, ...);\*(C'" 4 .el .IP "\f(CW\*(C`sa_rc_t \*(C'\fR\fBsa_sendf\fR\f(CW\*(C`(sa_t *\*(C'\fR\fIsa\fR\f(CW\*(C`, sa_addr_t *\*(C'\fR\fIraddr\fR\f(CW\*(C`, const char *\*(C'\fR\fIfmt\fR\f(CW\*(C`, ...);\*(C'\fR" 4 .IX Item "sa_rc_t sa_sendf(sa_t *sa, sa_addr_t *raddr, const char *fmt, ...);" Send formatted data data to remote address via socket. .Sp This formats a string according to the \fIprintf\fR\|(3)\-style format specification \fIfmt\fR 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. .Sp The underlying string formatting engine is just a minimal one and for security and independence reasons intentionally not directly based on s[n]\fIprintf\fR\|(3). It understands only the following format specifications: "\f(CW\*(C`%%\*(C'\fR\*(L", \*(R"\f(CW%c\fR" (\f(CW\*(C`char\*(C'\fR), "\f(CW%s\fR" (\f(CW\*(C`char *\*(C'\fR) and "\f(CW%d\fR" (\f(CW\*(C`int\*(C'\fR) 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]\fIprintf\fR\|(3) and then send this to the remote address via \fIsa_send\fR\|(3) instead. .Sp Example: \f(CW\*(C`sa_sendf(sa, saa, "%s=%d\en", cp, i);\*(C'\fR .Sh "Socket Error Handling" .IX Subsection "Socket Error Handling" This \s-1API\s0 part provides error handling operations only. .ie n .IP "\*(C`char *\*(C'\fR\fBsa_error\fR\f(CW\*(C`(sa_rc_t \*(C'\fR\fIrv\fR\f(CW\*(C`);\*(C'" 4 .el .IP "\f(CW\*(C`char *\*(C'\fR\fBsa_error\fR\f(CW\*(C`(sa_rc_t \*(C'\fR\fIrv\fR\f(CW\*(C`);\*(C'\fR" 4 .IX Item "char *sa_error(sa_rc_t rv);" Return the string representation corresponding to the return code value \fIrv\fR. The returned string has to be treated read-only by the application and is not required to be deallocated. .SH "SEE ALSO" .IX Header "SEE ALSO" .Sh "Standards" .IX Subsection "Standards" R. Gilligan, S. Thomson, J. Bound, W. Stevens: \&\fI\*(L"Basic Socket Interface Extensions for IPv6\*(R"\fR, \&\fB\s-1RFC\s0 2553\fR, March 1999. .PP W. Stevens: \&\fI\*(L"Advanced Sockets \s-1API\s0 for IPv6\*(R"\fR, \&\fB\s-1RFC\s0 2292\fR, February 1998. .PP R. Fielding, L. Masinter, T. Berners\-Lee: \&\fI\*(L"Uniform Resource Identifiers: Generic Syntax\*(R"\fR, \&\fB\s-1RFC\s0 2396\fR, August 1998. .PP R. Hinden, S. Deering: \&\fI\*(L"\s-1IP\s0 Version 6 Addressing Architecture\*(R"\fR, \&\fB\s-1RFC\s0 2373\fR, July 1998. .PP R. Hinden, B. Carpenter, L. Masinter: \&\fI\*(L"Format for Literal IPv6 Addresses in \s-1URL\s0's\*(R"\fR, \&\fB\s-1RFC\s0 2732\fR, December 1999. .Sh "Papers" .IX Subsection "Papers" Stuart Sechrest: \&\fI\*(L"An Introductory 4.4BSD Interprocess Communication Tutorial\*(R"\fR, FreeBSD 4.4 (/usr/share/doc/psd/20.ipctut/). .PP Samuel J. Leffler, Robert S. Fabry, William N. Joy, Phil Lapsley: \&\fI\*(L"An Advanced 4.4BSD Interprocess Communication Tutorial\*(R"\fR, FreeBSD 4.4 (/usr/share/doc/psd/21.ipc/). .PP Craig Metz: \&\fI\*(L"Protocol Independence Using the Sockets \s-1API\s0\*(R"\fR, http://www.usenix.org/publications/library/proceedings/usenix2000/freenix/metzprotocol.html, \&\s-1USENIX\s0 Annual Technical Conference, June 2000. .Sh "Manual Pages" .IX Subsection "Manual Pages" \&\fIsocket\fR\|(2), \&\fIaccept\fR\|(2), \&\fIbind\fR\|(2), \&\fIconnect\fR\|(2), \&\fIgetpeername\fR\|(2), \&\fIgetsockname\fR\|(2), \&\fIgetsockopt\fR\|(2), \&\fIioctl\fR\|(2), \&\fIlisten\fR\|(2), \&\fIread\fR\|(2), \&\fIrecv\fR\|(2), \&\fIselect\fR\|(2), \&\fIsend\fR\|(2), \&\fIshutdown\fR\|(2), \&\fIsocketpair\fR\|(2), \&\fIwrite\fR\|(2), \&\fIgetprotoent\fR\|(3), \&\fIprotocols\fR\|(4). .SH "HISTORY" .IX Header "HISTORY" \&\fB\s-1OSSP\s0 sa\fR was invented in August 2001 by Ralf S. Engelschall under contract with Cable & Wireless for use inside the \s-1OSSP\s0 project. Its creation was prompted by the requirement to implement an \s-1SMTP\s0 logging channel for the \fB\s-1OSSP\s0 l2\fR library. Its initial code was derived from a predecessor sub-library originally written for socket address abstraction inside the \fB\s-1OSSP\s0 lmtp2nntp\fR tool. .SH "AUTHOR" .IX Header "AUTHOR" .Vb 3 \& Ralf S. Engelschall \& rse@engelschall.com \& www.engelschall.com .Ve