/** * 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; }
/** * 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; }
/** * 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; }