Copyright (C) 2000-2012 |
GNU Info (libc.info)Out-of-Band DataOut-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' (Note: 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 (Note: 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 Note: Interrupt Input. You must also establish a handler for this signal, as described in Note: 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. Note: 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 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; } } } automatically generated by info2www version 1.2.2.9 |