ssize_t ConnectedDescriptor::Send(const uint8_t *buffer, unsigned int size) { if (!ValidWriteDescriptor()) return 0; ssize_t bytes_sent; #ifdef _WIN32 if (WriteDescriptor().m_type == PIPE_DESCRIPTOR) { DWORD bytes_written = 0; if (!WriteFile(ToHandle(WriteDescriptor()), buffer, size, &bytes_written, NULL)) { OLA_WARN << "WriteFile() failed with " << GetLastError(); bytes_sent = -1; } else { bytes_sent = bytes_written; } } else if (WriteDescriptor().m_type == SOCKET_DESCRIPTOR) { bytes_sent = send(ToFD(WriteDescriptor()), reinterpret_cast<const char*>(buffer), size, 0); } else { OLA_WARN << "Send() called on unsupported descriptor type"; return 0; } #else // BSD Sockets #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { bytes_sent = send(WriteDescriptor(), buffer, size, MSG_NOSIGNAL); } else { #endif bytes_sent = write(WriteDescriptor(), buffer, size); #if HAVE_DECL_MSG_NOSIGNAL } #endif #endif if (bytes_sent < 0 || static_cast<unsigned int>(bytes_sent) != size) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } return bytes_sent; }
/* * Write data to this descriptor. * @param buffer the data to write * @param size the length of the data * @return the number of bytes sent */ ssize_t ConnectedDescriptor::Send(const uint8_t *buffer, unsigned int size) { if (!ValidWriteDescriptor()) return 0; ssize_t bytes_sent; #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) bytes_sent = send(WriteDescriptor(), buffer, size, MSG_NOSIGNAL); else #endif #ifdef _WIN32 if (WriteDescriptor().m_type == HANDLE_DESCRIPTOR) { DWORD bytes_written = 0; if (!WriteFile(WriteDescriptor().m_handle.m_handle, buffer, size, &bytes_written, NULL)) { OLA_WARN << "WriteFile() failed with " << GetLastError(); bytes_sent = -1; } else { bytes_sent = bytes_written; } } else { bytes_sent = write(WriteDescriptor().m_handle.m_fd, buffer, size); } #else bytes_sent = write(WriteDescriptor(), buffer, size); #endif if (bytes_sent < 0 || static_cast<unsigned int>(bytes_sent) != size) OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); return bytes_sent; }
ssize_t ConnectedDescriptor::Send(IOQueue *ioqueue) { if (!ValidWriteDescriptor()) return 0; int iocnt; const struct IOVec *iov = ioqueue->AsIOVec(&iocnt); ssize_t bytes_sent = 0; #ifdef _WIN32 /* There is no scatter/gather functionality for generic descriptors on * Windows, so this is implemented as a write loop. Derived classes should * re-implement Send() using scatter/gather I/O where available. */ int bytes_written = 0; for (int io = 0; io < iocnt; ++io) { bytes_written = Send(reinterpret_cast<const uint8_t*>(iov[io].iov_base), iov[io].iov_len); if (bytes_written == 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); bytes_sent = -1; break; } bytes_sent += bytes_written; } #else #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { struct msghdr message; memset(&message, 0, sizeof(message)); message.msg_name = NULL; message.msg_namelen = 0; message.msg_iov = reinterpret_cast<iovec*>(const_cast<IOVec*>(iov)); message.msg_iovlen = iocnt; bytes_sent = sendmsg(WriteDescriptor(), &message, MSG_NOSIGNAL); } else { #else { #endif bytes_sent = writev(WriteDescriptor(), reinterpret_cast<const struct iovec*>(iov), iocnt); } #endif ioqueue->FreeIOVec(iov); if (bytes_sent < 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } else { ioqueue->Pop(bytes_sent); } return bytes_sent; } int ConnectedDescriptor::Receive(uint8_t *buffer, unsigned int size, unsigned int &data_read) { // NOLINT int ret; uint8_t *data = buffer; data_read = 0; if (!ValidReadDescriptor()) return -1; while (data_read < size) { #ifdef _WIN32 if (ReadDescriptor().m_type == PIPE_DESCRIPTOR) { if (!ReadDescriptor().m_async_data_size) { OLA_WARN << "No async data buffer for descriptor " << ReadDescriptor(); return -1; } // Check if data was read by the async ReadFile() call DWORD async_data_size = *ReadDescriptor().m_async_data_size; if (async_data_size > 0) { DWORD size_to_copy = std::min(static_cast<DWORD>(size), async_data_size); memcpy(buffer, ReadDescriptor().m_async_data, size_to_copy); data_read = size_to_copy; if (async_data_size > size) { memmove(ReadDescriptor().m_async_data, &(ReadDescriptor().m_async_data[size_to_copy]), async_data_size - size_to_copy); } *ReadDescriptor().m_async_data_size -= size_to_copy; } return 0; } else if (ReadDescriptor().m_type == SOCKET_DESCRIPTOR) { ret = recv(ToFD(ReadDescriptor()), reinterpret_cast<char*>(data), size - data_read, 0); if (ret < 0) { if (WSAGetLastError() == WSAEWOULDBLOCK) { return 0; } else if (WSAGetLastError() != WSAEINTR) { OLA_WARN << "read failed, " << WSAGetLastError(); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; } else { OLA_WARN << "Descriptor type not implemented for reading: " << ReadDescriptor().m_type; return -1; } } #else if ((ret = read(ReadDescriptor(), data, size - data_read)) < 0) { if (errno == EAGAIN) return 0; if (errno != EINTR) { OLA_WARN << "read failed, " << strerror(errno); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; }
/** * Send an IOQueue. * This attempts to send as much of the IOQueue data as possible. The IOQueue * may be non-empty when this completes if the descriptor buffer is full. * @returns the number of bytes sent. */ ssize_t ConnectedDescriptor::Send(IOQueue *ioqueue) { if (!ValidWriteDescriptor()) return 0; int iocnt; const struct IOVec *iov = ioqueue->AsIOVec(&iocnt); ssize_t bytes_sent = 0; #ifdef _WIN32 /* There is no scatter/gather functionality for generic descriptors on * Windows, so this is implemented as a write loop. Derived classes should * re-implement Send() using scatter/gather I/O where available. */ int bytes_written = 0; for (int io = 0; io < iocnt; ++io) { bytes_written = write(WriteDescriptor().m_handle.m_fd, iov[io].iov_base, iov[io].iov_len); if (bytes_written == -1) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); break; } bytes_sent += bytes_written; } #else #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { struct msghdr message; memset(&message, 0, sizeof(message)); message.msg_name = NULL; message.msg_namelen = 0; message.msg_iov = reinterpret_cast<iovec*>(const_cast<IOVec*>(iov)); message.msg_iovlen = iocnt; bytes_sent = sendmsg(WriteDescriptor(), &message, MSG_NOSIGNAL); } else { #else { #endif bytes_sent = writev(WriteDescriptor(), reinterpret_cast<const struct iovec*>(iov), iocnt); } #endif ioqueue->FreeIOVec(iov); if (bytes_sent < 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } else { ioqueue->Pop(bytes_sent); } return bytes_sent; } /* * Read data from this descriptor. * @param buffer a pointer to the buffer to store new data in * @param size the size of the buffer * @param data_read a value result argument which returns the amount of data * copied into the buffer * @returns -1 on error, 0 on success. */ int ConnectedDescriptor::Receive(uint8_t *buffer, unsigned int size, unsigned int &data_read) { // NOLINT int ret; uint8_t *data = buffer; data_read = 0; if (!ValidReadDescriptor()) return -1; while (data_read < size) { #ifdef _WIN32 if ((ret = read(ReadDescriptor().m_handle.m_fd, data, size - data_read)) < 0) { #else if ((ret = read(ReadDescriptor(), data, size - data_read)) < 0) { #endif if (errno == EAGAIN) return 0; if (errno != EINTR) { OLA_WARN << "read failed, " << strerror(errno); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; } return 0; } /* * Check if the remote end has closed the connection. * @return true if the socket is closed, false otherwise */ bool ConnectedDescriptor::IsClosed() const { return DataRemaining() == 0; } // LoopbackDescriptor // ------------------------------------------------ /* * Setup this loopback socket */ bool LoopbackDescriptor::Init() { if (m_handle_pair[0] != INVALID_DESCRIPTOR || m_handle_pair[1] != INVALID_DESCRIPTOR) return false; if (!CreatePipe(m_handle_pair)) return false; SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); return true; } /* * Close the loopback socket * @return true if close succeeded, false otherwise */ bool LoopbackDescriptor::Close() { if (m_handle_pair[0] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[0].m_handle.m_handle); #else close(m_handle_pair[0]); #endif } if (m_handle_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[1].m_handle.m_handle); #else close(m_handle_pair[1]); #endif } m_handle_pair[0] = INVALID_DESCRIPTOR; m_handle_pair[1] = INVALID_DESCRIPTOR; return true; } /* * Close the write portion of the loopback socket * @return true if close succeeded, false otherwise */ bool LoopbackDescriptor::CloseClient() { if (m_handle_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[1].m_handle.m_handle); #else close(m_handle_pair[1]); #endif } m_handle_pair[1] = INVALID_DESCRIPTOR; return true; } // PipeDescriptor // ------------------------------------------------ /* * Create a new pipe socket */ bool PipeDescriptor::Init() { if (m_in_pair[0] != INVALID_DESCRIPTOR || m_out_pair[1] != INVALID_DESCRIPTOR) return false; if (!CreatePipe(m_in_pair)) return false; if (!CreatePipe(m_out_pair)) { #ifdef _WIN32 CloseHandle(m_in_pair[0].m_handle.m_handle); CloseHandle(m_in_pair[1].m_handle.m_handle); #else close(m_in_pair[0]); close(m_in_pair[1]); #endif m_in_pair[0] = m_in_pair[1] = INVALID_DESCRIPTOR; return false; } SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); return true; } /* * Fetch the other end of the pipe socket. The caller now owns the new * PipeDescriptor. * @returns NULL if the socket wasn't initialized correctly. */ PipeDescriptor *PipeDescriptor::OppositeEnd() { if (m_in_pair[0] == INVALID_DESCRIPTOR || m_out_pair[1] == INVALID_DESCRIPTOR) return NULL; if (!m_other_end) { m_other_end = new PipeDescriptor(m_out_pair, m_in_pair, this); m_other_end->SetReadNonBlocking(); } return m_other_end; } /* * Close this PipeDescriptor */ bool PipeDescriptor::Close() { if (m_in_pair[0] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_in_pair[0].m_handle.m_handle); #else close(m_in_pair[0]); #endif } if (m_out_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_out_pair[1].m_handle.m_handle); #else close(m_out_pair[1]); #endif } m_in_pair[0] = INVALID_DESCRIPTOR; m_out_pair[1] = INVALID_DESCRIPTOR; return true; } /* * Close the write portion of this PipeDescriptor */ bool PipeDescriptor::CloseClient() { if (m_out_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_out_pair[1].m_handle.m_handle); #else close(m_out_pair[1]); #endif } m_out_pair[1] = INVALID_DESCRIPTOR; return true; } // UnixSocket // ------------------------------------------------ /* * Create a new unix socket */ bool UnixSocket::Init() { #ifdef _WIN32 return false; #else int pair[2]; if ((m_handle != INVALID_DESCRIPTOR) || m_other_end) return false; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair)) { OLA_WARN << "socketpair() failed, " << strerror(errno); return false; } m_handle = pair[0]; SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); m_other_end = new UnixSocket(pair[1], this); m_other_end->SetReadNonBlocking(); return true; #endif } /* * Fetch the other end of the unix socket. The caller now owns the new * UnixSocket. * @returns NULL if the socket wasn't initialized correctly. */ UnixSocket *UnixSocket::OppositeEnd() { return m_other_end; } /* * Close this UnixSocket */ bool UnixSocket::Close() { #ifdef _WIN32 return true; #else if (m_handle != INVALID_DESCRIPTOR) { close(m_handle); } m_handle = INVALID_DESCRIPTOR; return true; #endif } /* * Close the write portion of this UnixSocket */ bool UnixSocket::CloseClient() { #ifndef _WIN32 if (m_handle != INVALID_DESCRIPTOR) shutdown(m_handle, SHUT_WR); #endif m_handle = INVALID_DESCRIPTOR; return true; } // DeviceDescriptor // ------------------------------------------------ DeviceDescriptor::DeviceDescriptor(int fd) { #ifdef _WIN32 m_handle.m_handle.m_fd = fd; m_handle.m_type = GENERIC_DESCRIPTOR; m_handle.m_event_handle = 0; #else m_handle = fd; #endif }