static gboolean initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { g_debug (G_STRLOC ": %s", G_STRFUNC); DasomServer *server = DASOM_SERVER (initable); GSocketAddress *address; GError *local_error = NULL; server->listener = G_SOCKET_LISTENER (g_socket_service_new ()); /* server->listener = G_SOCKET_LISTENER (g_threaded_socket_service_new (-1)); */ if (g_unix_socket_address_abstract_names_supported ()) address = g_unix_socket_address_new_with_type (server->address, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); else { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Abstract UNIX domain socket names are not supported."); return FALSE; } g_socket_listener_add_address (server->listener, address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, NULL, &local_error); g_object_unref (address); if (local_error) { g_propagate_error (error, local_error); return FALSE; } server->is_using_listener = TRUE; server->run_signal_handler_id = g_signal_connect (G_SOCKET_SERVICE (server->listener), "incoming", (GCallback) on_new_connection, server); /* server->run_signal_handler_id = g_signal_connect (G_SOCKET_SERVICE (server->listener), "run", G_CALLBACK (on_run), server); */ return TRUE; }
GSocketAddress * socket_address_from_string (const char *name) { #ifdef G_OS_UNIX int i, len; for (i = 0; i < G_N_ELEMENTS (unix_socket_address_types); i++) { len = strlen (unix_socket_address_types[i]); if (!strncmp (name, unix_socket_address_types[i], len) && name[len] == ':') { return g_unix_socket_address_new_with_type (name + len + 1, -1, (GUnixSocketAddressType)i); } } #endif return NULL; }
static void use_unix_address (gboolean synchronous) { GSocketAddressEnumerator *enumerator; GSocketAddress *sockaddr; sockaddr = g_unix_socket_address_new_with_type (info, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); if (sockaddr == NULL) { fprintf (stderr, "Failed to create unix socket with name '%s'\n", info); return_value = 1; return; } enumerator = g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); g_object_unref (sockaddr); printf ("Proxies for path '%s' are:\n", info); run_with_enumerator (synchronous, enumerator); g_object_unref (enumerator); }
/* note that address_entry has already been validated => exactly one of path, tmpdir or abstract keys are set */ static gboolean try_unix (GDBusServer *server, const gchar *address_entry, GHashTable *key_value_pairs, GError **error) { gboolean ret; const gchar *path; const gchar *tmpdir; const gchar *abstract; GSocketAddress *address; ret = FALSE; address = NULL; path = g_hash_table_lookup (key_value_pairs, "path"); tmpdir = g_hash_table_lookup (key_value_pairs, "tmpdir"); abstract = g_hash_table_lookup (key_value_pairs, "abstract"); if (path != NULL) { address = g_unix_socket_address_new (path); } else if (tmpdir != NULL) { gint n; GString *s; GError *local_error; retry: s = g_string_new (tmpdir); g_string_append (s, "/dbus-"); for (n = 0; n < 8; n++) g_string_append_c (s, random_ascii ()); /* prefer abstract namespace if available */ if (g_unix_socket_address_abstract_names_supported ()) address = g_unix_socket_address_new_with_type (s->str, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); else address = g_unix_socket_address_new (s->str); g_string_free (s, TRUE); local_error = NULL; if (!g_socket_listener_add_address (server->listener, address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, /* source_object */ NULL, /* effective_address */ &local_error)) { if (local_error->domain == G_IO_ERROR && local_error->code == G_IO_ERROR_ADDRESS_IN_USE) { g_error_free (local_error); goto retry; } g_propagate_error (error, local_error); goto out; } ret = TRUE; goto out; } else if (abstract != NULL) { if (!g_unix_socket_address_abstract_names_supported ()) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Abstract name space not supported")); goto out; } address = g_unix_socket_address_new_with_type (abstract, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); } else { g_assert_not_reached (); } if (!g_socket_listener_add_address (server->listener, address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, /* source_object */ NULL, /* effective_address */ error)) goto out; ret = TRUE; out: if (address != NULL) { /* Fill out client_address if the connection attempt worked */ if (ret) { server->is_using_listener = TRUE; switch (g_unix_socket_address_get_address_type (G_UNIX_SOCKET_ADDRESS (address))) { case G_UNIX_SOCKET_ADDRESS_ABSTRACT: server->client_address = g_strdup_printf ("unix:abstract=%s", g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (address))); break; case G_UNIX_SOCKET_ADDRESS_PATH: server->client_address = g_strdup_printf ("unix:path=%s", g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (address))); break; default: g_assert_not_reached (); break; } } g_object_unref (address); } return ret; }
int main (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GMainLoop *loop; GSocketAddress *address; GSocketService *listener; char *path, *base; char *http_address = NULL; int http_port = 0; int display = 1; const GOptionEntry entries[] = { { "port", 'p', 0, G_OPTION_ARG_INT, &http_port, "Httpd port", "PORT" }, { "address", 'a', 0, G_OPTION_ARG_STRING, &http_address, "Ip address to bind to ", "ADDRESS" }, { NULL } }; context = g_option_context_new ("[:DISPLAY] - broadway display daemon"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); exit (1); } if (argc > 1) { if (*argv[1] != ':') { g_printerr ("Usage broadwayd [:DISPLAY]\n"); exit (1); } display = strtol(argv[1]+1, NULL, 10); if (display == 0) { g_printerr ("Failed to parse display num %s\n", argv[1]); exit (1); } } if (http_port == 0) http_port = 8080 + (display - 1); server = broadway_server_new (http_address, http_port, &error); if (server == NULL) { g_printerr ("%s\n", error->message); return 1; } base = g_strdup_printf ("broadway%d.socket", display); path = g_build_filename (g_get_user_runtime_dir (), base, NULL); g_free (base); g_print ("Listening on %s\n", path); address = g_unix_socket_address_new_with_type (path, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); g_free (path); listener = g_socket_service_new (); if (!g_socket_listener_add_address (G_SOCKET_LISTENER (listener), address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, G_OBJECT (server), NULL, &error)) { g_printerr ("Can't listen: %s\n", error->message); return 1; } g_object_unref (address); g_signal_connect (listener, "incoming", G_CALLBACK (incoming_client), NULL); g_socket_service_start (G_SOCKET_SERVICE (listener)); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); return 0; }
int main (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; GMainLoop *loop; GInetAddress *inet; GSocketAddress *address; GSocketService *listener; char *path, *basename; 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[] = { { "port", 'p', 0, G_OPTION_ARG_INT, &http_port, "Httpd port", "PORT" }, { "address", 'a', 0, G_OPTION_ARG_STRING, &http_address, "Ip address to bind to ", "ADDRESS" }, #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 } }; setlocale (LC_ALL, ""); context = g_option_context_new ("[:DISPLAY] - broadway display daemon"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); exit (1); } display = NULL; if (argc > 1) { if (*argv[1] != ':') { g_printerr ("Usage broadwayd [:DISPLAY]\n"); exit (1); } display = argv[1]; } if (display == NULL) { #ifdef G_OS_UNIX if (g_unix_socket_address_abstract_names_supported ()) display = ":0"; else #endif display = ":tcp"; } if (g_str_has_prefix (display, ":tcp")) { port = strtol (display + strlen (":tcp"), NULL, 10); inet = g_inet_address_new_from_string ("127.0.0.1"); g_print ("Listening on 127.0.0.1:%d\n", port + 9090); address = g_inet_socket_address_new (inet, port + 9090); g_object_unref (inet); } #ifdef G_OS_UNIX else if (display[0] == ':' && g_ascii_isdigit(display[1])) { port = strtol (display + strlen (":"), NULL, 10); basename = g_strdup_printf ("broadway%d.socket", port + 1); path = g_build_filename (g_get_user_runtime_dir (), basename, NULL); g_free (basename); g_print ("Listening on %s\n", path); address = g_unix_socket_address_new_with_type (path, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); g_free (path); } #endif else { g_printerr ("Failed to parse display %s\n", display); exit (1); } if (http_port == 0) http_port = 8080 + port; if (unixsocket_address != NULL) server = broadway_server_on_unix_socket_new (unixsocket_address, &error); else server = broadway_server_new (http_address, http_port, ssl_cert, ssl_key, &error); if (server == NULL) { g_printerr ("%s\n", error->message); return 1; } listener = g_socket_service_new (); if (!g_socket_listener_add_address (G_SOCKET_LISTENER (listener), address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, G_OBJECT (server), NULL, &error)) { g_printerr ("Can't listen: %s\n", error->message); return 1; } g_object_unref (address); g_signal_connect (listener, "incoming", G_CALLBACK (incoming_client), NULL); g_socket_service_start (G_SOCKET_SERVICE (listener)); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); return 0; }
static void dasom_im_init (DasomIM *im) { g_debug (G_STRLOC ": %s", G_STRFUNC); GSocketClient *client; GSocketAddress *address; GSocket *socket; GError *error = NULL; address = g_unix_socket_address_new_with_type (DASOM_ADDRESS, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); client = g_socket_client_new (); im->connection = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (address), NULL, &error); g_object_unref (address); g_object_unref (client); if (im->connection == NULL) { g_critical (G_STRLOC ": %s: %s", G_STRFUNC, error->message); g_clear_error (&error); return; } socket = g_socket_connection_get_socket (im->connection); if (!socket) { g_critical (G_STRLOC ": %s: %s", G_STRFUNC, "Can't get socket"); return; } DasomMessage *message; DasomConnectionType type = DASOM_CONNECTION_DASOM_IM; dasom_send_message (socket, DASOM_MESSAGE_CONNECT, &type, sizeof (DasomConnectionType), NULL); g_socket_condition_wait (socket, G_IO_IN, NULL, NULL); message = dasom_recv_message (socket); if (G_UNLIKELY (message == NULL || message->header->type != DASOM_MESSAGE_CONNECT_REPLY)) { dasom_message_unref (message); g_error ("Couldn't connect to dasom daemon"); } dasom_message_unref (message); im->result = g_slice_new0 (DasomResult); im->preedit_string = g_strdup (""); GMutex mutex; g_mutex_init (&mutex); g_mutex_lock (&mutex); if (G_UNLIKELY (dasom_im_sockets_context == NULL)) { dasom_im_sockets_context = g_main_context_new (); dasom_im_sockets_context_ref_count++; } else { dasom_im_sockets_context = g_main_context_ref (dasom_im_sockets_context); dasom_im_sockets_context_ref_count++; } g_mutex_unlock (&mutex); /* when g_main_context_iteration(), iterate only sockets */ im->sockets_context_source = g_socket_create_source (socket, G_IO_IN, NULL); g_source_set_can_recurse (im->sockets_context_source, TRUE); g_source_attach (im->sockets_context_source, dasom_im_sockets_context); g_source_set_callback (im->sockets_context_source, (GSourceFunc) on_incoming_message, im, NULL); im->default_context_source = g_socket_create_source (socket, G_IO_IN, NULL); g_source_set_can_recurse (im->default_context_source, TRUE); g_source_set_callback (im->default_context_source, (GSourceFunc) on_incoming_message, im, NULL); g_source_attach (im->default_context_source, NULL); }
/* TODO: Declare an extension point called GDBusTransport (or similar) * and move code below to extensions implementing said extension * point. That way we can implement a D-Bus transport over X11 without * making libgio link to libX11... */ static GIOStream * g_dbus_address_connect (const gchar *address_entry, const gchar *transport_name, GHashTable *key_value_pairs, GCancellable *cancellable, GError **error) { GIOStream *ret; GSocketConnectable *connectable; const gchar *nonce_file; connectable = NULL; ret = NULL; nonce_file = NULL; if (FALSE) { } #ifdef G_OS_UNIX else if (g_strcmp0 (transport_name, "unix") == 0) { const gchar *path; const gchar *abstract; path = g_hash_table_lookup (key_value_pairs, "path"); abstract = g_hash_table_lookup (key_value_pairs, "abstract"); if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address '%s' - the unix transport requires exactly one of the " "keys 'path' or 'abstract' to be set"), address_entry); } else if (path != NULL) { connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path)); } else if (abstract != NULL) { connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT)); } else { g_assert_not_reached (); } } #endif else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0) { const gchar *s; const gchar *host; glong port; gchar *endp; gboolean is_nonce; is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0); host = g_hash_table_lookup (key_value_pairs, "host"); if (host == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address '%s' - the host attribute is missing or malformed"), address_entry); goto out; } s = g_hash_table_lookup (key_value_pairs, "port"); if (s == NULL) s = "0"; port = strtol (s, &endp, 10); if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address '%s' - the port attribute is missing or malformed"), address_entry); goto out; } if (is_nonce) { nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile"); if (nonce_file == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address '%s' - the noncefile attribute is missing or malformed"), address_entry); goto out; } } /* TODO: deal with family key/value-pair */ connectable = g_network_address_new (host, port); } else if (g_strcmp0 (address_entry, "autolaunch:") == 0) { gchar *autolaunch_address; autolaunch_address = get_session_address_platform_specific (error); if (autolaunch_address != NULL) { ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error); g_free (autolaunch_address); goto out; } else { g_prefix_error (error, _("Error auto-launching: ")); } } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Unknown or unsupported transport '%s' for address '%s'"), transport_name, address_entry); } if (connectable != NULL) { GSocketClient *client; GSocketConnection *connection; g_assert (ret == NULL); client = g_socket_client_new (); connection = g_socket_client_connect (client, connectable, cancellable, error); g_object_unref (connectable); g_object_unref (client); if (connection == NULL) goto out; ret = G_IO_STREAM (connection); if (nonce_file != NULL) { gchar nonce_contents[16 + 1]; size_t num_bytes_read; FILE *f; /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */ f = fopen (nonce_file, "rb"); if (f == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error opening nonce file '%s': %s"), nonce_file, g_strerror (errno)); g_object_unref (ret); ret = NULL; goto out; } num_bytes_read = fread (nonce_contents, sizeof (gchar), 16 + 1, f); if (num_bytes_read != 16) { if (num_bytes_read == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error reading from nonce file '%s': %s"), nonce_file, g_strerror (errno)); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error reading from nonce file '%s', expected 16 bytes, got %d"), nonce_file, (gint) num_bytes_read); } g_object_unref (ret); ret = NULL; fclose (f); goto out; } fclose (f); if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret), nonce_contents, 16, NULL, cancellable, error)) { g_prefix_error (error, _("Error writing contents of nonce file '%s' to stream:"), nonce_file); g_object_unref (ret); ret = NULL; goto out; } } } out: return ret; }
/* TODO: Declare an extension point called GDBusTransport (or similar) * and move code below to extensions implementing said extension * point. That way we can implement a D-Bus transport over X11 without * making libgio link to libX11... */ static GIOStream * g_dbus_address_connect (const gchar *address_entry, const gchar *transport_name, GHashTable *key_value_pairs, GCancellable *cancellable, GError **error) { GIOStream *ret; GSocketConnectable *connectable; const gchar *nonce_file; connectable = NULL; ret = NULL; nonce_file = NULL; if (FALSE) { } #ifdef G_OS_UNIX else if (g_strcmp0 (transport_name, "unix") == 0) { const gchar *path; const gchar *abstract; path = g_hash_table_lookup (key_value_pairs, "path"); abstract = g_hash_table_lookup (key_value_pairs, "abstract"); if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address `%s' - the unix transport requires exactly one of the " "keys `path' or `abstract' to be set"), address_entry); } else if (path != NULL) { connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path)); } else if (abstract != NULL) { connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT)); } else { g_assert_not_reached (); } } #endif else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0) { const gchar *s; const gchar *host; guint port; gchar *endp; gboolean is_nonce; is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0); host = g_hash_table_lookup (key_value_pairs, "host"); if (host == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address `%s' - the host attribute is missing or malformed"), address_entry); goto out; } s = g_hash_table_lookup (key_value_pairs, "port"); if (s == NULL) s = "0"; port = strtol (s, &endp, 10); if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address `%s' - the port attribute is missing or malformed"), address_entry); goto out; } if (is_nonce) { nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile"); if (nonce_file == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Error in address `%s' - the noncefile attribute is missing or malformed"), address_entry); goto out; } } /* TODO: deal with family */ connectable = g_network_address_new (host, port); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Unknown or unsupported transport `%s' for address `%s'"), transport_name, address_entry); } if (connectable != NULL) { GSocketClient *client; GSocketConnection *connection; g_assert (ret == NULL); client = g_socket_client_new (); connection = g_socket_client_connect (client, connectable, cancellable, error); g_object_unref (connectable); g_object_unref (client); if (connection == NULL) goto out; ret = G_IO_STREAM (connection); if (nonce_file != NULL) { gchar *nonce_contents; gsize nonce_length; /* TODO: too dangerous to read the entire file? (think denial-of-service etc.) */ if (!g_file_get_contents (nonce_file, &nonce_contents, &nonce_length, error)) { g_prefix_error (error, _("Error reading nonce file `%s':"), nonce_file); g_object_unref (ret); ret = NULL; goto out; } if (nonce_length != 16) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("The nonce-file `%s' was %" G_GSIZE_FORMAT " bytes. Expected 16 bytes."), nonce_file, nonce_length); g_free (nonce_contents); g_object_unref (ret); ret = NULL; goto out; } if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret), nonce_contents, nonce_length, NULL, cancellable, error)) { g_prefix_error (error, _("Error write contents of nonce file `%s' to stream:"), nonce_file); g_object_unref (ret); ret = NULL; g_free (nonce_contents); goto out; } g_free (nonce_contents); } } out: return ret; }