Re: GVariant support for Unix fds (Was Re: GDBus/GVariant plans for next GLib release)



Hey Ryan,

Sorry for the lag,

On Sat, 2009-10-31 at 17:27 -0400, Ryan Lortie wrote:
> On Tue, 2009-10-20 at 11:17 -0400, David Zeuthen wrote:
> > So how about something like 1. and 2. below? We'd put
> > 
> >  g_dbus_connection_get_handle_for_unix_fd()
> >  g_dbus_connection_set_handle_for_unix_fd()
> 
> I was actually thinking that we could introduce a GDBusFDSet:
> 
> gint g_dbus_fd_set_add_fd (gint fd) {
>   list_of_fds[fd_count] = dup (fd);
>   return fd_count++;
> }
> 
> gint g_dbus_fd_set_get_fd (gint index) {
>   return dup (list_of_fds[index]);
> }
> 
> g_dbus_fd_set_finalize () {
>   foreach (fd in list_of_fds) close (fd);
> }
> 
> You'd add fds to that and get ints back (starting at 0 per the set).
> Then when sending the dbus message you'd give the GVariant and the
> DBusFDSet to the appropriate function.
> 
>   var fd = open("file");
>   var fdset = new FDSet ();
>   var message = new GVariant ("(sh)",
>                               "hello world",
>                               fdset.add_fd (fd));
> 
>   g_dbus_proxy_invoke_with_fds (proxy, "Foo", message, fdset, ...);
> 
> When receiving messages, you get a DBusFDSet handed to you in the event
> that there were file descriptors (or just %NULL in case not).
> 
> The fds held in the GDBusFDSet are closed when the set is finalized.
> There is no doubt about who owns which fd in this case -- and in the
> case you elect to ignore fds that were sent to you then everything is
> still cleaned up properly.

Hmm, I don't like this approach. It means you'd have to pass this
GDBusFDSet object around in code you use to build/parse the GVariant. In
particular, your proposed GTypeSerializer would need support for it.
That's problematic because that one lives in libgobject, not libgio
(where GDBusFDSet would live).

I still think the approach I described works better.

For example, suppose I have a C type mapping that maps a{sh} to a
GHashTable from strings to gint. I'd like to write code like this

 my_hash = g_hash_table_new (g_str_hash, g_str_equal);
 g_hash_table_insert (my_hash,
                      "fd-for-client",
                      GINT_TO_POINTER (fd_for_client));

 /* need to keep fd_for_client alive until we hand off the hash */

 <other code>

 foo_bar_invoke_process_client (proxy, my_hash, <async stuff>); 
 g_hash_table_unref (my_hash);

 /* it's now safe to close the fd, the dbus stuff has already dupped
  * it... note that we could have just used a GDestroyNotify for the
  * values in my_hash to do this.
  */
 close (fd_for_client);

where the latter function represents a generated function for the
ProcessClient() method on the foo.Bar interface that takes a single
a{sh} parameter represented by a GHashTable.

On the receiving end it would look like this. Suppose the GimmeFds
function returns a a{sh}:

 my_hash = foo_bar_invoke_gimme_fds_sync (proxy, cancelable, &error);

 fd = GPOINTER_TO_INT (g_hash_table_lookup (my_hash, "stream1"));
 if (fd > 0)
   {
     fd_for_stream1 = dup (fd);
   }

 /* the value destroy notifier on my_hash closes all fds */
 g_hash_table_unref (my_hash);

 <now use fd_for_stream1 and close it when done>

Thoughts?

Thanks,
David



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]