Example #1
0
/* This function is like write. But it does not return -1 on error.
 * It does return gnutls_errno instead.
 *
 * In case of E_AGAIN and E_INTERRUPTED errors, you must call gnutls_write_flush(),
 * until it returns ok (0).
 *
 * We need to push exactly the data in n, since we cannot send less
 * data. In TLS the peer must receive the whole packet in order
 * to decrypt and verify the integrity.
 *
 */
ssize_t
_gnutls_io_write_buffered (gnutls_session_t session,
                           const void *iptr, size_t n)
{
    size_t left;
    unsigned j, x, sum = 0;
    ssize_t retval, i;
    const opaque *ptr;
    int ret;
    gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;

    /* to know where the procedure was interrupted.
     */
    session->internals.direction = 1;

    ptr = iptr;

    /* In case the previous write was interrupted, check if the
     * iptr != NULL and we have data in the buffer.
     * If this is true then return an error.
     */
    if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_INVALID_REQUEST;
    }

    /* If data in the buffer exist
     */
    if (iptr == NULL)
    {
        /* checking is handled above */
        ret =
            _gnutls_buffer_get (&session->internals.record_send_buffer, &ptr, &n);
        if (ret < 0)
        {
            gnutls_assert ();
            return ret;
        }

        _gnutls_write_log
        ("WRITE: Restoring old write. (%d bytes to send)\n", n);
    }

    _gnutls_write_log ("WRITE: Will write %d bytes to %d.\n", n, fd);

    i = 0;
    left = n;
    while (left > 0)
    {

        if (session->internals._gnutls_push_func == NULL)
            i = send (GNUTLS_POINTER_TO_INT(fd), &ptr[n - left], left, 0);
        else
            i = session->internals._gnutls_push_func (fd, &ptr[n - left], left);

        if (i == -1)
        {
            if (errno == EAGAIN || errno == EINTR)
            {
                session->internals.record_send_buffer_prev_size += n - left;

                retval =
                    _gnutls_buffer_insert (&session->internals.
                                           record_send_buffer,
                                           &ptr[n - left], left);
                if (retval < 0)
                {
                    gnutls_assert ();
                    return retval;
                }

                _gnutls_write_log
                ("WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n",
                 left, n - left);

                retval = RET (errno);

                return retval;
            }
            else
            {
                gnutls_assert ();
                return GNUTLS_E_PUSH_ERROR;
            }
        }
        left -= i;


        if (_gnutls_log_level >= 7)
        {
            char line[128];
            char tmp[16];


            _gnutls_write_log
            ("WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n",
             i, fd, left, n);
            for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
            {
                line[0] = 0;

                if (sum > n - left)
                    break;

                sprintf (tmp, "%.4x - ", x);
                _gnutls_str_cat (line, sizeof (line), tmp);

                for (j = 0; j < 16; j++)
                {
                    if (sum < n - left)
                    {
                        sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
                        _gnutls_str_cat (line, sizeof (line), tmp);
                    }
                    else
                        break;
                }
                _gnutls_write_log ("%s\n", line);
            }
        }
    }

    retval = n + session->internals.record_send_buffer_prev_size;

    session->internals.record_send_buffer.length = 0;
    session->internals.record_send_buffer_prev_size = 0;

    return retval;

}
Example #2
0
/* This is a send function for the gnutls handshake 
 * protocol. Just makes sure that all data have been sent.
 */
ssize_t
_gnutls_handshake_io_send_int (gnutls_session_t session,
			       content_type_t type,
			       gnutls_handshake_description_t htype,
			       const void *iptr, size_t n)
{
  size_t left;
  ssize_t ret = 0;
  const opaque *ptr;
  ssize_t retval = 0;

  ptr = iptr;

  if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL
      && n == 0)
    {
      gnutls_datum bdata;

      /* resuming previously interrupted write
       */
      gnutls_assert ();

      /* checking is handled above */
      _gnutls_buffer_get_datum (&session->internals.handshake_send_buffer, &bdata, session->internals.handshake_send_buffer.length);

      ptr = bdata.data;
      n = bdata.size;

      type = session->internals.handshake_send_buffer_type;
      htype = session->internals.handshake_send_buffer_htype;

    }
  else if (session->internals.handshake_send_buffer.length > 0)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }
#ifdef WRITE_DEBUG
  else
    {
      size_t sum = 0, x, j;

      _gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
			 gnutls_transport_get_ptr (session));
      for (x = 0; x < ((n) / 16) + 1; x++)
	{
	  if (sum > n)
	    break;

	  _gnutls_write_log ("%.4x - ", x);
	  for (j = 0; j < 16; j++)
	    {
	      if (sum < n)
		{
		  _gnutls_write_log ("%.2x ", ((unsigned char *) ptr)[sum++]);
		}
	      else
		break;
	    }
	  _gnutls_write_log ("\n");
	}
      _gnutls_write_log ("\n");
    }
#endif

  if (n == 0)
    {				/* if we have no data to send */
      gnutls_assert ();
      return 0;
    }
  else if (ptr == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }


  left = n;
  while (left > 0)
    {
      ret = _gnutls_send_int (session, type, htype, &ptr[n - left], left);

      if (ret <= 0)
	{
	  if (ret == 0)
	    {
	      gnutls_assert ();
	      ret = GNUTLS_E_INTERNAL_ERROR;
	    }

	  if (left > 0
	      && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN))
	    {
	      gnutls_assert ();

	      retval =
		_gnutls_buffer_append (&session->internals.
				       handshake_send_buffer, &ptr[n - left],
				       left);
	      if (retval < 0)
		{
		  gnutls_assert ();
		  return retval;
		}

	      session->internals.handshake_send_buffer_prev_size += n - left;

	      session->internals.handshake_send_buffer_type = type;
	      session->internals.handshake_send_buffer_htype = htype;

	    }
	  else
	    {
	      session->internals.handshake_send_buffer_prev_size = 0;
	      session->internals.handshake_send_buffer.length = 0;
	    }

	  gnutls_assert ();
	  return ret;
	}
      left -= ret;
    }

  retval = n + session->internals.handshake_send_buffer_prev_size;

  session->internals.handshake_send_buffer.length = 0;
  session->internals.handshake_send_buffer_prev_size = 0;

  return retval;

}
Example #3
0
/* This function writes the data that are left in the
 * TLS write buffer (ie. because the previous write was
 * interrupted.
 */
ssize_t _gnutls_io_write_flush(gnutls_session_t session)
{
	gnutls_datum_t msg;
	mbuffer_head_st *send_buffer =
	    &session->internals.record_send_buffer;
	int ret;
	ssize_t sent = 0, tosend = 0;
	giovec_t iovec[MAX_QUEUE];
	int i = 0;
	mbuffer_st *cur;

	session->internals.direction = 1;
	_gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
			  (int) send_buffer->byte_length);

	for (cur = _mbuffer_head_get_first(send_buffer, &msg);
	     cur != NULL; cur = _mbuffer_head_get_next(cur, &msg)) {
		iovec[i].iov_base = msg.data;
		iovec[i++].iov_len = msg.size;
		tosend += msg.size;

		/* we buffer up to MAX_QUEUE messages */
		if (i >= MAX_QUEUE) {
			gnutls_assert();
			return GNUTLS_E_INTERNAL_ERROR;
		}
	}

	if (tosend == 0) {
		gnutls_assert();
		return 0;
	}

	ret = _gnutls_writev(session, iovec, i, tosend);
	if (ret >= 0) {
		_mbuffer_head_remove_bytes(send_buffer, ret);
		_gnutls_write_log
		    ("WRITE: wrote %d bytes, %d bytes left.\n", ret,
		     (int) send_buffer->byte_length);

		sent += ret;
	} else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
		_gnutls_write_log("WRITE interrupted: %d bytes left.\n",
				  (int) send_buffer->byte_length);
		return ret;
	} else if (ret == GNUTLS_E_LARGE_PACKET) {
		_mbuffer_head_remove_bytes(send_buffer, tosend);
		_gnutls_write_log
		    ("WRITE cannot send large packet (%u bytes).\n",
		     (unsigned int) tosend);
		return ret;
	} else {
		_gnutls_write_log("WRITE error: code %d, %d bytes left.\n",
				  ret, (int) send_buffer->byte_length);

		gnutls_assert();
		return ret;
	}

	if (sent < tosend) {
		return gnutls_assert_val(GNUTLS_E_AGAIN);
	}

	return sent;
}
Example #4
0
/* This function is like write. But it does not return -1 on error.
 * It does return gnutls_errno instead.
 *
 * In case of E_AGAIN and E_INTERRUPTED errors, you must call gnutls_write_flush(),
 * until it returns ok (0).
 *
 * We need to push exactly the data in n, since we cannot send less
 * data. In TLS the peer must receive the whole packet in order
 * to decrypt and verify the integrity. 
 *
 */
ssize_t
_gnutls_io_write_buffered (gnutls_session_t session,
			   const void *iptr, size_t n)
{
  size_t left;
  unsigned j, x, sum = 0;
  ssize_t retval, i;
  const opaque *ptr;
  gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;

  /* to know where the procedure was interrupted.
   */
  session->internals.direction = 1;

  ptr = iptr;

  /* In case the previous write was interrupted, check if the
   * iptr != NULL and we have data in the buffer.
   * If this is true then return an error.
   */
  if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  /* If data in the buffer exist
   */
  if (iptr == NULL)
    {
      gnutls_datum bdata;
      /* checking is handled above */
      _gnutls_buffer_get_datum (&session->internals.record_send_buffer, &bdata, session->internals.record_send_buffer.length);

      ptr = bdata.data;
      n = bdata.size;

      _gnutls_write_log
	("WRITE: Restoring old write. (%d bytes to send)\n", n);
    }

  _gnutls_write_log ("WRITE: Will write %d bytes to %p.\n", n, fd);

  i = 0;
  left = n;
  while (left > 0)
    {

      session->internals.errnum = 0;

      if (session->internals._gnutls_push_func == NULL)
	{
	  i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0);
#if HAVE_WINSOCK2_H
	  if (i < 0)
	    {
	      int tmperr = WSAGetLastError ();
	      switch (tmperr)
		{
		case WSAEWOULDBLOCK:
		  session->internals.errnum = EAGAIN;
		  break;

		case WSAEINTR:
		  session->internals.errnum = EINTR;
		  break;

		default:
		  session->internals.errnum = EIO;
		  break;
		}
	      WSASetLastError (tmperr);
	    }
#endif
	}
      else
	i = session->internals._gnutls_push_func (fd, &ptr[n - left], left);

      if (i == -1)
	{
	  int err = session->internals.errnum ? session->internals.errnum
	    : errno;

	  if (err == EAGAIN || err == EINTR)
	    {
	      session->internals.record_send_buffer_prev_size += n - left;

	      retval =
		_gnutls_buffer_append (&session->internals.record_send_buffer,
				       &ptr[n - left], left);
	      if (retval < 0)
		{
		  gnutls_assert ();
		  return retval;
		}

	      _gnutls_write_log
		("WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n",
		 left, n - left);

	      if (err == EAGAIN)
		return GNUTLS_E_AGAIN;
	      return GNUTLS_E_INTERRUPTED;
	    }
	  else
	    {
	      gnutls_assert ();
	      return GNUTLS_E_PUSH_ERROR;
	    }
	}
      left -= i;


      if (_gnutls_log_level >= 7)
	{
	  char line[128];
	  char tmp[16];


	  _gnutls_write_log
	    ("WRITE: wrote %d bytes to %p. Left %d bytes. Total %d bytes.\n",
	     i, fd, left, n);
	  for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
	    {
	      line[0] = 0;

	      if (sum > n - left)
		break;

	      sprintf (tmp, "%.4x - ", x);
	      _gnutls_str_cat (line, sizeof (line), tmp);

	      for (j = 0; j < 16; j++)
		{
		  if (sum < n - left)
		    {
		      sprintf (tmp, "%.2x ",
			       ((const unsigned char *) ptr)[sum++]);
		      _gnutls_str_cat (line, sizeof (line), tmp);
		    }
		  else
		    break;
		}
	      _gnutls_write_log ("%s\n", line);
	    }
	}
    }

  retval = n + session->internals.record_send_buffer_prev_size;

  session->internals.record_send_buffer.length = 0;
  session->internals.record_send_buffer_prev_size = 0;

  return retval;

}