简体   繁体   中英

Unix Network Programming Clarification

I was going through the classic book Unix Network Programming , when I stumbled upon this program (Section 6.8, page 179-180)

#include    "unp.h"

int
main(int argc, char **argv)
{
    int                 i, maxi, maxfd, listenfd, connfd, sockfd;
    int                 nready, client[FD_SETSIZE];
    ssize_t             n;
    fd_set              rset, allset;
    char                buf[MAXLINE];
    socklen_t           clilen;
    struct sockaddr_in  cliaddr, servaddr;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(SERV_PORT);

    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

    Listen(listenfd, LISTENQ);

    maxfd = listenfd;           /* initialize */
    maxi = -1;                  /* index into client[] array */
    for (i = 0; i < FD_SETSIZE; i++)
        client[i] = -1;         /* -1 indicates available entry */
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);

    for ( ; ; ) {
        rset = allset;      /* structure assignment */
        nready = Select(maxfd+1, &rset, NULL, NULL, NULL);

        if (FD_ISSET(listenfd, &rset)) {    /* new client connection */
            clilen = sizeof(cliaddr);
            connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

            for (i = 0; i < FD_SETSIZE; i++)
                if (client[i] < 0) {
                    client[i] = connfd; /* save descriptor */
                    break;
                }
            if (i == FD_SETSIZE)
                err_quit("too many clients");

            FD_SET(connfd, &allset);    /* add new descriptor to set */
            if (connfd > maxfd)
                maxfd = connfd;         /* for select */
            if (i > maxi)
                maxi = i;               /* max index in client[] array */

            if (--nready <= 0)
                continue;               /* no more readable descriptors */
        }

        for (i = 0; i <= maxi; i++) {   /* check all clients for data */
            if ( (sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset)) {
                if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
                        /*4connection closed by client */
                    Close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                } else
                    Writen(sockfd, buf, n);

                if (--nready <= 0)
                    break;              /* no more readable descriptors */
            }
        }
    }
}    

The author mentions that this program is not safe against DOS attack. Quoting from the book,

"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 (system call), which will read the 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 by this one client, and will not service any other clients until malicious client either sends a newline or terminates"

I am not sure if I understand this correctly. Why will the read system call be called the second time for this malicious client, since it only sent 1 byte of data, that gets notified by the first call to select . The subsequent calls to select will never have this malicious file descriptor set as there is no activity. Am I missing something here?

My guess here is that there is a typo in the code, instead of Read, it should be some version of Readline method mentioned at other places in the book.

Note : The code contains Read and Select (with capital R and S), which are nothing but error handled wrappers of read and select system call

Yes, it seems likely that it was intended to be Readline .

In the downloadable source code that file is tcpcliserv/tcpservselect01.c and there is a corresponding .lc file (with line number annotations) which uses Readline instead of Read , and it was Readline in the second edition of the book ( source code ). About the only way to make sense of the parenthetic comment "(other than a newline)" is to assume that the intended read function reads up to a newline.

Oddly, it hasn't been reported in the errata . Maybe you should do so.

I think that the problem that he was pointing out was that, as you noted in your NOTE, this code uses Read which is a wrapper of read . My guess, since I'm not about to dig out my copy of the book right now, is that Read will try to call read a second time to finish receiving the data that is never coming.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM