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
Value
|
Interpretation
|
Urgent
Pointer
|
0
|
BSD interpretation (Linux)
|
After urgent byte
|
1
|
RFC793 interpretation
|
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.
Figure 14.1:
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
details omitted):
Figure 14.2:
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.
TIP
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.
No comments:
Post a Comment