You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2012/08/10 20:15:10 UTC

svn commit: r1371798 - in /qpid/proton/branches/driver_abstraction/proton-c: ./ src/ src/drivers/

Author: kgiusti
Date: Fri Aug 10 18:15:10 2012
New Revision: 1371798

URL: http://svn.apache.org/viewvc?rev=1371798&view=rev
Log:
checkpoint - it compiles

Added:
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c   (with props)
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c   (contents, props changed)
      - copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c   (contents, props changed)
      - copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h   (with props)
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c   (contents, props changed)
      - copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c
Removed:
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_openssl.c
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c
    qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c
Modified:
    qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt
    qpid/proton/branches/driver_abstraction/proton-c/src/driver.c
    qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h

Modified: qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt Fri Aug 10 18:15:10 2012
@@ -50,20 +50,20 @@ add_custom_command (
 
 if (POLLER STREQUAL poll)
   set (pn_driver_impl
-       src/drivers/driver_poll.c
+       src/drivers/poll.c
   )
 elseif (POLLER STREQUAL select)
   set (pn_driver_impl
-       src/drivers/driver_select.c
+       src/drivers/select.c
   )
 endif (POLLER STREQUAL poll)
 
 # Link in openssl if present
 if (SSL_IMPL STREQUAL openssl)
-  set (pn_driver_ssl_impl src/drivers/driver_openssl.c)
+  set (pn_driver_ssl_impl src/drivers/openssl.c)
   set (LINK_DEPS ${LINK_DEPS} ssl crypto)
 else (SSL_IMPL STREQUAL openssl)
-  set (pn_driver_ssl_impl src/drivers/driver_no_ssl.c)
+  set (pn_driver_ssl_impl src/drivers/ssl_stub.c)
 endif (SSL_IMPL STREQUAL openssl)
 
 

Modified: qpid/proton/branches/driver_abstraction/proton-c/src/driver.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/driver.c?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/driver.c (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/driver.c Fri Aug 10 18:15:10 2012
@@ -25,6 +25,7 @@
 #include <proton/sasl.h>
 #include "util.h"
 #include "driver_impl.h"
+#include "drivers/ssl.h"
 
 #include <stdio.h>
 #include <time.h>
@@ -168,6 +169,7 @@ pn_connector_t *pn_listener_accept(pn_li
       pn_connector_t *c = pn_connector_fd(l->driver, sock, NULL);
       snprintf(c->name, PN_CONNECTOR_NAME_MAX, "%s:%s", host, serv);
       c->listener = l;
+      pn_listener_init_ssl_client( l, c );  // @todo KAG: deal with error case!!!
       return c;
     }
   }
@@ -186,6 +188,7 @@ void pn_listener_free(pn_listener_t *l)
   if (!l) return;
 
   if (l->driver) pn_driver_remove_listener(l->driver, l);
+  pn_listener_free_ssl(l);
   pn_listener_impl_destroy(l);
   free(l);
 }
@@ -282,6 +285,7 @@ pn_connector_t *pn_connector_fd(pn_drive
   c->read = pn_connector_read;
   c->write = pn_connector_write;
   c->tick = pn_connector_tick;
+  c->io_handler = pn_io_handler;
   c->input_size = 0;
   c->input_eos = false;
   c->output_size = 0;
@@ -368,10 +372,11 @@ void pn_connector_free(pn_connector_t *c
   if (!ctor) return;
 
   if (ctor->driver) pn_driver_remove_connector(ctor->driver, ctor);
+
+  pn_connector_impl_destroy(ctor);
   ctor->connection = NULL;
   ctor->transport = NULL;
   pn_sasl_free(ctor->sasl);
-  pn_connector_impl_destroy(ctor);
   free(ctor);
 }
 
@@ -592,21 +597,13 @@ void pn_connector_process(pn_connector_t
       c->pending_tick = false;
     }
 
-    if (c->pending_read) {
-      c->read(c);
-      c->pending_read = false;
-    }
-    pn_connector_process_input(c);
-    pn_connector_process_output(c);
-    if (c->pending_write) {
-      c->write(c);
-      c->pending_write = false;
-    }
+    c->io_handler(c);
+
     if (c->output_size == 0 && c->input_done && c->output_done) {
       if (c->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV)) {
         fprintf(stderr, "Closed %s\n", c->name);
       }
-      pn_connector_close(c);
+      pn_connector_shutdown_ssl(c);   // AMQP finished, perform clean shutdown
     }
   }
 }
@@ -672,7 +669,10 @@ void pn_driver_wakeup(pn_driver_t *d)
 
 void pn_driver_wait(pn_driver_t *d, int timeout)
 {
-  pn_driver_impl_wait(d, timeout);
+  // if SSL/TlS has data available, no need to wait for I/O
+  if (!pn_driver_ssl_data_ready(d)) {
+      pn_driver_impl_wait(d, timeout);
+  }
   d->listener_next = d->listener_head;
   d->connector_next = d->connector_head;
 }
@@ -707,3 +707,28 @@ pn_connector_t *pn_driver_connector(pn_d
 
   return NULL;
 }
+
+
+/** default I/O handling routine */
+int pn_io_handler(pn_connector_t *c)
+{
+    if (c->pending_read) {
+      c->read(c);
+      c->pending_read = false;
+    }
+    pn_connector_process_input(c);
+    pn_connector_process_output(c);
+    if (c->pending_write) {
+      c->write(c);
+      c->pending_write = false;
+    }
+    return 0;
+}
+
+/** stub handling routine */
+int pn_null_io_handler(pn_connector_t *c)
+{
+    return 0;
+}
+
+

Modified: qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h Fri Aug 10 18:15:10 2012
@@ -84,6 +84,9 @@ struct pn_connector_t {
   void (*read)(pn_connector_t *);
   void (*write) (pn_connector_t *);
   time_t (*tick)(pn_connector_t *sel, time_t now);
+
+  int (*io_handler)(pn_connector_t *);
+
   size_t input_size;
   char input[PN_CONNECTOR_IO_BUF_SIZE];
   bool input_eos;
@@ -105,8 +108,9 @@ struct pn_connector_t {
 
 int pn_connector_impl_init( struct pn_connector_t *);
 void pn_connector_impl_destroy( struct pn_connector_t *);
-
 void pn_driver_impl_wait(struct pn_driver_t *, int timeout_ms);
+int pn_io_handler(pn_connector_t *);
+int pn_null_io_handler(pn_connector_t *);
 
 
 #endif /* driver.h */

Added: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c?rev=1371798&view=auto
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c (added)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c Fri Aug 10 18:15:10 2012
@@ -0,0 +1,744 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#define _POSIX_C_SOURCE 1
+
+#include <proton/driver.h>
+#include "../driver_impl.h"
+#include "../util.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/socket.h>
+
+
+/** @file
+ * SSL/TLS support API.
+ *
+ * This file contains stub implementations of the SSL/TLS API.  This implementation is
+ * used if there is no SSL/TLS support in the system's environment.
+ */
+
+static int ssl_initialized;
+
+struct pn_listener_ssl_impl_t {
+    SSL_CTX *ctx;
+    bool allow_unsecured;
+    bool ca_db;
+    char *keyfile_pw;
+};
+typedef struct pn_listener_ssl_impl_t pn_listener_ssl_impl_t;
+
+
+struct pn_connector_ssl_impl_t {
+
+    enum { SSL_CLIENT, SSL_SERVER } mode;
+    SSL_CTX *ctx;   // NULL if mode=SSL_SERVER - uses listener's ctx
+    SSL *ssl;
+    BIO *sbio;
+    char *keyfile_pw;
+    bool read_stalled;  // SSL has data to read, but client buffer is full.
+};
+typedef struct pn_connector_ssl_impl_t pn_connector_ssl_impl_t;
+
+/* */
+static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata);
+static int configure_ca_database(SSL_CTX *ctx, const char *certificate_db);
+static int start_check_for_ssl( pn_connector_t *client );
+static int handle_check_for_ssl( pn_connector_t *client );
+static int start_ssl_connect(pn_connector_t *client);
+static int handle_ssl_connect( pn_connector_t *client );
+static int start_ssl_accept(pn_connector_t *client);
+static int handle_ssl_accept(pn_connector_t *client);
+static int start_ssl_connection_up( pn_connector_t *c );
+static int handle_ssl_connection_up( pn_connector_t *c );
+static int start_clear_connected( pn_connector_t *c );
+static int start_ssl_shutdown( pn_connector_t *c );
+static int handle_ssl_shutdown( pn_connector_t *c );
+
+/** Public API - visible to application code */
+
+int pn_listener_ssl_server_init(pn_listener_t *listener,
+                                const char *certificate_file,
+                                const char *private_key_file,
+                                const char *password,
+                                const char *certificate_db)
+{
+    listener->ssl = calloc(1, sizeof(pn_listener_ssl_impl_t));
+    // note: see pn_listener_free_ssl for cleanup/deallocation
+    if (!listener->ssl) {
+        perror("calloc()");
+        return -1;
+    }
+    pn_listener_ssl_impl_t *impl = listener->ssl;
+
+    if (!ssl_initialized) {
+        ssl_initialized = 1;
+        SSL_library_init();
+    }
+
+    impl->ctx = SSL_CTX_new(SSLv23_server_method());
+    if (!impl->ctx) {
+        perror("unable to initialize SSL context");
+        return -2;
+    }
+
+    if (SSL_CTX_use_certificate_chain_file(impl->ctx, certificate_file) != 1) {
+        fprintf(stderr, "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
+        return -3;
+    }
+
+    if (password) {
+        impl->keyfile_pw = pn_strdup(password);  // @todo: obfuscate me!!!
+        SSL_CTX_set_default_passwd_cb(impl->ctx, keyfile_pw_cb);
+        SSL_CTX_set_default_passwd_cb_userdata(impl->ctx, impl->keyfile_pw);
+    }
+
+    if (SSL_CTX_use_PrivateKey_file(impl->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
+        fprintf(stderr, "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
+        return -4;
+    }
+
+    if (certificate_db) {
+        impl->ca_db = true;
+        if (configure_ca_database(impl->ctx, certificate_db)) {
+            return -5;
+        }
+    }
+    return 0;
+}
+
+
+int pn_listener_ssl_allow_unsecured_clients(pn_listener_t *listener)
+{
+    if (!listener->ssl) {
+        fprintf(stderr, "SSL not initialized");
+        return -1;
+    }
+
+    listener->ssl->allow_unsecured = true;
+    return 0;
+}
+
+
+
+int pn_connector_ssl_client_init(pn_connector_t *connector,
+                                 const char *certificate_db)
+{
+    connector->ssl = calloc(1, sizeof(pn_connector_ssl_impl_t));
+    if (!connector->ssl) {
+        perror("calloc()");
+        return -1;
+    }
+    pn_connector_ssl_impl_t *impl = connector->ssl;
+
+    impl->mode = SSL_CLIENT;
+
+    if (!ssl_initialized) {
+        ssl_initialized = 1;
+        SSL_library_init();
+    }
+
+    impl->ctx = SSL_CTX_new(SSLv23_client_method());
+    if (!impl->ctx) {
+        perror("unable to initialize SSL context");
+        return -2;
+    }
+
+    if (configure_ca_database(impl->ctx, certificate_db)) {
+        return -3;
+    }
+
+    /* Force servers to authenticate */
+    SSL_CTX_set_verify( connector->ssl->ctx,
+                        SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                        0 /*?verify callback?*/ );
+
+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
+    SSL_CTX_set_verify_depth(connector->ssl->ctx, 1);
+#endif
+
+    /* make the socket nonblocking*/
+    int flags = fcntl(connector->fd, F_GETFL, 0);
+
+    flags |= O_NONBLOCK;
+    if (fcntl(connector->fd, F_SETFL, flags)) {
+        // @todo: better error handling - fail this connection
+        perror("fcntl");
+        return -1;
+    }
+
+    return start_ssl_connect( connector );    // start connecting!
+}
+
+
+int pn_connector_ssl_set_client_auth(pn_connector_t *connector,
+                                     const char *certificate_file,
+                                     const char *private_key_file,
+                                     const char *password)
+{
+    // @todo check state to verify not yet connected!
+
+    pn_connector_ssl_impl_t *impl = connector->ssl;
+
+    if (!impl || impl->mode != SSL_CLIENT) {
+        fprintf(stderr, "Error: connector not configured as SSL client.\n");
+        return -1;
+    }
+
+    if (SSL_CTX_use_certificate_chain_file(impl->ctx, certificate_file) != 1) {
+        fprintf(stderr, "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
+        return -3;
+    }
+
+    if (password) {
+        impl->keyfile_pw = pn_strdup(password);  // @todo: obfuscate me!!!
+        SSL_CTX_set_default_passwd_cb(impl->ctx, keyfile_pw_cb);
+        SSL_CTX_set_default_passwd_cb_userdata(impl->ctx, impl->keyfile_pw);
+    }
+
+    if (SSL_CTX_use_PrivateKey_file(impl->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
+        fprintf(stderr, "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
+        return -4;
+    }
+
+    return 0;
+}
+
+
+int pn_connector_ssl_authenticate_client(pn_connector_t *connector,
+                                         const char *trusted_CAs_file)
+{
+    pn_connector_ssl_impl_t *impl = connector->ssl;
+
+    if (!impl || impl->mode != SSL_SERVER) {
+        fprintf(stderr, "Error: connector not configured as SSL server.\n");
+    }
+
+    // @todo: make sure certificate_db is set...
+
+
+    // load the CA's that we trust - this will be sent to the client when client
+    // authentication is requested
+    STACK_OF(X509_NAME) *cert_names;
+    cert_names = SSL_load_client_CA_file( trusted_CAs_file );
+    if (cert_names != NULL)
+        SSL_set_client_CA_list(impl->ssl, cert_names);
+    else {
+        fprintf(stderr, "Unable to process file of trusted_CAs: %s\n", trusted_CAs_file);
+        return -1;
+    }
+
+    SSL_set_verify( impl->ssl,
+                    SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                    0 /*?verify callback?*/);
+    return 0;
+}
+
+
+/** Abstraction API - visible to Driver only - see ssl.h */
+
+
+int pn_driver_ssl_data_ready( pn_driver_t *d )
+{
+    int ready = 0;
+
+    // check if any stalled readers exist, and if they have buffer space available.
+    pn_connector_t *c = d->connector_head;
+    while (c) {
+        if (!c->closed && c->ssl) {
+            pn_connector_ssl_impl_t *impl = c->ssl;
+            if (impl->read_stalled && (c->input_size < PN_CONNECTOR_IO_BUF_SIZE)) {
+                impl->read_stalled = 0;
+                c->pending_read = true;
+                ready += 1;
+            }
+        }
+        c = c->connector_next;
+    }
+    return ready;
+}
+
+
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c)
+{
+    if (!l->ssl) return 0;
+    assert(!c->ssl);
+
+    c->ssl = calloc(1, sizeof(pn_connector_ssl_impl_t));
+    if (!c->ssl) {
+        perror("calloc()");
+        return -1;
+    }
+    pn_connector_ssl_impl_t *impl = c->ssl;
+
+    impl->mode = SSL_SERVER;
+    impl->ctx = NULL;    // share the acceptor's context
+
+    /* make the socket nonblocking*/
+    int flags = fcntl(c->fd, F_GETFL, 0);
+
+    flags |= O_NONBLOCK;
+    if (fcntl(c->fd, F_SETFL, flags)) {
+        // @todo: better error handling - fail this connection
+        perror("fcntl");
+        return -1;
+    }
+
+    if (l->ssl->allow_unsecured) {
+        return start_check_for_ssl(c);
+    } else {
+        return start_ssl_accept(c);
+    }
+}
+
+void pn_connector_shutdown_ssl( pn_connector_t *c)
+{
+    if (c->ssl) {
+        if (start_ssl_shutdown(c) == 0)
+            return;  // shutting down
+    }
+    // if no ssl or shutdown fails, just close the underlying socket
+    pn_connector_close(c);
+}
+
+void pn_listener_free_ssl( pn_listener_t *l )
+{
+    if (l->ssl) {
+        pn_listener_ssl_impl_t *impl = l->ssl;
+        // note: ctx is referenced counted - will not actually free until all child SSL
+        // connections are freed.
+        if (impl->ctx) SSL_CTX_free(impl->ctx);
+        if (impl->keyfile_pw) {
+            memset( impl->keyfile_pw, 0, strlen( impl->keyfile_pw ) );
+            free( impl->keyfile_pw );
+        }
+        free(l->ssl);
+        l->ssl = NULL;
+    }
+}
+
+
+void pn_connector_free_ssl( pn_connector_t *c )
+{
+    if (c->ssl) {
+        pn_connector_ssl_impl_t *impl = c->ssl;
+        if (impl->ssl) SSL_free(impl->ssl);
+        if (impl->sbio) BIO_free(impl->sbio);
+        if (impl->ctx) SSL_CTX_free(impl->ctx);
+        if (impl->keyfile_pw) {
+            memset( impl->keyfile_pw, 0, strlen( impl->keyfile_pw ) );
+            free( impl->keyfile_pw );
+        }
+        free(c->ssl);
+        c->ssl = NULL;
+    }
+}
+
+
+/** Private: */
+
+static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata)
+{
+    strncpy(buf, (char *)userdata, size);   // @todo: un-obfuscate me!!!
+    buf[size - 1] = '\0';
+    return(strlen(buf));
+}
+
+
+// Configure the database containing trusted CA certificates
+static int configure_ca_database(SSL_CTX *ctx, const char *certificate_db)
+{
+    // certificates can be either a file or a directory, which determines how it is passed
+    // to SSL_CTX_load_verify_locations()
+    struct stat sbuf;
+    if (stat( certificate_db, &sbuf ) != 0) {
+        fprintf(stderr, "stat(%s) failed: %s\n", certificate_db, strerror(errno));
+        return -1;
+    }
+    const char *file;
+    const char *dir;
+    if (S_ISDIR(sbuf.st_mode)) {
+        dir = certificate_db;
+        file = NULL;
+    } else {
+        dir = NULL;
+        file = certificate_db;
+    }
+
+    if (SSL_CTX_load_verify_locations( ctx, file, dir ) != 1) {
+        fprintf(stderr, "SSL_CTX_load_verify_locations( %s ) failed\n", certificate_db);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+
+
+/* STATE: check_for_ssl
+ *
+ * The server will allow both encrypted and non-encrypted clients.  Determine if
+ * encryption is being used by peeking at the first few bytes of incoming data.
+ */
+
+static int start_check_for_ssl( pn_connector_t *client )
+{
+    client->status |= PN_SEL_RD;
+    client->io_handler = handle_check_for_ssl;
+    return 0;
+}
+
+
+static int handle_check_for_ssl( pn_connector_t *client )
+{
+    unsigned char buf[5];
+    int rc;
+    int retries = 3;
+
+    do {
+        rc = recv(client->fd, buf, sizeof(buf), MSG_PEEK);
+        if (rc == sizeof(buf))
+            break;
+        if (rc < 0 && errno != EINTR && errno != EAGAIN) {
+            perror("handle_check_for_ssl() recv failed:");
+            break;
+        }
+    } while (retries-- > 0);
+
+    if (rc == sizeof(buf)) {
+        /*
+         * SSLv2 Client Hello format
+         * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+         *
+         * Bytes 0-1: RECORD-LENGTH
+         * Byte    2: MSG-CLIENT-HELLO (1)
+         * Byte    3: CLIENT-VERSION-MSB
+         * Byte    4: CLIENT-VERSION-LSB
+         *
+         * Allowed versions:
+         * 2.0 - SSLv2
+         * 3.0 - SSLv3
+         * 3.1 - TLS 1.0
+         * 3.2 - TLS 1.1
+         * 3.3 - TLS 1.2
+         *
+         * The version sent in the Client-Hello is the latest version supported by
+         * the client. NSS may send version 3.x in an SSLv2 header for
+         * maximum compatibility.
+         */
+        int isSSL2Handshake = buf[2] == 1 &&   // MSG-CLIENT-HELLO
+          ((buf[3] == 3 && buf[4] <= 3) ||    // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+           (buf[3] == 2 && buf[4] == 0));     // SSL 2
+
+        /*
+         * SSLv3/TLS Client Hello format
+         * RFC 2246
+         *
+         * Byte    0: ContentType (handshake - 22)
+         * Bytes 1-2: ProtocolVersion {major, minor}
+         *
+         * Allowed versions:
+         * 3.0 - SSLv3
+         * 3.1 - TLS 1.0
+         * 3.2 - TLS 1.1
+         * 3.3 - TLS 1.2
+         */
+        int isSSL3Handshake = buf[0] == 22 &&  // handshake
+          (buf[1] == 3 && buf[2] <= 3);       // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+
+        if (isSSL2Handshake || isSSL3Handshake) {
+            if (client->driver->trace & PN_TRACE_DRV) fprintf(stderr, "Connector %s using encryption.\n", client->name);
+            return start_ssl_accept( client );
+        }
+    }
+    if (client->driver->trace & PN_TRACE_DRV) fprintf(stderr, "Connector %s not using encryption.\n", client->name);
+    return start_clear_connected( client );
+}
+
+
+/* STATE: ssl_connect
+ *
+ * Start the SSL connection to the server.  This will require I/O to complete the
+ * handshake.
+ */
+static int start_ssl_connect(pn_connector_t *client)
+{
+    pn_connector_ssl_impl_t *impl = client->ssl;
+    if (!impl) return -1;
+
+    impl->ssl = SSL_new(impl->ctx);
+    impl->sbio = BIO_new_socket( client->fd, BIO_NOCLOSE );
+    SSL_set_bio(impl->ssl, impl->sbio, impl->sbio);
+#if 0
+    // @todo reconnect support
+    if (conn->reconnecting && conn->session) {
+        printf("Resuming old session...\n");
+        SSL_set_session(conn->ssl, conn->session);
+        SSL_SESSION_free(conn->session);
+        conn->session = NULL;
+    }
+#endif
+    return handle_ssl_connect(client);
+}
+
+
+int handle_ssl_connect( pn_connector_t *client )
+{
+    pn_connector_ssl_impl_t *impl = client->ssl;
+    if (!impl) return -1;
+
+    int rc = SSL_connect( impl->ssl );
+    switch (SSL_get_error( impl->ssl, rc )) {
+    case SSL_ERROR_NONE:
+        // connection completed
+        return start_ssl_connection_up( client );
+
+    case SSL_ERROR_WANT_READ:
+        printf("  need read...\n");
+        client->status |= PN_SEL_RD;
+        break;
+    case SSL_ERROR_WANT_WRITE:
+        printf("  need write...\n");
+        client->status |= PN_SEL_WR;
+        break;
+    default:
+        fprintf(stderr, "SSL_connect() failure");
+        return -1;
+    }
+
+    client->io_handler = handle_ssl_connect;
+    return 0;
+}
+
+
+
+/* STATE: ssl_accept
+ *
+ * Accept the client connection.  This may require I/O to complete the handshake.
+ */
+
+static int start_ssl_accept(pn_connector_t *client)
+{
+    pn_connector_ssl_impl_t *impl = client->ssl;
+    if (!impl) return -1;
+
+    impl->sbio = BIO_new_socket(client->fd, BIO_NOCLOSE);
+    impl->ssl = SSL_new(impl->ctx);
+    SSL_set_bio(impl->ssl, impl->sbio, impl->sbio);
+
+    return handle_ssl_accept(client);
+}
+
+static int handle_ssl_accept(pn_connector_t *client)
+{
+    pn_connector_ssl_impl_t *impl = client->ssl;
+    if (!impl) return -1;
+
+    int rc = SSL_accept(impl->ssl);
+    switch (SSL_get_error(impl->ssl, rc)) {
+    case SSL_ERROR_NONE:
+        // connection completed
+        return start_ssl_connection_up( client );
+
+    case SSL_ERROR_WANT_READ:
+        printf("  need read...\n");
+        client->status |= PN_SEL_RD;
+        break;
+    case SSL_ERROR_WANT_WRITE:
+        printf("  need write...\n");
+        client->status |= PN_SEL_WR;
+        break;
+    default:
+        fprintf(stderr, "SSL_accept() failure\n");
+        return -1;
+    }
+    client->io_handler = handle_ssl_accept;
+    return 0;
+}
+
+
+/* STATE: ssl_connection_up
+ *
+ * The SSL connection is up and data is passing!
+ */
+int start_ssl_connection_up( pn_connector_t *c )
+{
+    printf("ssl_connection_up\n");
+    c->io_handler = handle_ssl_connection_up;
+    c->status |= PN_SEL_RD;
+    return 0;
+}
+
+
+int handle_ssl_connection_up( pn_connector_t *c )
+{
+    int rc;
+    int ssl_err;
+    int read_blocked = 0;
+    int write_blocked = 0;
+    int need_read = 0;
+    int need_write = 0;
+    int input_space;
+    pn_connector_ssl_impl_t *impl = c->ssl;
+    assert(impl);
+
+    printf("handle_ssl_connection_up\n");
+
+    c->status &= ~(PN_SEL_RD | PN_SEL_WR);
+
+    do {
+        input_space = PN_CONNECTOR_IO_BUF_SIZE - c->input_size;
+        if (!read_blocked && input_space > 0) {
+            rc = SSL_read(impl->ssl, &c->input[c->input_size], input_space);
+            printf("read %d possible bytes: actual = %d\n", input_space, rc);
+            ssl_err = SSL_get_error( impl->ssl, rc );
+            if (ssl_err == SSL_ERROR_NONE) {
+                c->input_size += rc;
+                printf("... read bytes now =%d\n", (int)c->input_size);
+            } else if (ssl_err == SSL_ERROR_WANT_READ) {
+                // socket read blocked
+                printf("need read\n");
+                read_blocked = 1;
+                need_read = 1;
+            } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
+                printf("need write\n");
+                read_blocked = 1;
+                write_blocked = 1;
+                need_write = 1;
+            } else {
+                if (ssl_err == SSL_ERROR_ZERO_RETURN) {
+                    /* remote shutdown */
+                    printf("zero return (read)\n");
+                } else {
+                    perror("Unexpected SSL read failure, errno:");
+                    printf("- SSL read status: %d\n", ssl_err);
+                }
+                return start_ssl_shutdown(c);
+            }
+        }
+
+        // we need to re-call SSL_read when the receive buffer is drained (do not need to wait for I/O!)
+        if (!read_blocked && SSL_pending(impl->ssl) && PN_CONNECTOR_IO_BUF_SIZE == c->input_size) {
+            printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  >>>>> READ STALLED <<<<<< !!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+            impl->read_stalled = true;
+        }
+
+        if (!write_blocked && c->output_size > 0) {
+
+            rc = SSL_write( impl->ssl, c->output, c->output_size );
+            ssl_err = SSL_get_error( impl->ssl, rc );
+            if (ssl_err == SSL_ERROR_NONE) {
+                c->output_size -= rc;
+                if (c->output_size > 0)
+                    memmove(c->output, c->output + rc, c->output_size);
+            } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
+                /* We would have blocked */
+                printf("need write\n");
+                write_blocked = 1;
+                need_write = 1;
+            } else if (ssl_err == SSL_ERROR_WANT_READ) {
+                printf("need read\n");
+                read_blocked = 1;
+                write_blocked = 1;
+                need_read = 1;
+            } else {
+                if (ssl_err == SSL_ERROR_ZERO_RETURN)
+                    printf("zero return (write)\n");
+                else {
+                    perror("Unexpected SSL_write failure, errno:");
+                    printf("- SSL write status: %d\n", ssl_err);
+                }
+                return start_ssl_shutdown(c);
+            }
+        }
+
+    } while ((!read_blocked && c->input_size < PN_CONNECTOR_IO_BUF_SIZE) ||
+             (!write_blocked && c->output_size));
+
+    if (need_read) c->status |= PN_SEL_RD;
+    if (need_write) c->status |= PN_SEL_WR;
+
+    return 0;
+}
+
+
+/* STATE: clear_connected
+ *
+ * The peer has connected without SSL (in the clear).  Use the default I/O handler
+ */
+static int start_clear_connected( pn_connector_t *c )
+{
+    pn_connector_free_ssl( c );
+    c->io_handler = pn_io_handler;
+    return 0;
+}
+
+
+/* STATE: ssl_shutdown
+ *
+ * Shutting down the SSL connection.
+ */
+static int start_ssl_shutdown( pn_connector_t *c )
+{
+    return handle_ssl_shutdown( c );
+}
+
+static int handle_ssl_shutdown( pn_connector_t *c )
+{
+    int rc;
+    pn_connector_ssl_impl_t *impl = c->ssl;
+    if (!impl) return -1;
+
+    printf("handle_ssl_shutdown...\n");
+
+    do {
+        rc = SSL_shutdown( impl->ssl );
+    } while (rc == 0);
+
+    switch (SSL_get_error( impl->ssl, rc )) {
+    case SSL_ERROR_WANT_READ:
+        printf("  need read...\n");
+        c->status |= PN_SEL_RD;
+        break;
+    case SSL_ERROR_WANT_WRITE:
+        printf("  need write...\n");
+        c->status |= PN_SEL_WR;
+        break;
+    default: // whatever- consider us closed
+    case SSL_ERROR_NONE:
+        // shutdown completed
+        pn_connector_close( c );
+        return 0;
+    }
+    c->io_handler = handle_ssl_shutdown;
+    return 0;
+}
+
+
+
+

Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
    (empty)

Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
    (empty)

Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h?rev=1371798&view=auto
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h (added)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h Fri Aug 10 18:15:10 2012
@@ -0,0 +1,75 @@
+#ifndef PROTON_SRC_DRIVERS_SSL_H
+#define PROTON_SRC_DRIVERS_SSL_H 1
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#define _POSIX_C_SOURCE 1
+
+/** @file
+ * Internal API for SSL/TLS support in the Driver Layer.
+ *
+ * Generic API to abstract the implementation of SSL/TLS from the Driver codebase.
+ *
+ */
+
+
+/** Configure SSL/TLS on a connector that has just been accepted on the given listener.
+ *
+ * @param[in,out] l the listener that has accepted the connnector c.
+ * @param[in,out] c the connector that will be configured for SSL/TLS (client mode).
+ * @return 0 on success, else an error code if SSL/TLS cannot be configured.
+ */
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c);
+
+
+/** Start the SSL/TLS shutdown handshake.
+ *
+ * The SSL/TLS shutdown involves a protocol handshake.  This call will initiate the
+ * shutdown process, which may not complete on return from this function.  Once the
+ * handshake is completed, the connector will be closed and pn_connector_closed() will
+ * return TRUE.
+ *
+ * @param[in,out] c the connector to shutdown.
+ */
+void pn_connector_shutdown_ssl( pn_connector_t *c);
+
+
+/** Release any SSL/TLS related resources used by the listener.
+ *
+ * @param[in,out] l the listener to clean up.
+ */
+void pn_listener_free_ssl( pn_listener_t *l);
+
+
+/** Release any SSL/TLS related resources used by the connector.
+ *
+ * @param[in,out] c the connector to clean up.
+ */
+void pn_connector_free_ssl( pn_connector_t *c);
+
+/** Check if the SSL/TLS layer has data ready for reading or writing
+ *
+ * @param[in] d the driver
+ * @return 0 if no data ready, else !0
+ */
+int pn_driver_ssl_data_ready( pn_driver_t *d );
+
+#endif /* ssl.h */

Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c Fri Aug 10 18:15:10 2012
@@ -22,6 +22,7 @@
 #define _POSIX_C_SOURCE 1
 
 #include <proton/driver.h>
+#include "ssl.h"
 
 
 /** @file
@@ -65,3 +66,29 @@ int pn_connector_ssl_authenticate_peer(p
 {
     return -1;
 }
+
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c)
+{
+    return 0;  // support routine - always succeed.
+}
+
+void pn_connector_shutdown_ssl( pn_connector_t *c)
+{
+    // since there's no SSL/TLS, we just close the connector
+    pn_connector_close( c );
+}
+
+
+void pn_listener_free_ssl( pn_listener_t * )
+{
+}
+
+
+void pn_connector_free_ssl( pn_connector_t * )
+{
+}
+
+int pn_driver_ssl_data_ready( pn_driver_t * )
+{
+    return 0;
+}

Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org