Esempio n. 1
0
ArchSocket
ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress* addr)
{
	assert(s != NULL);

	// create new socket and temporary address
	ArchSocketImpl* socket = new ArchSocketImpl;
	ArchNetAddress tmp = ArchNetAddressImpl::alloc(sizeof(struct sockaddr));

	// accept on socket
	SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
	if (fd == INVALID_SOCKET) {
		int err = getsockerror_winsock();
		delete socket;
		free(tmp);
		*addr = NULL;
		if (err == WSAEWOULDBLOCK) {
			return NULL;
		}
		throwError(err);
	}

	try {
		setBlockingOnSocket(fd, false);
	}
	catch (...) {
		close_winsock(fd);
		delete socket;
		free(tmp);
		*addr = NULL;
		throw;
	}

	// initialize socket
	socket->m_socket    = fd;
	socket->m_refCount  = 1;
	socket->m_event     = WSACreateEvent_winsock();
	socket->m_pollWrite = true;

	// copy address if requested
	if (addr != NULL) {
		*addr = ARCH->copyAddr(tmp);
	}

	free(tmp);
	return socket;
}
Esempio n. 2
0
CArchSocket
CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
{
	// create socket
	SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
	if (fd == INVALID_SOCKET) {
		throwError(getsockerror_winsock());
	}
	try {
		setBlockingOnSocket(fd, false);
	}
	catch (...) {
		close_winsock(fd);
		throw;
	}

	// allocate socket object
	CArchSocketImpl* socket = new CArchSocketImpl;
	socket->m_socket        = fd;
	socket->m_refCount      = 1;
	socket->m_event         = WSACreateEvent_winsock();
	socket->m_pollWrite     = true;
	return socket;
}
Esempio n. 3
0
int
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
{
	int i;
	DWORD n;

	// prepare sockets and wait list
	bool canWrite = false;
	WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
	for (i = 0, n = 0; i < num; ++i) {
		// reset return flags
		pe[i].m_revents = 0;

		// set invalid flag if socket is bogus then go to next socket
		if (pe[i].m_socket == NULL) {
			pe[i].m_revents |= kPOLLNVAL;
			continue;
		}

		// select desired events
		long socketEvents = 0;
		if ((pe[i].m_events & kPOLLIN) != 0) {
			socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
		}
		if ((pe[i].m_events & kPOLLOUT) != 0) {
			socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;

			// if m_pollWrite is false then we assume the socket is
			// writable.  winsock doesn't signal writability except
			// when the state changes from unwritable.
			if (!pe[i].m_socket->m_pollWrite) {
				canWrite         = true;
				pe[i].m_revents |= kPOLLOUT;
			}
		}

		// if no events then ignore socket
		if (socketEvents == 0) {
			continue;
		}

		// select socket for desired events
		WSAEventSelect_winsock(pe[i].m_socket->m_socket,
							pe[i].m_socket->m_event, socketEvents);

		// add socket event to wait list
		events[n++] = pe[i].m_socket->m_event;
	}

	// if no sockets then return immediately
	if (n == 0) {
		return 0;
	}

	// add the unblock event
	CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
	CArchThread thread     = mt->newCurrentThread();
	WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
	ARCH->closeThread(thread);
	if (unblockEvent == NULL) {
		unblockEvent  = new WSAEVENT;
		m_unblockEvents.push_back(unblockEvent);
		*unblockEvent = WSACreateEvent_winsock();
		mt->setNetworkDataForCurrentThread(unblockEvent);
	}
	events[n++] = *unblockEvent;

	// prepare timeout
	DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
	if (canWrite) {
		// if we know we can write then don't block
		t = 0;
	}

	// wait
	DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);

	// reset the unblock event
	WSAResetEvent_winsock(*unblockEvent);

	// handle results
	if (result == WSA_WAIT_FAILED) {
		if (getsockerror_winsock() == WSAEINTR) {
			// interrupted system call
			ARCH->testCancelThread();
			return 0;
		}
		throwError(getsockerror_winsock());
	}
	if (result == WSA_WAIT_TIMEOUT && !canWrite) {
		return 0;
	}
	if (result == WSA_WAIT_EVENT_0 + n - 1) {
		// the unblock event was signalled
		return 0;
	}
	for (i = 0, n = 0; i < num; ++i) {
		// skip events we didn't check
		if (pe[i].m_socket == NULL ||
			(pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
			continue;
		}

		// get events
		WSANETWORKEVENTS info;
		if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
							pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
			continue;
		}
		if ((info.lNetworkEvents & FD_READ) != 0) {
			pe[i].m_revents |= kPOLLIN;
		}
		if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
			pe[i].m_revents |= kPOLLIN;
		}
		if ((info.lNetworkEvents & FD_WRITE) != 0) {
			pe[i].m_revents |= kPOLLOUT;

			// socket is now writable so don't bothing polling for
			// writable until it becomes unwritable.
			pe[i].m_socket->m_pollWrite = false;
		}
		if ((info.lNetworkEvents & FD_CONNECT) != 0) {
			if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
				pe[i].m_revents |= kPOLLERR;
			}
			else {
				pe[i].m_revents |= kPOLLOUT;
				pe[i].m_socket->m_pollWrite = false;
			}
		}
		if ((info.lNetworkEvents & FD_CLOSE) != 0) {
			if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
				pe[i].m_revents |= kPOLLERR;
			}
			else {
				if ((pe[i].m_events & kPOLLIN) != 0) {
					pe[i].m_revents |= kPOLLIN;
				}
				if ((pe[i].m_events & kPOLLOUT) != 0) {
					pe[i].m_revents |= kPOLLOUT;
				}
			}
		}
		if (pe[i].m_revents != 0) {
			++n;
		}
	}

	return (int)n;
}