Understanding the Urgent Pointer
A socket interface provides a general network interface. This includes how it deals with out-of-band data. The TCP implementation of urgent data, however, falls somewhat short of what a general concept might include for out-of-band data.
Although the entire string 'rejoiced' was sent as out-of-band data using send(2), the following observations can be made at the receiving end:
- Only the d character was received as out-of-band data.
- The d character was received ahead of the remaining characters in 'rejoice'.
The fact that the d byte was received ahead of the bytes 'rejoice' does indeed demonstrate that the d byte was more urgent. It shows that the byte ordering has been disturbed by an urgency factor.
Understanding TCP Urgent Mode
The fact that only one byte was received as out-of-band data has to do with the mapping of a TCP protocol concept to a socket concept. The TCP urgent mode is mapped to the more general socket
concept of out-of-band data. The TCP protocol itself does not actually provide out-of-band data facilities. The closest concept to this socket idea is TCP's urgent mode of communications. A little bit of discussion of the TCP protocol is necessary in this section in order to provide you with an understanding of how urgent mode works.
When the send(2) socket interface function is used with the flag bit MSG_OOB set, the data is written to the TCP outgoing queue and an urgent pointer is established. The precise location of this pointer is determined by the tcp_stdurg setting that was covered earlier. Table 14.2 reviews the two interpretations and indicates where the urgent pointer is placed.
Table 14.2: The TCP Urgent Pointer Based Upon tcp_stdurg Settings
BSD interpretation (Linux)
After urgent byte
Before urgent byte
Figure 14.1 shows how the TCP sending buffer can be visualized after the send(2) call has returned from queuing the string 'rejoiced' as out-of-band data. Although we are most interested in the BSD interpretation (because of Linux), both interpretations are illustrated in the figure.
Here is a graphical representation of the TCP urgent pointers.
The sequence of events that occur from calling send(2) using the MSG_OOB flag are as follows for the BSD interpretation (tcp_stdurg=0):
- The data is placed into the TCP outgoing queue (in this case, the beginning of the empty TCP buffer).
- The TCP urgent mode is started (a TCP URG bit is set to true).
- The urgent pointer is computed to point after the last byte that was entered into the outgoing TCP queue.
In the example program oobsend.c, the send(2) call was followed by a call to sleep(3). This action causes the Linux kernel to perform the following:
- Send what it has queued so far in the TCP buffer, rather than wait indefinitely for more data.
- The packet header that is now created by the TCP protocol software now has the URG bit set. This indicates that TCP urgent mode has been used (this is because the send(2) call used the MSG_OOB flag bit).
- A TCP urgent pointer is computed and placed into the packet header. In this case (tcp_stdurg=0), this pointer points after the last byte of out-of-band data that was queued.
- The TCP packet header containing the URG bit, urgent pointer, and all packet data that was waiting to be sent is now transmitted to the network interface device as one physical packet.
After these steps take place, the packet speeds on its way to the receiving host over the network. This packet is received at the remote end, conceptually as shown in Figure 14.2 (with protocol
The TCP header bit URG=1 indicates that urgent data immediately precedes the byte at offset 8.
When a packet is received with the URG bit set to true, as shown in Figure 14.2, the Linux kernel will notify the process (or process group) that owns the socket, with the signal SIGURG. This is done because the packet contains an urgent pointer (that is why the URG bit is set in the TCP header).
The application oobrecv.c, upon handling the SIGURG signal, reads the out-of-band data by calling upon recv(2) with the flag bit MSG_OOB set. This causes the Linux kernel to return only the out-of-band data. Because TCP does not record where the out-of-band data starts, the socket API can return only the one byte prior to the urgent pointer within the packet (assuming that tcp_stdurg=0). Consequently, in our example, only the d byte is returned as outof-band data. Any subsequent read of in-band data will read the remaining bytes 'rejoice', and any data that follows the urgent byte, if any exists.
Even if the out-of-band data was not read in the signal handling function, only the bytes 'rejoice' and subsequent nonurgent data would be read, if any. The d byte would be prevented from being
returned in the normal inband data because it has been identified as out-of-band data.
Urgent Mode When tcp_stdurg=1
Space does not permit us to dwell on this case, but a few comments are worthwhile. When tcp_stdurg=l, a strange thing often happens— urgent mode is often entered and its corresponding urgent pointer is received without any corresponding urgent data to be read. If the urgent pointer happens to be at the end of the last data byte included within the packet, then there might not be any following byte received. The urgent data byte might follow in a subsequent packet.
For this reason, when this mode of operation is used, the recv(2) call with the MSG_OOB flag set does not necessarily return an out-of-band byte for TCP when the signal SIGURG is raised.
When tcp_stdurg=1 under Linux, a recv(2) call will return the errno value EAGAIN when no urgent data is available to read. Some other UNIX implementations (BSD UNIX, for example) return the errno value EWOULDBLOCK instead. To handle the situation where the urgent data byte was unavailable, you must perform the following (remember this applies only when tcp_stdurg=1):
- Record the SIGURG event in a flag (say, a variable named urg_mode=1).
- Return from your signal handler.
- Continue to read in-band data within your application.
- When the urg_mode value is true, try to read some out-of-band data, by using recv(2) and the MSG_OOB flag bit.
- If step 4 yields data, then set urg_mode=0 and return to normal processing. Repeat step 3.
- If step 4 does not yield any out-of-band data, continue processing while leaving urg_mode set true. Repeat step 3.
Again, it must be emphasized that you probably won't use these steps for Linux code, unless a change in direction is made for Linux. Linux uses the BSD (tcp_stdurg=0) mode of urgent data by default, which is easier to cope with.