Streams with connections permit out-of-band data that is
delivered with higher priority than ordinary data. Typically the
reason for sending out-of-band data is to send notice of an
exceptional condition. To send out-of-band data use
send, specifying the flag MSG_OOB (see Sending Data).
Out-of-band data are received with higher priority because the
receiving process need not read it in sequence; to read the next
available out-of-band data, use recv with the MSG_OOB
flag (see Receiving Data). Ordinary read operations do not read
out-of-band data; they read only ordinary data.
When a socket finds that out-of-band data are on their way, it sends a
SIGURG signal to the owner process or process group of the
socket. You can specify the owner using the F_SETOWN command
to the fcntl function; see Interrupt Input. You must
also establish a handler for this signal, as described in Signal Handling, in order to take appropriate action such as reading the
out-of-band data.
Alternatively, you can test for pending out-of-band data, or wait
until there is out-of-band data, using the select function; it
can wait for an exceptional condition on the socket. See Waiting for I/O, for more information about select.
Notification of out-of-band data (whether with SIGURG or with
select) indicates that out-of-band data are on the way; the data
may not actually arrive until later. If you try to read the
out-of-band data before it arrives, recv fails with an
EWOULDBLOCK error.
Sending out-of-band data automatically places a “mark” in the stream
of ordinary data, showing where in the sequence the out-of-band data
“would have been”. This is useful when the meaning of out-of-band
data is “cancel everything sent so far”. Here is how you can test,
in the receiving process, whether any ordinary data was sent before
the mark:
success = ioctl (socket, SIOCATMARK, &atmark);
The integer variable atmark is set to a nonzero value if
the socket's read pointer has reached the “mark”.
Here's a function to discard any ordinary data preceding the
out-of-band mark:
int
discard_until_mark (int socket)
{
while (1)
{
/* This is not an arbitrary limit; any size will do. */
char buffer[1024];
int atmark, success;
/* If we have reached the mark, return. */
success = ioctl (socket, SIOCATMARK, &atmark);
if (success < 0)
perror ("ioctl");
if (result)
return;
/* Otherwise, read a bunch of ordinary data and discard it.This is guaranteed not to read past the markif it starts before the mark. */
success = read (socket, buffer, sizeof buffer);
if (success < 0)
perror ("read");
}
}
If you don't want to discard the ordinary data preceding the mark, you
may need to read some of it anyway, to make room in internal system
buffers for the out-of-band data. If you try to read out-of-band data
and get an EWOULDBLOCK error, try reading some ordinary data
(saving it so that you can use it when you want it) and see if that
makes room. Here is an example:
struct buffer
{
char *buf;
int size;
struct buffer *next;
};
/* Read the out-of-band data from SOCKET and return itas a `struct buffer', which records the address of the dataand its size.It may be necessary to read some ordinary datain order to make room for the out-of-band data.If so, the ordinary data are saved as a chain of buffersfound in the `next' field of the value. */
struct buffer *
read_oob (int socket)
{
struct buffer *tail = 0;
struct buffer *list = 0;
while (1)
{
/* This is an arbitrary limit.Does anyone know how to do this without a limit? */
#define BUF_SZ 1024
char *buf = (char *) xmalloc (BUF_SZ);
int success;
int atmark;
/* Try again to read the out-of-band data. */
success = recv (socket, buf, BUF_SZ, MSG_OOB);
if (success >= 0)
{
/* We got it, so return it. */
struct buffer *link
= (struct buffer *) xmalloc (sizeof (struct buffer));
link->buf = buf;
link->size = success;
link->next = list;
return link;
}
/* If we fail, see if we are at the mark. */
success = ioctl (socket, SIOCATMARK, &atmark);
if (success < 0)
perror ("ioctl");
if (atmark)
{
/* At the mark; skipping past more ordinary data cannot help.So just wait a while. */
sleep (1);
continue;
}
/* Otherwise, read a bunch of ordinary data and save it.This is guaranteed not to read past the markif it starts before the mark. */
success = read (socket, buf, BUF_SZ);
if (success < 0)
perror ("read");
/* Save this data in the buffer list. */
{
struct buffer *link
= (struct buffer *) xmalloc (sizeof (struct buffer));
link->buf = buf;
link->size = success;
/* Add the new link to the end of the list. */
if (tail)
tail->next = link;
else
list = link;
tail = link;
}
}
}
Published under the terms of the GNU General Public License