7.11 fcntl Function
fcntl stands for "file control" and
this function performs various descriptor control operations.
Before describing the function and how it affects a socket, we need
to look at the bigger picture. Figure 7.20 summarizes the different operations
performed by fcntl, ioctl, and routing
sockets.
The first six operations can be applied to
sockets by any process; the second two (interface operations) are
less common, but are still general-purpose; and the last two (ARP
and routing table) are issued by administrative programs such as
ifconfig and route. We will talk more about the
various ioctl operations in Chapter 17 and routing sockets in
Chapter
18.
There are multiple ways to perform the first
four operations, but we note in the final column that POSIX
specifies that fcntl is the preferred way. We also note
that POSIX provides the sockatmark function (Section
24.3) as the preferred way to test for the out-of-band mark.
The remaining operations, with a blank final column, have not been
standardized by POSIX.
We also note that the first two operations,
setting a socket for nonblocking I/O and for signal-driven I/O,
have been set historically using the FNDELAY and
FASYNC commands with fcntl. POSIX defines the
O_XXX constants.
The fcntl function provides the
following features related to network programming:
-
Nonblocking
I/O鈥?/span> We can set the O_NONBLOCK file status flag
using the F_SETFL command to set a socket as nonblocking.
We will describe nonblocking I/O in Chapter 16.
-
Signal-driven
I/O鈥?/span> We can set the O_ASYNC file status flag using
the F_SETFL command, which causes the SIGIO
signal to be generated when the status of a socket changes. We will
discuss this in Chapter 25.
-
The F_SETOWN command lets us set the
socket owner (the process ID or process group ID) to receive the
SIGIO and SIGURG signals. The former signal is
generated when signal-driven I/O is enabled for a socket (Chapter 25) and the
latter signal is generated when new out-of-band data arrives for a
socket
(Chapter 24). The F_GETOWN
command returns the current owner of the socket.
The term "socket owner" is defined by POSIX.
Historically, Berkeley-derived implementations have called this
"the process group ID of the socket" because the variable that
stores this ID is the so_pgid member of the
socket structure (p. 438 of TCPv2).
#include <fcntl.h>
|
int fcntl(intfd, int cmd, ... /* int arg */ );
|
Returns: depends on cmd if OK, -1 on error
|
Each descriptor (including a socket) has a set
of file flags that is fetched with the F_GETFL command and
set with the F_SETFL command. The two flags that affect a
socket are
We will describe both of these features in more
detail later. For now, we note that typical code to enable
nonblocking I/O, using fcntl, would be:
int flags;
/* Set a socket as nonblocking */
if ( (flags = fcntl (fd, F_GETFL, 0)) < 0)
err_sys("F_GETFL error");
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
Beware of code that you may encounter that
simply sets the desired flag.
/* Wrong way to set a socket as nonblocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
err_sys("F_SETFL error");
While this sets the nonblocking flag, it also
clears all the other file status flags. The only correct way to set
one of the file status flags is to fetch the current flags,
logically OR in the new flag, and then set the flags.
The following code turns off the nonblocking
flag, assuming flags was set by the call to fcntl
shown above:
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
The two signals SIGIO and
SIGURG are different from other signals in that they are
generated for a socket only if the socket has been assigned an
owner with the F_SETOWN command. The integer arg value for the F_SETOWN command
can be either a positive integer, specifying the process ID to
receive the signal, or a negative integer whose absolute value is
the process group ID to receive the signal. The F_GETOWN
command returns the socket owner as the return value from the
fcntl function, either the process ID (a positive return
value) or the process group ID (a negative value other than 鈥?).
The difference between specifying a process or a process group to
receive the signal is that the former causes only a single process
to receive the signal, while the latter causes all processes in the
process group (perhaps more than one) to receive the signal.
When a new socket is created by socket,
it has no owner. But when a new socket is created from a listening
socket, the socket owner is inherited from the listening socket by
the connected socket (as are many socket options [pp. 462鈥?63 of
TCPv2]).
|