Asynchronous GIO Server/Client - c

I would like to create an Asynchronous server and client application that communicate via sockets using GIO. As I am newbie to GIO, on browsing I got the below code - which is my client. I am unable to find any examples of the server. Please guide me in this regard.
GMainLoop *loop;
GMainContext *ctx;
struct conn
{
GSocketClient *client;
GSocketConnection *conn;
GInputStream *in;
GOutputStream *out;
gchar data[8192];
unsigned int count;
};
static void
read_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
printf("## %s\n", __FUNCTION__);
struct conn *c = (struct conn *)user_data;
gssize len = g_input_stream_read_finish(c->in, res, NULL);
g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
if (c->count++ == 1) {
printf("End of life as I know it...\n");
g_main_loop_quit(loop);
}
}
static void
write_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
}
static void
connect_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
printf("## %s\n", __FUNCTION__);
struct conn *c = (struct conn *)user_data;
c->conn = g_socket_client_connect_to_host_finish(c->client, res, NULL);
printf("I'm\n");
c->in = g_io_stream_get_input_stream(G_IO_STREAM (c->conn));
c->out = g_io_stream_get_output_stream(G_IO_STREAM (c->conn));
char *data = "hello world!!!\n";
printf("I'm here\n");
g_output_stream_write_async(c->out, data, strlen(data), G_PRIORITY_DEFAULT, NULL, write_done_cb, c);
g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
}
int
main(int argc, char **argv)
{
g_type_init();
struct conn *c = g_malloc0(sizeof *c);
ctx = g_main_context_new();
loop = g_main_loop_new(ctx, FALSE);
g_main_context_push_thread_default(ctx);
c->client = g_socket_client_new();
g_socket_client_connect_to_host_async(c->client, "localhost", 1500, NULL, connect_done_cb, c);
g_main_loop_run(loop);
g_io_stream_close(G_IO_STREAM(c->conn), NULL, NULL);
g_object_unref(c->client);
g_object_unref(c->conn);
g_main_context_pop_thread_default(ctx);
g_main_loop_unref(loop);
g_main_context_unref(ctx);
return 0;
}

Hope this would help you
#include <glib.h>
#include <gio/gio.h>
/* this function will get called everytime a client attempts to connect */
gboolean
incoming_callback (GSocketService *service,
GSocketConnection *connection,
GObject *source_object,
gpointer user_data)
{
g_print("Received Connection from client!\n");
GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
gchar message[1024];
g_input_stream_read (istream,
message,
1024,
NULL,
NULL);
g_print("Message was: \"%s\"\n", message);
return FALSE;
}
int
main (int argc, char **argv)
{
/* initialize glib */
g_type_init();
GError * error = NULL;
/* create the new socketservice */
GSocketService * service = g_socket_service_new ();
/* connect to the port */
g_socket_listener_add_inet_port ((GSocketListener*)service,
1500, /* your port goes here */
NULL,
&error);
/* don't forget to check for errors */
if (error != NULL)
{
g_error (error->message);
}
/* listen to the 'incoming' signal */
g_signal_connect (service,
"incoming",
G_CALLBACK (incoming_callback),
NULL);
/* start the socket service */
g_socket_service_start (service);
/* enter mainloop */
g_print ("Waiting for client!\n");
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
return 0;
}

Related

How to make wait for a pthread of a GTK window to close

I have a code that takes a URL and downloads it using libcurl and displays a nice loading bar in another window, in another part of my code, I run the downloadFile function in a for loop, and what happens is that it first downloads the files and then displays all the progress windows, what am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <inttypes.h>
#include <unistd.h>
#include <byteswap.h>
#ifndef _WIN32
#include <sys/stat.h>
#endif
#include <gtk/gtk.h>
#include <curl/curl.h>
#include <pthread.h>
struct MemoryStruct {
uint8_t* memory;
size_t size;
};
struct PathFileStruct {
char* file_path;
FILE* file_pointer;
};
GtkWidget *progress_bar;
GtkWidget *button;
GtkWidget *window;
//Thread
pthread_t thread;
int thread_running = 0;
CURL* new_handle;
//LibCurl progress function
int progress_func(void *ptr, double t, double d, double ultotal, double ulnow)
{
if(t == 0) {
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), 0);
return 0;
}
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), d/t);
while(gtk_events_pending())
gtk_main_iteration();
return 0;
}
static size_t write_data(void* data, size_t size, size_t nmemb, void* file_stream)
{
size_t written = fwrite(data, size, nmemb, file_stream);
return written;
}
//LibCurl download function
void *download(void *ptr)
{
if (new_handle) {
curl_easy_perform(new_handle);
curl_easy_cleanup(new_handle);
}
thread_running = 0;
return NULL;
}
//Start download function
void start_download(GtkWidget *widget, gpointer data)
{
if(thread_running)
return;
thread_running = 1;
if(pthread_create(&thread, NULL, download, NULL)) {
fprintf(stderr, "Error creating thread\n");
thread_running = 0;
return;
}
pthread_join(thread, NULL);
}
void *progressDialog() {
gtk_init(NULL, NULL);
//Create window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "LibCurl Download Progress Bar");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 50);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
//Create progress bar
progress_bar = gtk_progress_bar_new();
gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(progress_bar), TRUE);
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), "Downloading");
//Create container for the window
GtkWidget *main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add(GTK_CONTAINER(window), main_box);
gtk_box_pack_start(GTK_BOX(main_box), progress_bar, FALSE, FALSE, 0);
gtk_widget_show_all(window);
start_download(window, NULL);
//gtk_main();
}
int downloadFile(char *download_url, char *output_path) {
new_handle = curl_easy_init();
curl_easy_setopt(new_handle, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(new_handle, CURLOPT_URL, download_url);
curl_easy_setopt(new_handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(new_handle, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(new_handle, CURLOPT_PROGRESSFUNCTION, progress_func);
curl_easy_setopt(new_handle, CURLOPT_PROGRESSDATA, progress_bar);
FILE* output_file = fopen(output_path, "wb");
if (!output_file) {
fprintf(stderr, "Error: The file \"%s\" couldn't be opened. Will exit now.\n", output_path);
exit(EXIT_FAILURE);
}
printf("Downloading file \"%s\".\n", download_url);
struct PathFileStruct* struct_to_save = malloc(sizeof(struct PathFileStruct));
struct_to_save->file_path = malloc(strlen(output_path) + 1);
strcpy(struct_to_save->file_path, output_path);
struct_to_save->file_pointer = output_file;
curl_easy_setopt(new_handle, CURLOPT_WRITEDATA, output_file);
curl_easy_setopt(new_handle, CURLOPT_PRIVATE, struct_to_save);
pthread_t inputTimer;
pthread_create(&inputTimer, NULL, &progressDialog, NULL);
pthread_join(inputTimer, NULL);
return 0;
}

The name is not activable on g_dbus_proxy_call_sync

On a GNOME Xorg session, to get the return value of method GetIdletime exposed on DBus, you can either use
$ dbus-send --print-reply --dest=org.gnome.Mutter.IdleMonitor /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime
or
$ gdbus call --session --dest org.gnome.Mutter.IdleMonitor --object-path /org/gnome/Mutter/IdleMonitor/Core --method org.gnome.Mutter.IdleMonitor.GetIdletime
I need to retrieve this value by using GDBus API, so I wrote the following code
/*
* Compile with:
* gcc -Wall print_user_idle_time-gnome.c -o print_user_idle_time-gnome `pkg-config --libs gio-2.0 --cflags`
*/
#include <gio/gio.h>
static void
print_user_idle_time (GDBusProxy *proxy)
{
guint64 user_idle_time;
gchar *method = "GetIdletime";
GError *error = NULL;
GVariant *ret = NULL;
ret = g_dbus_proxy_call_sync(proxy,
method,
NULL,
G_DBUS_CALL_FLAGS_NONE, -1,
NULL, &error);
if (!ret) {
g_dbus_error_strip_remote_error (error);
g_print ("GetIdletime failed: %s\n", error->message);
g_error_free (error);
return;
}
user_idle_time = g_variant_get_uint64 (ret);
g_print("%lu\n", user_idle_time);
g_variant_unref (ret);
}
int
main (int argc, char *argv[])
{
GDBusProxy *proxy = NULL;
gchar *name = "org.gnome.Mutter.IdleMonitor";
gchar *object_path = "/org/gnome/Mutter/IdleMonitor/Core";
gchar *interface_name = "org.gnome.Mutter.IdleMonitor";
/* Create a D-Bus proxy */
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
name,
object_path,
interface_name,
NULL, NULL);
g_assert (proxy != NULL);
print_user_idle_time (proxy);
g_object_unref (proxy);
return 0;
}
But when I run it I get error GetIdletime failed: The name is not activable. What is wrong? Thank you
org.gnome.Mutter.IdleMonitor is on the session bus, not the system bus; so you need to use G_BUS_TYPE_SESSION.

How does a method get called using C, after the dbus-send command is issued?

I'm learning how to use D-Bus on C with GLib. So far I've created a D-Bus service which calls my application, and I get a response after using the 'dbus-send' command. I have two files, one with the D-Bus code and one with the functions to call. The 'test_method_start' function lets us know that it has been called successfully, and creates a new thread. The second funtion tells us that we are stopping, and exits the thread.
I'm obviously missing something out, because I'm not seeing the result of the function calls. Can anyone tell me where I'm going wrong? I'm referring to the example here.
Here's the code snippets:
File1.c:
void test_method_start()
{
printf("Test method started\n")``;
//syslog(LOG_NOTICE, "Test method started\n");
if (!(pthread_create(&socketServerThread, NULL,
socketServerLoop, &socketServerParam)))
{
printf("Socket Server thread created successfully\n");
}
else
fprintf(stderr, "Error creating Socket Server thread\n");
pthread_exit(NULL);
}
void test_method_stop()
{
printf("Test method ended\n");
pthread_exit(NULL);
}
File2.c:
/*
* dbusClient
*/
/** Headers **/
#include "dbusClient.h"
#include <glib.h>
#include <gio/gio.h>
#include <gio/gioerror.h>
#include <gio/gdbuserror.h>
#include <stdlib.h>
#include <stdio.h>
/** Function Predeclarations **/
/** Globals **/
/** The service name on the bus. **/
static const gchar service[] = "org.test.DBusClient";
/** The object we publish on the bus. **/
static const gchar object_path[] = "/org/test/DBusObject";
/** Introspection data for the one object, in the internal form. **/
static GDBusNodeInfo *introspection_data = NULL;
/** Introspection data for the one object in XML form **/
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.test.DBusClientInterface'>"
" <method name='test_method_start'>"
" <arg type='s' name='message' direction='in'/>"
" <arg type='s' name='response' direction='out'/>"
" </method>"
" <method name='test_method_stop'>"
" <arg type='s' name='message' direction='in'/>"
" <arg type='s' name='response' direction='out'/>"
" </method>"
" </interface>"
"</node>";
/** Object Callbacks **/
/* Handle a request for a property */
static GVariant *handle_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
printf("handle_get_property\n");
/* Print an optional log message */
#ifdef VERBOSE
fprintf (stderr, "[server 0] "
"handle_get_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n",
connection, sender, object_path, interface_name, property_name,
user_data);
#endif
/* We currently don't have any properties,
so this should be an error. */
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"[server 0] Invalid property '%s'",
property_name);
// And we're done
return NULL;
} // handle_get_property
/* Handle a call to a method */
static void handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
printf("handle_method_call\n");
#ifdef VERBOSE
gchar *paramstr = g_variant_print (parameters, TRUE);
fprintf (stderr, "[server 0] "
"handle_method_call (%p,\"%s\",\"%s\",\"%s\",\"%s",
\"\",invocation),%p)\n",
connection, sender, object_path, interface_name, method_name,
paramstr, user_data);
g_free (paramstr);
#endif
/* Default: No such method */
if (g_strcmp0 (method_name, "test_method_start") == 0)
{
const gchar *greeting;
g_variant_get (parameters, "(&s)", &greeting);
if (g_strcmp0 (greeting, "Return Unregistered") == 0)
{
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"As requested, here's a GError not registered
(G_IO_ERROR_FAILED_HANDLED)");
}
else if (g_strcmp0 (greeting, "Return Registered") == 0)
{
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
"As requested, here's a GError that is
registered
(G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
}
else if (g_strcmp0 (greeting, "Return Raw") == 0)
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.gtk.GDBus.SomeErrorName",
"As requested, here's a raw D-Bus error");
}
else
{
gchar *response;
response = g_strdup_printf ("You greeted me with '%s'.
Thanks!", greeting);
g_dbus_method_invocation_return_value
(invocation,
g_variant_new ("(s)", response));
g_free (response);
}
}
else if (g_strcmp0 (method_name, "test_method_stop") == 0)
{
const gchar *greeting;
g_variant_get (parameters, "(&s)", &greeting);
if (g_strcmp0 (greeting, "Return Unregistered") == 0)
{
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"As requested, here's a GError not registered
(G_IO_ERROR_FAILED_HANDLED)");
}
else if (g_strcmp0 (greeting, "Return Registered") == 0)
{
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
"As requested, here's a GError that is registered
(G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
}
else if (g_strcmp0 (greeting, "Return Raw") == 0)
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.gtk.GDBus.SomeErrorName",
"As requested, here's a raw D-Bus error");
}
else
{
gchar *response;
response = g_strdup_printf ("You greeted me with
'%s'.Thanks!", greeting);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", response));
g_free (response);
}
}
else
{
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
"[server 0] Invalid method: '%s'",
method_name);
}
} // handle_method_call
/* Handle a request to set a property. */
static gboolean handle_set_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GVariant *value,
GError **error,
gpointer user_data)
{
printf("handle_set_property\n");
/* Print an optional log message */
#ifdef VERBOSE
gchar *valstr = g_variant_print (value, TRUE);
fprintf (stderr, "[server 0] "
"handle_set_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",
\"%s\",(error),%p)\n",
connection, sender, object_path,
interface_name, property_name,
valstr, user_data);
g_free (valstr);
#endif
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"[server 0] No such property: '%s'",
property_name);
return 0;
} // handle_set_property
/** Bus Callbacks **/
/* When the bus gets acquired... */
static void on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
printf("on_bus_acquired\n");
static GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
handle_get_property,
handle_set_property
};
guint registration_id;
// GError *error = NULL;
// An optional notification
#ifdef VERBOSE
fprintf (stderr, "[server 0] on_bus_acquired (%p, \"%s\", %p)\n",
connection, name, user_data);
#endif
registration_id = g_dbus_connection_register_object (connection,
object_path,
introspection_data->interfaces[0],
&interface_vtable,
NULL, // Optional user data
NULL, // Func. for freeing user data
NULL); // GError
// Check to see whether or not the call succeeded.
printf("g_assert registration_id = %d\n", registration_id);
g_assert (registration_id > 0);
} // on_bus_acquired
static void on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
// An optional notification
#ifdef VERBOSE
fprintf (stderr, "[server 0] on_name_acquired (%p, \"%s\", %p)\n",
connection, name, user_data);
#endif
} // on_name_acquired
static void on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
// An optional notification
#ifdef VERBOSE
fprintf (stderr, "[server 0] on_name_lost (%p, \"%s\", %p)\n",
connection, name, user_data);
#endif
// Things seem to have gone badly wrong, so give up
exit (1);
} // on_name_lost
/** Main **/
void *dbusLoop(void *dbusParam)
{
guint owner_id;
GMainLoop *loop;
printf("Reached dbusLoop\n");
// Build an internal representation of the interface
printf("Register the object\n");
introspection_data = g_dbus_node_info_new_for_xml
(introspection_xml, NULL);
g_assert (introspection_data != NULL);
// Request the name on the bus
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
service,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
// Start the main loop
printf("Start the loop\n");
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
// Tell the bus that we're done with the name
printf("Release the owner_id\n");
g_bus_unown_name (owner_id);
// Clean up after ourselves
g_dbus_node_info_unref (introspection_data);
//Exit and join main thread
pthread_exit(NULL);
} // main
My command line statement is:
dbus-send --session --print-reply --type=method_call --dest=org.test.DBusClient /org/test/DBusObject org.test.DBusClientInterface.test_method_start string:"Hello"
and the response is:
method return sender=:1.364 -> dest=:1.376 reply_serial=2
string "You greeted me with 'Hello'. Thanks!"
What should I be doing now to get "test_method_start" to run?
Thanks for any help.
You should not be calling pthread_exit on a thread you didn't start. test_method_start is called by a thread created by someone else.
How do you expect test_method_start to be called when you never call it anywhere or take its address? There is no magic to DBUS; you have to call it from handle_method_call if you want it to be called. You seem to have the code to check if the method name is "test_method_start", so you would call it inside that if.

Is there a way to check if someone listens to dbus signal?

Is there a way to check for listening clients in DBus?
Is it even possible to do? I'm using gdbus.
Background
I'm creating service which interfaces with serial ports and I want to implicitly open serial ports if someone is listening and automatically close it if last client disconnects. I could do it with open/close methods but there is risk that one client closes connection when other is still listening.
Another solution to my problem would be connection counting, but there is also risk that client forgets to close port or crashes.
Do you have any other idea how to implement this?
My code (shortened)
Based on:
https://github.com/bratsche/glib/blob/master/gio/tests/gdbus-example-server.c
#include <gio/gio.h>
#include <stdlib.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#endif
/* ---------------------------------------------------------------------------------------------------- */
static GDBusNodeInfo *introspection_data = NULL;
/* Introspection data for the service we are exporting */
static const gchar introspection_xml[] =
"<node>"
" <interface name='info.skorepa.serial.port'>"
" <signal name='DataRecieved'>"
" <arg type='ay' name='data'/>"
" </signal>"
" </interface>"
"</node>";
/* ---------------------------------------------------------------------------------------------------- */
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
// nothing - signal only
}
static GVariant *
handle_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
// nothing - signal only
}
static gboolean
handle_set_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GVariant *value,
GError **error,
gpointer user_data)
{
// nothing - no properties
}
/* for now */
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
handle_get_property,
handle_set_property
};
/* ---------------------------------------------------------------------------------------------------- */
// Here I emit signal - for now I just emit every 2 seconds
static gboolean
on_timeout_cb (gpointer user_data)
{
GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
GVariantBuilder *builder;
GVariantBuilder *invalidated_builder;
GError *error;
error = NULL;
printf("Constructing array\n");
builder = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
printf("Adding 65\n");
g_variant_builder_add (builder,
"y",
65);
printf("Adding 66\n");
g_variant_builder_add (builder,
"y",
66);
printf("Emitting signal\n");
g_dbus_connection_emit_signal (connection,
NULL,
"/info/skorepa/TestObject",
"info.skorepa.serial.port",
"DataRecieved",
g_variant_new ("(ay)",
builder),
&error);
printf("Checking for errors\n");
g_assert_no_error (error);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
guint registration_id;
registration_id = g_dbus_connection_register_object (connection,
"/info/skorepa/TestObject",
introspection_data->interfaces[0],
&interface_vtable,
NULL, /* user_data */
NULL, /* user_data_free_func */
NULL); /* GError** */
g_assert (registration_id > 0);
/* swap value of properties Foo and Bar every two seconds */
g_timeout_add_seconds (2,
on_timeout_cb,
connection);
}
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
exit (1);
}
int
main (int argc, char *argv[])
{
guint owner_id;
GMainLoop *loop;
g_type_init ();
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
g_assert (introspection_data != NULL);
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
"info.skorepa.serial",
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_bus_unown_name (owner_id);
g_dbus_node_info_unref (introspection_data);
return 0;
}
Compiled using:
gcc signal-sample.c `pkg-config --cflags --libs glib-2.0 gio-2.0` -o test
Thank you
Is there a way to check for listening clients in DBus?
No, it is not possible, due to the way D-Bus is designed.
When a client wants to subscribe to a signal, they send an AddMatch method call to the D-Bus daemon, which registers that state internally. When your service emits a signal, it sends the signal to the D-Bus daemon, which then forwards it to the clients who have subscribed to that signal (subject to various policy rules about broadcasts and permissions). Your service can’t know about the internal subscription state in the D-Bus daemon.
The pattern for handling this kind of thing is for your service to explicitly expose a subscribe or open method which clients must call in order to open a serial port. You can have a second method for closing the serial port when the client is done with it; and you can also listen for client disconnections to close the ports automatically. (In GDBus, this is done using g_bus_watch_name() and passing it the unique name of the client, which looks something like :1.5.)

g_io_channel + socket = client, and GIO not work properly

dude here im gonna create client and combine with GIO Channel, and after i put it all together, it seems appears to work on socket, but the g_io_channel not as watching, like crashing or such..
please see following code :
#include <stdio.h>
#include <gio/gio.h> // g_timeout_add
#include <gtk/gtk.h> // gtk
#include <netinet/in.h> //sockaddr_in
#include <sys/socket.h> // socket();
#include <arpa/inet.h> // inet_addr();
#include <string.h> // memset();
struct dada
{
gint id_sock;
guint id_gio_watch;
};
gboolean incoming(GIOChannel *chan, GIOCondition condition, struct dada *didi )
{
int byte;
int insock = g_io_channel_unix_get_fd(chan);
#define MAXMAX 128
char buff[128];
printf("sock : %d\n",insock);
byte = recv(insock,buff,MAXMAX-1,0);
if(byte <= 0)
{
perror("recv");
close(didi->id_sock);
g_source_remove(didi->id_gio_watch);
return FALSE;
}
else
{
buff[byte] = '\0';
printf("coming : %s",buff);
}
return TRUE;
}
// gtk area
void hello(GtkWidget *widget, gpointer data)
{
g_print("Haii world %s\n", (char *)data);
}
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print("a delete event has been occured properly :D\n");
return(0);
}
void destroy(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
// end of gtk area
int main(int argc, char **argv)
{
//gtk bussines from here
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
button = gtk_button_new_with_label("ohayo");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(hello), (gpointer)"hha" );
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
gtk_container_add(GTK_CONTAINER(window),button);
gtk_widget_show(button);
gtk_widget_show(window);
//gtk bussiness done here...
// network code //
struct dada didi;
memset(&didi,0,sizeof(didi));
struct sockaddr_in my; // set my network device info
gint rootsock; // handle the root socket
//socket
rootsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//binding
memset(&my,0,sizeof(my));
my.sin_addr.s_addr = inet_addr("127.0.0.1");
my.sin_family = AF_INET;
my.sin_port = htons(1111);
//bind(rootsock,(struct sockaddr*)&my,sizeof(my));
printf("sock : %d\n",rootsock);
connect(rootsock,(struct sockaddr*)&my,sizeof(my));
didi.id_sock = rootsock;
didi.id_gio_watch = g_io_add_watch(g_io_channel_unix_new(didi.id_sock),G_IO_IN|G_IO_OUT,(GIOFunc)incoming,&didi);
// network code //
gtk_main();
return 0;
}
compiling :
$ gcc -o konek_gioglib konek_gioglib.c `pkg-config glib-2.0 --libs --cflags gtk+-2.0`
my own pc run as server with port 1111 and stream connection ( TCP ) :
$ nc -v -l 1111
running my app :
$ ./konek_gioglib
sock : 6
sock : 6
server got connection and send some word :
$ nc -v -l 1111
Connection from 127.0.0.1 port 1111 [tcp/*] accepted
a
a
and when the server send something, gtk window show but with error like these :
is there anyone dont mind to explain, why these things could happened to mine ?
well last night I brainstormed myself with my own heart, and finally could make these thing work,
here the proper code
#include <stdio.h>
#include <gio/gio.h> // g_timeout_add
#include <gtk/gtk.h> // gtk
#include <netinet/in.h> //sockaddr_in
#include <sys/socket.h> // socket();
#include <arpa/inet.h> // inet_addr();
#include <string.h> // memset();
#include <fcntl.h>
#include <stdlib.h>
struct dada
{
gint id_sock;
guint id_gio_connect;
guint id_gio_watch;
};
gboolean readdata(GIOChannel *chan,GIOCondition condition, struct dada *didi)
{
gchar dada[20] = {0};
int dadaz =0;
if( condition != G_IO_IN )
return FALSE;
if(dadaz = recv(g_io_channel_unix_get_fd(chan),dada,19,0)<=0)
{
perror("recv");
close(didi->id_sock);
g_source_remove(didi->id_gio_connect);
g_source_remove(didi->id_gio_watch);
exit(0);
return FALSE;
}
printf("data in : %s\n",dada);
return TRUE;
}
gboolean incoming(GIOChannel *chan, GIOCondition condition, struct dada *didi )
{
if( condition & G_IO_ERR || condition & G_IO_HUP )
return FALSE;
didi->id_gio_watch = g_io_add_watch(chan,G_IO_IN | G_IO_ERR | G_IO_HUP,(GIOFunc)readdata,didi);
return FALSE;
}
// gtk area
void hello(GtkWidget *widget, gpointer data)
{
g_print("Haii world %s\n", (char *)data);
}
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print("a delete event has been occured properly :D\n");
return(0);
}
void destroy(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
// end of gtk area
int main(int argc, char **argv)
{
//gtk bussines from here
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
button = gtk_button_new_with_label("ohayo");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(hello), (gpointer)"hha" );
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
gtk_container_add(GTK_CONTAINER(window),button);
gtk_widget_show(button);
gtk_widget_show(window);
//gtk bussiness done here...
// network code //
struct dada didi;
memset(&didi,0,sizeof(didi));
struct sockaddr_in your; // set my network device info
gint rootsock; // handle the root socket
//socket
rootsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
memset(&your,0,sizeof(your));
printf("sock : %d\n",rootsock);
your.sin_family = AF_INET;
your.sin_addr.s_addr = inet_addr("127.0.0.1");
your.sin_port = htons(1111);
connect(rootsock,(struct sockaddr*)&your,sizeof(your));
didi.id_sock = rootsock;
didi.id_gio_connect = g_io_add_watch(g_io_channel_unix_new(didi.id_sock),G_IO_IN | G_IO_OUT | G_IO_ERR | G_IO_HUP,(GIOFunc)incoming,&didi);
// network code //
gtk_main();
return 0;
}
and the only different had made is the "worked" code , need :
- gio for connecting, and gio for watching
instead of be "non-worked" code ( only gio for connecting ), but again i just wondering "why", why on connect() need two gio (recursively) in order make these "gio things" work,
these is really odd, if I see back then on g_io_channel + socket = server , still just get one client ? in C language
which on accept() just need only one gio and only for watching.
if someone could explain these, how great it'll be :)

Resources