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

📄 loop.c

📁 unix高级编程源代码.<<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 + -