Пример #1
0
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;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
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;
  }
Пример #4
0
/**
 * 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
}