Remove refcounting, but note whether or not the CA file has been loaded.
authorDan Winship <danw@src.gnome.org>
Tue, 23 Sep 2003 19:35:44 +0000 (19:35 +0000)
committerDan Winship <danw@src.gnome.org>
Tue, 23 Sep 2003 19:35:44 +0000 (19:35 +0000)
* libsoup/soup-gnutls.c (SoupGNUTLSCred): Remove refcounting, but
note whether or not the CA file has been loaded.
(SoupGNUTLSChannel): add a "hostname" field.
(verify_certificate): Remove the comment about not being able to
verify the hostname because of soup problems. Now it's because of
GNUTLS problems instead.
(soup_ssl_wrap_iochannel): Renamed from soup_ssl_get_iochannel,
and takes a hostname and a creds argument now.
(soup_ssl_get_client_credentials,
soup_ssl_get_server_credentials): Return client/server credentials
structures.
(soup_ssl_free_client_credentials,
soup_ssl_free_server_credentials): and free them.

* libsoup/soup-session.c (class_init, set_property, get_property):
add ssl_ca_file property
(get_host_for_message): when returning an SSL host for the first
time, create a client credentials structure for the session.
(run_queue): Pass the ssl creds to the new connection. Also fix an
unrelated bug that caused infinite loops on "bad hostname".

* libsoup/soup-server.c: Use GObject properties, including
ssl_cert_file and ssl_key_file properties.
(soup_server_new): Remove "protocol" argument; if the cert file
and key file properties were set, create a server credential
structure from them and pass that to soup_socket_server_new.

* libsoup/soup-connection.c (SoupConnectionPrivate): Rename
dest_uri to origin_uri to match RFC 2616 terminology. Add an
"ssl_creds" field.
(class_init, set_property, get_property): add SSL_CREDS property
(soup_connection_connect_async, soup_connection_connect_sync):
Pass ssl_creds to soup_socket_client_new calls.

* libsoup/soup-socket.c: Use GObject properties, including an
ssl_creds property
(soup_socket_set_flags): Gone (replaced with boolean properties)
(soup_socket_new): Make this take a list of properties
(listen_watch): copy ssl creds from listener to new socket
(soup_socket_start_ssl): Pass remote hostname and socket creds
structure to soup_ssl_wrap_iochannel.
(soup_socket_client_new_async, soup_socket_client_new_sync,
soup_socket_server_new): Replace the SSL boolean with an ssl_creds
structure.

* libsoup/soup-misc.c (soup_set_ssl_ca_file,
soup_set_ssl_cert_files, soup_get_ssl_ca_file,
soup_get_ssl_cert_files): Gone. SSL state is now per-session or
per-server.

* tests/get.c: add a "-c CAfile" argument, for loading a CA
certificate file to validate https connections against

* tests/simple-httpd.c: Add "-c certfile" and "-k keyfile"
arguments for loading an SSL server certificate. Only start an SSL
server if those arguments were used.

* tests/test-cert.pem:
* tests/test-key.pem: SSL certificate for testing simple-httpd

* tests/revserver.c: Update for API changes
* tests/simple-proxy.c: Likewise

20 files changed:
ChangeLog
libsoup/soup-connection.c
libsoup/soup-connection.h
libsoup/soup-gnutls.c
libsoup/soup-misc.c
libsoup/soup-misc.h
libsoup/soup-server.c
libsoup/soup-server.h
libsoup/soup-session.c
libsoup/soup-session.h
libsoup/soup-socket.c
libsoup/soup-socket.h
libsoup/soup-ssl.h
tests/Makefile.am
tests/get.c
tests/revserver.c
tests/simple-httpd.c
tests/simple-proxy.c
tests/test-cert.pem [new file with mode: 0644]
tests/test-key.pem [new file with mode: 0644]

index 0848ad4..9462906 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,68 @@
+2003-09-23  Dan Winship  <danw@ximian.com>
+
+       * libsoup/soup-gnutls.c (SoupGNUTLSCred): Remove refcounting, but
+       note whether or not the CA file has been loaded.
+       (SoupGNUTLSChannel): add a "hostname" field.
+       (verify_certificate): Remove the comment about not being able to
+       verify the hostname because of soup problems. Now it's because of
+       GNUTLS problems instead.
+       (soup_ssl_wrap_iochannel): Renamed from soup_ssl_get_iochannel,
+       and takes a hostname and a creds argument now.
+       (soup_ssl_get_client_credentials,
+       soup_ssl_get_server_credentials): Return client/server credentials
+       structures.
+       (soup_ssl_free_client_credentials,
+       soup_ssl_free_server_credentials): and free them.
+
+       * libsoup/soup-session.c (class_init, set_property, get_property):
+       add ssl_ca_file property
+       (get_host_for_message): when returning an SSL host for the first
+       time, create a client credentials structure for the session.
+       (run_queue): Pass the ssl creds to the new connection. Also fix an
+       unrelated bug that caused infinite loops on "bad hostname".
+
+       * libsoup/soup-server.c: Use GObject properties, including
+       ssl_cert_file and ssl_key_file properties.
+       (soup_server_new): Remove "protocol" argument; if the cert file
+       and key file properties were set, create a server credential
+       structure from them and pass that to soup_socket_server_new.
+
+       * libsoup/soup-connection.c (SoupConnectionPrivate): Rename
+       dest_uri to origin_uri to match RFC 2616 terminology. Add an
+       "ssl_creds" field.
+       (class_init, set_property, get_property): add SSL_CREDS property
+       (soup_connection_connect_async, soup_connection_connect_sync):
+       Pass ssl_creds to soup_socket_client_new calls.
+
+       * libsoup/soup-socket.c: Use GObject properties, including an
+       ssl_creds property
+       (soup_socket_set_flags): Gone (replaced with boolean properties)
+       (soup_socket_new): Make this take a list of properties
+       (listen_watch): copy ssl creds from listener to new socket
+       (soup_socket_start_ssl): Pass remote hostname and socket creds
+       structure to soup_ssl_wrap_iochannel.
+       (soup_socket_client_new_async, soup_socket_client_new_sync,
+       soup_socket_server_new): Replace the SSL boolean with an ssl_creds
+       structure.
+
+       * libsoup/soup-misc.c (soup_set_ssl_ca_file,
+       soup_set_ssl_cert_files, soup_get_ssl_ca_file,
+       soup_get_ssl_cert_files): Gone. SSL state is now per-session or
+       per-server.
+
+       * tests/get.c: add a "-c CAfile" argument, for loading a CA
+       certificate file to validate https connections against
+
+       * tests/simple-httpd.c: Add "-c certfile" and "-k keyfile"
+       arguments for loading an SSL server certificate. Only start an SSL
+       server if those arguments were used.
+
+       * tests/test-cert.pem: 
+       * tests/test-key.pem: SSL certificate for testing simple-httpd
+
+       * tests/revserver.c: Update for API changes
+       * tests/simple-proxy.c: Likewise
+
 2003-09-22  Dan Winship  <danw@ximian.com>
 
        * libsoup/soup-message-io.c: Move RESPONSE_BLOCK_SIZE #define here
index f6c2acb..93d6a91 100644 (file)
@@ -21,6 +21,7 @@
 #include <netinet/tcp.h>
 #include <netinet/in.h>
 
+#include "soup-address.h"
 #include "soup-connection.h"
 #include "soup-marshal.h"
 #include "soup-message.h"
 
 struct SoupConnectionPrivate {
        SoupSocket  *socket;
-       SoupUri     *proxy_uri, *dest_uri;
-       time_t       last_used;
+
+       /* proxy_uri is the URI of the proxy server we are connected
+        * to, if any. origin_uri is the URI of the origin server.
+        * conn_uri is the uri of the host we are actually directly
+        * connected to, which will be proxy_uri if there's a proxy
+        * and origin_uri if not.
+        */
+       SoupUri     *proxy_uri, *origin_uri, *conn_uri;
+       gpointer     ssl_creds;
 
        SoupMessage *cur_req;
+       time_t       last_used;
 };
 
 #define PARENT_TYPE G_TYPE_OBJECT
@@ -53,8 +62,9 @@ static guint signals[LAST_SIGNAL] = { 0 };
 enum {
   PROP_0,
 
-  PROP_DEST_URI,
+  PROP_ORIGIN_URI,
   PROP_PROXY_URI,
+  PROP_SSL_CREDS,
 
   LAST_PROP
 };
@@ -82,8 +92,8 @@ finalize (GObject *object)
 
        if (conn->priv->proxy_uri)
                soup_uri_free (conn->priv->proxy_uri);
-       if (conn->priv->dest_uri)
-               soup_uri_free (conn->priv->dest_uri);
+       if (conn->priv->origin_uri)
+               soup_uri_free (conn->priv->origin_uri);
 
        g_free (conn->priv);
 
@@ -166,10 +176,10 @@ class_init (GObjectClass *object_class)
 
        /* properties */
        g_object_class_install_property (
-               object_class, PROP_DEST_URI,
-               g_param_spec_pointer (SOUP_CONNECTION_DEST_URI,
-                                     "Destination URI",
-                                     "The HTTP destination server to use for this connection",
+               object_class, PROP_ORIGIN_URI,
+               g_param_spec_pointer (SOUP_CONNECTION_ORIGIN_URI,
+                                     "Origin URI",
+                                     "The HTTP origin server to use for this connection",
                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
        g_object_class_install_property (
                object_class, PROP_PROXY_URI,
@@ -177,6 +187,12 @@ class_init (GObjectClass *object_class)
                                      "Proxy URI",
                                      "The HTTP Proxy to use for this connection",
                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_SSL_CREDS,
+               g_param_spec_pointer (SOUP_CONNECTION_SSL_CREDENTIALS,
+                                     "SSL credentials",
+                                     "Opaque SSL credentials for this connection",
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
@@ -188,10 +204,11 @@ SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
  * @...:
  *
  * Creates an HTTP connection. You must set at least one of
- * %SOUP_CONNECTION_DEST_URI or %SOUP_CONNECTION_PROXY_URI. If you set a
- * destination URI but no proxy URI, this will be a direct connection. If
- * you set a proxy URI and an https destination URI, this will be a tunnel.
- * Otherwise it will be an http proxy connection.
+ * %SOUP_CONNECTION_ORIGIN_URI or %SOUP_CONNECTION_PROXY_URI. If you
+ * set an origin server URI but no proxy URI, this will be a direct
+ * connection. If you set a proxy URI and an https origin server URI,
+ * this will be a tunnel. Otherwise it will be an http proxy
+ * connection.
  *
  * You must call soup_connection_connect_async() or
  * soup_connection_connect_sync() to connect it after creating it.
@@ -220,13 +237,22 @@ set_property (GObject *object, guint prop_id,
        gpointer pval;
 
        switch (prop_id) {
-       case PROP_DEST_URI:
+       case PROP_ORIGIN_URI:
                pval = g_value_get_pointer (value);
-               conn->priv->dest_uri = pval ? soup_uri_copy (pval) : NULL;
+               conn->priv->origin_uri = pval ? soup_uri_copy (pval) : NULL;
+               if (!conn->priv->proxy_uri)
+                       conn->priv->conn_uri = conn->priv->origin_uri;
                break;
        case PROP_PROXY_URI:
                pval = g_value_get_pointer (value);
                conn->priv->proxy_uri = pval ? soup_uri_copy (pval) : NULL;
+               if (conn->priv->proxy_uri)
+                       conn->priv->conn_uri = conn->priv->proxy_uri;
+               else
+                       conn->priv->conn_uri = conn->priv->origin_uri;
+               break;
+       case PROP_SSL_CREDS:
+               conn->priv->ssl_creds = g_value_get_pointer (value);
                break;
        default:
                break;
@@ -240,15 +266,18 @@ get_property (GObject *object, guint prop_id,
        SoupConnection *conn = SOUP_CONNECTION (object);
 
        switch (prop_id) {
-       case PROP_DEST_URI:
-               g_value_set_pointer (value, conn->priv->dest_uri ?
-                                    soup_uri_copy (conn->priv->dest_uri) :
+       case PROP_ORIGIN_URI:
+               g_value_set_pointer (value, conn->priv->origin_uri ?
+                                    soup_uri_copy (conn->priv->origin_uri) :
                                     NULL);
                break;
        case PROP_PROXY_URI:
                g_value_set_pointer (value, conn->priv->proxy_uri ?
                                     soup_uri_copy (conn->priv->proxy_uri) :
                                     NULL);
+       case PROP_SSL_CREDS:
+               g_value_set_pointer (value, conn->priv->ssl_creds);
+               break;
        default:
                break;
        }
@@ -298,12 +327,15 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
                return;
        }
 
+       if (conn->priv->conn_uri->protocol == SOUP_PROTOCOL_HTTPS)
+               soup_socket_start_ssl (sock);
+
        /* See if we need to tunnel */
-       if (conn->priv->proxy_uri && conn->priv->dest_uri) {
+       if (conn->priv->proxy_uri && conn->priv->origin_uri) {
                SoupMessage *connect_msg;
 
                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
-                                                        conn->priv->dest_uri);
+                                                        conn->priv->origin_uri);
                g_signal_connect (connect_msg, "finished",
                                  G_CALLBACK (tunnel_connect_finished), conn);
 
@@ -328,8 +360,6 @@ soup_connection_connect_async (SoupConnection *conn,
                               SoupConnectionCallback callback,
                               gpointer user_data)
 {
-       const SoupUri *uri;
-
        g_return_if_fail (SOUP_IS_CONNECTION (conn));
        g_return_if_fail (conn->priv->socket == NULL);
 
@@ -338,14 +368,10 @@ soup_connection_connect_async (SoupConnection *conn,
                                          G_CALLBACK (callback), user_data);
        }
 
-       if (conn->priv->proxy_uri)
-               uri = conn->priv->proxy_uri;
-       else
-               uri = conn->priv->dest_uri;
-
        conn->priv->socket =
-               soup_socket_client_new_async (uri->host, uri->port,
-                                             uri->protocol == SOUP_PROTOCOL_HTTPS,
+               soup_socket_client_new_async (conn->priv->conn_uri->host,
+                                             conn->priv->conn_uri->port,
+                                             conn->priv->ssl_creds,
                                              socket_connect_result, conn);
        g_signal_connect (conn->priv->socket, "disconnected",
                          G_CALLBACK (socket_disconnected), conn);
@@ -362,36 +388,36 @@ soup_connection_connect_async (SoupConnection *conn,
 guint
 soup_connection_connect_sync (SoupConnection *conn)
 {
-       const SoupUri *uri;
        guint status;
 
        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
        g_return_val_if_fail (conn->priv->socket == NULL, SOUP_STATUS_MALFORMED);
 
-       if (conn->priv->proxy_uri)
-               uri = conn->priv->proxy_uri;
-       else
-               uri = conn->priv->dest_uri;
-
        conn->priv->socket =
-               soup_socket_client_new_sync (uri->host, uri->port,
-                                            uri->protocol == SOUP_PROTOCOL_HTTPS,
+               soup_socket_client_new_sync (conn->priv->conn_uri->host,
+                                            conn->priv->conn_uri->port,
+                                            conn->priv->ssl_creds,
                                             &status);
 
-       if (SOUP_STATUS_IS_SUCCESSFUL (status) &&
-           conn->priv->proxy_uri && conn->priv->dest_uri) {
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status))
+               goto fail;
+
+       if (conn->priv->conn_uri->protocol == SOUP_PROTOCOL_HTTPS)
+               soup_socket_start_ssl (conn->priv->socket);
+
+       if (conn->priv->proxy_uri && conn->priv->origin_uri) {
                SoupMessage *connect_msg;
 
                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
-                                                        conn->priv->dest_uri);
+                                                        conn->priv->origin_uri);
                soup_connection_send_request (conn, connect_msg);
                status = connect_msg->status_code;
                g_object_unref (connect_msg);
        }
 
        if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
-               if (conn->priv->socket)
-                       g_object_unref (conn->priv->socket);
+       fail:
+               g_object_unref (conn->priv->socket);
                conn->priv->socket = NULL;
        }
 
index f40287c..d18ddbe 100644 (file)
@@ -46,8 +46,9 @@ typedef struct {
 GType soup_connection_get_type (void);
 
 
-#define SOUP_CONNECTION_DEST_URI "dest-uri"
-#define SOUP_CONNECTION_PROXY_URI "proxy-uri"
+#define SOUP_CONNECTION_ORIGIN_URI      "origin-uri"
+#define SOUP_CONNECTION_PROXY_URI       "proxy-uri"
+#define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
 
 SoupConnection *soup_connection_new            (const char       *propname1,
                                                ...);
index 3f751ef..30b5ca8 100644 (file)
 
 #include <gnutls/gnutls.h>
 
-#include "soup-misc.h"
 #include "soup-ssl.h"
+#include "soup-misc.h"
 
 #define DH_BITS 1024
 
 typedef struct {
        gnutls_certificate_credentials cred;
-       guint ref_count;
+       gboolean have_ca_file;
 } SoupGNUTLSCred;
 
-static void
-soup_gnutls_cred_ref (SoupGNUTLSCred *cred)
-{
-       cred->ref_count++;
-}
-
-static void
-soup_gnutls_cred_unref (SoupGNUTLSCred *cred)
-{
-       cred->ref_count--;
-       if (!cred->ref_count) {
-               gnutls_certificate_free_credentials (cred->cred);
-               g_free (cred);
-       }
-}
-
-static SoupGNUTLSCred *client_cred = NULL;
-static char *ca_file = NULL;
-static SoupGNUTLSCred *server_cred = NULL;
-
 typedef struct {
        GIOChannel channel;
-       gint fd;
+       int fd;
        GIOChannel *real_sock;
        gnutls_session session;
        SoupGNUTLSCred *cred;
+       char *hostname;
        gboolean established;
        SoupSSLType type;
 } SoupGNUTLSChannel;
 
 static gboolean
-verify_certificate (gnutls_session session, const charhostname)
+verify_certificate (gnutls_session session, const char *hostname)
 {
        int status;
 
-       if (!soup_get_ssl_ca_file ())
-               return TRUE;
-
        status = gnutls_certificate_verify_peers (session);
 
        if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) {
@@ -106,11 +84,6 @@ verify_certificate (gnutls_session session, const char* hostname)
                        return FALSE;
                }
 #if 0
-                /* Due to the Soup design, we don't have enough
-                * information to check the certificate vs. the
-                * hostname at this point.  This should really be
-                * fixed, but I don't think we intend to keep Soup
-                * around long enough to make it worthwhile. */
                if (!gnutls_x509_check_certificates_hostname(
                            &cert_list[0], hostname))
                {
@@ -141,13 +114,15 @@ do_handshake (SoupGNUTLSChannel *chan, GError **err)
                return G_IO_STATUS_ERROR;
        }
 
-       if (chan->type == SOUP_SSL_TYPE_CLIENT)
-               if (!verify_certificate (chan->session, NULL)) {
+       if (chan->type == SOUP_SSL_TYPE_CLIENT &&
+           chan->cred->have_ca_file) {
+               if (!verify_certificate (chan->session, chan->hostname)) {
                        g_set_error (err, G_IO_CHANNEL_ERROR,
                                     G_IO_CHANNEL_ERROR_FAILED,
                                     "Unable to verify certificate");
                        return G_IO_STATUS_ERROR;
                }
+       }
 
        return G_IO_STATUS_NORMAL;
 }
@@ -291,7 +266,6 @@ soup_gnutls_free (GIOChannel *channel)
        SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel;
        g_io_channel_unref (chan->real_sock);
        gnutls_deinit (chan->session);
-       soup_gnutls_cred_unref (chan->cred);
        g_free (chan);
 }
 
@@ -357,86 +331,19 @@ init_dh_params (void)
        return FALSE;
 }
 
-static SoupGNUTLSCred *
-get_credentials (SoupSSLType type)
-{
-       gnutls_certificate_credentials cred;
-       SoupGNUTLSCred *scred;
-
-       gnutls_certificate_allocate_credentials (&cred);
-
-       if (type == SOUP_SSL_TYPE_CLIENT) {
-               if (soup_get_ssl_ca_file ())
-                       if (gnutls_certificate_set_x509_trust_file (
-                                   cred, soup_get_ssl_ca_file (),
-                                   GNUTLS_X509_FMT_PEM) < 0)
-                       {
-                               g_warning ("Failed to set SSL trust file "
-                                          "(%s).", soup_get_ssl_ca_file ());
-                               goto THROW_CREATE_ERROR;
-                       }
-       } else {
-               const char *cert_file, *key_file;
-
-               soup_get_ssl_cert_files (&cert_file, &key_file);
-
-               if (cert_file) {
-                       if (!key_file) {
-                               g_warning ("SSL certificate file specified "
-                                          "without key file.");
-                               goto THROW_CREATE_ERROR;
-                       }
-
-                       if (gnutls_certificate_set_x509_key_file (
-                                   cred, cert_file, key_file,
-                                   GNUTLS_X509_FMT_PEM) != 0)
-                       {
-                               g_warning ("Failed to set SSL certificate "
-                                          "and key files (%s, %s).",
-                                          cert_file, key_file);
-                               goto THROW_CREATE_ERROR;
-                       }
-               } else if (key_file) {
-                       g_warning ("SSL key file specified without "
-                                  "certificate file.");
-                       goto THROW_CREATE_ERROR;
-               }
-       
-               if (!dh_params)
-                       if (!init_dh_params ())
-                               goto THROW_CREATE_ERROR;
-
-               gnutls_certificate_set_dh_params (cred, dh_params);
-       }
-
-       scred = g_new0 (SoupGNUTLSCred, 1);
-       scred->cred = cred;
-       scred->ref_count = 1;
-
-       return scred;
-
-    THROW_CREATE_ERROR:
-       gnutls_certificate_free_credentials (cred);
-       return NULL;
-}
-
 GIOChannel *
-soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type)
+soup_ssl_wrap_iochannel (GIOChannel *sock, SoupSSLType type,
+                        const char *hostname, gpointer cred_pointer)
 {
-       static gboolean initialized = FALSE;
        SoupGNUTLSChannel *chan = NULL;
        GIOChannel *gchan = NULL;
        gnutls_session session = NULL;
-       SoupGNUTLSCred *cred;
+       SoupGNUTLSCred *cred = cred_pointer;
        int sockfd;
        int ret;
 
        g_return_val_if_fail (sock != NULL, NULL);
-
-       if (!initialized) {
-               gnutls_global_init ();
-               initialized = TRUE;
-       }
+       g_return_val_if_fail (cred_pointer != NULL, NULL);
 
        sockfd = g_io_channel_unix_get_fd (sock);
        if (!sockfd) {
@@ -446,38 +353,8 @@ soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type)
 
        chan = g_new0 (SoupGNUTLSChannel, 1);
 
-       if (type == SOUP_SSL_TYPE_CLIENT) {
-               const char *new_ca_file = soup_get_ssl_ca_file ();
-
-               if ((new_ca_file && !ca_file) ||
-                   (ca_file && !new_ca_file) ||
-                   (ca_file && strcmp (ca_file, new_ca_file)))
-               {
-                       if (client_cred)
-                               soup_gnutls_cred_unref (client_cred);
-                       client_cred = NULL;
-                       g_free (ca_file);
-                       ca_file = g_strdup (new_ca_file);
-               }
-
-               if (!client_cred)
-                       client_cred = get_credentials (type);
-               if (!client_cred)
-                       goto THROW_CREATE_ERROR;
-
-               cred = client_cred;
-
-               ret = gnutls_init (&session, GNUTLS_CLIENT);
-       } else {
-               if (!server_cred)
-                       server_cred = get_credentials (type);
-               if (!server_cred)
-                       goto THROW_CREATE_ERROR;
-
-               cred = server_cred;
-
-               ret = gnutls_init (&session, GNUTLS_SERVER);
-       }
+       ret = gnutls_init (&session,
+                          (type == SOUP_SSL_TYPE_CLIENT) ? GNUTLS_CLIENT : GNUTLS_SERVER);
        if (ret)
                goto THROW_CREATE_ERROR;
 
@@ -487,14 +364,9 @@ soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type)
        if (gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE,
                                    cred->cred) != 0)
                goto THROW_CREATE_ERROR;
-       soup_gnutls_cred_ref (cred);
-
-       if (type == SOUP_SSL_TYPE_SERVER) {
-               gnutls_certificate_server_set_request (
-                       session, GNUTLS_CERT_REQUEST);
 
+       if (type == SOUP_SSL_TYPE_SERVER)
                gnutls_dh_set_prime_bits (session, DH_BITS);
-       }
 
        gnutls_transport_set_ptr (session, sockfd);
 
@@ -502,6 +374,7 @@ soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type)
        chan->real_sock = sock;
        chan->session = session;
        chan->cred = cred;
+       chan->hostname = g_strdup (hostname);
        chan->type = type;
        g_io_channel_ref (sock);
 
@@ -520,4 +393,78 @@ soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type)
        return NULL;
 }
 
+gpointer
+soup_ssl_get_client_credentials (const char *ca_file)
+{
+       SoupGNUTLSCred *cred;
+       int status;
+
+       gnutls_global_init ();
+
+       cred = g_new0 (SoupGNUTLSCred, 1);
+       gnutls_certificate_allocate_credentials (&cred->cred);
+
+       if (ca_file) {
+               cred->have_ca_file = TRUE;
+               status = gnutls_certificate_set_x509_trust_file (
+                       cred->cred, ca_file, GNUTLS_X509_FMT_PEM);
+               if (status < 0) {
+                       g_warning ("Failed to set SSL trust file (%s).",
+                                  ca_file);
+                       /* Since we set have_ca_file though, this just
+                        * means that no certs will validate, so we're
+                        * ok securitywise if we just return these
+                        * creds to the caller.
+                        */
+               }
+       }
+
+       return cred;
+}
+
+void
+soup_ssl_free_client_credentials (gpointer client_creds)
+{
+       SoupGNUTLSCred *cred = client_creds;
+
+       gnutls_certificate_free_credentials (cred->cred);
+       g_free (cred);
+}
+
+gpointer
+soup_ssl_get_server_credentials (const char *cert_file, const char *key_file)
+{
+       SoupGNUTLSCred *cred;
+
+       gnutls_global_init ();
+       if (!dh_params) {
+               if (!init_dh_params ())
+                       return NULL;
+       }
+
+       cred = g_new0 (SoupGNUTLSCred, 1);
+       gnutls_certificate_allocate_credentials (&cred->cred);
+
+       if (gnutls_certificate_set_x509_key_file (cred->cred,
+                                                 cert_file, key_file,
+                                                 GNUTLS_X509_FMT_PEM) != 0) {
+               g_warning ("Failed to set SSL certificate and key files "
+                          "(%s, %s).", cert_file, key_file);
+               soup_ssl_free_server_credentials (cred);
+               return NULL;
+       }
+
+       gnutls_certificate_set_dh_params (cred->cred, dh_params);
+       return cred;
+}
+
+void
+soup_ssl_free_server_credentials (gpointer server_creds)
+{
+       SoupGNUTLSCred *cred = server_creds;
+
+       gnutls_certificate_free_credentials (cred->cred);
+       g_free (cred);
+}
+
 #endif /* HAVE_GNUTLS_GNUTLS_H */
index 63b77f6..eb284dd 100644 (file)
@@ -312,73 +312,6 @@ soup_base64_decode (const char   *text,
        return ret; 
 }
 
-static char *ssl_ca_file   = NULL;
-static char *ssl_cert_file = NULL;
-static char *ssl_key_file  = NULL;
-
-/**
- * soup_set_ca_file:
- * @ca_file: the path to a CA file
- *
- * Specify a file containing CA certificates to be used to verify
- * peers.
- */
-void
-soup_set_ssl_ca_file (const char *ca_file)
-{
-       g_free (ssl_ca_file);
-
-       ssl_ca_file = g_strdup (ca_file);
-}
-
-/**
- * soup_set_ssl_cert_files
- * @cert_file: the file containing the SSL client certificate
- * @key_file: the file containing the SSL private key
- *
- * Specify a SSL client certificate to be used for client
- * authentication with the HTTP server
- */
-void
-soup_set_ssl_cert_files (const char *cert_file, const char *key_file)
-{
-       g_free (ssl_cert_file);
-       g_free (ssl_key_file);
-
-       ssl_cert_file = g_strdup (cert_file);
-       ssl_key_file  = g_strdup (key_file);
-}
-
-/**
- * soup_get_ca_file:
- *
- * Return value: A file containing CA certificates to be used to verify
- * peers.
- */
-const char *
-soup_get_ssl_ca_file (void)
-{
-       return ssl_ca_file;
-}
-
-/**
- * soup_get_ssl_cert_files
- * @cert_file: the file containing the SSL client certificate
- * @key_file: the file containing the SSL private key
- *
- * Specify a SSL client certificate to be used for client
- * authentication with the HTTP server
- */
-void
-soup_get_ssl_cert_files (const char **cert_file, const char **key_file)
-{
-       if (cert_file)
-               *cert_file = ssl_cert_file;
-
-       if (key_file)
-               *key_file = ssl_key_file;
-}
-
 typedef struct {
        gpointer instance;
        guint    real_id, self_id;
index 5855ddd..0a9afef 100644 (file)
@@ -8,17 +8,6 @@
 
 #include <glib-object.h>
 
-/* SSL setup routines */
-
-void               soup_set_ssl_ca_file      (const char   *ca_file);
-
-void               soup_set_ssl_cert_files   (const char   *cert_file, 
-                                             const char   *key_file);
-
-const char        *soup_get_ssl_ca_file      (void);
-void               soup_get_ssl_cert_files   (const char  **cert_file,
-                                             const char  **key_file);
-
 /* Base64 encoding/decoding */
 
 char              *soup_base64_encode        (const char   *text,
index b3b4475..452bf76 100644 (file)
 #include "soup-server-auth.h"
 #include "soup-server-message.h"
 #include "soup-socket.h"
+#include "soup-ssl.h"
 
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class;
 
 struct SoupServerPrivate {
-       SoupProtocol       proto;
+       SoupAddress       *interface;
        guint              port;
 
+       char              *ssl_cert_file, *ssl_key_file;
+       gpointer           ssl_creds;
+
        GMainLoop         *loop;
 
        SoupSocket        *listen_sock;
@@ -41,6 +45,22 @@ struct SoupServerPrivate {
        SoupServerHandler *default_handler;
 };
 
+enum {
+  PROP_0,
+
+  PROP_PORT,
+  PROP_INTERFACE,
+  PROP_SSL_CERT_FILE,
+  PROP_SSL_KEY_FILE,
+
+  LAST_PROP
+};
+
+static void set_property (GObject *object, guint prop_id,
+                         const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+                         GValue *value, GParamSpec *pspec);
+
 static void
 init (GObject *object)
 {
@@ -77,6 +97,14 @@ finalize (GObject *object)
 {
        SoupServer *server = SOUP_SERVER (object);
 
+       if (server->priv->interface)
+               g_object_unref (server->priv->interface);
+
+       g_free (server->priv->ssl_cert_file);
+       g_free (server->priv->ssl_key_file);
+       if (server->priv->ssl_creds)
+               soup_ssl_free_server_credentials (server->priv->ssl_creds);
+
        if (server->priv->listen_sock)
                g_object_unref (server->priv->listen_sock);
 
@@ -110,59 +138,137 @@ class_init (GObjectClass *object_class)
 
        /* virtual method override */
        object_class->finalize = finalize;
+       object_class->set_property = set_property;
+       object_class->get_property = get_property;
+
+       /* properties */
+       g_object_class_install_property (
+               object_class, PROP_PORT,
+               g_param_spec_uint (SOUP_SERVER_PORT,
+                                  "Port",
+                                  "Port to listen on",
+                                  0, 65536, 0,
+                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_INTERFACE,
+               g_param_spec_object (SOUP_SERVER_INTERFACE,
+                                    "Interface",
+                                    "Address of interface to listen on",
+                                    SOUP_TYPE_ADDRESS,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_SSL_CERT_FILE,
+               g_param_spec_string (SOUP_SERVER_SSL_CERT_FILE,
+                                     "SSL certificate file",
+                                     "File containing server SSL certificate",
+                                     NULL,
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_SSL_KEY_FILE,
+               g_param_spec_string (SOUP_SERVER_SSL_KEY_FILE,
+                                     "SSL key file",
+                                     "File containing server SSL key",
+                                     NULL,
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 SOUP_MAKE_TYPE (soup_server, SoupServer, class_init, init, PARENT_TYPE)
 
-
-static SoupServer *
-new_server (SoupAddress *address, SoupProtocol proto)
+static void
+set_property (GObject *object, guint prop_id,
+             const GValue *value, GParamSpec *pspec)
 {
-       SoupServer *server;
-       SoupSocket *sock = NULL;
-
-       g_return_val_if_fail (address, NULL);
+       SoupServer *server = SOUP_SERVER (object);
 
-       sock = soup_socket_server_new (address,
-                                      proto == SOUP_PROTOCOL_HTTPS,
-                                      NULL, NULL);
-       if (!sock)
-               return NULL;
-       address = soup_socket_get_local_address (sock);
+       switch (prop_id) {
+       case PROP_PORT:
+               server->priv->port = g_value_get_uint (value);
+               break;
+       case PROP_INTERFACE:
+               if (server->priv->interface)
+                       g_object_unref (server->priv->interface);
+               server->priv->interface = g_value_get_object (value);
+               if (server->priv->interface)
+                       g_object_ref (server->priv->interface);
+               break;
+       case PROP_SSL_CERT_FILE:
+               server->priv->ssl_cert_file =
+                       g_strdup (g_value_get_string (value));
+               break;
+       case PROP_SSL_KEY_FILE:
+               server->priv->ssl_key_file =
+                       g_strdup (g_value_get_string (value));
+               break;
+       default:
+               break;
+       }
+}
 
-       server = g_object_new (SOUP_TYPE_SERVER, NULL);
-       server->priv->port = soup_address_get_port (address);
-       server->priv->proto = proto;
-       server->priv->listen_sock = sock;
+static void
+get_property (GObject *object, guint prop_id,
+             GValue *value, GParamSpec *pspec)
+{
+       SoupServer *server = SOUP_SERVER (object);
 
-       return server;
+       switch (prop_id) {
+       case PROP_PORT:
+               g_value_set_uint (value, server->priv->port);
+               break;
+       case PROP_INTERFACE:
+               g_value_set_object (value, g_object_ref (server->priv->interface));
+               break;
+       case PROP_SSL_CERT_FILE:
+               g_value_set_string (value, g_strdup (server->priv->ssl_cert_file));
+               break;
+       case PROP_SSL_KEY_FILE:
+               g_value_set_string (value, g_strdup (server->priv->ssl_key_file));
+               break;
+       default:
+               break;
+       }
 }
 
 SoupServer *
-soup_server_new (SoupProtocol proto, guint port)
+soup_server_new (const char *optname1, ...)
 {
-       SoupAddress *address;
        SoupServer *server;
+       va_list ap;
 
-       address = soup_address_new_any (SOUP_ADDRESS_FAMILY_IPV4, port);
-       server = new_server (address, proto);
-       g_object_unref (address);
+       va_start (ap, optname1);
+       server = (SoupServer *)g_object_new_valist (SOUP_TYPE_SERVER,
+                                                   optname1, ap);
+       va_end (ap);
 
-       return server;
-}
+       if (!server)
+               return NULL;
+       if (!server->priv->interface) {
+               server->priv->interface =
+                       soup_address_new_any (SOUP_ADDRESS_FAMILY_IPV4,
+                                             server->priv->port);
+       }
 
-SoupServer *
-soup_server_new_with_host (const char *host, SoupProtocol proto, guint port)
-{
-       SoupAddress *address;
-       SoupServer *server;
+       if (server->priv->ssl_cert_file && server->priv->ssl_key_file) {
+               server->priv->ssl_creds = soup_ssl_get_server_credentials (
+                       server->priv->ssl_cert_file,
+                       server->priv->ssl_key_file);
+       }
 
-       address = soup_address_new (host, port);
-       if (!address)
+       server->priv->listen_sock =
+               soup_socket_server_new (server->priv->interface,
+                                       server->priv->ssl_creds,
+                                       NULL, NULL);
+       if (!server->priv->listen_sock) {
+               g_object_unref (server);
                return NULL;
+       }
 
-       server = new_server (address, proto);
-       g_object_unref (address);
+       /* Re-resolve the interface address, in particular in case
+        * the passed-in address had SOUP_ADDRESS_ANY_PORT.
+        */
+       g_object_unref (server->priv->interface);
+       server->priv->interface =
+               soup_socket_get_local_address (server->priv->listen_sock);
+       server->priv->port = soup_address_get_port (server->priv->interface);
 
        return server;
 }
@@ -180,9 +286,13 @@ soup_server_get_protocol (SoupServer *server)
 {
        g_return_val_if_fail (SOUP_IS_SERVER (server), 0);
 
-       return server->priv->proto;
+       if (server->priv->ssl_cert_file && server->priv->ssl_key_file)
+               return SOUP_PROTOCOL_HTTPS;
+       else
+               return SOUP_PROTOCOL_HTTP;
 }
 
+
 static void start_request (SoupServer *, SoupSocket *);
 
 static void
index bfef890..4c9adf6 100644 (file)
@@ -63,11 +63,13 @@ struct SoupServerHandler {
        gpointer                user_data;
 };
 
-SoupServer        *soup_server_new            (SoupProtocol           proto,
-                                              guint                  port);
-SoupServer        *soup_server_new_with_host  (const char            *host,
-                                              SoupProtocol           proto,
-                                              guint                  port);
+#define SOUP_SERVER_PORT          "port"
+#define SOUP_SERVER_INTERFACE     "interface"
+#define SOUP_SERVER_SSL_CERT_FILE "ssl-cert-file"
+#define SOUP_SERVER_SSL_KEY_FILE  "ssl-key-file"
+
+SoupServer        *soup_server_new            (const char            *optname1,
+                                              ...);
 
 SoupProtocol       soup_server_get_protocol   (SoupServer            *serv);
 guint              soup_server_get_port       (SoupServer            *serv);
index 2e0e978..abb756e 100644 (file)
@@ -19,6 +19,7 @@
 #include "soup-connection-ntlm.h"
 #include "soup-marshal.h"
 #include "soup-message-queue.h"
+#include "soup-ssl.h"
 #include "soup-uri.h"
 
 typedef struct {
@@ -37,6 +38,9 @@ struct SoupSessionPrivate {
        guint max_conns, max_conns_per_host;
        gboolean use_ntlm;
 
+       char *ssl_ca_file;
+       gpointer ssl_creds;
+
        SoupMessageQueue *queue;
 
        GHashTable *hosts; /* SoupUri -> SoupSessionHost */
@@ -73,6 +77,7 @@ enum {
   PROP_MAX_CONNS,
   PROP_MAX_CONNS_PER_HOST,
   PROP_USE_NTLM,
+  PROP_SSL_CA_FILE,
 
   LAST_PROP
 };
@@ -206,6 +211,13 @@ class_init (GObjectClass *object_class)
                                      "Whether or not to use NTLM authentication",
                                      FALSE,
                                      G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_SSL_CA_FILE,
+               g_param_spec_string (SOUP_SESSION_SSL_CA_FILE,
+                                     "SSL CA file",
+                                     "File containing SSL CA certificates",
+                                     NULL,
+                                     G_PARAM_READWRITE));
 }
 
 SOUP_MAKE_TYPE (soup_session, SoupSession, class_init, init, PARENT_TYPE)
@@ -255,6 +267,10 @@ set_property (GObject *object, guint prop_id,
        case PROP_USE_NTLM:
                session->priv->use_ntlm = g_value_get_boolean (value);
                break;
+       case PROP_SSL_CA_FILE:
+               g_free (session->priv->ssl_ca_file);
+               session->priv->ssl_ca_file = g_strdup (g_value_get_string (value));
+               break;
        default:
                break;
        }
@@ -281,6 +297,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_USE_NTLM:
                g_value_set_boolean (value, session->priv->use_ntlm);
                break;
+       case PROP_SSL_CA_FILE:
+               g_value_set_string (value, session->priv->ssl_ca_file);
+               break;
        default:
                break;
        }
@@ -324,6 +343,13 @@ get_host_for_message (SoupSession *session, SoupMessage *msg)
        host->root_uri = soup_uri_copy_root (source);
 
        g_hash_table_insert (session->priv->hosts, host->root_uri, host);
+
+       if (host->root_uri->protocol == SOUP_PROTOCOL_HTTPS &&
+           !session->priv->ssl_creds) {
+               session->priv->ssl_creds =
+                       soup_ssl_get_client_credentials (session->priv->ssl_ca_file);
+       }
+
        return host;
 }
 
@@ -792,6 +818,7 @@ run_queue (SoupSession *session, gboolean try_pruning)
                /* If the hostname is known to be bad, fail right away */
                if (host->error) {
                        soup_message_set_status (msg, host->error);
+                       msg->status = SOUP_MESSAGE_STATUS_FINISHED;
                        soup_message_finished (msg);
                }
 
@@ -830,8 +857,9 @@ run_queue (SoupSession *session, gboolean try_pruning)
                conn = g_object_new (
                        (session->priv->use_ntlm ?
                         SOUP_TYPE_CONNECTION_NTLM : SOUP_TYPE_CONNECTION),
-                       SOUP_CONNECTION_DEST_URI, host->root_uri,
+                       SOUP_CONNECTION_ORIGIN_URI, host->root_uri,
                        SOUP_CONNECTION_PROXY_URI, session->priv->proxy_uri,
+                       SOUP_CONNECTION_SSL_CREDENTIALS, session->priv->ssl_creds,
                        NULL);
                g_signal_connect (conn, "authenticate",
                                  G_CALLBACK (connection_authenticate),
index 1d35cdf..2f2d9e7 100644 (file)
@@ -43,6 +43,7 @@ GType soup_session_get_type (void);
 #define SOUP_SESSION_MAX_CONNS          "max-conns"
 #define SOUP_SESSION_MAX_CONNS_PER_HOST "max-conns-per-host"
 #define SOUP_SESSION_USE_NTLM           "use-ntlm"
+#define SOUP_SESSION_SSL_CA_FILE        "ssl-ca-file"
 
 SoupSession    *soup_session_new              (void);
 SoupSession    *soup_session_new_with_options (const char            *optname1,
index 8939ff2..1c1de7d 100644 (file)
@@ -40,30 +40,45 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+enum {
+       PROP_0,
+
+       PROP_NON_BLOCKING,
+       PROP_NODELAY,
+       PROP_REUSEADDR,
+       PROP_IS_SERVER,
+       PROP_SSL_CREDENTIALS,
+
+       LAST_PROP
+};
+
 struct SoupSocketPrivate {
        int sockfd;
        SoupAddress *local_addr, *remote_addr;
        GIOChannel *iochannel;
 
-       guint watch;
-       guint flags;
+       guint non_blocking:1;
+       guint nodelay:1;
+       guint reuseaddr:1;
+       guint is_server:1;
+       gpointer ssl_creds;
 
+       guint           watch;
        guint           read_tag, write_tag, error_tag;
        GByteArray     *read_buf;
 };
 
-#define SOUP_SOCKET_FLAG_SSL    (1<<8)
-
-#define SOUP_SOCKET_SET_FLAG(sock, flag) (sock)->priv->flags |= (flag)
-#define SOUP_SOCKET_CLEAR_FLAG(sock, flag) (sock)->priv->flags &= ~(flag)
-#define SOUP_SOCKET_CHECK_FLAG(sock, flag) ((sock)->priv->flags & (flag))
-
 #ifdef HAVE_IPV6
 #define soup_sockaddr_max sockaddr_in6
 #else
 #define soup_sockaddr_max sockaddr_in
 #endif
 
+static void set_property (GObject *object, guint prop_id,
+                         const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+                         GValue *value, GParamSpec *pspec);
+
 static void
 init (GObject *object)
 {
@@ -121,6 +136,8 @@ class_init (GObjectClass *object_class)
 
        /* virtual method override */
        object_class->finalize = finalize;
+       object_class->set_property = set_property;
+       object_class->get_property = get_property;
 
        /* signals */
        signals[CONNECT_RESULT] =
@@ -165,59 +182,145 @@ class_init (GObjectClass *object_class)
                              soup_marshal_NONE__OBJECT,
                              G_TYPE_NONE, 1,
                              SOUP_TYPE_SOCKET);
+
+       /* properties */
+       g_object_class_install_property (
+               object_class, PROP_NON_BLOCKING,
+               g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
+                                     "Non-blocking",
+                                     "Whether or not the socket uses non-blocking I/O",
+                                     TRUE,
+                                     G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_NODELAY,
+               g_param_spec_boolean (SOUP_SOCKET_FLAG_NODELAY,
+                                     "NODELAY",
+                                     "Whether or not the socket uses TCP NODELAY",
+                                     TRUE,
+                                     G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_REUSEADDR,
+               g_param_spec_boolean (SOUP_SOCKET_FLAG_REUSEADDR,
+                                     "REUSEADDR",
+                                     "Whether or not the socket uses the TCP REUSEADDR flag",
+                                     TRUE,
+                                     G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_IS_SERVER,
+               g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
+                                     "Server",
+                                     "Whether or not the socket is a server socket",
+                                     FALSE,
+                                     G_PARAM_READABLE));
+       g_object_class_install_property (
+               object_class, PROP_SSL_CREDENTIALS,
+               g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
+                                     "SSL credentials",
+                                     "SSL credential information, passed from the session to the SSL implementation",
+                                     G_PARAM_READWRITE));
 }
 
 SOUP_MAKE_TYPE (soup_socket, SoupSocket, class_init, init, PARENT_TYPE)
 
 
-/**
- * soup_socket_new:
- *
- * Return value: a new (disconnected) socket
- **/
-SoupSocket *
-soup_socket_new (void)
-{
-       return g_object_new (SOUP_TYPE_SOCKET, NULL);
-}
-
 static void
-update_fdflags (SoupSocket *sock, guint mask)
+update_fdflags (SoupSocket *sock)
 {
        int flags, opt;
 
-       if (mask & SOUP_SOCKET_FLAG_NONBLOCKING) {
-               flags = fcntl (sock->priv->sockfd, F_GETFL, 0);
-               g_return_if_fail (flags != -1);
+       if (!sock->priv->sockfd)
+               return;
 
-               if (sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING)
+       flags = fcntl (sock->priv->sockfd, F_GETFL, 0);
+       if (flags != -1) {
+               if (sock->priv->non_blocking)
                        flags |= O_NONBLOCK;
                else
                        flags &= ~O_NONBLOCK;
                fcntl (sock->priv->sockfd, F_SETFL, flags);
        }
-       if (mask & SOUP_SOCKET_FLAG_NODELAY) {
-               opt = (sock->priv->flags & SOUP_SOCKET_FLAG_NODELAY) != 0;
-               setsockopt (sock->priv->sockfd, IPPROTO_TCP,
-                           TCP_NODELAY, &opt, sizeof (opt));
+
+       opt = (sock->priv->nodelay != 0);
+       setsockopt (sock->priv->sockfd, IPPROTO_TCP,
+                   TCP_NODELAY, &opt, sizeof (opt));
+
+       opt = (sock->priv->reuseaddr != 0);
+       setsockopt (sock->priv->sockfd, SOL_SOCKET,
+                   SO_REUSEADDR, &opt, sizeof (opt));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+             const GValue *value, GParamSpec *pspec)
+{
+       SoupSocket *sock = SOUP_SOCKET (object);
+
+       switch (prop_id) {
+       case PROP_NON_BLOCKING:
+               sock->priv->non_blocking = g_value_get_boolean (value);
+               update_fdflags (sock);
+               break;
+       case PROP_NODELAY:
+               sock->priv->nodelay = g_value_get_boolean (value);
+               update_fdflags (sock);
+               break;
+       case PROP_REUSEADDR:
+               sock->priv->reuseaddr = g_value_get_boolean (value);
+               update_fdflags (sock);
+               break;
+       case PROP_SSL_CREDENTIALS:
+               sock->priv->ssl_creds = g_value_get_pointer (value);
+               break;
+       default:
+               break;
        }
-       if (mask & SOUP_SOCKET_FLAG_REUSEADDR) {
-               opt = (sock->priv->flags & SOUP_SOCKET_FLAG_REUSEADDR) != 0;
-               setsockopt (sock->priv->sockfd, SOL_SOCKET,
-                           SO_REUSEADDR, &opt, sizeof (opt));
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+             GValue *value, GParamSpec *pspec)
+{
+       SoupSocket *sock = SOUP_SOCKET (object);
+
+       switch (prop_id) {
+       case PROP_NON_BLOCKING:
+               g_value_set_boolean (value, sock->priv->non_blocking);
+               break;
+       case PROP_NODELAY:
+               g_value_set_boolean (value, sock->priv->nodelay);
+               break;
+       case PROP_REUSEADDR:
+               g_value_set_boolean (value, sock->priv->reuseaddr);
+               break;
+       case PROP_IS_SERVER:
+               g_value_set_boolean (value, sock->priv->is_server);
+               break;
+       case PROP_SSL_CREDENTIALS:
+               g_value_set_pointer (value, sock->priv->ssl_creds);
+               break;
+       default:
+               break;
        }
 }
 
-void
-soup_socket_set_flags (SoupSocket *sock, guint mask, guint flags)
+
+/**
+ * soup_socket_new:
+ *
+ * Return value: a new (disconnected) socket
+ **/
+SoupSocket *
+soup_socket_new (const char *optname1, ...)
 {
-       g_return_if_fail (SOUP_IS_SOCKET (sock));
+       SoupSocket *sock;
+       va_list ap;
 
-       sock->priv->flags |= mask & flags;
-       sock->priv->flags &= ~(mask & ~flags);
+       va_start (ap, optname1);
+       sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
+                                                 optname1, ap);
+       va_end (ap);
 
-       if (sock->priv->sockfd)
-               update_fdflags (sock, mask);
+       return sock;
 }
 
 static GIOChannel *
@@ -234,6 +337,18 @@ get_iochannel (SoupSocket *sock)
 }
 
 static gboolean
+idle_connect_result (gpointer user_data)
+{
+       SoupSocket *sock = user_data;
+
+       sock->priv->watch = 0;
+
+       g_signal_emit (sock, signals[CONNECT_RESULT], 0,
+                      sock->priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
+       return FALSE;
+}
+
+static gboolean
 connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
 {
        SoupSocket *sock = data;
@@ -253,29 +368,13 @@ connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        if (error)
                goto cant_connect;
 
-       if (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SSL))
-               soup_socket_start_ssl (sock);
-
-       g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_OK);
-       return FALSE;
+       return idle_connect_result (sock);
 
  cant_connect:
        g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_CANT_CONNECT);
        return FALSE;
 }
 
-static gboolean
-idle_connect_result (gpointer user_data)
-{
-       SoupSocket *sock = user_data;
-
-       sock->priv->watch = 0;
-
-       g_signal_emit (sock, signals[CONNECT_RESULT], 0,
-                      sock->priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
-       return FALSE;
-}
-
 static void
 got_address (SoupAddress *addr, guint status, gpointer user_data)
 {
@@ -315,17 +414,14 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
 {
        struct sockaddr *sa;
        int len, status;
-       gboolean sync;
 
        g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
-       g_return_val_if_fail (!SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
+       g_return_val_if_fail (!sock->priv->is_server, SOUP_STATUS_MALFORMED);
        g_return_val_if_fail (sock->priv->sockfd == -1, SOUP_STATUS_MALFORMED);
        g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
 
-       sync = !(sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING);
-
        sock->priv->remote_addr = g_object_ref (remote_addr);
-       if (sync) {
+       if (!sock->priv->non_blocking) {
                status = soup_address_resolve_sync (remote_addr);
                if (!SOUP_STATUS_IS_SUCCESSFUL (status))
                        return status;
@@ -333,7 +429,7 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
 
        sa = soup_address_get_sockaddr (sock->priv->remote_addr, &len);
        if (!sa) {
-               if (sync)
+               if (!sock->priv->non_blocking)
                        return SOUP_STATUS_CANT_RESOLVE;
 
                g_object_ref (sock);
@@ -346,7 +442,7 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
                g_free (sa);
                goto done;
        }
-       update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
+       update_fdflags (sock);
 
        status = connect (sock->priv->sockfd, sa, len);
        g_free (sa);
@@ -368,12 +464,12 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
        }
 
  done:
-       if (sync) {
-               return sock->priv->sockfd != -1 ?
-                       SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT;
-       } else {
+       if (sock->priv->non_blocking) {
                sock->priv->watch = g_idle_add (idle_connect_result, sock);
                return SOUP_STATUS_CONTINUE;
+       } else {
+               return sock->priv->sockfd != -1 ?
+                       SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT;
        }
 }
 
@@ -395,17 +491,17 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        if (sockfd == -1)
                return TRUE;
 
-       new = soup_socket_new ();
+       new = g_object_new (SOUP_TYPE_SOCKET, NULL);
        new->priv->sockfd = sockfd;
-       new->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
-                           SOUP_SOCKET_FLAG_NODELAY |
-                           SOUP_SOCKET_FLAG_SERVER |
-                           (sock->priv->flags & SOUP_SOCKET_FLAG_SSL));
-       update_fdflags (new, SOUP_SOCKET_FLAG_ALL);
+       new->priv->non_blocking = sock->priv->non_blocking;
+       new->priv->nodelay = sock->priv->nodelay;
+       new->priv->is_server = TRUE;
+       new->priv->ssl_creds = sock->priv->ssl_creds;
+       update_fdflags (new);
 
        new->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
 
-       if (SOUP_SOCKET_CHECK_FLAG (new, SOUP_SOCKET_FLAG_SSL))
+       if (new->priv->ssl_creds)
                soup_socket_start_ssl (new);
        else
                get_iochannel (new);
@@ -434,7 +530,7 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        int sa_len;
 
        g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
-       g_return_val_if_fail (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
+       g_return_val_if_fail (sock->priv->is_server, FALSE);
        g_return_val_if_fail (sock->priv->sockfd == -1, FALSE);
        g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
 
@@ -450,7 +546,7 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
        if (sock->priv->sockfd < 0)
                goto cant_listen;
-       update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
+       update_fdflags (sock);
 
        /* Bind */
        if (bind (sock->priv->sockfd, sa, sa_len) != 0)
@@ -487,11 +583,11 @@ soup_socket_start_ssl (SoupSocket *sock)
        GIOChannel *chan;
 
        chan = get_iochannel (sock);
-       sock->priv->iochannel = soup_ssl_get_iochannel (
-               sock->priv->iochannel,
-               SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER) ?
-               SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT);
-       SOUP_SOCKET_SET_FLAG (sock, SOUP_SOCKET_FLAG_SSL);
+       sock->priv->iochannel = soup_ssl_wrap_iochannel (
+               sock->priv->iochannel, sock->priv->is_server ?
+               SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
+               soup_address_get_name (sock->priv->remote_addr),
+               sock->priv->ssl_creds);
 }
        
 
@@ -499,7 +595,7 @@ soup_socket_start_ssl (SoupSocket *sock)
  * soup_socket_client_new_async:
  * @hostname: remote machine to connect to
  * @port: remote port to connect to
- * @ssl: whether or not to use SSL
+ * @ssl_creds: SSL credentials structure, or %NULL if not SSL
  * @callback: callback to call when the socket is connected
  * @user_data: data for @callback
  *
@@ -509,16 +605,17 @@ soup_socket_start_ssl (SoupSocket *sock)
  * Return value: the new socket (not yet ready for use).
  **/
 SoupSocket *
-soup_socket_client_new_async (const char *hostname, guint port, gboolean ssl, 
+soup_socket_client_new_async (const char *hostname, guint port,
+                             gpointer ssl_creds,
                              SoupSocketCallback callback, gpointer user_data)
 {
        SoupSocket *sock;
 
        g_return_val_if_fail (hostname != NULL, NULL);
 
-       sock = soup_socket_new ();
-       sock->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
-                            (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
+       sock = g_object_new (SOUP_TYPE_SOCKET,
+                            SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
+                            NULL);
        soup_socket_connect (sock, soup_address_new (hostname, port));
 
        if (callback) {
@@ -532,7 +629,7 @@ soup_socket_client_new_async (const char *hostname, guint port, gboolean ssl,
  * soup_socket_client_new_sync:
  * @hostname: remote machine to connect to
  * @port: remote port to connect to
- * @ssl: whether or not to use SSL
+ * @ssl_creds: SSL credentials structure, or %NULL if not SSL
  * @status_ret: pointer to return the soup status in
  *
  * Creates a connection to @hostname and @port. If @status_ret is not
@@ -541,16 +638,18 @@ soup_socket_client_new_async (const char *hostname, guint port, gboolean ssl,
  * Return value: the new socket, or %NULL if it could not connect.
  **/
 SoupSocket *
-soup_socket_client_new_sync (const char *hostname, guint port, gboolean ssl,
-                            guint *status_ret)
+soup_socket_client_new_sync (const char *hostname, guint port,
+                            gpointer ssl_creds, guint *status_ret)
 {
        SoupSocket *sock;
        guint status;
 
        g_return_val_if_fail (hostname != NULL, NULL);
 
-       sock = soup_socket_new ();
-       sock->priv->flags = ssl ? SOUP_SOCKET_FLAG_SSL : 0;
+       sock = g_object_new (SOUP_TYPE_SOCKET,
+                            SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
+                            NULL);
+       sock->priv->non_blocking = FALSE;
        status = soup_socket_connect (sock, soup_address_new (hostname, port));
 
        if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
@@ -567,7 +666,7 @@ soup_socket_client_new_sync (const char *hostname, guint port, gboolean ssl,
  * soup_socket_server_new:
  * @local_addr: Local address to bind to. (Use soup_address_any_new() to
  * accept connections on any local address)
- * @ssl: Whether or not this is an SSL server.
+ * @ssl_creds: SSL credentials, or %NULL if this is not an SSL server
  * @callback: Callback to call when a client connects
  * @user_data: data to pass to @callback.
  *
@@ -578,7 +677,7 @@ soup_socket_client_new_sync (const char *hostname, guint port, gboolean ssl,
  * Returns: a new #SoupSocket, or NULL if there was a failure.
  **/
 SoupSocket *
-soup_socket_server_new (SoupAddress *local_addr, gboolean ssl,
+soup_socket_server_new (SoupAddress *local_addr, gpointer ssl_creds,
                        SoupSocketListenerCallback callback,
                        gpointer user_data)
 {
@@ -586,10 +685,10 @@ soup_socket_server_new (SoupAddress *local_addr, gboolean ssl,
 
        g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
 
-       sock = soup_socket_new ();
-       sock->priv->flags = (SOUP_SOCKET_FLAG_SERVER |
-                            SOUP_SOCKET_FLAG_NONBLOCKING |
-                            (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
+       sock = g_object_new (SOUP_TYPE_SOCKET,
+                            SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
+                            NULL);
+       sock->priv->is_server = TRUE;
        if (!soup_socket_listen (sock, local_addr)) {
                g_object_unref (sock);
                return NULL;
index 5b3e49f..56a9c45 100644 (file)
@@ -35,18 +35,16 @@ typedef struct {
        void (*new_connection) (SoupSocket *, SoupSocket *);
 } SoupSocketClass;
 
-#define SOUP_SOCKET_FLAG_NONBLOCKING (1<<0)
-#define SOUP_SOCKET_FLAG_NODELAY     (1<<1)
-#define SOUP_SOCKET_FLAG_SERVER      (1<<2)
-#define SOUP_SOCKET_FLAG_REUSEADDR   (1<<3)
-#define SOUP_SOCKET_FLAG_ALL         ( ~0 )
+#define SOUP_SOCKET_FLAG_NONBLOCKING "non-blocking"
+#define SOUP_SOCKET_FLAG_NODELAY     "nodelay"
+#define SOUP_SOCKET_FLAG_REUSEADDR   "reuseaddr"
+#define SOUP_SOCKET_IS_SERVER        "is-server"
+#define SOUP_SOCKET_SSL_CREDENTIALS  "ssl-creds"
 
 GType soup_socket_get_type (void);
 
-SoupSocket    *soup_socket_new                (void);
-void           soup_socket_set_flags          (SoupSocket         *sock,
-                                              guint               mask,
-                                              guint               flags);
+SoupSocket    *soup_socket_new                (const char         *optname1,
+                                              ...);
 
 guint          soup_socket_connect            (SoupSocket         *sock,
                                               SoupAddress        *rem_addr);
@@ -66,15 +64,15 @@ typedef void (*SoupSocketListenerCallback)    (SoupSocket         *listener,
 
 SoupSocket    *soup_socket_client_new_async   (const char         *hostname,
                                               guint               port,
-                                              gboolean            ssl,
+                                              gpointer            ssl_creds,
                                               SoupSocketCallback  callback,
                                               gpointer            user_data);
 SoupSocket    *soup_socket_client_new_sync    (const char         *hostname,
                                               guint               port,
-                                              gboolean            ssl,
+                                              gpointer            ssl_creds,
                                               guint              *status);
 SoupSocket    *soup_socket_server_new         (SoupAddress        *local_addr,
-                                              gboolean            ssl,
+                                              gpointer            ssl_creds,
                                               SoupSocketListenerCallback,
                                               gpointer            user_data);
 
index 3480d35..31baaf0 100644 (file)
@@ -13,6 +13,15 @@ typedef enum {
        SOUP_SSL_TYPE_SERVER
 } SoupSSLType;
 
-GIOChannel *soup_ssl_get_iochannel (GIOChannel *sock, SoupSSLType type);
+gpointer    soup_ssl_get_client_credentials  (const char  *ca_file);
+void        soup_ssl_free_client_credentials (gpointer     creds);
+gpointer    soup_ssl_get_server_credentials  (const char  *cert_file,
+                                             const char  *key_file);
+void        soup_ssl_free_server_credentials (gpointer     creds);
+
+GIOChannel *soup_ssl_wrap_iochannel          (GIOChannel  *sock,
+                                             SoupSSLType  type,
+                                             const char  *remote_host,
+                                             gpointer     credentials);
 
 #endif /* SOUP_SSL_H */
index 58fff78..cb099e2 100644 (file)
@@ -20,4 +20,4 @@ revserver_SOURCES = revserver.c
 revserver_LDFLAGS = `pkg-config --libs gthread-2.0`
 uri_parsing_SOURCES = uri-parsing.c
 
-EXTRA_DIST = libsoup.supp
+EXTRA_DIST = libsoup.supp test-cert.pem test-key.pem
index efb9b9d..d3f4928 100644 (file)
@@ -197,20 +197,24 @@ get_url (const char *url)
 static void
 usage (void)
 {
-       fprintf (stderr, "Usage: get [-r] URL\n");
+       fprintf (stderr, "Usage: get [-c CAfile] [-r] URL\n");
        exit (1);
 }
 
 int
 main (int argc, char **argv)
 {
+       const char *cafile = NULL;
        int opt;
 
        g_type_init ();
-       session = soup_session_new ();
 
-       while ((opt = getopt (argc, argv, "r")) != -1) {
+       while ((opt = getopt (argc, argv, "c:r")) != -1) {
                switch (opt) {
+               case 'c':
+                       cafile = optarg;
+                       break;
+
                case 'r':
                        recurse = TRUE;
                        break;
@@ -232,6 +236,10 @@ main (int argc, char **argv)
                exit (1);
        }
 
+       session = soup_session_new_with_options (
+               SOUP_SESSION_SSL_CA_FILE, cafile,
+               NULL);
+
        if (recurse) {
                char *outdir;
 
index deecf81..cce251e 100644 (file)
@@ -120,7 +120,9 @@ new_connection (SoupSocket *listener, SoupSocket *client, gpointer user_data)
        pthread_t pth;
 
        g_object_ref (client);
-       soup_socket_set_flags (client, SOUP_SOCKET_FLAG_NONBLOCKING, 0);
+       g_object_set (G_OBJECT (client),
+                     SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
+                     NULL);
 
        if (pthread_create (&pth, NULL, start_thread, client) != 0) {
                g_warning ("Could not start thread");
@@ -161,7 +163,7 @@ main (int argc, char **argv)
                exit (1);
        }
 
-       listener = soup_socket_server_new (addr, port,
+       listener = soup_socket_server_new (addr, NULL,
                                           new_connection, NULL);
        g_object_unref (addr);
        if (!listener) {
index 74bcb78..db2ad41 100644 (file)
@@ -125,48 +125,61 @@ main (int argc, char **argv)
        int opt;
        int port = SOUP_ADDRESS_ANY_PORT;
        int ssl_port = SOUP_ADDRESS_ANY_PORT;
+       const char *ssl_cert_file = NULL, *ssl_key_file = NULL;
 
        g_type_init ();
        signal (SIGINT, quit);
 
-       while ((opt = getopt (argc, argv, "p:s:")) != -1) {
+       while ((opt = getopt (argc, argv, "p:k:c:s:")) != -1) {
                switch (opt) {
                case 'p':
                        port = atoi (optarg);
                        break;
+               case 'k':
+                       ssl_key_file = optarg;
+                       break;
+               case 'c':
+                       ssl_cert_file = optarg;
+                       break;
                case 's':
                        ssl_port = atoi (optarg);
                        break;
                default:
-                       fprintf (stderr, "Usage: %s [-p port] [-s ssl-port]\n",
+                       fprintf (stderr, "Usage: %s [-p port] [-c ssl-cert-file -k ssl-key-file [-s ssl-port]]\n",
                                 argv[0]);
                        exit (1);
                }
        }
 
-       server = soup_server_new (SOUP_PROTOCOL_HTTP, port);
+       server = soup_server_new (SOUP_SERVER_PORT, port,
+                                 NULL);
        if (!server) {
                fprintf (stderr, "Unable to bind to server port %d\n", port);
                exit (1);
        }
        soup_server_add_handler (server, NULL, NULL,
                                 server_callback, NULL, NULL);
-
-       ssl_server = soup_server_new (SOUP_PROTOCOL_HTTPS, ssl_port);
-       if (!ssl_server) {
-               fprintf (stderr, "Unable to bind to SSL server port %d\n", ssl_port);
-               exit (1);
-       }
-       soup_server_add_handler (ssl_server, NULL, NULL,
-                                server_callback, NULL, NULL);
-
        printf ("\nStarting Server on port %d\n",
                soup_server_get_port (server));
        soup_server_run_async (server);
 
-       printf ("Starting SSL Server on port %d\n", 
-               soup_server_get_port (ssl_server));
-       soup_server_run_async (ssl_server);
+       if (ssl_cert_file && ssl_key_file) {
+               ssl_server = soup_server_new (
+                       SOUP_SERVER_PORT, ssl_port,
+                       SOUP_SERVER_SSL_CERT_FILE, ssl_cert_file,
+                       SOUP_SERVER_SSL_KEY_FILE, ssl_key_file,
+                       NULL);
+
+               if (!ssl_server) {
+                       fprintf (stderr, "Unable to bind to SSL server port %d\n", ssl_port);
+                       exit (1);
+               }
+               soup_server_add_handler (ssl_server, NULL, NULL,
+                                        server_callback, NULL, NULL);
+               printf ("Starting SSL Server on port %d\n", 
+                       soup_server_get_port (ssl_server));
+               soup_server_run_async (ssl_server);
+       }
 
        printf ("\nWaiting for requests...\n");
 
index 3af0a75..fafebcc 100644 (file)
@@ -147,7 +147,8 @@ main (int argc, char **argv)
                }
        }
 
-       server = soup_server_new (SOUP_PROTOCOL_HTTP, port);
+       server = soup_server_new (SOUP_SERVER_PORT, port,
+                                 NULL);
        if (!server) {
                fprintf (stderr, "Unable to bind to server port %d\n", port);
                exit (1);
diff --git a/tests/test-cert.pem b/tests/test-cert.pem
new file mode 100644 (file)
index 0000000..a6b6608
--- /dev/null
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjzCCAvigAwIBAgIBADANBgkqhkiG9w0BAQQFADCBkjELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEPMA0GA1UE
+ChMGWGltaWFuMRUwEwYDVQQLEwxTb3VwIEtpdGNoZW4xEjAQBgNVBAMTCWxvY2Fs
+aG9zdDEeMBwGCSqGSIb3DQEJARYPc291cEB4aW1pYW4uY29tMB4XDTAzMDkyMzE4
+Mzc0MVoXDTEzMDkyMzE4Mzc0MVowgZIxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1N
+YXNzYWNodXNldHRzMQ8wDQYDVQQHEwZCb3N0b24xDzANBgNVBAoTBlhpbWlhbjEV
+MBMGA1UECxMMU291cCBLaXRjaGVuMRIwEAYDVQQDEwlsb2NhbGhvc3QxHjAcBgkq
+hkiG9w0BCQEWD3NvdXBAeGltaWFuLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAwzT/WxfdXqb2hbyjQav3FtN7tLxj3UbZKCKDYlizBsNLxb9exfebhV4h
+CoAcaSNvLUnk3tAXnk+BDsIC1V4SbwqHYR17PnO3YZ8fkNwh5RGZwNx+zafdfFyu
++3Sh+mE03bljpDlTsgPL8CiFCd68MPRnuHoKt5iTpSyLC6Df0qcCAwEAAaOB8jCB
+7zAdBgNVHQ4EFgQU9A9omrgBK5Kkl6FRxrgJU2voj4Uwgb8GA1UdIwSBtzCBtIAU
+9A9omrgBK5Kkl6FRxrgJU2voj4WhgZikgZUwgZIxCzAJBgNVBAYTAlVTMRYwFAYD
+VQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZCb3N0b24xDzANBgNVBAoTBlhp
+bWlhbjEVMBMGA1UECxMMU291cCBLaXRjaGVuMRIwEAYDVQQDEwlsb2NhbGhvc3Qx
+HjAcBgkqhkiG9w0BCQEWD3NvdXBAeGltaWFuLmNvbYIBADAMBgNVHRMEBTADAQH/
+MA0GCSqGSIb3DQEBBAUAA4GBAGCV56N7bEDNdE76T8i68gS00NIVVosVQjS39Ojd
+ED+rvq0YYvuc2UXlzAonuCJfwFc73g4wSIjS0xijF5rnugZ+aay0LNv2y+Rf34CQ
+RNswrwurFjlxgTOO+Wx2IM64mAnBfj43M8uKEZFqAiGKrZZ0xIqyUMlku0FgXDH2
+Jvpg
+-----END CERTIFICATE-----
diff --git a/tests/test-key.pem b/tests/test-key.pem
new file mode 100644 (file)
index 0000000..9bea9bf
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDDNP9bF91epvaFvKNBq/cW03u0vGPdRtkoIoNiWLMGw0vFv17F
+95uFXiEKgBxpI28tSeTe0BeeT4EOwgLVXhJvCodhHXs+c7dhnx+Q3CHlEZnA3H7N
+p918XK77dKH6YTTduWOkOVOyA8vwKIUJ3rww9Ge4egq3mJOlLIsLoN/SpwIDAQAB
+AoGAOGAi6zzuKrrPcXo0L/ApEQeMr3rE4I/ogUXOaeWx9l8KkBafmU7UNGUl57Fu
+AxM/tXWkypCQcaEGZau0Q8jCS5wKgynNi72F4OzBqgjgW4vvtrjfC1LagnCd2ZMX
+V5XVECjO/sEDg0hJeOsXlKbECAgvHMU3dSCGO7DmuG9tIxkCQQDsth1VvVjOdfp6
+klOfYzbAM1p9HIcNPJMeuBFqq//UHX4aPqh/6G6W06TOTN+bjZBmitG9yjV958t2
+rPxl64f7AkEA0x0WOLm5S0LNsv7zwjXuTcj+NCHL36b3dK90oxX8Gq69PANL/EJY
+ItpHNLgzzo4DRmQy8q0WZlC9HYk1YljERQJAEN7+AkFnlfeErb3GJgMNQO+oEGi7
+G29o0PSvkRnHNxgPB9HVcqBfWXKmOWnzOgQB+b0FK/DAlUOzFbdImf8KhwJAFLty
+hzeV/tIcqUtoXNY3BOSMMkpvXxNikc75QVrTWzt10gLw32EUjreo7oB4dfx0TeFh
+L3vYC0w6hkAHQhU9kQJAPSEQ+Bqzlk6BrQNrNFEVzi1Rwpz7LOzhOjuYW6bsiAdX
+axA4r6Xh25x08ZU7cqX7gwVLHL6pgrEKuUs0Nc5Klg==
+-----END RSA PRIVATE KEY-----