Beispiel #1
0
void
CArchNetworkWinsock::closeSocketForWrite(CArchSocket s)
{
	assert(s != NULL);

	if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
		if (getsockerror_winsock() != WSAENOTCONN) {
			throwError(getsockerror_winsock());
		}
	}
}
Beispiel #2
0
void
ArchNetworkWinsock::closeSocketForRead(ArchSocket s)
{
	assert(s != NULL);

	if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
		if (getsockerror_winsock() != WSAENOTCONN) {
			throwError(getsockerror_winsock());
		}
	}
}
Beispiel #3
0
bool
CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
{
	assert(s    != NULL);
	assert(addr != NULL);

	if (connect_winsock(s->m_socket, &addr->m_addr,
							addr->m_len) == SOCKET_ERROR) {
		if (getsockerror_winsock() == WSAEISCONN) {
			return true;
		}
		if (getsockerror_winsock() == WSAEWOULDBLOCK) {
			return false;
		}
		throwError(getsockerror_winsock());
	}
	return true;
}
Beispiel #4
0
void
CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
{
	assert(s != 0);

	int flag = blocking ? 0 : 1;
	if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}
}
Beispiel #5
0
void
CArchNetworkWinsock::listenOnSocket(CArchSocket s)
{
	assert(s != NULL);

	// hardcoding backlog
	if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}
}
Beispiel #6
0
void
CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr)
{
	assert(s    != NULL);
	assert(addr != NULL);

	if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}
}
Beispiel #7
0
bool
CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse)
{
	assert(s != NULL);

	// get old state
	BOOL oflag;
	int size = sizeof(oflag);
	if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
								SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}

	// set new state
	BOOL flag = reuse ? 1 : 0;
	size     = sizeof(flag);
	if (setsockopt_winsock(s->m_socket, SOL_SOCKET,
								SO_REUSEADDR, &flag, size) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}

	return (oflag != 0);
}
Beispiel #8
0
bool
CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay)
{
	assert(s != NULL);

	// get old state
	BOOL oflag;
	int size = sizeof(oflag);
	if (getsockopt_winsock(s->m_socket, IPPROTO_TCP,
								TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}

	// set new state
	BOOL flag = noDelay ? 1 : 0;
	size     = sizeof(flag);
	if (setsockopt_winsock(s->m_socket, IPPROTO_TCP,
								TCP_NODELAY, &flag, size) == SOCKET_ERROR) {
		throwError(getsockerror_winsock());
	}

	return (oflag != 0);
}
Beispiel #9
0
size_t
CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
{
	assert(s != NULL);

	int n = recv_winsock(s->m_socket, buf, (int)len, 0);
	if (n == SOCKET_ERROR) {
		int err = getsockerror_winsock();
		if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
			return 0;
		}
		throwError(err);
	}
	return static_cast<size_t>(n);
}
Beispiel #10
0
CArchSocket
CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
{
	assert(s != NULL);

	// create new socket and temporary address
	CArchSocketImpl* socket = new CArchSocketImpl;
	CArchNetAddress tmp = CArchNetAddressImpl::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;
}
Beispiel #11
0
void
CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s)
{
	assert(s != NULL);

	// get the error from the socket layer
	int err  = 0;
	int size = sizeof(err);
	if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
									SO_ERROR, &err, &size) == SOCKET_ERROR) {
		err = getsockerror_winsock();
	}

	// throw if there's an error
	if (err != 0) {
		throwError(err);
	}
}
Beispiel #12
0
size_t
CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
{
	assert(s != NULL);

	int n = send_winsock(s->m_socket, buf, (int)len, 0);
	if (n == SOCKET_ERROR) {
		int err = getsockerror_winsock();
		if (err == WSAEINTR) {
			return 0;
		}
		if (err == WSAEWOULDBLOCK) {
			s->m_pollWrite = true;
			return 0;
		}
		throwError(err);
	}
	return static_cast<size_t>(n);
}
Beispiel #13
0
void
CArchNetworkWinsock::closeSocket(CArchSocket s)
{
	assert(s != NULL);

	// unref the socket and note if it should be released
	ARCH->lockMutex(m_mutex);
	const bool doClose = (--s->m_refCount == 0);
	ARCH->unlockMutex(m_mutex);

	// close the socket if necessary
	if (doClose) {
		if (close_winsock(s->m_socket) == SOCKET_ERROR) {
			// close failed.  restore the last ref and throw.
			int err = getsockerror_winsock();
			ARCH->lockMutex(m_mutex);
			++s->m_refCount;
			ARCH->unlockMutex(m_mutex);
			throwError(err);
		}
		WSACloseEvent_winsock(s->m_event);
		delete s;
	}
}
Beispiel #14
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;
}
Beispiel #15
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;
}