Example #1
0
size_t
network_poll(network_poll_t* pollobj, network_poll_event_t* events, size_t capacity,
             unsigned int timeoutms) {
	int avail = 0;
	size_t num_events = 0;

#if FOUNDATION_PLATFORM_WINDOWS
	//TODO: Refactor to keep fd_set across loop and rebuild on change (add/remove)
	int num_fd = 0;
	int ret = 0;
	size_t islot;
	fd_set fdread, fdwrite, fderr;
#endif

	if (!pollobj->num_sockets)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	int ret = poll(pollobj->pollfds, pollobj->num_sockets, timeoutms);

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	int ret = epoll_wait(pollobj->fd_poll, pollobj->events, pollobj->num_sockets + 1, timeoutms);
	int num_polled = ret;

#elif FOUNDATION_PLATFORM_WINDOWS

	FD_ZERO(&fdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&fderr);

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		socket_base_t* sockbase = _socket_base + pollobj->slots[islot].base;

		FD_SET(fd, &fdread);
		if (sockbase->state == SOCKETSTATE_CONNECTING)
			FD_SET(fd, &fdwrite);
		FD_SET(fd, &fderr);

		if (fd >= num_fd)
			num_fd = fd + 1;
	}

	if (!num_fd) {
		return num_events;
	}
	else {
		struct timeval tv;

		tv.tv_sec  = timeoutms / 1000;
		tv.tv_usec = (timeoutms % 1000) * 1000;

		ret = select(num_fd, &fdread, &fdwrite, &fderr, &tv);
	}

#else
#  error Not implemented
#endif

	if (ret < 0) {
		int err = NETWORK_SOCKET_ERROR;
		string_const_t errmsg = system_error_message(err);
		log_warnf(HASH_NETWORK, WARNING_SUSPICIOUS, STRING_CONST("Error in socket poll: %.*s (%d)"),
		          STRING_FORMAT(errmsg), err);
		if (!avail)
			return num_events;
		ret = avail;
	}
	if (!avail && !ret)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	struct pollfd* pfd = pollobj->pollfds;
	network_poll_slot_t* slot = pollobj->slots;
	for (size_t i = 0; i < pollobj->num_sockets; ++i, ++pfd, ++slot) {
		socket_t* sock = slot->sock;
		socket_base_t* sockbase = _socket_base + slot->base;
		int fd = slot->fd;
		if (pfd->revents & POLLIN) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && (pfd->revents & POLLOUT)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			pfd->events = POLLIN | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (pfd->revents & POLLERR) {
			pfd->events = POLLOUT | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (pfd->revents & POLLHUP) {
			pfd->events = POLLOUT | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	struct epoll_event* event = pollobj->events;
	for (int i = 0; i < num_polled; ++i, ++event) {
		FOUNDATION_ASSERT(pollobj->slots[ event->data.fd ].base >= 0);

		socket_t* sock = pollobj->slots[ event->data.fd ].sock;
		socket_base_t* sockbase = _socket_base + pollobj->slots[ event->data.fd ].base;
		int fd = pollobj->slots[ event->data.fd ].fd;
		if (event->events & EPOLLIN) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && (event->events & EPOLLOUT)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			struct epoll_event mod_event;
			mod_event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
			mod_event.data.fd = event->data.fd;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_MOD, fd, &mod_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (event->events & EPOLLERR) {
			struct epoll_event del_event;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_DEL, fd, &del_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (event->events & EPOLLHUP) {
			struct epoll_event del_event;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_DEL, fd, &del_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}

#elif FOUNDATION_PLATFORM_WINDOWS

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		socket_t* sock = pollobj->slots[islot].sock;
		socket_base_t* sockbase = _socket_base + pollobj->slots[islot].base;

		if (sockbase->fd != fd)
			continue;

		if (FD_ISSET(fd, &fdread)) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else { //SOCKETSTATE_CONNECTED
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && FD_ISSET(fd, &fdwrite)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (FD_ISSET(fd, &fderr)) {
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}
#else
#  error Not implemented
#endif

	return num_events;
}
Example #2
0
size_t
network_poll(network_poll_t* pollobj, network_poll_event_t* events, size_t capacity,
             unsigned int timeoutms) {
	int avail = 0;
	size_t num_events = 0;

#if FOUNDATION_PLATFORM_WINDOWS
	//TODO: Refactor to keep fd_set across loop and rebuild on change (add/remove)
	int num_fd = 0;
	int ret = 0;
	size_t islot;
	fd_set fdread, fdwrite, fderr;
#endif

	if (!pollobj->num_sockets)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	int ret = poll(pollobj->pollfds, (nfds_t)pollobj->num_sockets, (int)timeoutms);

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	int ret = epoll_wait(pollobj->fd_poll, pollobj->events,
	                     (int)pollobj->num_sockets + 1, (int)timeoutms);
	int num_polled = ret;

#elif FOUNDATION_PLATFORM_WINDOWS

	FD_ZERO(&fdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&fderr);

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		if (fd != NETWORK_SOCKET_INVALID) {
			socket_t* sock = pollobj->slots[islot].sock;

			FD_SET(fd, &fdread);
			if (sock->state == SOCKETSTATE_CONNECTING)
				FD_SET(fd, &fdwrite);
			FD_SET(fd, &fderr);

			if (fd >= num_fd)
				num_fd = fd + 1;
		}
	}

	if (!num_fd) {
		return num_events;
	}
	else {
		struct timeval tv;

		tv.tv_sec  = timeoutms / 1000;
		tv.tv_usec = (timeoutms % 1000) * 1000;

		ret = select(num_fd, &fdread, &fdwrite, &fderr,
		             (timeoutms != NETWORK_TIMEOUT_INFINITE) ? &tv : nullptr);
	}

#else
#  error Not implemented
#endif

	if (ret < 0) {
		int err = NETWORK_SOCKET_ERROR;
		string_const_t errmsg = system_error_message(err);
		log_warnf(HASH_NETWORK, WARNING_SUSPICIOUS, STRING_CONST("Error in socket poll: %.*s (%d)"),
		          STRING_FORMAT(errmsg), err);
		if (!avail)
			return num_events;
		ret = avail;
	}
	if (!avail && !ret)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	struct pollfd* pfd = pollobj->pollfds;
	network_poll_slot_t* slot = pollobj->slots;
	for (size_t islot = 0; islot < pollobj->num_sockets; ++islot, ++pfd, ++slot) {
		socket_t* sock = slot->sock;
		bool update_slot = false;
		bool had_error = false;
		if (pfd->revents & POLLERR) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (pfd->revents & POLLHUP) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (!had_error && (pfd->revents & POLLIN)) {
			if (sock->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if (!had_error && (sock->state == SOCKETSTATE_CONNECTING) && (pfd->revents & POLLOUT)) {
			int serr = 0;
			socklen_t slen = sizeof(int);
			getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&serr, &slen);
			if (!serr) {
				sock->state = SOCKETSTATE_CONNECTED;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
			}
			else {
				had_error = true;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
				socket_close(sock);
			}
			update_slot = true;
		}
		if (update_slot)
			network_poll_update_slot(pollobj, islot, sock);
	}

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	struct epoll_event* event = pollobj->events;
	for (int i = 0; i < num_polled; ++i, ++event) {
		socket_t* sock = pollobj->slots[ event->data.fd ].sock;
		bool update_slot = false;
		bool had_error = false;
		if (event->events & EPOLLERR) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (event->events & EPOLLHUP) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (!had_error && (event->events & EPOLLIN)) {
			if (sock->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if (!had_error && (sock->state == SOCKETSTATE_CONNECTING) && (event->events & EPOLLOUT)) {
			int serr = 0;
			socklen_t slen = sizeof(int);
			getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&serr, &slen);
			if (!serr) {
				sock->state = SOCKETSTATE_CONNECTED;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
			}
			else {
				had_error = true;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
				socket_close(sock);
			}
			update_slot = true;
		}
		if (update_slot)
			network_poll_update_slot(pollobj, (size_t)event->data.fd, sock);
	}

#elif FOUNDATION_PLATFORM_WINDOWS

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		socket_t* sock = pollobj->slots[islot].sock;
		bool update_slot = false;

		if (FD_ISSET(fd, &fdread)) {
			if (sock->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else { //SOCKETSTATE_CONNECTED
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sock->state == SOCKETSTATE_CONNECTING) && FD_ISSET(fd, &fdwrite)) {
			update_slot = true;
			sock->state = SOCKETSTATE_CONNECTED;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (FD_ISSET(fd, &fderr)) {
			update_slot = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (update_slot)
			network_poll_update_slot(pollobj, islot, sock);
	}
#else
#  error Not implemented
#endif

	return num_events;
}