Out-of-Band Data (The GNU C Library)

#### 16.9.8 Out-of-Band Data ¶

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-Driven 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 Input or Output, 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 (atmark)
            return;

          /* Otherwise, read a bunch of ordinary data and discard it.
             This is guaranteed not to read past the mark
             if 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 it
       as a ‘struct buffer’, which records the address of the data
       and its size.

       It may be necessary to read some ordinary data
       in order to make room for the out-of-band data.
       If so, the ordinary data are saved as a chain of buffers
       found 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 mark
             if 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;
          }
        }
    }