+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
#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
enum {
PROP_0,
- PROP_DEST_URI,
+ PROP_ORIGIN_URI,
PROP_PROXY_URI,
+ PROP_SSL_CREDS,
LAST_PROP
};
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);
/* 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,
"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)
* @...:
*
* 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.
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;
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;
}
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);
SoupConnectionCallback callback,
gpointer user_data)
{
- const SoupUri *uri;
-
g_return_if_fail (SOUP_IS_CONNECTION (conn));
g_return_if_fail (conn->priv->socket == NULL);
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);
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;
}
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,
...);
#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 char* hostname)
+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) {
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))
{
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;
}
SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel;
g_io_channel_unref (chan->real_sock);
gnutls_deinit (chan->session);
- soup_gnutls_cred_unref (chan->cred);
g_free (chan);
}
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) {
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;
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);
chan->real_sock = sock;
chan->session = session;
chan->cred = cred;
+ chan->hostname = g_strdup (hostname);
chan->type = type;
g_io_channel_ref (sock);
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 */
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;
#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,
#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;
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)
{
{
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);
/* 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;
}
{
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
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);
#include "soup-connection-ntlm.h"
#include "soup-marshal.h"
#include "soup-message-queue.h"
+#include "soup-ssl.h"
#include "soup-uri.h"
typedef struct {
guint max_conns, max_conns_per_host;
gboolean use_ntlm;
+ char *ssl_ca_file;
+ gpointer ssl_creds;
+
SoupMessageQueue *queue;
GHashTable *hosts; /* SoupUri -> SoupSessionHost */
PROP_MAX_CONNS,
PROP_MAX_CONNS_PER_HOST,
PROP_USE_NTLM,
+ PROP_SSL_CA_FILE,
LAST_PROP
};
"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)
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;
}
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;
}
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;
}
/* 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);
}
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),
#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,
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)
{
/* virtual method override */
object_class->finalize = finalize;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
/* signals */
signals[CONNECT_RESULT] =
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 *
}
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;
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)
{
{
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;
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);
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);
}
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;
}
}
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);
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);
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)
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);
}
* 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
*
* 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) {
* 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
* 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)) {
* 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.
*
* 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)
{
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;
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);
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);
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 */
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
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;
exit (1);
}
+ session = soup_session_new_with_options (
+ SOUP_SESSION_SSL_CA_FILE, cafile,
+ NULL);
+
if (recurse) {
char *outdir;
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");
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) {
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");
}
}
- 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);
--- /dev/null
+-----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-----
--- /dev/null
+-----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-----