예제 #1
0
/**
 * Similar to write(2) with the exception that this function will block until
 * <em>all</em> data has been written or an error occurs.
 *
 * @return @c size when succesful or @c SOCKET_ERROR if an error occurred.
 */
ssize_t writeAll(Socket *sock, const void *buf, size_t size, size_t *rawByteCount)
{
	size_t ignored;
	size_t &rawBytes = rawByteCount != NULL ? *rawByteCount : ignored;
	rawBytes = 0;

	if (!sock
	    || sock->fd[SOCK_CONNECTION] == INVALID_SOCKET)
	{
		debug(LOG_ERROR, "Invalid socket (EBADF)");
		setSockErr(EBADF);
		return SOCKET_ERROR;
	}

	if (sock->writeError)
	{
		return SOCKET_ERROR;
	}

	if (size > 0)
	{
		if (!sock->isCompressed)
		{
			wzMutexLock(socketThreadMutex);
			if (socketThreadWrites.empty())
			{
				wzSemaphorePost(socketThreadSemaphore);
			}
			std::vector<uint8_t> &writeQueue = socketThreadWrites[sock];
			writeQueue.insert(writeQueue.end(), static_cast<char const *>(buf), static_cast<char const *>(buf) + size);
			wzMutexUnlock(socketThreadMutex);
			rawBytes = size;
		}
		else
		{
			sock->zDeflate.next_in = (Bytef *)buf;
			sock->zDeflate.avail_in = size;
			sock->zDeflateInSize += sock->zDeflate.avail_in;
			do
			{
				size_t alreadyHave = sock->zDeflateOutBuf.size();
				sock->zDeflateOutBuf.resize(alreadyHave + size + 20);  // A bit more than size should be enough to always do everything in one go.
				sock->zDeflate.next_out = (Bytef *)&sock->zDeflateOutBuf[alreadyHave];
				sock->zDeflate.avail_out = sock->zDeflateOutBuf.size() - alreadyHave;

				int ret = deflate(&sock->zDeflate, Z_NO_FLUSH);
				ASSERT(ret != Z_STREAM_ERROR, "zlib compression failed!");

				// Remove unused part of buffer.
				sock->zDeflateOutBuf.resize(sock->zDeflateOutBuf.size() - sock->zDeflate.avail_out);
			}
			while (sock->zDeflate.avail_out == 0);

			ASSERT(sock->zDeflate.avail_in == 0, "zlib didn't compress everything!");
		}
	}

	return size;
}
예제 #2
0
/**
 * Test whether the given socket still has an open connection.
 *
 * @return true when the connection is open, false when it's closed or in an
 *         error state, check getSockErr() to find out which.
 */
static bool connectionIsOpen(Socket* sock)
{
	const SocketSet set = {std::vector<Socket *>(1, sock)};

	ASSERT_OR_RETURN((setSockErr(EBADF), false),
		sock && sock->fd[SOCK_CONNECTION] != INVALID_SOCKET, "Invalid socket");

	// Check whether the socket is still connected
	int ret = checkSockets(&set, 0);
	if (ret == SOCKET_ERROR)
	{
		return false;
	}
	else if (ret == (int)set.fds.size() && sock->ready)
	{
		/* The next recv(2) call won't block, but we're writing. So
		 * check the read queue to see if the connection is closed.
		 * If there's no data in the queue that means the connection
		 * is closed.
		 */
#if defined(WZ_OS_WIN)
		unsigned long readQueue;
		ret = ioctlsocket(sock->fd[SOCK_CONNECTION], FIONREAD, &readQueue);
#else
		int readQueue;
		ret = ioctl(sock->fd[SOCK_CONNECTION], FIONREAD, &readQueue);
#endif
		if (ret == SOCKET_ERROR)
		{
			debug(LOG_NET, "socket error");
			return false;
		}
		else if (readQueue == 0)
		{
			// Disconnected
			setSockErr(ECONNRESET);
			debug(LOG_NET, "Read queue empty - failing (ECONNRESET)");
			return false;
		}
	}

	return true;
}
예제 #3
0
/**
 * Similar to read(2) with the exception that this function won't be
 * interrupted by signals (EINTR).
 */
ssize_t readNoInt(Socket* sock, void* buf, size_t max_size, size_t *rawByteCount)
{
	size_t ignored;
	size_t &rawBytes = rawByteCount != NULL? *rawByteCount : ignored;
	rawBytes = 0;

	if (sock->fd[SOCK_CONNECTION] == INVALID_SOCKET)
	{
		debug(LOG_ERROR, "Invalid socket");
		setSockErr(EBADF);
		return SOCKET_ERROR;
	}

	if (sock->isCompressed)
	{
		if (sock->zInflateNeedInput)
		{
			// No input data, read some.

			sock->zInflateInBuf.resize(max_size + 1000);

			ssize_t received;
			do
			{  //                                                  v----- This weird cast is because recv() takes a char * on windows instead of a void *...
				received = recv(sock->fd[SOCK_CONNECTION], (char *)&sock->zInflateInBuf[0], sock->zInflateInBuf.size(), 0);
			} while (received == SOCKET_ERROR && getSockErr() == EINTR);
			if (received < 0)
			{
				return received;
			}

			sock->zInflate.next_in = &sock->zInflateInBuf[0];
			sock->zInflate.avail_in = received;
			rawBytes = received;

			if (received == 0)
			{
				sock->readDisconnected = true;
			}
			else
			{
				sock->zInflateNeedInput = false;
			}
		}

		sock->zInflate.next_out = (Bytef *)buf;
		sock->zInflate.avail_out = max_size;
		int ret = inflate(&sock->zInflate, Z_NO_FLUSH);
		ASSERT(ret != Z_STREAM_ERROR, "zlib inflate not working!");
		char const *err = NULL;
		switch (ret)
		{
			case Z_NEED_DICT:  err = "Z_NEED_DICT";  break;
			case Z_DATA_ERROR: err = "Z_DATA_ERROR"; break;
			case Z_MEM_ERROR:  err = "Z_MEM_ERROR";  break;
		}
		if (err != NULL)
		{
			debug(LOG_ERROR, "Couldn't decompress data from socket. zlib error %s", err);
			return -1;  // Bad data!
		}

		if (sock->zInflate.avail_out != 0)
		{
			sock->zInflateNeedInput = true;
			ASSERT(sock->zInflate.avail_in == 0, "zlib not consuming all input!");
		}

		return max_size - sock->zInflate.avail_out;  // Got some data, return how much.
	}

	ssize_t received;
	do
	{
		received = recv(sock->fd[SOCK_CONNECTION], (char*)buf, max_size, 0);
		if (received == 0)
		{
			sock->readDisconnected = true;
		}
	} while (received == SOCKET_ERROR && getSockErr() == EINTR);

	sock->ready = false;

	rawBytes = received;
	return received;
}