⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loop.c

📁 unix环境高级编程的源代码
💻 C
字号:
#include    "calld.h"
#include    <sys/time.h>
#include    <errno.h>

static void    cli_done(int);
static void child_done(int);

static fd_set    allset;    /* one bit per client conn, plus one for listenfd */
                        /* modified by loop() and cli_done() */

void
loop(void)
{
    int         i, n, maxfd, maxi, listenfd, nread;
    char     buf[MAXLINE];
    Client    *cliptr;
    uid_t     uid;
    fd_set     rset;

    if (signal_intr(SIGCHLD, sig_chld) == SIG_ERR)
        log_sys("signal error");

                /* obtain descriptor to listen for client requests on */
    if ( (listenfd = serv_listen(CS_CALL)) < 0)
        log_sys("serv_listen error");

    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);
    maxfd = listenfd;
    maxi = -1;

    for ( ; ; ) {
        if (chld_flag)
            child_done(maxi);
        rset = allset;        /* rset gets modified each time around */
        if ( (n = select(maxfd + 1, &rset, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR) {
                    /* caught SIGCHLD, find entry with childdone set */
                child_done(maxi);
                continue;        /* issue the select again */
            } else
                log_sys("select error");
        }

        if (FD_ISSET(listenfd, &rset)) {
                    /* accept new client request */
            if ( (clifd = serv_accept(listenfd, &uid)) < 0)
                log_sys("serv_accept error: %d", clifd);

            i = client_add(clifd, uid);
            FD_SET(clifd, &allset);
            if (clifd > maxfd)
                maxfd = clifd;    /* max fd for select() */
            if (i > maxi)
                maxi = i;        /* max index in client[] array */
            log_msg("new connection: uid %d, fd %d", uid, clifd);
            continue;
        }

            /* Go through client[] array.
               Read any client data that has arrived. */

        for (cliptr = &client[0]; cliptr <= &client[maxi]; cliptr++) {
            if ( (clifd = cliptr->fd) < 0)
                continue;
            if (FD_ISSET(clifd, &rset)) {
                        /* read argument buffer from client */
                if ( (nread = read(clifd, buf, MAXLINE)) < 0)
                    log_sys("read error on fd %d", clifd);

                else if (nread == 0) {
                    /* The client has terminated or closed the stream
                       pipe.  Now we can release its device lock. */

                    log_msg("closed: uid %d, fd %d",
                                        cliptr->uid, clifd);
                    lock_rel(cliptr->pid);
                    cli_done(clifd);
                    continue;
                }

                /* Data has arrived from the client.  Process the
                   client's request. */

                if (buf[nread-1] != 0) {
                    log_quit("request from uid %d not null terminated:"
                             " %*.*s", uid, nread, nread, buf);
                    cli_done(clifd);
                    continue;
                }
                log_msg("starting: %s, from uid %d", buf, uid);

                        /* Parse the arguments, set options.  Since
                           we may need to try calling again for this
                           client, save options in client[] array. */
                if (buf_args(buf, cli_args) < 0)
                    log_quit("command line error: %s", buf);
                cliptr->Debug = Debug;
                cliptr->parity = parity;
                strcpy(cliptr->sysname, sysname);
                strcpy(cliptr->speed, (speed == NULL) ? "" : speed);
                cliptr->childdone = 0;
                cliptr->sysftell = 0;
                cliptr->foundone = 0;

                if (request(cliptr) < 0) {
                        /* system not found, or unable to connect */
                    if (send_err(cliptr->fd, -1, errmsg) < 0)
                        log_sys("send_err error");
                    cli_done(clifd);
                    continue;
                }
                /* At this point request() has forked a child that is
                   trying to dial the remote system.  We'll find
                   out the child's status when it terminates. */
            }
        }
    }
}

/* Go through the client[] array looking for clients whose dialing
   children have terminated.  This function is called by loop() when
   chld_flag (the flag set by the SIGCHLD handler) is nonzero. */

static void
child_done(int maxi)
{
    Client    *cliptr;

again:
    chld_flag = 0;    /* to check when done with loop for more SIGCHLDs */
    for (cliptr = &client[0]; cliptr <= &client[maxi]; cliptr++) {
        if ( (clifd = cliptr->fd) < 0)
            continue;
        if (cliptr->childdone) {
            log_msg("child done: pid %d, status %d",
                            cliptr->pid, cliptr->childdone-1);

            /* If the child was successful (exit(0)), just clear
               the flag.  When the client terminates, we'll read
               the EOF on the stream pipe above and release
               the device lock. */

            if (cliptr->childdone == 1) {    /* child did exit(0) */
                cliptr->childdone = 0;
                continue;
            }

            /* Unsuccessful: child did exit(1).  Release the device
               lock and try again from where we left off. */

            cliptr->childdone = 0;
            lock_rel(cliptr->pid);    /* unlock the device entry */
            if (request(cliptr) < 0) {
                        /* still unable, time to give up */
                if (send_err(cliptr->fd, -1, errmsg) < 0)
                    log_sys("send_err error");
                cli_done(clifd);
                continue;
            }
            /* request() has forked another child for this client */
        }
    }
    if (chld_flag)    /* additional SIGCHLDs have been caught */
        goto again;    /* need to check all childdone flags again */
}

/* Clean up when we're done with a client. */

static void
cli_done(int clifd)
{
    client_del(clifd);        /* delete entry in client[] array */
    FD_CLR(clifd, &allset);    /* turn off bit in select() set */
    close(clifd);            /* close our end of stream pipe */
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -