On Wed, 29 Sep 2010 17:17:56 +0200
Nikos Mavrogiannopoulos <[email protected]> wrote:

> On 09/29/2010 04:48 PM, Michael Blumenkrantz wrote:
> 
> > If that were the case, wouldn't it also fail when I have paused execution
> > as I described previously?  Additionally, the only function that is sending
> > data on that socket during that time is gnutls_handshake.
> 
> I can only speculate as I cannot reproduce the issue. If you think you
> know how to reproduce it, check mini-egain example, and see whether you
> can emulate the behavior you're seeing there.
> 
> To the point. As I see the problem is not on receiving. This happens
> normally as I see from your log. Check with wireshark and other ways
> that the send is occuring as it should.
> 
> regards,
> Nikos
Hmm I have spent some time working on a very tiny async app using gnutls.  It
utilizes a single callback to handshake and then disconnect from a server, as I
will describe later.  In my testing with this, however, I uncovered a larger
and previously unknown bug in pre-existing software which I have now begun the
long task of attempting to fix.  Thank you for your advice.

In thanks, I have written and documented a small test program (attached) which
performs an asynchronous remote connection to verisign.com (an easy site to
find that has an ssl certificate).  It requires eina and ecore from the
EFL/enlightenment.org to compile/run, but should serve as a good standalone
reading example to include since it is well-commented and short (11
gnutls calls, 3 ecore calls total).  Feel free to modify/redistribute if you
would like, with or without attribution.  I hope you find it useful.

-- 
Mike Blumenkrantz
Zentific: Our boolean values are huge.
#include <Ecore.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <gnutls/gnutls.h>

#define print(...) fprintf(stderr, "line %i: ", __LINE__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n")

static int done = 0;

static void
tls_log_func (int level, const char *str)
{
  fprintf (stderr, "|<%d>| %s", level, str);
}

static const char*
SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
{
   switch (status)
     {
      case GNUTLS_HANDSHAKE_HELLO_REQUEST:
        return "Hello request";
      case GNUTLS_HANDSHAKE_CLIENT_HELLO:
        return "Client hello";
      case GNUTLS_HANDSHAKE_SERVER_HELLO:
        return "Server hello";
      case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
        return "New session ticket";
      case GNUTLS_HANDSHAKE_CERTIFICATE_PKT:
        return "Certificate packet";
      case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE:
        return "Server key exchange";
      case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
        return "Certificate request";
      case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
        return "Server hello done";
      case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
        return "Certificate verify";
      case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
        return "Client key exchange";
      case GNUTLS_HANDSHAKE_FINISHED:
        return "Finished";
      case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
        return "Supplemental";
     }
   return NULL;
}

/* Connects to the peer and returns a socket
 * descriptor.
 */
static int
tcp_connect (void)
{
  const char *PORT = "443";
  const char *SERVER = "69.58.181.89"; //verisign.com
  int err, sd;
  int flag = 1, curstate = 0;
  struct sockaddr_in sa;

  /* sets some fd options such as nonblock */
  fcntl(sd, F_SETFL, O_NONBLOCK);
  fcntl(sd, F_SETFD, FD_CLOEXEC);
  setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate));

  setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
  sd = socket (AF_INET, SOCK_STREAM, 0);

  memset (&sa, '\0', sizeof (sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons (atoi (PORT));
  inet_pton (AF_INET, SERVER, &sa.sin_addr);

  /* connects to server
   */
  err = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
  if (err < 0)
    {
      fprintf (stderr, "Connect error\n");
      exit (1);
    }

  return sd;
}

/* closes the given socket descriptor.
 */
static void
tcp_close (int sd)
{
  shutdown (sd, SHUT_RDWR);	/* no more receptions */
  close (sd);
}

static Eina_Bool
_process_data(gnutls_session_t client, Ecore_Fd_Handler *fd_handler)
{
   static int ret, lastret;
   
   if (!done)
     {
        lastret = ret;
        ret = gnutls_handshake (client);
        /* avoid printing messages infinity times */
        if (lastret != ret)
          {
             print("gnutls returned with: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
             if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
               print("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(client)));
             print("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(client)));
             print("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(client)));
          }

        if (gnutls_error_is_fatal(ret))
          {
             print("yarrr this be an error!");
             exit(1);
          }
        
     }
  if (ret == GNUTLS_E_SUCCESS)
    {
       done = 1;
       print("Handshake successful!");
       ecore_main_loop_quit();
    }

   return ECORE_CALLBACK_RENEW;
}

int
main (void)
{
  /* credentials */
  gnutls_anon_client_credentials_t c_anoncred;
  gnutls_certificate_credentials_t c_certcred;
  
  gnutls_session_t client;
  int sd;

  /* General init. */
  gnutls_global_init ();
  ecore_init();
  gnutls_global_set_log_function (tls_log_func);
    gnutls_global_set_log_level (6);

  /* Init client */
  gnutls_anon_allocate_client_credentials (&c_anoncred);
  gnutls_certificate_allocate_credentials (&c_certcred);
  gnutls_init (&client, GNUTLS_CLIENT);
  /* set very specific priorities */
  gnutls_priority_set_direct(client, "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0", NULL);
  gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred);
  gnutls_credentials_set (client, GNUTLS_CRD_CERTIFICATE, c_certcred);


  /* connect to the peer
   */
  sd = tcp_connect ();

  /* associate gnutls with socket */
  gnutls_transport_set_ptr (client, (gnutls_transport_ptr_t) sd);
  /* add a callback for data being available for send/receive on socket */
  if (!ecore_main_fd_handler_add(sd, ECORE_FD_READ | ECORE_FD_WRITE, (Ecore_Fd_Cb)_process_data, client, NULL, NULL))
    {
       print("could not create fd handler!");
       exit(1);
    }
  /* begin main loop */
  ecore_main_loop_begin();

  gnutls_bye (client, GNUTLS_SHUT_RDWR);

  gnutls_deinit (client);

  tcp_close (sd);
  
  return 0;
}
_______________________________________________
Help-gnutls mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/help-gnutls

Reply via email to