broadway: Initial SSL support

Use the new --cert and --key parameters to broadwayd to pass paths to
cert and key files.

https://bugzilla.gnome.org/show_bug.cgi?id=730364
This commit is contained in:
Michael Natterer 2014-12-15 11:25:43 +00:00 committed by Martyn Russell
parent 4288d7d7f4
commit c00cc269c5
3 changed files with 83 additions and 19 deletions

View File

@ -42,6 +42,8 @@ struct _BroadwayServer {
char *address;
int port;
char *ssl_cert;
char *ssl_key;
GSocketService *service;
BroadwayOutput *output;
guint32 id_counter;
@ -85,7 +87,8 @@ struct _BroadwayServerClass
typedef struct HttpRequest {
BroadwayServer *server;
GSocketConnection *connection;
GSocketConnection *socket_connection;
GIOStream *connection;
GDataInputStream *data;
GString *request;
} HttpRequest;
@ -93,7 +96,7 @@ typedef struct HttpRequest {
struct BroadwayInput {
BroadwayServer *server;
BroadwayOutput *output;
GSocketConnection *connection;
GIOStream *connection;
GByteArray *buffer;
GSource *source;
gboolean seen_time;
@ -155,6 +158,8 @@ broadway_server_finalize (GObject *object)
BroadwayServer *server = BROADWAY_SERVER (object);
g_free (server->address);
g_free (server->ssl_cert);
g_free (server->ssl_key);
G_OBJECT_CLASS (broadway_server_parent_class)->finalize (object);
}
@ -172,6 +177,7 @@ static void start (BroadwayInput *input);
static void
http_request_free (HttpRequest *request)
{
g_object_unref (request->socket_connection);
g_object_unref (request->connection);
g_object_unref (request->data);
g_string_free (request->request, TRUE);
@ -661,14 +667,13 @@ broadway_server_read_all_input_nonblocking (BroadwayInput *input)
GInputStream *in;
gssize res;
guint8 buffer[1024];
GError *error;
GError *error = NULL;
if (input == NULL)
return;
in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
in = g_io_stream_get_input_stream (input->connection);
error = NULL;
res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in),
buffer, sizeof (buffer), NULL, &error);
@ -796,7 +801,8 @@ broadway_server_block_for_input (BroadwayServer *server, char op,
/* Not found, read more, blocking */
in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
in = g_io_stream_get_input_stream (input->connection);
res = g_input_stream_read (in, buffer, sizeof (buffer), NULL, NULL);
if (res <= 0)
return NULL;
@ -909,9 +915,11 @@ send_error (HttpRequest *request,
error_code, reason,
error_code, reason,
reason);
/* TODO: This should really be async */
g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
res, strlen (res), NULL, NULL, NULL);
g_output_stream_write_all (g_io_stream_get_output_stream (request->connection),
res, strlen (res), NULL, NULL, NULL);
g_free (res);
http_request_free (request);
}
@ -1004,8 +1012,8 @@ start_input (HttpRequest *request)
g_print ("v7 proto response:\n%s", res);
#endif
g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
res, strlen (res), NULL, NULL, NULL);
g_output_stream_write_all (g_io_stream_get_output_stream (request->connection),
res, strlen (res), NULL, NULL, NULL);
g_free (res);
}
else
@ -1015,7 +1023,7 @@ start_input (HttpRequest *request)
return;
}
socket = g_socket_connection_get_socket (request->connection);
socket = g_socket_connection_get_socket (request->socket_connection);
setsockopt (g_socket_get_fd (socket), IPPROTO_TCP,
TCP_NODELAY, (char *) &flag, sizeof(int));
@ -1028,12 +1036,13 @@ start_input (HttpRequest *request)
g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
input->output =
broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), 0);
broadway_output_new (g_io_stream_get_output_stream (request->connection), 0);
/* This will free and close the data input stream, but we got all the buffered content already */
http_request_free (request);
in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
in = g_io_stream_get_input_stream (input->connection);
input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL);
g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
g_source_attach (input->source, NULL);
@ -1101,11 +1110,12 @@ send_data (HttpRequest *request,
"Content-Length: %"G_GSIZE_FORMAT"\r\n"
"\r\n",
mimetype, len);
/* TODO: This should really be async */
g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
g_output_stream_write_all (g_io_stream_get_output_stream (request->connection),
res, strlen (res), NULL, NULL, NULL);
g_free (res);
g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
g_output_stream_write_all (g_io_stream_get_output_stream (request->connection),
data, len, NULL, NULL, NULL);
http_request_free (request);
}
@ -1202,11 +1212,49 @@ handle_incoming_connection (GSocketService *service,
GInputStream *in;
request = g_new0 (HttpRequest, 1);
request->connection = g_object_ref (connection);
request->socket_connection = g_object_ref (connection);
request->server = BROADWAY_SERVER (source_object);
request->request = g_string_new ("");
in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
if (request->server->ssl_cert && request->server->ssl_key)
{
GError *error = NULL;
GTlsCertificate *certificate;
certificate = g_tls_certificate_new_from_files (request->server->ssl_cert,
request->server->ssl_key,
&error);
if (!certificate)
{
g_warning ("Cannot create TLS certificate: %s", error->message);
g_error_free (error);
return FALSE;
}
request->connection = g_tls_server_connection_new (G_IO_STREAM (connection),
certificate,
&error);
if (!request->connection)
{
g_warning ("Cannot create TLS connection: %s", error->message);
g_error_free (error);
return FALSE;
}
if (!g_tls_connection_handshake (G_TLS_CONNECTION (request->connection),
NULL, &error))
{
g_warning ("Cannot create TLS connection: %s", error->message);
g_error_free (error);
return FALSE;
}
}
else
{
request->connection = g_object_ref (connection);
}
in = g_io_stream_get_input_stream (request->connection);
request->data = g_data_input_stream_new (in);
g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data), FALSE);
@ -1219,7 +1267,11 @@ handle_incoming_connection (GSocketService *service,
}
BroadwayServer *
broadway_server_new (char *address, int port, GError **error)
broadway_server_new (char *address,
int port,
const char *ssl_cert,
const char *ssl_key,
GError **error)
{
BroadwayServer *server;
GInetAddress *inet_address;
@ -1228,6 +1280,8 @@ broadway_server_new (char *address, int port, GError **error)
server = g_object_new (BROADWAY_TYPE_SERVER, NULL);
server->port = port;
server->address = g_strdup (address);
server->ssl_cert = g_strdup (ssl_cert);
server->ssl_key = g_strdup (ssl_key);
if (address == NULL)
{

View File

@ -21,6 +21,8 @@ typedef struct _BroadwayServerClass BroadwayServerClass;
BroadwayServer *broadway_server_new (char *address,
int port,
const char *ssl_cert,
const char *ssl_key,
GError **error);
BroadwayServer *broadway_server_on_unix_socket_new (char *address,
GError **error);

View File

@ -419,6 +419,8 @@ main (int argc, char *argv[])
char *http_address = NULL;
char *unixsocket_address = NULL;
int http_port = 0;
char *ssl_cert = NULL;
char *ssl_key = NULL;
char *display;
int port = 0;
const GOptionEntry entries[] = {
@ -427,6 +429,8 @@ main (int argc, char *argv[])
#ifdef G_OS_UNIX
{ "unixsocket", 'u', 0, G_OPTION_ARG_STRING, &unixsocket_address, "Unix domain socket address", "ADDRESS" },
#endif
{ "cert", 'c', 0, G_OPTION_ARG_STRING, &ssl_cert, "SSL certificate path", "PATH" },
{ "key", 'k', 0, G_OPTION_ARG_STRING, &ssl_key, "SSL key path", "PATH" },
{ NULL }
};
@ -493,7 +497,11 @@ main (int argc, char *argv[])
if (unixsocket_address != NULL)
server = broadway_server_on_unix_socket_new (unixsocket_address, &error);
else
server = broadway_server_new (http_address, http_port, &error);
server = broadway_server_new (http_address,
http_port,
ssl_cert,
ssl_key,
&error);
if (server == NULL)
{