mirror of
https://github.com/NishiOwO/ircservices5.git
synced 2025-04-21 16:54:38 +00:00
1015 lines
52 KiB
HTML
1015 lines
52 KiB
HTML
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Style-Type" content="text/css"/>
|
|
<style type="text/css">@import "style.css";</style>
|
|
<title>IRC Services Technical Reference Manual - 3. Communication (socket) handling</title>
|
|
</head>
|
|
|
|
<body>
|
|
<h1 class="title" id="top">IRC Services Technical Reference Manual</h1>
|
|
|
|
<h2 class="section-title">3. Communication (socket) handling</h2>
|
|
|
|
<p class="section-toc">
|
|
3-1. <a href="#s1">Overview</a>
|
|
<br/>3-2. <a href="#s2">Creating, configuring, and destroying sockets</a>
|
|
<br/> 3-2-1. <a href="#s2-1">Interface routines</a>
|
|
<br/> 3-2-2. <a href="#s2-2">Socket callbacks</a>
|
|
<br/>3-3. <a href="#s3">Establishing and breaking connections</a>
|
|
<br/> 3-3-1. <a href="#s3-1">Outgoing connections</a>
|
|
<br/> 3-3-2. <a href="#s3-2">Incoming connections</a>
|
|
<br/> 3-3-3. <a href="#s3-2">Disconnecting</a>
|
|
<br/>3-4. <a href="#s4">Sending and receiving data</a>
|
|
<br/> 3-4-1. <a href="#s4-1">Sending data</a>
|
|
<br/> 3-4-2. <a href="#s4-2">Receiving data</a>
|
|
<br/> 3-4-3. <a href="#s4-3">Muting sockets</a>
|
|
<br/>3-5. <a href="#s5">Retrieving socket information</a>
|
|
<br/>3-6. <a href="#s6">The socket polling routine</a>
|
|
</p>
|
|
|
|
<p class="backlink"><a href="2.html">Previous section: Core Services functionality</a> |
|
|
<a href="index.html">Table of Contents</a> |
|
|
<a href="4.html">Next section: The module system</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s1">3-1. Overview</h3>
|
|
|
|
<p>In Services, all network communication is performed through the socket
|
|
subsystem, defined in the files <tt>sockets.c</tt> and <tt>sockets.h</tt>.
|
|
This subsystem provides routines for managing sockets, which have a type of
|
|
<tt>Socket *</tt>, connecting to or accepting connections from the
|
|
network, and sending and receiving data.</p>
|
|
|
|
<p>All network communication in Services is performed asynchronously. Send
|
|
(write) operations buffer the data given and return immediately; receive
|
|
(read) operations are performed via <i>callbacks</i>, functions called by
|
|
the central polling routine when particular events occur, and the actual
|
|
reading routines operate on a read buffer which is filled by the polling
|
|
routine as data is received from the remote host. The polling routine
|
|
itself is called by the Services main loop.</p>
|
|
|
|
<p>The socket subsystem is designed so that it can be used in other
|
|
programs as well with minimal changes. (In fact, I currently use it in the
|
|
HTTP server I wrote for my personal domain.) Note, however, that only TCP
|
|
connections over IPv4 are supported. The socket subsystem uses the
|
|
following functions from other Services source files, so replacements or
|
|
stubs will need to be provided: <tt>log()</tt>, <tt>log_perror()</tt>,
|
|
<tt>log_debug()</tt>, <tt>log_perror_debug()</tt>, <tt>pack_ip()</tt>.</p>
|
|
|
|
<p>Below, <a href="#s2">section 3-2</a> discusses the creation and
|
|
management of socket objects, including a list of callbacks;
|
|
<a href="#s3">section 3</a> discusses connecting to (and listening for
|
|
connections from) remote hosts; <a href="#s4">section 3-4</a> discusses
|
|
sending and receiving data; <a href="#s5">section 3-5</a> discusses
|
|
functions for retrieving information about sockets; and
|
|
<a href="#s6">section 3-6</a> discusses the socket polling routine in
|
|
detail.</p>
|
|
|
|
<p>All socket routines which can fail return a valid error code in the
|
|
system variable <tt>errno</tt> on failure. The error codes returned are
|
|
generally the same as those returned by the equivalent system calls or
|
|
standard library functions; special note of particular error codes is
|
|
included where appropriate.</p>
|
|
|
|
<p>There are a few preprocessor constants and macros used in the source
|
|
that are worth mentioning:</p>
|
|
|
|
<dl>
|
|
<dt><tt><b>SOCK_MIN_BUFSIZE</b></tt></dt>
|
|
<dd>Sets both the minimum socket buffer size and the increment by which
|
|
the buffer size is increased when necessary. Defined in
|
|
<tt>sockets.h</tt>.</dd>
|
|
|
|
<dt><tt><b>WARN_ON_BUFSIZE</b></tt></dt>
|
|
<dd>If defined, causes a warning message to be logged when a socket's
|
|
read or write buffer cannot be expanded due to the per-connection
|
|
or total buffer size limit (as set by <tt>sock_set_buflimits()</tt>).
|
|
Only one warning is logged per socket. Optionally defined in
|
|
<tt>sockets.c</tt>.</dd>
|
|
|
|
<dt><tt><b>DISABLE_SWRITEMAP</b></tt></dt>
|
|
<dd>If defined, disables the <tt>swritemap()</tt> function (see
|
|
<a href="#s4">section 3-4</a>), removing a dependency on the
|
|
<tt>munmap()</tt> system call and the <tt>sys/mman.h</tt> header
|
|
file. Optionally defined in <tt>sockets.c</tt>.</dd>
|
|
|
|
<dt><tt><b>TRACE_CALLS</b></tt></dt>
|
|
<dd>If defined, enables tracing of function calls (entry and exit) via
|
|
<tt>log_debug()</tt>. Optionally defined in <tt>sockets.c</tt>.</dd>
|
|
|
|
<dt><tt><b>ENTER</b>(<i>fmt</i>,...)</tt>
|
|
<br/><tt><b>ENTER_WITH</b>(<i>retfmt</i>, <i>fmt</i>,...)</tt></dt>
|
|
<dd>Used in function call tracing to log entry to a function, along
|
|
with the values of any parameters. <tt><i>fmt</i></tt> is a
|
|
<tt>printf()</tt>-style format string (which must be a string
|
|
literal) for formatting the function parameter values (passed as
|
|
extra parameters to the macro), and should cause each parameter to
|
|
be written in an appropriate format separated by commas.
|
|
<tt>ENTER_WITH()</tt> is used for functions which return a value,
|
|
and takes an extra parameter, <tt><i>retfmt</i></tt>, which is the
|
|
format string to use to display the return value, such as
|
|
<tt>"%d"</tt> or <tt>"%p"</tt> (the parameter is passed here to
|
|
avoid having to include it at every return point). These macros
|
|
do nothing if function call tracing is not enabled. Defined in
|
|
<tt>sockets.c</tt>.</dd>
|
|
|
|
<dt><tt><b>RETURN</b></tt>
|
|
<br/><tt><b>RETURN_WITH</b>(<i>val</i>)</tt></dt>
|
|
<dd>Used in function tracing to log exit from a function (and
|
|
perform the <tt>return</tt> as well). <tt>RETURN</tt> is used for
|
|
<tt>void</tt> functions, while <tt>RETURN_WITH()</tt> is used for
|
|
functions that return a value. If function call tracing is not
|
|
enabled, these macros simply perform a <tt>return</tt>. Defined in
|
|
<tt>sockets.c</tt>.</dd>
|
|
</dl>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s2">3-2. Creating, configuring, and destroying sockets</h3>
|
|
|
|
<p>Before any other operations can be performed, a socket object must be
|
|
created, either explicitly or by accepting a connection from a listener
|
|
socket (see <a href="#s3-2">section 3-3-2</a>. Socket objects are the
|
|
means by which the socket subsystem keeps track of sockets, and are used
|
|
in place of system socket descriptors with all relevant functions.</p>
|
|
|
|
<p>Before actually establishing a connection, certain aspects of socket
|
|
behavior can be configured. In particular, it is important to set up
|
|
proper callback routines (see <a href="#s2-2">section 3-2-2</a>) or you
|
|
will be unable to do anything useful with the socket! Sockets can also be
|
|
set to be blocking (applying only to write operations occurring then the
|
|
write buffer is full), and a write timeout can be set, causing the socket
|
|
to be automatically disconnected if a certain amount of time passes without
|
|
being able to send any data to the remote host. All configuration routines
|
|
can be called regardless of whether the socket is connected or not.</p>
|
|
|
|
<p>When a socket object is no longer needed, it should be destroyed in
|
|
order to free resources used by the socket. If a connected socket is
|
|
destroyed, it is automatically disconnected first.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s2-1">3-2-1. Interface routines</h4>
|
|
|
|
<p>The following routines are used for creating, configuring, and
|
|
destroying sockets:</p>
|
|
|
|
<dl>
|
|
<dt><tt>Socket *sock_new()</tt></dt>
|
|
<dd>Creates and returns a new, unconnected socket object. The socket
|
|
has no callbacks associated with it, and defaults to no write
|
|
timeout and non-blocking mode. The socket's internal read and
|
|
write buffers are each created with a size of
|
|
<tt>SOCK_MIN_BUFSIZE</tt> bytes.</dd>
|
|
|
|
<dt><tt>void sock_setcb(Socket *<i>s</i>, SocketCallbackID <i>which</i>,
|
|
SocketCallback <i>func</i>)</tt></dt>
|
|
<dd>Sets the function for the callback event selected by
|
|
<tt><i>which</i></tt> (one of the <tt>SCB_*</tt> constants) to the
|
|
function <tt><i>func</i></tt> for the given socket. If
|
|
<tt><i>func</i></tt> is <tt>NULL</tt>, then no function will be
|
|
called for the selected callback event.</dd>
|
|
|
|
<dt><tt>sock_set_wto(Socket *<i>s</i>, int <i>seconds</i>)</tt></dt>
|
|
<dd>Sets the write timeout for the given socket to
|
|
<tt><i>seconds</i></tt> seconds. If data is buffered for sending
|
|
and no data can be sent within the specified interval, the socket
|
|
will automatically be disconnected, as if the remote host had
|
|
closed the connection. A value of zero for <tt><i>seconds</i></tt>
|
|
clears the timeout, allowing data to be buffered indefinitely.</dd>
|
|
|
|
<dt><tt>sock_set_blocking(Socket *<i>s</i>, int <i>blocking</i>)</tt></dt>
|
|
<dd>Sets whether write operations should block or return an error
|
|
(<tt>EAGAIN</tt>) if no buffer space is available for data passed
|
|
to one of the send routines and the remote host is not ready to
|
|
accept more data. Note that if sufficient buffer space is
|
|
available, write operations will always return immediately
|
|
regardless of this setting.</dd>
|
|
|
|
<dt><tt>void sock_free(Socket *<i>s</i>)</tt></dt>
|
|
<dd>Destroys the given socket, freeing all resources used by the
|
|
socket. If the socket is connected to a remote host, the
|
|
connection is automatically terminated, as if <tt>disconn()</tt>
|
|
(see <a href="#s3-3">section 3-3-3</a>) had been called.</dd>
|
|
</dl>
|
|
|
|
<p>There are two other routines which operate on the socket subsystem as a
|
|
whole, rather then on a particular socket:</p>
|
|
|
|
<dl>
|
|
<dt><tt>sock_set_buflimits(uint32 <i>per_conn</i>, uint32 <i>total</i>)</tt></dt>
|
|
<dd>Sets the maximum combined send and receive buffer size allowed for
|
|
a single socket (first parameter) and for all sockets as a whole
|
|
(second parameter), in bytes. Any data that arrives when one of
|
|
these limits has been reached will not be received until buffer
|
|
space becomes available; any send operations performed will fail if
|
|
no space is available. A value of zero for either parameter
|
|
disables the respective limit; any other value is rounded down to a
|
|
multiple of <tt>SOCK_MIN_BUFSIZE</tt> (values smaller than
|
|
<tt>SOCK_MIN_BUFSIZE</tt> are rounded up).</dd>
|
|
|
|
<dt><tt>sock_set_rto(int <i>msec</i>)</tt></dt>
|
|
<dd>Sets the read timeout used by the socket polling routine, in
|
|
milliseconds. If no socket activity occurs during this interval,
|
|
the polling routine will return control to its caller. Zero is a
|
|
valid value, and tells the polling routine to return immediately if
|
|
no data has been received by the system. A negative value disables
|
|
the timeout, causing the polling routine to wait indefinitely for
|
|
socket activity.</dd>
|
|
</dl>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s2-2">3-2-2. Socket callbacks</h4>
|
|
|
|
<p>As mentioned above, the socket subsystem makes use of <i>callbacks</i>
|
|
for socket activity processing. Rather than having the caller code
|
|
explicitly read from the socket, potentially blocking if no data is
|
|
available, a polling routine (discussed in <a href="#s6">section 3-6</a>)
|
|
monitors all sockets for activity, "calling back" to the caller when
|
|
certain events occur. The functions to be called for each event can be
|
|
set independently for each socket, using the aforementioned
|
|
<tt>sock_setcb()</tt> routine; events to which no function is assigned
|
|
(the default state) are ignored. Two parameters are passed to the callback
|
|
function: a <tt>Socket *</tt> parameter indicating the socket on which
|
|
the event occured, and a <tt>void *</tt> parameter whose meaning
|
|
depends on the particular callback (some callbacks do not use it at all).
|
|
The exact callback function signature is:</p>
|
|
|
|
<div class="code">void <i>callback</i>(Socket *<i>s</i>, void *<i>param</i>)</div>
|
|
|
|
<p>This type (a pointer to it, rather) is defined as <tt>SocketCallback</tt>
|
|
in <tt>sockets.h</tt>.</p>
|
|
|
|
<p>The following events (listed by the name of the constant used as the
|
|
<tt><i>which</i></tt> parameter to <tt>sock_setcb()</tt>) can have callback
|
|
functions attached to them:</p>
|
|
|
|
<dl>
|
|
<dt><tt><b>SCB_CONNECT</b></tt></dt>
|
|
<dd>Called when a connection initiated by calling the <tt>conn()</tt>
|
|
routine (see <a href="#s3-1">section 3-3-1</a>) completes
|
|
successfully. The <tt>void *</tt> parameter is not used.</dd>
|
|
|
|
<dt><tt><b>SCB_DISCONNECT</b></tt></dt>
|
|
<dd>Called when an existing connection is broken, either by the remote
|
|
host or by calling the <tt>disconn()</tt> routine (see
|
|
<a href="#s3-3">section 3-3-3</a>), or when a connection initiated
|
|
by calling the <tt>conn()</tt> routine fails. The
|
|
<tt>void *</tt> parameter indicates the type of disconnection:
|
|
<ul><li><b><tt>DISCONN_LOCAL</tt>:</b> The connection was broken
|
|
locally by calling the <tt>disconn()</tt> routine.</li>
|
|
<li><b><tt>DISCONN_REMOTE</tt>:</b> The connection was broken
|
|
by the remote host.</li>
|
|
<li><b><tt>DISCONN_CONNFAIL</tt>:</b> The connection attempt
|
|
was rejected by the remote host or otherwise failed.</li></ul>
|
|
For remote disconnection events (<tt>DISCONN_REMOTE</tt> and
|
|
<tt>DISCONN_CONNFAIL</tt>), the global <tt>errno</tt> variable
|
|
indicates the cause of the disconnection if known, zero
|
|
otherwise.</dd>
|
|
|
|
<dt><tt><b>SCB_ACCEPT</b></tt></dt>
|
|
<dd>Called when a remote host connects to a listener socket (see
|
|
<a href="#s3-2">section 3-3-2</a>). The primary socket parameter
|
|
to the callback is the listener socket, and the
|
|
<tt>void *</tt> parameter is the newly-created socket (of type
|
|
<tt>Socket *</tt>). Note that listener sockets will
|
|
immediately drop all incoming connections if no function is
|
|
assigned to this callback.</dd>
|
|
|
|
<dt><tt><b>SCB_READ</b></tt></dt>
|
|
<dd>Called when data has been received on the socket and is available
|
|
for reading (see <a href="#s4-2">section 3-4-2</a>). The
|
|
<tt>void *</tt> parameter, cast to <tt>uint32</tt>, is the
|
|
number of bytes of data available for reading.</dd>
|
|
|
|
<dt><tt><b>SCB_READLINE</b></tt></dt>
|
|
<dd>Called when data has been received on the socket and is available
|
|
for reading, much like <tt>SCB_READ</tt>; however, this callback is
|
|
only called when a full line of data (containing a newline) is
|
|
available to be read. If both this callback and <tt>SCB_READ</tt>
|
|
have functions assigned to them, both functions will be called in
|
|
turn until there is no more data to process; see
|
|
<a href="#s4-2">section 3-4-2</a> for details.</dd>
|
|
|
|
<dt><tt><b>SCB_TRIGGER</b></tt></dt>
|
|
<dd>Called when a <i>write trigger</i> is encountered on the socket.
|
|
Write triggers are created using the <tt>swrite_trigger()</tt>
|
|
routine, described in <a href="#s4-1">section 3-4-1</a>. A write
|
|
trigger causes this callback to be called when all data before the
|
|
trigger has been successfully sent to the remote host, but before
|
|
any data beyond the trigger has been sent. The
|
|
<tt>void *</tt> parameter is the arbitrary value passed to
|
|
<tt>swrite_trigger()</tt>.</dd>
|
|
</dl>
|
|
|
|
<p>Internally, callback functions are called using the local
|
|
<tt>do_callback()</tt> routine. This routine sets the <tt>SF_CALLBACK</tt>
|
|
flag on the socket while the callback is in progress, to ensure that the
|
|
socket is not destroyed while it is still in use. The routine also checks
|
|
after the callback returns whether any flags were set indicating that the
|
|
connection was broken (<tt>SF_BROKEN</tt>) or that the socket should be
|
|
destroyed (<tt>SF_DELETEME</tt>) or disconnected locally
|
|
(<tt>SF_DISCONNECT</tt>). The function returns 0 if the socket was
|
|
disconnected, 1 otherwise. It also returns 1 if either the socket or the
|
|
callback is unspecified (<tt>NULL</tt> or zero), to simplify the caller's
|
|
logic.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s3">3-3. Establishing and breaking connections</h3>
|
|
|
|
<p>From the point of view of any particular host, there are two general
|
|
ways in which a connection to a remote host can be established: either by
|
|
actively connecting to the remote host (outgoing), or by waiting for the
|
|
remote host to request a connection (incoming). The socket subsystem
|
|
supports both of these, the former via the <tt>conn()</tt> routine and the
|
|
latter via listener sockets. Outgoing connections are handled
|
|
asynchronously, like all other socket operations, and the
|
|
<tt>SCB_CONNECT</tt> callback is used to inform the caller when the
|
|
connection has completed.</p>
|
|
|
|
<p>Once a connection has been established, it can also be broken at either
|
|
the local or the remote side. The socket subsystem provides the
|
|
<tt>disconn()</tt> routine for deliberately closing a connection, and
|
|
notifies the caller of a connection closed by the remote host through the
|
|
<tt>SCB_DISCONNECT</tt> callback.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-1">3-3-1. Outgoing connections</h4>
|
|
|
|
<p>To establish a connection to a remote host, the caller should first
|
|
create a socket, configure it as appropriate (including, at minimum, the
|
|
<tt>SCB_CONNECT</tt> and <tt>SCB_DISCONNECT</tt> callbacks), then call the
|
|
<tt>conn()</tt> routine:</p>
|
|
|
|
<div class="code">int <b>conn</b>(Socket *<i>s</i>,
|
|
const char *<i>host</i>, int <i>port</i>,
|
|
const char *<i>lhost</i>, int <i>lport</i>)</div>
|
|
|
|
<p>This routine attempts to establish a TCP connection to the host
|
|
specified by <tt><i>host</i></tt> on TCP port number <tt><i>port</i></tt>.
|
|
The hostname may be specified as either a hostname, which is passed to the
|
|
system's <tt>gethostbyname()</tt> address lookup function (if the call
|
|
returns multiple addresses, the first one returned by the system will be
|
|
used), or a numeric IPv4 address, which is parsed directly. The address to
|
|
be used for the local side of the socket can also be specified with the
|
|
<tt><i>lhost</i></tt> and <tt><i>lport</i></tt> parameters; values of
|
|
<tt>NULL</tt> and zero, respectively, leave the choice of the corresponding
|
|
parameter to the system.</p>
|
|
|
|
<p>If an error is encountered in setting up the connection, such as an
|
|
invalid host name or port number, the <tt>conn()</tt> routine returns -1
|
|
and sets <tt>errno</tt> appropriately; the value in <tt>errno</tt> may be
|
|
negative, indicating a hostname resolution failure (pass the negative of
|
|
this value to <tt>hstrerror()</tt> to obtain an error message string).
|
|
Otherwise, the routine returns zero, signifying that the connection is in
|
|
process.</p>
|
|
|
|
<p>When the connection completes, the socket subsystem calls the socket's
|
|
<tt>SCB_CONNECT</tt> callback function to notify the caller that the
|
|
connection is ready for use. Alternatively, the connection may be refused
|
|
by the remote host, in which case the socket's <tt>SCB_DISCONNECT</tt>
|
|
callback is called with a parameter of <tt>DISCONN_CONNFAIL</tt>.</p>
|
|
|
|
<p>Note that when a connection is made to the local host or a sufficiently
|
|
close remote host, the connection may complete or be rejected immediately.
|
|
If the connection is rejected, <tt>conn()</tt> will return an error, but if
|
|
it is accepted, the <tt>SCB_CONNECT</tt> callback will be called
|
|
immediately, before <tt>conn()</tt> returns; the caller must therefore
|
|
perform all necessary setup for the callback function before calling
|
|
<tt>conn()</tt>.</p>
|
|
|
|
<p>Internally, <tt>conn()</tt> sets the <tt>SF_CONNECTING</tt> flag on the
|
|
socket while the connection is being processed by the system; the socket
|
|
polling routine then watches for the connection to complete or fail,
|
|
setting the <tt>SF_CONNECTED</tt> flag in the former case and calling the
|
|
appropriate callback. If the connection completes immediately,
|
|
<tt>conn()</tt> itself sets the <tt>SF_CONNECTED</tt> flag.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-2">3-3-2. Incoming connections</h4>
|
|
|
|
<p>In order to accept connections from remote hosts, a <i>listener
|
|
socket</i>, which "listens" for connections on a specified port, must first
|
|
be created. This is done with the <tt>open_listener()</tt> routine:</p>
|
|
|
|
<div class="code">int <b>open_listener</b>(Socket *<i>s</i>, const char *<i>host</i>,
|
|
int <i>port</i>, int <i>backlog</i>)</div>
|
|
|
|
<p>This function turns the given socket into a listener socket which will
|
|
accept connections on the given TCP port. If <tt><i>host</i></tt> is not
|
|
<tt>NULL</tt>, connections will only be accepted on the corresponding IP
|
|
address (processed the same way as for <tt>conn()</tt>—note in
|
|
particular that if the hostname has multiple addresses associated with it,
|
|
only one will be used). The <tt><i>backlog</i></tt> value is passed
|
|
directly to the system's <tt>listen()</tt> function, and indicates how many
|
|
connections the system should allow to be pending (recognized by the system
|
|
but not yet accepted by the program).</p>
|
|
|
|
<p>In order to actually accept connections, a function must be assigned to
|
|
the socket's <tt>SCB_ACCEPT</tt> callback (if no function is assigned, any
|
|
connections received by the socket will be dropped immediately). The
|
|
<tt>void *</tt> parameter passed to this function is a new socket
|
|
object that has been created for the connection, already connected to the
|
|
remote host. The new socket is initialized in the same manner as sockets
|
|
created with <tt>sock_new()</tt>, so the accept callback will need to
|
|
configure the socket appropriately (setting callback functions and so on).
|
|
The new socket can be used in the same manner as sockets explicitly created
|
|
with <tt>sock_new()</tt>, except that the socket will be automatically
|
|
destroyed when disconnected (thus the caller must be careful not to
|
|
continue using the socket after the connection is closed).</p>
|
|
|
|
<p>Internally, the <tt>SF_LISTENER</tt> flag is used to mark an active
|
|
listener socket. When a read event occurs on such a socket, the
|
|
<tt>do_accept()</tt> internal routine accepts the connection, creates a
|
|
new socket object (with the <tt>SF_SELFCREATED</tt> flag set, to indicate
|
|
that the socket was created internally rather than an external
|
|
<tt>sock_new()</tt> call and should be destroyed upon disconnection), sets
|
|
up the new socket with the accepted connection, and calls the listener
|
|
socket's <tt>SCB_ACCEPT</tt> callback function.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-3">3-3-3. Disconnecting</h4>
|
|
|
|
<p>When a connection is no longer needed, the <tt>disconn()</tt> routine
|
|
can be called to disconnect a connected socket from the remote host:</p>
|
|
|
|
<div class="code">void <b>disconn</b>(Socket *<i>s</i>)</div>
|
|
|
|
<p>This routine first flushes the socket's write buffer if any unsent data
|
|
remains, then calls the socket's <tt>SCB_DISCONNECT</tt> callback with a
|
|
parameter of <tt>DISCONN_LOCAL</tt>. The return value is zero on success,
|
|
-1 on error (such as an invalid or listener socket). If there is unsent
|
|
data remaining in the write buffer and it cannot be immediately sent to the
|
|
remote host, however, then <tt>disconn()</tt> will return successfully
|
|
without calling the <tt>SCB_DISCONNECT</tt> callback; in this case, the
|
|
callback will be called by the socket polling routine once all the data has
|
|
been sent.</p>
|
|
|
|
<p>A connection may also be closed by the remote host; in this case, the
|
|
socket subsystem will automatically return the socket to an unconnected
|
|
state, calling the <tt>SCB_DISCONNECT</tt> callback with a parameter of
|
|
<tt>DISCONN_REMOTE</tt>. In this case, there is no point in attempting to
|
|
send any data remaining in the write buffer, and it is simply discarded.
|
|
If the disconnection is detected while a socket callback is being processed
|
|
(for example, when an attempt to send data to the remote host fails), the
|
|
disconnection will be postponed until the callback completes, so callback
|
|
functions do not need to worry about checking the socket's status after
|
|
every send operation.</p>
|
|
|
|
<p>Listener sockets cannot be closed with <tt>disconn()</tt>; a separate
|
|
function, <tt>close_listener()</tt>, is used to stop the socket from
|
|
accepting new connections and return it to an unused (unconnected) state.</p>
|
|
|
|
<p>Internally, disconnection is handled by the <tt>do_disconn()</tt>
|
|
routine, which is called for all types of disconnections—local,
|
|
remote, and connection failures—with the code appropriate to the
|
|
disconnection reason. The code may be bitwise OR'd with
|
|
<tt>DISCONN_RESUME_FLAG</tt>, a local flag (masked out before calling the
|
|
disconnect callback) indicating that the call to <tt>do_disconn()</tt> is
|
|
being made to continue a disconnection in progress. The routine performs
|
|
the following operations:</p>
|
|
|
|
<ul>
|
|
<li class="spaced">Ensures that the socket pointer is not <tt>NULL</tt> and
|
|
does not reference a listener socket, returning an error (-1 with
|
|
<tt>EINVAL</tt>) in either case.</li>
|
|
|
|
<li class="spaced">Checks whether the socket's <tt>SF_DISCONNECTING</tt>
|
|
flag, indicating a disconnection operation in progress, is set. If
|
|
the flag is set and the <tt>DISCONN_RESUME_FLAG</tt> flag is not
|
|
set in the disconnection code, the disconnection request is ignored
|
|
and success (zero) is returned.</li>
|
|
|
|
<li class="spaced">Checks whether the socket's <tt>SF_DISCONN_REQ</tt>
|
|
flag, indicating a disconnection request in progress, is set. If
|
|
so, and if the disconnection code is <tt>DISCONN_LOCAL</tt>, the
|
|
request is ignored. (Remote disconnects and connection failures
|
|
are passed through, overriding local disconnects, so that if a
|
|
remote disconnect is detected while <tt>disconn()</tt> is flushing
|
|
the write buffer, for example, the disconnect callback will see the
|
|
code <tt>DISCONN_REMOTE</tt> rather than <tt>DISCONN_LOCAL</tt>.</li>
|
|
|
|
<li class="spaced">Checks the socket's <tt>SF_CONNECTING</tt> and
|
|
<tt>SF_CONNECTED</tt> flags. If neither flag is set, the socket is
|
|
not connected, so there is nothing to do, and the request is
|
|
ignored.</li>
|
|
|
|
<li class="spaced">Sets the socket's <tt>SF_DISCONN_REQ</tt> flag.</li>
|
|
|
|
<li class="spaced">Clears the socket's file descriptor from the set of
|
|
descriptors to check for read status (see <a href="#s6">section
|
|
3-6</a>).</li>
|
|
|
|
<li class="spaced">If the disconnection code is <tt>DISCONN_LOCAL</tt> and
|
|
there is unsent data in the write buffer, calls
|
|
<tt>flush_write_buffer()</tt> (see <a href="#s4-1">section
|
|
3-4-1</a>) to send the data out. If the data cannot be sent
|
|
immediately, the socket's <tt>SF_DISCONNECT</tt> flag is set, and
|
|
success is returned; <tt>do_disconn()</tt> must be called again by
|
|
the socket polling routine with the <tt>DISCONN_RESUME_FLAG</tt>
|
|
flag set in the code once all data has been sent.</li>
|
|
|
|
<li class="spaced">Sets the socket's <tt>SF_DISCONNECTING</tt> flag.</li>
|
|
|
|
<li class="spaced">Shuts down communications on the socket at the system
|
|
level, by calling <tt>shutdown()</tt> and <tt>close()</tt>. (The
|
|
actual closing of the file descriptor is handled by
|
|
<tt>sock_closefd()</tt>, an internal routine that takes care of
|
|
clearing socket object fields and file descriptor set bits
|
|
appropriately.)</li>
|
|
|
|
<li class="spaced">Clears out the socket's write map list (ses
|
|
<a href="#s4-1">section 3-4-1</a>).</li>
|
|
|
|
<li class="spaced">Calls the socket's <tt>SCB_DISCONNECT</tt> callback
|
|
function, if one is set, passing the disconnection code with the
|
|
<tt>DISCONN_RESUME_FLAG</tt> internal flag cleared.</li>
|
|
|
|
<li class="spaced">Clears the socket's <tt>SF_DISCONNECTING</tt> flag.</li>
|
|
|
|
<li class="spaced">If the socket's file descriptor is no longer unset
|
|
(meaning that the disconnect callback function reconnected the
|
|
socket), aborts further processing and returns success.</li>
|
|
|
|
<li class="spaced">Clears the socket's <tt>SF_CONNECTING</tt> and
|
|
<tt>SF_CONNECTED</tt> flags.</li>
|
|
|
|
<li class="spaced">If the socket's <tt>SF_SELFCREATED</tt> flag, indicating
|
|
a socket created by accepting a connection, or <tt>SF_DELETEME</tt>
|
|
flag, indicating a delayed destroy operation, is set, destroys the
|
|
socket; otherwise frees all buffer space used by the socket.</li>
|
|
</ul>
|
|
|
|
<p>Note that the values used for the disconnection codes do not include
|
|
zero; this is to avoid unexpected consequences when the value is
|
|
converted to a pointer for use as the <tt>void *</tt> argument
|
|
to the callback function. (Theoretically, conversions both ways
|
|
should handle the zero and <tt>NULL</tt> values appropriately, but
|
|
there's always the possibility of a broken compiler
|
|
. . .)</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s4">3-4. Sending and receiving data</h3>
|
|
|
|
<p>The socket subsystem includes several routines for sending data to and
|
|
receiving data from remote systems, which more or less mimic the standard
|
|
system and library functions for reading and writing data. These routines
|
|
never block, however; send operations store the given data in the socket's
|
|
write buffer and return immediately (with the exception discussed under
|
|
<tt>sock_set_blocking()</tt> in <a href="#s2-1">section 3-2-1</a>), while
|
|
receive operations return an end-of-file condition if there is not enough
|
|
data in the read buffer to satisfy the operation.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s4-1">3-4-1. Sending data</h4>
|
|
|
|
<p>There are two main families of data sending routines: string-based
|
|
(stdio-like) routines and buffer-based routines. The interfaces are as
|
|
follows:</p>
|
|
|
|
<dl>
|
|
<dt><tt>int <b>sputs</b>(const char *<i>str</i>, Socket *<i>s</i>)</tt></dt>
|
|
<dd>Sends the given null-terminated string to the given socket, like
|
|
<tt>fputs()</tt>. (Does <i>not</i> write a trailing newline.)
|
|
Returns the number of bytes written, or -1 on failure.</dd>
|
|
|
|
<dt><tt>int <b>sockprintf</b>(Socket *<i>s</i>, const char *<i>fmt</i>, ...)</tt>
|
|
<br/><tt>int <b>vsockprintf</b>(Socket *<i>s</i>, const char *<i>fmt</i>, va_list <i>args</i></tt></dt>
|
|
<dd>Formats the variadic argument list according to the format string
|
|
<tt><i>fmt</i></tt> and sends it to the given socket, like
|
|
<tt>fprintf()</tt>. Returns the number of bytes written, or -1 on
|
|
failure.</dd>
|
|
|
|
<dt><tt>int32 <b>swrite</b>(Socket *<i>s</i>, const char *<i>buf</i>, int32 <i>len</i>)</tt></dt>
|
|
<dd>Sends data from buffer <tt><i>buf</i></tt> of length
|
|
<tt><i>len</i></tt> to the given socket, like <tt>write()</tt>.
|
|
Returns the number of bytes written, or -1 on failure.</dd>
|
|
|
|
<dt><tt>int32 <b>swritemap</b>(Socket *<i>s</i>, const char *<i>buf</i>, int32 <i>len</i>)</tt></dt>
|
|
<dd>Sends data to the given socket, like <tt>swrite()</tt>; the buffer
|
|
<tt><i>buf</i></tt> is taken to be a region of memory (of length
|
|
<tt><i>len</i></tt>) mapped with <tt>mmap()</tt>, and will be freed
|
|
automatically with <tt>munmap()</tt> when all of the data has been
|
|
sent to the socket. If <tt>DISABLE_SWRITEMAP</tt> (see
|
|
<a href="#s1">section 3-1</a>) is defined, returns the error
|
|
<tt>ENOSYS</tt>.</dd>
|
|
|
|
<dt><tt>int <b>swrite_trigger</b>(Socket *<i>s</i>, void *<i>data</i>)</tt></dt>
|
|
<dd>Inserts a <i>write trigger</i> at the socket's current write buffer
|
|
position, causing the socket's <tt>SCB_TRIGGER</tt> callback
|
|
function to be called when all data written prior to the
|
|
<tt>swrite_trigger()</tt> call has been successfully sent to the
|
|
remote host, and before any data written subsequently has been
|
|
sent. The value passed as the <tt><i>data</i></tt> parameter is
|
|
passed on unmodified to the callback function.</dd>
|
|
</dl>
|
|
|
|
<p>The first three functions perform the actual writing using the internal
|
|
<tt>buffered_write()</tt> routine. This function first resets the
|
|
timestamp used for detecting send timeouts if there is no data waiting to
|
|
be sent (either in the write buffer or in mapped buffers, as described
|
|
below), then copies the caller's data into the socket's write buffer up to
|
|
the current buffer size and calls the <tt>flush_write_buffer()</tt> routine
|
|
to send out any buffered data that can be sent without blocking; these two
|
|
steps are repeated until all of the caller's data has been buffered (and
|
|
possibly sent).</p>
|
|
|
|
<p>The <tt>flush_write_buffer()</tt> routine, in turn, first checks for
|
|
mapped write buffers and write triggers, as described below, then calls the
|
|
system's <tt>send()</tt> function to send a single contiguous block of data
|
|
to the remote host. The data actually sent (which may be none at all, if
|
|
the system is not ready to accept any more data for the socket) is removed
|
|
from the write buffer, and the number of bytes sent is returned. The
|
|
routine returns -1 on system error (or invalid parameter), and -2 if the
|
|
socket was in the middle of a disconnect and there is no more data to
|
|
send. <tt>flush_write_buffer()</tt> also manages the set of file
|
|
descriptors to watch for write-ready events, used in the polling routine,
|
|
and shrinks the socket's buffers if a send operation removes all pending
|
|
data from the write buffer.</p>
|
|
|
|
<p>If an attempt to flush the write buffer fails when the buffer is full,
|
|
<tt>buffered_write()</tt> attempts to expand the buffer. This is done by
|
|
calling <tt>resize_how_much()</tt> to find out how much the buffer should
|
|
be expanded by (the current implementation uses a constant 10%, rounded up
|
|
to the next multiple of <tt>SOCK_MIN_BUFSIZE</tt>), then performs the actual
|
|
resize operation. If <tt>resize_how_much()</tt> returns zero, meaning that
|
|
trying to expand the buffer would exceed the per-connection or total buffer
|
|
size limit, or if the attempt to resize the buffer fails, then
|
|
<tt>buffered_write()</tt> either returns an <tt>EAGAIN</tt> error or blocks
|
|
until some buffer space can be freed, depending on whether the socket has
|
|
been set blocking via <tt>sock_set_blocking()</tt> or not.</p>
|
|
|
|
<p>In order to avoid the overhead of moving data around on every send
|
|
operation, the write buffer is used circularly, through the use of four
|
|
pointers in the <tt>Socket</tt> structure:</p>
|
|
<ul>
|
|
<li><b><tt>wbuf</tt>:</b> Points to the base address of the buffer.</li>
|
|
<li><b><tt>wptr</tt>:</b> Points to the first byte of valid data in the
|
|
buffer.</li>
|
|
<li><b><tt>wend</tt>:</b> Points to the first byte after the last byte of
|
|
valid data in the buffer.</li>
|
|
<li><b><tt>wtop</tt>:</b> Points to one byte beyond the last byte of the
|
|
buffer (for convenience).</li>
|
|
</ul>
|
|
|
|
<p>The <tt>wbuf</tt> and <tt>wtop</tt> pointers remain constant (except for
|
|
changes in the location or size of the buffer itself) for the life of the
|
|
socket, while the <tt>wptr</tt> and <tt>wend</tt> pointers advance
|
|
circularly through the buffer space as data is added and removed. The
|
|
amount of data in the buffer can be computed as
|
|
<tt>wend - wptr</tt>, modulo the buffer size; note that this
|
|
difference will be negative if <tt>wend</tt> has wrapped around to the
|
|
beginning of the buffer but <tt>wptr</tt> has not, so the buffer size
|
|
(<tt>wtop - wbuf</tt>) must be added to the result, as is done
|
|
in the <tt>write_buffer_len()</tt> function. Thus an empty buffer is
|
|
indicated by <tt>wend == wptr</tt>, while a full buffer is
|
|
indicated by <tt>wend == wptr-1</tt> (again, modulo the buffer
|
|
size), leaving a one-byte pad to avoid a full buffer being mistakenly
|
|
treated as an empty one.</p>
|
|
|
|
<p>The last two functions for sending data, <tt>swritemap()</tt> and
|
|
<tt>swrite_trigget()</tt>, record their data in the <i>write-map list</i>,
|
|
a singly-linked list of structures containing information on mapped buffers
|
|
and write triggers. The structure is <tt>struct wmapinfo</tt>, defined
|
|
within the <tt>Socket</tt> structure definition in <tt>sockets.c</tt>, and
|
|
contains the following fields:</p>
|
|
|
|
<ul>
|
|
<li><b><tt>next</tt>:</b> A pointer to the next structure in the list.</li>
|
|
<li><b><tt>wait</tt>:</b> The number of bytes left to send from the write
|
|
buffer before processing this structure.</li>
|
|
<li><b><tt>map</tt>, <tt>maplen</tt>:</b> The buffer pointer and buffer
|
|
length (for write triggers, the data for the callback function and
|
|
zero).</li>
|
|
<li><b><tt>pos</tt>:</b> The current position within the buffer (the number
|
|
of bytes sent from the buffer so far).</li>
|
|
</ul>
|
|
|
|
<p>The head of the list is stored in the <tt>writemap</tt> field of the
|
|
socket object; the tail of the list is also recorded in the
|
|
<tt>writemap_tail</tt> field for efficiency reasons. If the list is empty,
|
|
both fields are <tt>NULL</tt>.</p>
|
|
|
|
<p>When <tt>swritemap()</tt> or <tt>swrite_trigger()</tt> is called, a new
|
|
structure is created and appended to the list, with the <tt>map</tt> and
|
|
<tt>maplen</tt> fields set to the buffer pointer and length (or the trigger
|
|
data and zero), the <tt>pos</tt> field set to zero, and the <tt>wait</tt>
|
|
field set to the current length of the write buffer. The
|
|
<tt>flush_write_buffer()</tt> then checks at the beginning of the routine
|
|
whether the first write-map structure (if one exists) is ready for
|
|
processing (has a <tt>wait</tt> value of zero). If so, data is sent from
|
|
the mapped buffer instead of the socket's write buffer; in the case of a
|
|
write trigger, the <tt>SF_WTRIGGER</tt> flag is set, to cause the polling
|
|
routine to call the socket's write trigger callback function and to prevent
|
|
any further buffer flushes from occurring before then. Otherwise, data is
|
|
sent from the socket's write buffer as usual, and every write-map
|
|
structure's <tt>wait</tt> field is decremented by the number of bytes sent.
|
|
<i>Implementation note: This roundabout method is a result of adding the
|
|
<tt>swritemap()</tt> and <tt>swrite_trigger()</tt> fields after the initial
|
|
socket subsystem design was complete (in fact, Services does not use them
|
|
at all—I added them for my HTTP server). A more intelligent design
|
|
would use a write-map or similar structure for every block of data to be
|
|
sent, possibly pointing into a common buffer like the current write
|
|
buffer.</i></p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s4-2">3-4-2. Receiving data</h4>
|
|
|
|
<p>Like send operations, there are two main groups of receive routines,
|
|
string- (or character-) based and buffer-based:</p>
|
|
|
|
<dl>
|
|
<dt><tt>int <b>sgetc</b>(Socket *<i>s</i>)</tt></dt>
|
|
<dd>Reads a single byte (character) from the socket, returning the
|
|
value of the byte read or <tt>EOF</tt> if no data is available.
|
|
Assumes the socket passed in is valid.</dd>
|
|
|
|
<dt><tt>int <b>sgets</b>(char *<i>buf</i>, int32 <i>len</i>, Socket *<i>s</i>)</tt></dt>
|
|
<dd>Reads a line of data (ending with an LF character, value 0x0A) from
|
|
the given socket, storing it in <tt><i>buf</i></tt>. If the string
|
|
(including the null terminator) requires more than <tt><i>len</i></tt>
|
|
bytes, it is truncated to <tt><i>len</i>-1</tt> bytes, but the
|
|
entire string (to the newline) is removed from the socket'S buffer.
|
|
Returns <tt><i>buf</i></tt>, or <tt>NULL</tt> if no complete line
|
|
is available to read or an error occurs.</dd>
|
|
|
|
<dt><tt>int <b>sgets2</b>(char *<i>buf</i>, int32 <i>len</i>, Socket *<i>s</i>)</tt></dt>
|
|
<dd>Reads a line of data from the given socket and stores it in
|
|
<tt><i>buf</i></tt>, like <tt>sgets()</tt>; however, a trailing
|
|
LF or CR/LF pair will be stripped from the string before it is
|
|
returned.</dd>
|
|
|
|
<dt><tt>int <b>sread</b>(Socket *<i>s</i>, char *<i>buf</i>, int32 <i>len</i>)</tt></dt>
|
|
<dd>Reads a block of data from the socket, returning the number of
|
|
bytes successfully read (which may be less than <tt><i>len</i></tt>,
|
|
or zero, if insufficient data is available in the socket's
|
|
buffer to satisfy the requsst). Returns -1 on error.</dd>
|
|
</dl>
|
|
|
|
<p>All four of these functions operate on the socket's read buffer. This
|
|
buffer is filled by the socket polling routine (see <a href="#s6">section
|
|
3-6</a>) when data has been received by the system and is available for
|
|
reading from the socket. The routines are intended to be called from the
|
|
<tt>SCB_READ</tt> or <tt>SCB_READLINE</tt> callbacks, which are called by
|
|
the polling routine when data is available.</p>
|
|
|
|
<p>The use of two distinct callbacks for reading data is to facilitate the
|
|
processing of both binary and textual data. When data has been received on
|
|
the socket's connection and stored in the buffer, the socket subsystem
|
|
first calls the <tt>SCB_READ</tt> callback function, passing the number of
|
|
bytes available for reading (an integer value, cast to <tt>void *</tt>
|
|
for the call). If the callback function leaves some data in the buffer (or
|
|
no function is assigned), and if at least one newline character is present
|
|
in the buffer, the <tt>SCB_READLINE</tt> callback function is then called,
|
|
again with the number of bytes available for reading. If there is still
|
|
data left in the buffer, both callbacks are called again in order,
|
|
repeating until either all data has been consumed or the
|
|
<tt>SCB_READ</tt>/<tt>SCB_READLINE</tt> pair does not read any data from
|
|
the socket's buffer.</p>
|
|
|
|
<p>The read buffer is handled in the same manner as the write buffer; four
|
|
fields (<tt><i>rbuf</i></tt>, <tt><i>rptr</i></tt>, <tt><i>rend</i></tt>,
|
|
and <tt><i>rtop</i></tt>) are used to manage data insertion and removal,
|
|
and like the write buffer, the read buffer is used circularly to avoid
|
|
overhead from moving data around.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s4-3">3-4-3. Muting sockets</h4>
|
|
|
|
<p>If the caller does not want to receive socket events for a certain
|
|
socket, the socket can be <i>muted</i>. The socket subsystem will not
|
|
attempt to receive any data from the remote host for a muted socket, and
|
|
will not call the <tt>SCB_READ</tt> or <tt>SCB_READLINE</tt> callbacks.
|
|
Listener sockets can also be muted, causing the socket subsystem to not
|
|
accept any connections from remote hosts or call the <tt>SCB_ACCEPT</tt>
|
|
callback (connection attempts will be left waiting in the operating
|
|
system's queue). Note that muting a socket does not have any effect on the
|
|
operating system's low-level data processing; if the OS automatically
|
|
accepts connection attempts at the protocol level, for example, the remote
|
|
host will still see the connection established. Also note that a socket in
|
|
the process of connecting or disconnecting will still call the
|
|
<tt>SCB_CONNECT</tt> or <tt>SCB_DISCONNECT</tt> callback when the operation
|
|
completes, and the write buffer will still be flushed normally, causing the
|
|
<tt>SCB_TRIGGER</tt> callback to be called if a write trigger is
|
|
encountered.</p>
|
|
|
|
<p>The functions for muting and unmuting sockets are:</p>
|
|
|
|
<dl>
|
|
<dt><tt>void <b>sock_mute</b>(Socket *<i>s</i>)</tt></dt>
|
|
<dd>Mutes the given socket, disabling all read and accept events.
|
|
Does nothing if the socket was already muted.</dd>
|
|
|
|
<dt><tt>void <b>sock_unmute</b>(Socket *<i>s</i>)</tt></dt>
|
|
<dd>Unmutes the given socket, allowing read and accept events to occur.
|
|
Does nothing if the socket was not muted. If any data is present
|
|
in the socket's read buffer, the <tt>SCB_READ</tt> and
|
|
<tt>SCB_READLINE</tt> callbacks will be called once regardless of
|
|
whether any new data has arrived on the socket.</dd>
|
|
</dl>
|
|
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s5">3-5. Retrieving socket information</h3>
|
|
|
|
<p>The following routines can be used to retrieve information on sockets:</p>
|
|
|
|
<dl>
|
|
<dt><tt>int <b>sock_isconn</b>(const Socket *<i>s</i>)</tt></dt>
|
|
<dd>Returns whether the socket is currently connected to a remote
|
|
host (nonzero if connected, else zero).</dd>
|
|
|
|
<dt><tt>int <b>sock_remote</b>(const Socket *<i>s</i>, struct sockaddr *<i>sa</i>,
|
|
int *<i>lenptr</i>)</tt></dt>
|
|
<dd>Retrieves the remote host's address if the socket is connected,
|
|
returning 0 on success, -1 on failure. Equivalent to the system
|
|
call <tt>getpeername()</tt> on ordinary sockets.</dd>
|
|
|
|
<dt><tt>int <b>sock_get_blocking</b>(const Socket *<i>s</i>)</tt></dt>
|
|
<dd>Returns whether the given socket is in blocking mode or not.
|
|
The return value is positive if the socket is in blocking mode,
|
|
zero if it is in non-blocking mode, or -1 if the socket parameter
|
|
is invalid.</dd>
|
|
|
|
<dt><tt>uint32 <b>read_buffer_len</b>(const Socket *<i>s</i>)</tt>
|
|
<br/><tt>uint32 <b>write_buffer_len</b>(const Socket *<i>s</i>)</tt></dt>
|
|
<dd>Returns the given socket's read or write buffer length (the
|
|
amount of data received but not processed, or buffered but not
|
|
yet sent, respectively), in bytes. The socket parameter must
|
|
point to a valid socket (it is not checked for validity).</dd>
|
|
|
|
<dt><tt>uint32 <b>sock_rwstat</b>(const Socket *<i>s</i>,
|
|
uint64 *<i>read_ret</i>, uint64 *<i>written_ret</i>)</tt></dt>
|
|
<dd>Returns the amount of data received and sent on the given socket.
|
|
The amount of data received is stored in the location pointed to by
|
|
<tt><i>read_ret</i></tt>, and the amount sent is stored in the
|
|
location pointed to by <tt><i>write_ret</i></tt>, both in bytes;
|
|
the amount of data sent does not include data stored in the write
|
|
buffer but not yet sent to the remote host. Either pointer can be
|
|
<tt>NULL</tt> if the corresponding value is not needed. The
|
|
routine returns 0 on success, -1 on failure.</dd>
|
|
|
|
<dt><tt>int <b>sock_bufstat</b>(const Socket *<i>s</i>,
|
|
uint32 *<i>socksize_ret</i>, uint32 *<i>totalsize_ret</i>,
|
|
int *<i>ratio1_ret</i>, int *<i>ratio2_ret</i>)</tt></dt>
|
|
<dd>Returns buffer size information about the given socket (if not
|
|
<tt>NULL</tt>) and about the socket subsystem as a whole.
|
|
<tt><i>socksize_ret</i></tt> is set to the number of bytes
|
|
allocated for the given socket's read and write buffers, and
|
|
<tt><i>ratio1_ret</i></tt> is set to the ratio of this value to
|
|
the per-socket buffer size limit set with
|
|
<tt>sock_set_buflimits()</tt>, expressed as a percentage rounded up
|
|
to the nearest integer; if a <tt>NULL</tt> value is passed for the
|
|
socket, <tt><i>socksize_ret</i></tt> will be left unmodified, and
|
|
<tt><i>ratio1_ret</i></tt> will be set to zero. Likewise,
|
|
<tt><i>totalsize_ret</i></tt> is set to the total number of bytes
|
|
allocated for socket buffers, and <tt><i>ratio2_ret</i></tt> is set
|
|
to the percentage ratio of this value to the total buffer size
|
|
limit. The function's return value is the larger of the two ratios
|
|
given above, also as a percentage. If the per-socket or total
|
|
buffer size limit is disabled, the corresponding ratio will be set
|
|
to zero. Any of the return talue parameters can be set to
|
|
<tt>NULL</tt>, in which case the corresponding value will not be
|
|
returned.</dd>
|
|
</dl>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s6">3-6. The socket polling routine</h3>
|
|
|
|
<p>The final socket interface routine, <tt>check_sockets()</tt>, is the
|
|
workhorse of the socket subsystem. The routine waits for activity to
|
|
occur, reading data from any sockets on which new data has been received,
|
|
flushing the write buffer when a socket becomes ready for sending more
|
|
data, and accepting connections from listener sockets on which a new
|
|
connection request is received. If a timeout has been set with
|
|
<tt>sock_set_rto()</tt> (see <a href="#s2-1">section 3-2-1</a>), the
|
|
routine returns control to the caller if no activity occurs within that
|
|
time (the name "rto", for "read timeout", is something of a misnomer, since
|
|
it applies to all types of activity: read-ready, write-ready, and new
|
|
connection).</p>
|
|
|
|
<p>When called, <tt>check_sockets()</tt> first sets up the file descriptor
|
|
sets and timeout value used in the <tt>select()</tt> system call (the file
|
|
descriptor sets are actually initialized and modified by other routines as
|
|
appropriate; <tt>check_sockets()</tt> makes a copy of them so the originals
|
|
are not modified by <tt>select()</tt>. The timeout is ordinarily the value
|
|
given to <tt>sock_set_rto()</tt>, but if one or more sockets with a write
|
|
timeout set has data pending in the write buffer, the timeout is reduced to
|
|
the time until the earliest timeout (with second resolution). Then
|
|
<tt>select()</tt> is invoked; signals are enabled only for the duration of
|
|
the <tt>select()</tt> call, and disabled immediately after
|
|
<tt>select()</tt> returns. (It is assumed that signals are disabled when
|
|
<tt>check_sockets()</tt> is called; <tt>init_signals()</tt> disables
|
|
signals before it returns, so this prerequisite is fulfulled.) The
|
|
<tt>select()</tt> call is made in a loop to ensure that a received signal
|
|
is not interpreted as an error.</p>
|
|
|
|
<p>After <tt>select()</tt> returns (and if it does not return an error),
|
|
<tt>check_sockets()</tt> then loops through each file descriptor used in
|
|
the <tt>select()</tt> call. The <tt>Socket</tt> structure corresponding to
|
|
each file descriptor is found from the <tt>sockets[]</tt> array, maintained
|
|
separately from the linked list of sockets for this purpose.</p>
|
|
|
|
<p>A write-ready event on a socket indicates either that a deferred
|
|
connection has completed or failed, or that a connected socket has is ready
|
|
to accept data for sending. In the latter case, <tt>check_sockets()</tt>
|
|
simply calls <tt>flush_write_buffer()</tt> to send data out;
|
|
<tt>flush_write_buffer()</tt> takes care of removing the file descriptor
|
|
from the set to check for write-ready events if all data is flushed from
|
|
the socket's write buffer. In the former case, <tt>check_sockets()</tt>
|
|
retrieves the value of the socket's <tt>SO_ERROR</tt> option, which
|
|
indicates the status of the connection attempt. A value of zero indicates
|
|
success, while nonzero is an <tt>errno</tt>-style error number; the
|
|
appropriate callback (<tt>SCB_CONNECT</tt> or <tt>SCB_DISCONNECT</tt>) is
|
|
called, the socket's descriptor is removed from the write-ready set, and if
|
|
the connection was successful and the socket is not muted, the descriptor
|
|
is then added to the read-ready set so that it is checked on the next call
|
|
to <tt>check_sockets()</tt>.</p>
|
|
|
|
<p>After processing any write-ready event for a socket, the socket is
|
|
checked for write trigger events as indicated by the <tt>SF_WTRIGGER</tt>
|
|
socket flag, and if the flag is set, the <tt>SCB_TRIGGER</tt> is called
|
|
repeatedly until the flag is no longer set. (The flag is cleared before
|
|
each call to the callback function, but the callback function may set a new
|
|
write trigger which is triggered before the function returns.)</p>
|
|
|
|
<p>A read-ready event on a socket indicates either that a connected socket
|
|
has received data or a disconnection event, or that a listener socket
|
|
received a connection request. The latter case is simple;
|
|
<tt>check_sockets()</tt> calls <tt>do_accept()</tt> to accept the
|
|
connection, then proceeds to the next file descriptor. In the former case,
|
|
the read buffer is first expanded if it is currently full, then
|
|
<tt>fill_read_buffer()</tt> is called to actually receive data from the
|
|
socket into the read buffer. <tt>fill_read_buffer()</tt> returns the
|
|
number of bytes read from the socket, or -1 on error, in which case the
|
|
socket is disconnected with the <tt>DISCONN_REMOTE</tt> code.
|
|
<i>Implementation note: As documented in the code, if data arrives on a
|
|
connection but the socket's read buffer is full and has reached the
|
|
per-socket or total buffer size limit, the data will be left alone, causing
|
|
<tt>select()</tt> to return immediately the next time it is called; this
|
|
results in the program "busy-waiting" until either data is removed from the
|
|
read buffer or space is made available to expand the buffer.</i></p>
|
|
|
|
<p>After reading data from the socket, <tt>check_sockets()</tt> calls the
|
|
<tt>SCB_READ</tt> and <tt>SCB_READLINE</tt> callbacks in turn, as described
|
|
in <a href="#s4-2">section 3-4-2</a>. Even if the socket was not returned
|
|
in the read-ready set from <tt>select()</tt>, the callbacks are still
|
|
called if the <tt>SF_UNMUTED</tt> flag is set; this flag is set by
|
|
<tt>sock_unmute()</tt> to indicate that a socket has just been unmuted, and
|
|
cleared by <tt>check_sockets()</tt> before calling the read callbacks.</p>
|
|
|
|
<p>Finally, <tt>check_sockets()</tt> checks whether a write timeout has
|
|
occurred on sockets that have a timeout set. If so, the socket is
|
|
disconnected with the <tt>DISCONN_REMOTE</tt> code, on the assumption that
|
|
the remote host is no longer reachable.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<p class="backlink"><a href="2.html">Previous section: Core Services functionality</a> |
|
|
<a href="index.html">Table of Contents</a> |
|
|
<a href="4.html">Next section: The module system</a></p>
|
|
|
|
</body>
|
|
</html>
|