Denial-of-Service Attacks
Unfortunately, there is a problem with the server that we just showed. Consider what happens if a malicious client connects to the server, sends one byte of data (other than a newline), and then goes to sleep. The server will call read, which will read the single byte of data from the client and then block in the next call to read, waiting for more data from this client. The server is then blocked (“hung” may be a better term) by this one client and will not service any other clients (either new client connections or existing clients’ data) until the malicious client either sends a newline or terminates.
‘pselect’ Function
The pselect function was invented by POSIX and is now supported by many of the Unix variants.
#include <sys/select.h>
#include <signal.h>
#include <time.h>
int pselect (int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);
pselect contains two changes from the normal select function:
pselect uses the timespec structure, another POSIX invention, instead of the timeval structure.
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
The difference in these two structures is with the second member: The tv_nsec member of the newer structure specifies nanoseconds, whereas the tv_usec member of the older structure specifies microseconds.
‘poll’ Function
The poll function originated with SVR3 and was originally limited to STREAMS devices (Chapter 31(See 9.20)). SVR4 removed this limitation, allowing poll to work with any descriptor. poll provides functionality that is similar to select, but poll provides additional information when dealing with STREAMS devices.
#include <poll.h>
int poll (struct pollfd *fdarray, unsigned long nfds, int timeout);
Each element of the array is a pollfd structure that specifies the conditions to be tested for a given descriptor, fd.
struct pollfd {
int fd; /* descriptor to check */
short events; /* events of interest on fd */
short revents; /* events that occurred on fd */
};
The conditions to be tested are specified by the events member, and the function returns the status for that descriptor in the corresponding revents member.
With regard to TCP and UDP sockets, the following conditions cause poll to return the specified revent. Unfortunately, POSIX leaves many holes (i.e., optional ways to return the same condition) in its definition of poll.
- All regular TCP data and all UDP data is considered normal.
- TCP’s out-of-band data (Chapter 24(See 9.13)) is considered priority band.
- When the read half of a TCP connection is closed (e.g., a FIN is received), this is also considered normal data and a subsequent read operation will return 0.
- The presence of an error for a TCP connection can be considered either normal data or an error (POLLERR). In either case, a subsequent read will return –1 with errno set to the appropriate value. This handles conditions such as the receipt of an RST or a timeout.
- The availability of a new connection on a listening socket can be considered either normal data or priority data. Most implementations consider this normal data.
- The completion of a nonblocking connect is considered to make a socket writable.
The number of elements in the array of structures is specified by the nfds argument.
Historically, this argument has been an unsigned long, which seems excessive. An unsigned int would be adequate. Unix 98 defines a new datatype for this argument: nfds_t.