Esempio n. 1
0
int private_vstream_fflush(ACL_VSTREAM *stream)
{
	unsigned char *ptr;
	int   n;

	acl_assert(stream);
	if (stream->wbuf == NULL || stream->wbuf_dlen == 0)
		return 0;

	ptr = stream->wbuf;
	while (stream->wbuf_dlen > 0) {
		n = __vstream_sys_write(stream, ptr, (int) stream->wbuf_dlen);
		if (n <= 0) {
			if (acl_last_error() == ACL_EINTR
				|| acl_last_error() == ACL_EAGAIN)
			{
				continue;
			}
			return (ACL_VSTREAM_EOF);
		}

		stream->wbuf_dlen -= n;
		ptr += n;
	}

	acl_assert(stream->wbuf_dlen >= 0);

	return (int) (ptr - stream->wbuf);
}
Esempio n. 2
0
bool queue_file::move_file(const char* queueName, const char* extName)
{
	acl::string buf(256);
	bool once_again = false;

	while (true)
	{
		buf.clear();
		buf << m_home << PATH_SEP << queueName << PATH_SEP << m_queueSub
			<< PATH_SEP << m_partName << "." << extName;

#ifdef WIN32
		// 在win32下必须先关闭文件句柄
		this->close();
#endif

		if (rename(m_filePath.c_str(), buf.c_str()) == 0)
			break;

		// 如果返回错误原因是目标路径不存在,则尝试创建目录结构

		if (once_again || acl_last_error() != ENOENT)
		{
			logger_error("move from %s to %s error(%s), errno: %d, %d",
				m_filePath.c_str(), buf.c_str(), acl_last_serror(),
				acl_last_error(), ENOENT);
			return (false);
		}

		// 设置重试标志位
		once_again = true;

		buf.clear();
		buf << m_home << PATH_SEP << queueName
			<< PATH_SEP << m_queueSub;

		// 创建队列目录
		if (acl_make_dirs(buf.c_str(), 0700) == -1)
		{
			logger_error("mkdir: %s error(%s)",
				buf.c_str(), acl_last_serror());
			return false;
		}
	}

#ifdef WIN32
	// win32 下需要重新再打开
	return (open(m_home, queueName, m_queueSub, m_partName, extName));
#else
	if (m_queueName != queueName)
		ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName));
	if (m_extName != extName)
		ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName));
	m_filePath.clear();
	m_filePath << m_home << PATH_SEP << m_queueName << PATH_SEP
		<< m_queueSub << PATH_SEP << m_partName << "." << m_extName;
#endif
	return (true);
}
Esempio n. 3
0
static void enable_listen(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp)
{
	const char *myname = "enable_listen";
	ACL_SOCKET sock;
	DWORD ReceiveLen = 0;

	sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
		0, 0, WSA_FLAG_OVERLAPPED);

	memset(&fdp->event_read->overlapped, 0,
		sizeof(fdp->event_read->overlapped));

	fdp->stream->type |= ACL_VSTREAM_TYPE_LISTEN_IOCP;
	fdp->stream->iocp_sock = sock;

	if (AcceptEx(ACL_VSTREAM_SOCK(fdp->stream), sock,
		fdp->event_read->myAddrBlock, 0,
		ACCEPT_ADDRESS_LENGTH, ACCEPT_ADDRESS_LENGTH,
		&ReceiveLen, &fdp->event_read->overlapped) == FALSE
		&& acl_last_error() !=ERROR_IO_PENDING)
	{
		acl_msg_warn("%s(%d): AcceptEx error(%s)",
			myname, __LINE__, acl_last_serror());
	}
}
Esempio n. 4
0
int socket_stream::sock_read(void *ctx, unsigned char *buf, size_t len)
{
#ifdef HAS_POLARSSL
	socket_stream* cli = (socket_stream*) ctx;
	ACL_VSTREAM* stream = cli->get_vstream();
	acl_assert(stream);
	int   ret, timeout = 120;

	if ((ret = acl_socket_read(ACL_VSTREAM_SOCK(stream), buf, len,
		timeout, stream, NULL)) < 0)
	{
		int   errnum = acl_last_error();
		if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK
#if ACL_EWOULDBLOCK != ACL_EAGAIN
			|| ret == ACL_EAGAIN
#endif
			)
			return POLARSSL_ERR_NET_WANT_READ;
		else if (errnum == ACL_ECONNRESET || errno == EPIPE)
			return POLARSSL_ERR_NET_CONN_RESET;
		else
			return POLARSSL_ERR_NET_RECV_FAILED;
	}

	return ret;
#else
	(void) ctx;
	(void) buf;
	(void) len;
	return -1;
#endif
}
Esempio n. 5
0
int polarssl_io::sock_read(void *ctx, unsigned char *buf, size_t len)
{
#ifdef HAS_POLARSSL
	polarssl_io* io = (polarssl_io*) ctx;
	int   ret, timeout = 120;
	ACL_VSTREAM* vs = io->stream_->get_vstream();
	ACL_SOCKET fd = ACL_VSTREAM_SOCK(vs);

	ret = acl_socket_read(fd, buf, len, timeout, vs, NULL);
	if (ret < 0)
	{
		int   errnum = acl_last_error();
		if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK
#if ACL_EWOULDBLOCK != ACL_EAGAIN
			|| ret == ACL_EAGAIN
#endif
			)
			return POLARSSL_ERR_NET_WANT_READ;
		else if (errnum == ACL_ECONNRESET || errno == EPIPE)
			return POLARSSL_ERR_NET_CONN_RESET;
		else
			return POLARSSL_ERR_NET_RECV_FAILED;
	}

	return ret;
#else
	(void) ctx;
	(void) buf;
	(void) len;
	logger_error("HAS_POLARSSL not defined!");
	return -1;
#endif
}
Esempio n. 6
0
int acl_set_eugid(uid_t euid, gid_t egid)
{
	int   saved_error = acl_last_error();
	char  tbuf[256];

	if (geteuid() != 0 && seteuid(0)) {
		acl_msg_error("set_eugid: seteuid(0): %s",
			acl_last_strerror(tbuf, sizeof(tbuf)));
		return -1;
	}
	if (setegid(egid) < 0) {
		acl_msg_error("set_eugid: setegid(%ld): %s", (long) egid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
		return -1;
	}
	if (setgroups(1, &egid) < 0) {
		acl_msg_error("set_eugid: setgroups(%ld): %s", (long) egid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
		return -1;
	}
	if (euid != 0 && seteuid(euid) < 0) {
		acl_msg_error("set_eugid: seteuid(%ld): %s", (long) euid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
		return -1;
	}
	if (acl_msg_verbose)
		acl_msg_info("set_eugid: euid %ld egid %ld",
			(long) euid, (long) egid);

	acl_set_error(saved_error);
	return 0;
}
Esempio n. 7
0
int ssl_aio_stream::__ssl_send(ACL_SOCKET, const void *buf, size_t len,
	int, ACL_VSTREAM*, void *ctx)
{
#ifdef HAS_POLARSSL
	ssl_aio_stream* cli = (ssl_aio_stream*) ctx;
	int   ret;

	while ((ret = ::ssl_write((ssl_context*) cli->ssl_,
		(unsigned char*) buf, len)) <= 0)
	{
		if (ret == POLARSSL_ERR_NET_WANT_READ
			|| ret == POLARSSL_ERR_NET_WANT_WRITE)
		{
			if (acl_last_error() != ACL_EWOULDBLOCK)
				acl_set_error(ACL_EWOULDBLOCK);
		}
		return ACL_VSTREAM_EOF;
	}
	return ret;
#else
	(void) buf;
	(void) len;
	(void) ctx;
	return -1;
#endif
}
Esempio n. 8
0
static int poll_write_wait(ACL_SOCKET fd, int timeout)
{
	const char *myname = "poll_write_wait";
	struct pollfd fds;
	int   delay = timeout * 1000;

	fds.events = POLLOUT | POLLHUP | POLLERR;
	fds.fd = fd;

	for (;;) {
		switch (poll(&fds, 1, delay)) {
		case -1:
			if (acl_last_error() != ACL_EINTR) {
				char tbuf[256];
				acl_msg_error("%s: poll error(%s)", myname,
					acl_last_strerror(tbuf, sizeof(tbuf)));
				return (-1);
			}
			continue;
		case 0:
			acl_set_error(ACL_ETIMEDOUT);
			return (-1);
		default:
			if ((fds.revents & (POLLHUP | POLLERR))
				|| !(fds.revents & POLLOUT))
			{
				return (-1);
			}
			return (0);
		}
	}
}
Esempio n. 9
0
int acl_readable(ACL_SOCKET fd)
{
	const char *myname = "poll_read_wait";
	struct pollfd fds;
	int   delay = 0;

	fds.events = POLLIN;
	fds.fd = fd;

	acl_set_error(0);

	for (;;) {
		switch (poll(&fds, 1, delay)) {
		case -1:
			if (acl_last_error() == ACL_EINTR)
				continue;

			acl_msg_error("%s(%d), %s: poll error(%s), fd: %d",
				__FILE__, __LINE__, myname,
				acl_last_serror(), (int) fd);
			return -1;
		case 0:
			return 0;
		default:
			if ((fds.revents & POLLIN)) {
				return 1;
			} else if (fds.revents & (POLLHUP | POLLERR)) {
				return 1;
			} else {
				return 0;
			}
		}
	}
}
Esempio n. 10
0
acl_off_t acl_lseek(ACL_FILE_HANDLE fh, acl_off_t offset, int whence)
{
	const char *myname = "acl_lseek";
	LARGE_INTEGER li;
	DWORD method;

	if (whence == SEEK_CUR)
		method = FILE_CURRENT;
	else if (whence == SEEK_SET)
		method = FILE_BEGIN;
	else if (whence == SEEK_END)
		method = FILE_END;
	else {
		acl_msg_error("%s(%d): invalid whence(%d)", myname, __LINE__, whence);
		return -1;
	}

	li.QuadPart = offset;
	li.LowPart = SetFilePointer(fh, li.LowPart, &li.HighPart, method);

	if (li.LowPart == 0xFFFFFFFF && acl_last_error() != NO_ERROR) {
		li.QuadPart = -1;
	}

	return li.QuadPart;
}
Esempio n. 11
0
int acl_sane_socketpair(int domain, int type, int protocol, ACL_SOCKET result[2])
{
	static int socketpair_ok_errors[] = {
		EINTR,
		0,
	};
	int     count;
	int     err;
	int     ret;

	/*
	 * Solaris socketpair() can fail with EINTR.
	 */
	while ((ret = socketpair(domain, type, protocol, result)) < 0) {
		for (count = 0; /* void */ ; count++) {
			if ((err = socketpair_ok_errors[count]) == 0)
				return (ret);
			if (acl_last_error() == err) {
				char tbuf[256];
				acl_msg_warn("socketpair: %s (trying again)",
					acl_last_strerror(tbuf, sizeof(tbuf)));
				sleep(1);
				break;
			}
		}
	}
	return (ret);
}
Esempio n. 12
0
int ssl_aio_stream::__sock_send(void *ctx, const unsigned char *buf, size_t len)
{
#ifdef HAS_POLARSSL
	ssl_aio_stream* cli = (ssl_aio_stream*) ctx;
	ACL_VSTREAM* stream = cli->get_vstream();
	acl_assert(stream);
	int   ret, errnum;

	if ((ret = acl_socket_write(ACL_VSTREAM_SOCK(stream), buf, len,
		0, stream, NULL)) < 0)
	{
		errnum = acl_last_error();
		if (errnum == ACL_EINTR)
			return POLARSSL_ERR_NET_WANT_WRITE;

		else if (errnum == ACL_EWOULDBLOCK)
			return POLARSSL_ERR_NET_WANT_WRITE;
#if ACL_EWOULDBLOCK != ACL_EAGAIN
		else if (errnum == ACL_EAGAIN)
			return POLARSSL_ERR_NET_WANT_WRITE;
#endif
		else if (errnum == ACL_ECONNRESET || errno == EPIPE)
			return POLARSSL_ERR_NET_CONN_RESET;
		else
			return POLARSSL_ERR_NET_SEND_FAILED;
	}

	return ret;
#else
	(void) ctx;
	(void) buf;
	(void) len;
	return -1;
#endif
}
Esempio n. 13
0
int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa,
	socklen_t len, int timeout)
{
	int   err;

	/*
	 * Sanity check. Just like with timed_wait(), the timeout must be a
	 * positive number.
	 */
	if (timeout < 0)
		acl_msg_panic("timed_connect: bad timeout: %d", timeout);

	/*
	 * Start the connection, and handle all possible results.
	 */
	if (acl_sane_connect(sock, sa, len) == 0)
		return (0);

	errno = acl_last_error();

#ifdef	ACL_UNIX
	if (errno != ACL_EINPROGRESS)
		return (-1);
#elif defined(ACL_WINDOWS)
	if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK)
		return (-1);
#endif

	/*
	 * A connection is in progress. Wait for a limited amount of time for
	 * something to happen. If nothing happens, report an error.
	 */
	if (acl_write_wait(sock, timeout) < 0)
		return (-1);

	/*
	 * Something happened. Some Solaris 2 versions have getsockopt() itself
	 * return the error, instead of returning it via the parameter list.
	 */
	len = sizeof(err);
	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) {
#ifdef  SUNOS5
	/*
	 * Solaris 2.4's socket emulation doesn't allow you
	 * to determine the error from a failed non-blocking
	 * connect and just returns EPIPE.  Create a fake
	 * error message for connect.   -- [email protected]
	 */
		if (errno == EPIPE)
			acl_set_error(ACL_ENOTCONN);
#endif
		return (-1);
	}

	if (err != 0) {
		acl_set_error(err);
		return (-1);
	} else
		return (0);
}
Esempio n. 14
0
int acl_read_wait(ACL_SOCKET fd, int timeout)
{
	const char *myname = "acl_read_wait";
	struct pollfd fds;
	int   delay = timeout * 1000;

	fds.events = POLLIN | POLLHUP | POLLERR;
	fds.fd = fd;

	acl_set_error(0);

	for (;;) {
		switch (poll(&fds, 1, delay)) {
		case -1:
			if (acl_last_error() == ACL_EINTR)
				continue;

			acl_msg_error("%s(%d), %s: poll error(%s), fd: %d",
				__FILE__, __LINE__, myname,
				acl_last_serror(), (int) fd);
			return -1;
		case 0:
			acl_set_error(ACL_ETIMEDOUT);
			return -1;
		default:
			if (fds.revents & (POLLHUP | POLLERR))
				return -1;
			else if ((fds.revents & POLLIN))
				return 0;
			else
				return -1;
		}
	}
}
Esempio n. 15
0
int acl_readable(ACL_SOCKET fd)
{
	const char *myname = "acl_readable";
	struct timeval tv;
	fd_set  rfds, xfds;
	int   errnum;

	/*
	 * Sanity checks.
	 */
	if ((unsigned) fd >= FD_SETSIZE)
		acl_msg_fatal("%s(%d), %s: fd %d does not fit in "
			"FD_SETSIZE: %d", __FILE__, __LINE__, myname,
			(int) fd, FD_SETSIZE);

	/*
	 * Initialize.
	 */
	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);
	FD_ZERO(&xfds);
	FD_SET(fd, &xfds);
	tv.tv_sec = 0;
	tv.tv_usec = 0;

	acl_set_error(0);

	/*
	 * Loop until we have an authoritative answer.
	 */
	for (;;) {
		switch (select((int) fd + 1, &rfds, (fd_set *) 0,
			&xfds, &tv))
		{
		case -1:
			errnum = acl_last_error();
#ifdef	ACL_WINDOWS
			if (errnum == WSAEINPROGRESS
				|| errnum == WSAEWOULDBLOCK
				|| errnum == ACL_EINTR)
			{
				continue;
			}
#else
			if (errnum == ACL_EINTR)
				continue;
#endif
			acl_msg_error("%s(%d), %s: select error(%s), fd: %d",
				__FILE__, __LINE__, myname,
				acl_last_serror(), (int) fd);
			return -1;
		case 0:
			return 0;
		default:
			return FD_ISSET(fd, &rfds);
		}
	}
}
Esempio n. 16
0
int acl_read_wait(ACL_SOCKET fd, int timeout)
{
    const char *myname = "acl_read_wait";
    struct pollfd fds;
    int   delay = timeout * 1000;
    time_t begin;

    fds.events = POLLIN | POLLHUP | POLLERR;
    fds.fd = fd;

    acl_set_error(0);

    for (;;) {
        time(&begin);

        switch (poll(&fds, 1, delay)) {
        case -1:
            if (acl_last_error() == ACL_EINTR)
                continue;

            acl_msg_error("%s(%d), %s: poll error(%s), fd: %d",
                          __FILE__, __LINE__, myname,
                          acl_last_serror(), (int) fd);
            return -1;
        case 0:
            acl_msg_warn("%s(%d), %s: poll timeout: %s, fd: %d, "
                         "delay: %d, spent: %ld", __FILE__, __LINE__,
                         myname, acl_last_serror(), fd, delay,
                         (long) (time(NULL) - begin));
            acl_set_error(ACL_ETIMEDOUT);
            return -1;
        default:
            if (fds.revents & (POLLHUP | POLLERR)) {
                acl_msg_warn("%s(%d), %s: poll error: %s, "
                             "fd: %d, delay: %d, spent: %ld",
                             __FILE__, __LINE__, myname,
                             acl_last_serror(), fd, delay,
                             (long) (time(NULL) - begin));
                return -1;
            } else if ((fds.revents & POLLIN))
                return 0;
            else {
                acl_msg_warn("%s(%d), %s: poll error: %s, "
                             "fd: %d, delay: %d, spent: %ld",
                             __FILE__, __LINE__, myname,
                             acl_last_serror(), fd, delay,
                             (long) (time(NULL) - begin));
                return -1;
            }
        }
    }
}
Esempio n. 17
0
static int __loop_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen)
{
	const unsigned char *ptr;
	int   n;

	ptr   = (const unsigned char *) vptr;
	while (dlen > 0) {
		n = __vstream_sys_write(stream, ptr, (int) dlen);
		if (n <= 0) {
			if (acl_last_error() == ACL_EINTR
				|| acl_last_error() == ACL_EAGAIN)
			{
				continue;
			}
			return (ACL_VSTREAM_EOF);
		}

		dlen  -= n;
		ptr   += n;
	}

	return (int) (ptr - (const unsigned char *) vptr);
}
Esempio n. 18
0
static int  __read_wait(ACL_SOCKET fd, int timeout)
{
	fd_set  read_fds;
	fd_set  except_fds;
	struct timeval tv;
	struct timeval *tp;

#ifdef	ACL_UNIX
	/*
	 * Sanity checks.
	 */
	acl_assert(FD_SETSIZE > (unsigned) fd);
#endif

	/*
	 * Use select() so we do not depend on alarm() and on signal() handlers.
	 * Restart the select when interrupted by some signal. Some select()
	 * implementations reduce the time to wait when interrupted, which is
	 * exactly what we want.
	 */
	FD_ZERO(&read_fds);
	FD_SET(fd, &read_fds);
	FD_ZERO(&except_fds);
	FD_SET(fd, &except_fds);
	if (timeout >= 0) {
		tv.tv_usec = 0;
		tv.tv_sec = timeout;
		tp = &tv;
	} else
		tp = 0;

	for (;;) {
		switch (select((int) fd + 1, &read_fds, (fd_set *) 0,
			&except_fds, tp))
		{
		case -1:
			if (acl_last_error() != ACL_EINTR)
				return -1;
			continue;
		case 0:
			acl_set_error(ACL_ETIMEDOUT);
			return (-1);
		default:
			return (0);
		}
	}
}
Esempio n. 19
0
const char *acl_last_serror(void)
{
	char *buf;
	int   error = acl_last_error();
	static int __buf_size = 4096;

	(void) acl_pthread_once(&once_control, thread_buf_init);
	buf = acl_pthread_getspecific(__errbuf_key);
	if (buf == NULL) {
		buf = acl_mymalloc(__buf_size);
		acl_pthread_setspecific(__errbuf_key, buf);
		if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) {
			__main_buf = buf;
			atexit(main_free_buf);
		}
	}
	return acl_strerror(error, buf, __buf_size);
}
Esempio n. 20
0
static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp)
{
	const char *myname = "enable_write";
	ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream);
	DWORD sendBytes;

	fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE;
	fdp->flag |= EVENT_FDTABLE_FLAG_WRITE;

	if (fdp->h_iocp == NULL) {
		fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd,
					ev->h_iocp, (DWORD) fdp, 0);
		if (fdp->h_iocp != ev->h_iocp)
			acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)",
				myname, __LINE__, acl_last_serror());
		fdp->flag |= EVENT_FDTABLE_FLAG_IOCP;
	}

	if (fdp->event_write == NULL) {
		fdp->event_write = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT));
		fdp->event_write->fdp = fdp;
	} else if (fdp->event_write->type == IOCP_EVENT_WRITE) {
		return;
	}

	fdp->event_write->type = IOCP_EVENT_WRITE;

	if ((fdp->stream->flag & ACL_VSTREAM_FLAG_CONNECTING)) {
		enable_connect(ev, fdp);
		fdp->stream->flag &= ~ACL_VSTREAM_FLAG_CONNECTING;
		return;
	}

	memset(&fdp->event_write->overlapped, 0,
		sizeof(fdp->event_write->overlapped));

	if (WriteFile((HANDLE) sockfd, NULL, 0,
			&sendBytes, &fdp->event_write->overlapped) == FALSE
		&& acl_last_error() != ERROR_IO_PENDING)
	{
		acl_msg_warn("%s(%d): WriteFile error(%s), sockfd(%d)",
			myname, __LINE__, acl_last_serror(), sockfd);
	}
}
Esempio n. 21
0
void acl_doze(unsigned delay)
{
#ifdef	ACL_UNIX
    struct timeval tv;

    tv.tv_sec = delay / 1000;
    tv.tv_usec = (delay - tv.tv_sec * 1000) * 1000;
    while (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv) < 0)
        if (acl_last_error() != ACL_EINTR) {
            char tbuf[256];
            acl_msg_fatal("doze: select: %s",
                          acl_last_strerror(tbuf, sizeof(tbuf)));
        }
#elif	defined(WIN32)
    Sleep(delay);
#else
#error "unknown OS"
#endif
}
Esempio n. 22
0
static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp)
{
	const char *myname = "enable_read";
	ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream);
	DWORD recvBytes;

	fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ;
	fdp->flag |= EVENT_FDTABLE_FLAG_READ;

	if (fdp->h_iocp == NULL) {
		fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd,
						ev->h_iocp, (DWORD) fdp, 0);
		if (fdp->h_iocp != ev->h_iocp)
			acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)",
				myname, __LINE__, acl_last_serror());
		fdp->flag |= EVENT_FDTABLE_FLAG_IOCP;
	}

	if (fdp->event_read == NULL) {
		fdp->event_read = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT));
		fdp->event_read->fdp = fdp;
	} else if (fdp->event_read->type == IOCP_EVENT_READ) {
		return;
	}

	fdp->event_read->type = IOCP_EVENT_READ;

	if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN)) {
		enable_listen(ev, fdp);
		return;
	}

	memset(&fdp->event_read->overlapped, 0,
		sizeof(fdp->event_read->overlapped));

	if (ReadFile((HANDLE) sockfd, NULL, 0,
			&recvBytes, &fdp->event_read->overlapped) == FALSE
		&& acl_last_error() != ERROR_IO_PENDING)
	{
		acl_msg_warn("%s(%d): ReadFile error(%s)",
			myname, __LINE__, acl_last_serror());
	}
}
Esempio n. 23
0
int acl_write_buf(ACL_SOCKET fd, const char *buf, int len, int timeout)
{
	int     count;

	while (len > 0) {
		if (timeout > 0 && acl_write_wait(fd, timeout) < 0)
			return -1;
		count = acl_socket_write(fd, buf, len, 0, NULL, NULL);
		if (count < 0) {
			if (acl_last_error() == ACL_EAGAIN && timeout > 0)
				continue;
			return -1;
		}
		if (count == 0)
			acl_msg_fatal("write returned 0");
		buf += count;
		len -= count;
	}
	return len;
}
Esempio n. 24
0
void acl_set_ugid(uid_t uid, gid_t gid)
{
	int   saved_error = acl_last_error();
	char  tbuf[256];

	if (geteuid() != 0)
		if (seteuid(0) < 0)
			acl_msg_fatal("seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf)));
	if (setgid(gid) < 0)
		acl_msg_fatal("setgid(%ld): %s", (long) gid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
	if (setgroups(1, &gid) < 0)
		acl_msg_fatal("setgroups(1, &%ld): %s", (long) gid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
	if (setuid(uid) < 0)
		acl_msg_fatal("setuid(%ld): %s", (long) uid,
			acl_last_strerror(tbuf, sizeof(tbuf)));
	if (acl_msg_verbose > 1)
		acl_msg_info("setugid: uid %ld gid %ld", (long) uid, (long) gid);
	acl_set_error(saved_error);
}
Esempio n. 25
0
int acl_write_wait(ACL_SOCKET fd, int timeout)
{
	const char *myname = "acl_write_wait";
	struct pollfd fds;
	int   delay = timeout * 1000;

	fds.events = POLLOUT | POLLHUP | POLLERR;
	fds.fd = fd;

	acl_set_error(0);

	for (;;) {
		switch (poll(&fds, 1, delay)) {
		case -1:
			if (acl_last_error() == ACL_EINTR)
				continue;
			acl_msg_error("%s(%d), %s: poll error(%s), fd: %d",
				__FILE__, __LINE__, myname,
				acl_last_serror(), (int) fd);
			return -1;
		case 0:
			acl_set_error(ACL_ETIMEDOUT);
			return -1;
		default:
			if ((fds.revents & (POLLHUP | POLLERR))) {
				acl_msg_error("%s(%d), %s: fd: %d,"
					"POLLHUP: %s, POLLERR: %s",
					__FILE__, __LINE__, myname, fd,
					fds.revents & POLLHUP ? "yes" : "no",
					fds.revents & POLLERR ? "yes" : "no");
				return -1;
			}
			if (fds.revents & POLLOUT)
				return 0;
			acl_msg_error("%s(%d), %s: unknown error, fd: %d",
				__FILE__, __LINE__, myname, fd);
			return -1;
		}
	}
}
Esempio n. 26
0
int acl_readable(ACL_SOCKET fd)
{
	struct pollfd fds;
	int    delay = 0;

	fds.events = POLLIN | POLLPRI;
	fds.fd = fd;

	acl_set_error(0);

	for (;;) {
		switch (__sys_poll(&fds, 1, delay)) {
#ifdef ACL_WINDOWS
		case SOCKET_ERROR:
#else
		case -1:
#endif
			if (acl_last_error() == ACL_EINTR)
				continue;

			acl_msg_error("%s(%d), %s: poll error(%s), fd: %d",
				__FILE__, __LINE__, __FUNCTION__,
				acl_last_serror(), (int) fd);
			return -1;
		case 0:
			return 0;
		default:
			if ((fds.revents & POLLIN)) {
				return 1;
			} else if (fds.revents & (POLLHUP | POLLERR)) {
				return 1;
			} else {
				return 0;
			}
		}
	}
}
Esempio n. 27
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_EVENT_TIMER *timer;
	int   delay, nready;
	ACL_EVENT_FDTABLE *fdp;
	EVENT_BUFFER *bp;

	delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000);
	if (delay < 0)
		delay = 0; /* 0 milliseconds at least */

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 epoll/kqueue/devpoll 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = (timer->when - eventp->present) / 1000;

		if (n <= 0)
			delay = 0;
		else if ((int) n < delay) {
			delay = (int) n;
			if (delay <= 0)  /* xxx */
				delay = 100;
		}
	}

	/* 设置描述字对象的状态,添加/删除之前设置的描述字对象 */

	event_set_all(eventp);

	if (eventp->fdcnt == 0) {
		if (eventp->fdcnt_ready == 0)
			sleep(1);
		goto TAG_DONE;
	}

	/* 如果已经有描述字准备好则检测超时时间置 0 */

	if (eventp->fdcnt_ready > 0)
		delay = 0;

	/* 调用 epoll/kquque/devpoll 系统调用检测可用描述字 */

	EVENT_BUFFER_READ(nready, ev->event_fd, ev->event_buf,
		ev->event_fdslots, delay);

	if (eventp->nested++ > 0)
		acl_msg_fatal("%s(%d): recursive call, nested: %d",
			myname, __LINE__, eventp->nested);
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_fatal("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查检测结果 */

	for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) {
#ifdef	USE_FDMAP
		ACL_SOCKET sockfd;

		sockfd = EVENT_GET_FD(bp);
		fdp = acl_fdmap_ctx(ev->fdmap, sockfd);
		if (fdp == NULL || fdp->stream == NULL)
			continue;
		if (sockfd != ACL_VSTREAM_SOCK(fdp->stream))
			acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname,
				__LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream));
#else
		fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp);
		if (fdp == NULL || fdp->stream == NULL)
			continue;
#endif

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		/* 检查描述字是否可读 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) {

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发
			 * ACL_VSTREAM 流在读时调用系统的 read 函数
			 */

			fdp->stream->sys_read_ready = 1;

			/* 给该描述字对象附加可读属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				if (fdp->listener)
					fdp->event_type |= ACL_EVENT_ACCEPT;

				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}

		/* 检查描述字是否可写 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) {

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}

#ifdef	EVENT_TEST_ERROR
		if (EVENT_TEST_ERROR(bp)) {
			/* 如果出现异常则设置异常属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_XCPT;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}
#endif
	}

TAG_DONE:

	/*
	 * Deliver timer events. Requests are sorted: we can stop when we reach
	 * the future or the list end. Allow the application to update the timer
	 * queue while it is being called back. To this end, we repeatedly pop
	 * the first request off the timer queue before delivering the event to
	 * the application.
	 */

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		/* 定时器时间间隔 > 0 且允许定时器被循环调用,则重设定时器 */
		if (timer->delay > 0 && timer->keep) {
			timer->ncount++;
			eventp->timer_request(eventp, timer->callback,
				timer->context, timer->delay, timer->keep);
		} else {
			acl_ring_detach(&timer->ring);	/* first this */
			timer->nrefer--;
			if (timer->nrefer != 0)
				acl_msg_fatal("%s(%d): nrefer(%d) != 0",
					myname, __LINE__, timer->nrefer);
			acl_myfree(timer);
		}
		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);
	}

	/* 处理准备好的描述字事件 */

	if (eventp->fdcnt_ready > 0)
		event_fire(eventp);

	eventp->nested--;
}
Esempio n. 28
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_POLL *ev = (EVENT_POLL *) eventp;
	ACL_EVENT_TIMER *timer;
	int   nready, i, revents;
	acl_int64 delay;
	ACL_EVENT_FDTABLE *fdp;

	delay = eventp->delay_sec * 1000000 + eventp->delay_usec;
	if (delay < DELAY_MIN)
		delay = DELAY_MIN;

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 poll 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = timer->when - eventp->present;
		if (n <= 0)
			delay = 0;
		else if (n < delay)
			delay = n;
	}

	/* 调用 event_prepare 检查有多少个描述字需要通过 poll 进行检测 */

	if (event_prepare(eventp) == 0) {
		/* 说明无须 poll 检测 */

		if (eventp->ready_cnt == 0)
			/* 为避免循环过快,休眠一下 */
			acl_doze(delay > DELAY_MIN ? (int) delay / 1000 : 1);

		goto TAG_DONE;
	}

	/* 如果已经有描述字准备好则 poll 检测超时时间置 0 */

	if (eventp->ready_cnt > 0)
		delay = 0;

	/* 调用 poll 系统调用检测可用描述字 */

	nready = poll(ev->fds, eventp->fdcnt, (int) (delay / 1000));

	if (eventp->nested++ > 0) {
		acl_msg_error("%s(%d): recursive call", myname, __LINE__);
		exit (1);
	}
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_error("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
			exit (1);
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查 poll 的检测结果集合 */

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = acl_fdmap_ctx(ev->fdmap, ev->fds[i].fd);
		if (fdp == NULL || fdp->stream == NULL)
			continue;

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		revents = ev->fds[i].revents;

		/* 检查描述字是否出现异常 */

		if ((revents & (POLLHUP | POLLERR)) != 0) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
			continue;
		}

		/* 检查描述字是否可读 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)
			&& (revents & POLLIN) )
		{
			/* 给该描述字对象附加可读属性 */
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}

			if (fdp->listener)
				fdp->event_type |= ACL_EVENT_ACCEPT;

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而
			 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数
			 */
			else
				fdp->stream->read_ready = 1;
		}

		/* 检查描述字是否可写 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)
			&& (revents & POLLOUT))
		{

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}
		}
	}

TAG_DONE:

	event_timer_trigger(eventp);

	/* 处理准备好的描述字事件 */
	if (eventp->ready_cnt > 0)
		event_fire(eventp);

	eventp->nested--;
}
Esempio n. 29
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp;
	ACL_EVENT_NOTIFY_FN worker_fn;
	void    *worker_arg;
	ACL_SOCKET sockfd;
	ACL_EVENT_TIMER *timer;
	int   select_delay, nready, i;
	ACL_EVENT_FDTABLE *fdp;
	ACL_RING timer_ring, *entry_ptr;
	struct timeval tv, *tvp;
	fd_set rmask;  /* enabled read events */
	fd_set wmask;  /* enabled write events */
	fd_set xmask;  /* for bad news mostly */

	acl_ring_init(&timer_ring);

	SET_TIME(eventp->event_present);
	THREAD_LOCK(&event_thr->event.tm_mutex);

	/*
	 * Find out when the next timer would go off. Timer requests are sorted.
	 * If any timer is scheduled, adjust the delay appropriately.
	 */
	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		select_delay = (int) (timer->when - eventp->event_present + 1000000 - 1) / 1000000;
		if (select_delay < 0) {
			select_delay = 0;
		} else if (eventp->delay_sec >= 0 && select_delay > eventp->delay_sec) {
			select_delay = eventp->delay_sec;
		}
	} else {
		select_delay = eventp->delay_sec;
	}

	THREAD_UNLOCK(&event_thr->event.tm_mutex);

	THREAD_LOCK(&event_thr->event.tb_mutex);

	if (event_thr_prepare(eventp) == 0) {
		if (eventp->fdcnt_ready == 0) {
			if (select_delay <= 0)
				select_delay = 1;
			sleep(select_delay);
		}

		THREAD_UNLOCK(&event_thr->event.tb_mutex);
		goto TAG_DONE;
	}

	if (eventp->fdcnt_ready > 0) {
		tv.tv_sec  = 0;
		tv.tv_usec = 0;
		tvp = &tv;
	} else if (select_delay < 0) {
		tvp = NULL;
	} else {
		tv.tv_sec  = select_delay;
		tv.tv_usec = eventp->delay_usec;
		tvp = &tv;
	}

	rmask = event_thr->rmask;
	wmask = event_thr->wmask;
	xmask = event_thr->xmask;

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

	event_thr->event.blocked = 1;
	nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp);
	event_thr->event.blocked = 0;

	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			char  ebuf[256];
			acl_msg_fatal("%s(%d), %s: event_loop: select: %s",
				__FILE__, __LINE__, myname,
				acl_last_strerror(ebuf, sizeof(ebuf)));
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	THREAD_LOCK(&event_thr->event.tb_mutex);

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = eventp->fdtabs[i];

		/* if fdp has been set in eventp->fdtabs_ready ? */
		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		sockfd = ACL_VSTREAM_SOCK(fdp->stream);

		if (FD_ISSET(sockfd, &xmask)) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->fdcnt_ready;
			eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			continue;
		}

		if (FD_ISSET(sockfd, &rmask)) {
			fdp->stream->sys_read_ready = 1;
			/* has been set in fdtabs_ready ? */
			if ((fdp->event_type & ACL_EVENT_READ) == 0) {
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		} else if (fdp->w_callback && FD_ISSET(sockfd, &wmask)) {
			fdp->event_type |= ACL_EVENT_WRITE;
			fdp->fdidx_ready = eventp->fdcnt_ready;
			eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
		}
	}

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

TAG_DONE:

	/*
	 * Deliver timer events. Requests are sorted: we can stop when we reach
	 * the future or the list end. Allow the application to update the timer
	 * queue while it is being called back. To this end, we repeatedly pop
	 * the first request off the timer queue before delivering the event to
	 * the application.
	 */

	SET_TIME(eventp->event_present);

	THREAD_LOCK(&event_thr->event.tm_mutex);

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->event_present)
			break;

		acl_ring_detach(&timer->ring);          /* first this */
		acl_ring_prepend(&timer_ring, &timer->ring);
	}

	THREAD_UNLOCK(&event_thr->event.tm_mutex);

	while (1) {
		entry_ptr = acl_ring_pop_head(&timer_ring);
		if (entry_ptr == NULL)
			break;

		timer         = ACL_RING_TO_TIMER(entry_ptr);
		worker_fn     = timer->callback;
		worker_arg    = timer->context;

		worker_fn(ACL_EVENT_TIME, worker_arg);

		acl_myfree(timer);
	}

	event_thr_fire(eventp);
}
Esempio n. 30
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_SELECT *ev = (EVENT_SELECT *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_SOCKET sockfd;
	ACL_EVENT_TIMER *timer;
	int   nready, i;
	acl_int64 delay;
	ACL_EVENT_FDTABLE *fdp;
	struct timeval tv, *tvp;
	fd_set rmask;  /* enabled read events */
	fd_set wmask;  /* enabled write events */
	fd_set xmask;  /* for bad news mostly */

	delay = eventp->delay_sec * 1000000 + eventp->delay_usec;

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 select 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = timer->when - eventp->present;

		if (n <= 0)
			delay = 0;
		else if (n < delay)
			delay = n;
	}

	/* 调用 event_prepare 检查有多少个描述字需要通过 select 进行检测 */

	if (event_prepare(eventp) == 0) {
		if (eventp->ready_cnt == 0) {
			delay /= 1000000;
			if (delay <= 0)
				delay = 1;
			/* 为避免循环过快,休眠一下 */
			sleep((int) delay);
		}

		goto TAG_DONE;
	}

	if (eventp->ready_cnt > 0) {
		tv.tv_sec  = 0;
		tv.tv_usec = 0;
		tvp = &tv;
	} else if (delay >= 0) {
#if defined(ACL_WINDOWS)
		tv.tv_sec  = (long) delay / 1000000;
		tv.tv_usec = (unsigned long) (delay - tv.tv_sec * 1000000);
#else
		tv.tv_sec  = (time_t) delay / 1000000;
		tv.tv_usec = (suseconds_t) (delay - tv.tv_sec * 1000000);
#endif
		tvp = &tv;
	} else
		tvp = NULL;

	rmask = ev->rmask;
	wmask = ev->wmask;
	xmask = ev->xmask;

	/* 调用 select 系统调用检测可用描述字 */

#ifdef ACL_WINDOWS
	nready = select(0, &rmask, &wmask, &xmask, tvp);
#else
	nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp);
#endif

	if (eventp->nested++ > 0)
		acl_msg_fatal("%s(%d): recursive call(%d)",
			myname, __LINE__, eventp->nested);
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_fatal("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查 select 的检测结果集合 */

	/* if some fdp was cleared from eventp->fdtabs in timer callback,
	 * which has no effection on the rest fdp in eventp->fdtabs
	 */

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = eventp->fdtabs[i];

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		sockfd = ACL_VSTREAM_SOCK(fdp->stream);

		/* 检查描述字是否出现异常 */

		if (FD_ISSET(sockfd, &xmask)) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
			continue;
		}

		/* 检查描述字是否可读 */

		if (FD_ISSET(sockfd, &rmask)) {
			/* 给该描述字对象附加可读属性 */
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}

			if (fdp->listener)
				fdp->event_type |= ACL_EVENT_ACCEPT;

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而
			 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数
			 */
			else
				fdp->stream->read_ready = 1;
		}

		/* 检查描述字是否可写 */

		if (FD_ISSET(sockfd, &wmask)) {

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}
		}
	}

TAG_DONE:

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 优先处理定时器中的任务 */

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		/* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,
		 * 则再重设定时器
		 */
		if (timer->delay > 0 && timer->keep) {
			timer->ncount++;
			eventp->timer_request(eventp, timer->callback,
				timer->context, timer->delay, timer->keep);
		} else {
			acl_ring_detach(&timer->ring); /* first this */
			timer->nrefer--;
			if (timer->nrefer != 0)
				acl_msg_fatal("%s(%d): nrefer(%d) != 0",
					myname, __LINE__, timer->nrefer);
			acl_myfree(timer);
		}
		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);
	}

	/* 处理准备好的描述字事件 */

	if (eventp->ready_cnt > 0)
		event_fire(eventp);

	eventp->nested--;
}