http_write(http_t     *http,		/* I - HTTP connection */
           const char *buffer,		/* I - Buffer for data */
	   size_t     length)		/* I - Number of bytes to write */
{
  ssize_t	tbytes,			/* Total bytes sent */
		bytes;			/* Bytes sent */


  DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
  http->error = 0;
  tbytes      = 0;

  while (length > 0)
  {
    DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));

    if (http->timeout_value > 0.0)
    {
#ifdef HAVE_POLL
      struct pollfd	pfd;		/* Polled file descriptor */
#else
      fd_set		output_set;	/* Output ready for write? */
      struct timeval	timeout;	/* Timeout value */
#endif /* HAVE_POLL */
      int		nfds;		/* Result from select()/poll() */

      do
      {
#ifdef HAVE_POLL
	pfd.fd     = http->fd;
	pfd.events = POLLOUT;

	while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
	       (errno == EINTR || errno == EAGAIN))
	  /* do nothing */;

#else
	do
	{
	  FD_ZERO(&output_set);
	  FD_SET(http->fd, &output_set);

	  timeout.tv_sec  = http->wait_value / 1000;
	  timeout.tv_usec = 1000 * (http->wait_value % 1000);

	  nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
	}
#  ifdef _WIN32
	while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
			    WSAGetLastError() == WSAEWOULDBLOCK));
#  else
	while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
#  endif /* _WIN32 */
#endif /* HAVE_POLL */

        if (nfds < 0)
	{
	  http->error = errno;
	  return (-1);
	}
	else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
	{
#ifdef _WIN32
	  http->error = WSAEWOULDBLOCK;
#else
	  http->error = EWOULDBLOCK;
#endif /* _WIN32 */
	  return (-1);
	}
      }
      while (nfds <= 0);
    }

#ifdef HAVE_SSL
    if (http->tls)
      bytes = _httpTLSWrite(http, buffer, (int)length);
    else
#endif /* HAVE_SSL */
    bytes = send(http->fd, buffer, length, 0);

    DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
                  CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));

    if (bytes < 0)
    {
#ifdef _WIN32
      if (WSAGetLastError() == WSAEINTR)
        continue;
      else if (WSAGetLastError() == WSAEWOULDBLOCK)
      {
        if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
          continue;

        http->error = WSAGetLastError();
      }
      else if (WSAGetLastError() != http->error &&
               WSAGetLastError() != WSAECONNRESET)
      {
        http->error = WSAGetLastError();
	continue;
      }

#else
      if (errno == EINTR)
        continue;
      else if (errno == EWOULDBLOCK || errno == EAGAIN)
      {
	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
          continue;
        else if (!http->timeout_cb && errno == EAGAIN)
	  continue;

        http->error = errno;
      }
      else if (errno != http->error && errno != ECONNRESET)
      {
        http->error = errno;
	continue;
      }
#endif /* _WIN32 */

      DEBUG_printf(("3http_write: error writing data (%s).",
                    strerror(http->error)));

      return (-1);
    }

    buffer += bytes;
    tbytes += bytes;
    length -= (size_t)bytes;
  }

#ifdef DEBUG
  http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
#endif /* DEBUG */

  DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));

  return (tbytes);
}