Example #1
0
EMACS_INT
emacs_gnutls_read (struct Lisp_Process *proc, char *buf, EMACS_INT nbyte)
{
  ssize_t rtnval;
  gnutls_session_t state = proc->gnutls_state;

  if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
    {
      emacs_gnutls_handshake (proc);
      return -1;
    }
  rtnval = fn_gnutls_record_recv (state, buf, nbyte);
  if (rtnval >= 0)
    return rtnval;
  else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
    /* The peer closed the connection. */
    return 0;
  else if (emacs_gnutls_handle_error (state, rtnval) == 0)
    /* non-fatal error */
    return -1;
  else {
    /* a fatal error occurred */
    return 0;
  }
}
Example #2
0
EMACS_INT
emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, EMACS_INT nbyte)
{
  ssize_t rtnval = 0;
  EMACS_INT bytes_written;
  gnutls_session_t state = proc->gnutls_state;

  if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
    {
#ifdef EWOULDBLOCK
      errno = EWOULDBLOCK;
#endif
#ifdef EAGAIN
      errno = EAGAIN;
#endif
      return 0;
    }

  bytes_written = 0;

  while (nbyte > 0)
    {
      rtnval = fn_gnutls_record_send (state, buf, nbyte);

      if (rtnval < 0)
	{
	  if (rtnval == GNUTLS_E_INTERRUPTED)
	    continue;
	  else
	    {
	      /* If we get GNUTLS_E_AGAIN, then set errno
		 appropriately so that send_process retries the
		 correct way instead of erroring out. */
	      if (rtnval == GNUTLS_E_AGAIN)
		{
#ifdef EWOULDBLOCK
		  errno = EWOULDBLOCK;
#endif
#ifdef EAGAIN
		  errno = EAGAIN;
#endif
		}
	      break;
	    }
	}

      buf += rtnval;
      nbyte -= rtnval;
      bytes_written += rtnval;
    }

  emacs_gnutls_handle_error (state, rtnval);
  return (bytes_written);
}
Example #3
0
EMACS_INT
emacs_gnutls_read (struct Lisp_Process *proc, char *buf, EMACS_INT nbyte)
{
  ssize_t rtnval;
  gnutls_session_t state = proc->gnutls_state;

  int log_level = proc->gnutls_log_level;

  if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
    {
      /* If the handshake count is under the limit, try the handshake
         again and increment the handshake count.  This count is kept
         per process (connection), not globally.  */
      if (proc->gnutls_handshakes_tried < GNUTLS_EMACS_HANDSHAKES_LIMIT)
        {
          proc->gnutls_handshakes_tried++;
          emacs_gnutls_handshake (proc);
          GNUTLS_LOG2i (5, log_level, "Retried handshake", 
                        proc->gnutls_handshakes_tried);
          return -1;
        }

      GNUTLS_LOG (2, log_level, "Giving up on handshake; resetting retries");
      proc->gnutls_handshakes_tried = 0;
      return 0;
    }
  rtnval = fn_gnutls_record_recv (state, buf, nbyte);
  if (rtnval >= 0)
    return rtnval;
  else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
    /* The peer closed the connection. */
    return 0;
  else if (emacs_gnutls_handle_error (state, rtnval) == 0)
    /* non-fatal error */
    return -1;
  else {
    /* a fatal error occurred */
    return 0;
  }
}
Example #4
0
EMACS_INT
emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, EMACS_INT nbyte)
{
  ssize_t rtnval = 0;
  EMACS_INT bytes_written;
  gnutls_session_t state = proc->gnutls_state;

  if (proc->gnutls_initstage != GNUTLS_STAGE_READY) {
#ifdef EWOULDBLOCK
    errno = EWOULDBLOCK;
#endif
#ifdef EAGAIN
    errno = EAGAIN;
#endif
    return 0;
  }

  bytes_written = 0;

  while (nbyte > 0)
    {
      rtnval = fn_gnutls_record_send (state, buf, nbyte);

      if (rtnval < 0)
	{
	  if (rtnval == GNUTLS_E_AGAIN || rtnval == GNUTLS_E_INTERRUPTED)
	    continue;
	  else
	    break;
	}

      buf += rtnval;
      nbyte -= rtnval;
      bytes_written += rtnval;
    }

  emacs_gnutls_handle_error (state, rtnval);
  return (bytes_written);
}
Example #5
0
static int
emacs_gnutls_handshake (struct Lisp_Process *proc)
{
  gnutls_session_t state = proc->gnutls_state;
  int ret;

  if (proc->gnutls_initstage < GNUTLS_STAGE_HANDSHAKE_CANDO)
    return -1;

  if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
    {
#ifdef WINDOWSNT
      /* On W32 we cannot transfer socket handles between different runtime
	 libraries, so we tell GnuTLS to use our special push/pull
	 functions.  */
      fn_gnutls_transport_set_ptr2 (state,
				    (gnutls_transport_ptr_t) proc,
				    (gnutls_transport_ptr_t) proc);
      fn_gnutls_transport_set_push_function (state, &emacs_gnutls_push);
      fn_gnutls_transport_set_pull_function (state, &emacs_gnutls_pull);

      /* For non blocking sockets or other custom made pull/push
	 functions the gnutls_transport_set_lowat must be called, with
	 a zero low water mark value. (GnuTLS 2.10.4 documentation)

	 (Note: this is probably not strictly necessary as the lowat
	  value is only used when no custom pull/push functions are
	  set.)  */
      /* According to GnuTLS NEWS file, lowat level has been set to
	 zero by default in version 2.11.1, and the function
	 gnutls_transport_set_lowat was removed from the library in
	 version 2.99.0.  */
      if (!fn_gnutls_check_version ("2.11.1"))
	fn_gnutls_transport_set_lowat (state, 0);
#else
      /* This is how GnuTLS takes sockets: as file descriptors passed
	 in.  For an Emacs process socket, infd and outfd are the
	 same but we use this two-argument version for clarity.  */
      fn_gnutls_transport_set_ptr2 (state,
				    (gnutls_transport_ptr_t) (long) proc->infd,
				    (gnutls_transport_ptr_t) (long) proc->outfd);
#endif

      proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
    }

  do
    {
      ret = fn_gnutls_handshake (state);
      emacs_gnutls_handle_error (state, ret);
    }
  while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0);

  proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;

  if (ret == GNUTLS_E_SUCCESS)
    {
      /* Here we're finally done.  */
      proc->gnutls_initstage = GNUTLS_STAGE_READY;
    }
  else
    {
      fn_gnutls_alert_send_appropriate (state, ret);
    }
  return ret;
}