lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
440 stars 70 forks source link

Problems with g_socket_create_source #266

Closed w-oertl closed 3 years ago

w-oertl commented 3 years ago

For an application I need a portable way to create a GSource for a GSocket. Unfortunately, I only get nil (Linux, Debian, GLib version 2.66.8):

#! /usr/bin/env lua5.3

local lgi = require 'lgi'
local Gio, GLib = lgi.Gio, lgi.GLib

local sock = Gio.Socket.new(Gio.SocketFamily.IPV4, Gio.SocketType.STREAM,
  Gio.SocketProtocol.TCP)
local source = sock:create_source(GLib.IOCondition.IN)
print(source) -- nil

Am I missing something? Is there a bug? Can I get an error message somehow? I'm stuck at this point. Thanks!

psychon commented 3 years ago

Huh. Weird.

Adding print(sock.create_source) prints lgi.fun (0x7fa68a143470): Gio.DatagramBased.create_source. This is the first time that I hear about this datagram based stuff. And this is exactly the problem.

The implementation of this interface eventually ends up here:

static GSource *
g_socket_datagram_based_create_source (GDatagramBased  *self,
                                       GIOCondition     condition,
                                       GCancellable    *cancellable)
{
  if (!check_datagram_based (self, NULL))
    return NULL;

  return g_socket_create_source (G_SOCKET (self), condition, cancellable);
}

Let's see if you can spot where the nil comes from... ;-)

Anyway, I don't think you can call g_socket_create_source() through LGI. And it is not even LGI's fault.

At the bottom of https://developer.gnome.org/gio/stable/GSocket.html#g-socket-create-source, there is a small [skip] with a mouse over text saying "Exposed in C code, not necessarily available in other languages". Just because they wrote [skip] means that gobject-introspection silently skips this function. Thus, since LGI does not know about this function, it cannot provide bindings to it. Sorry.

w-oertl commented 3 years ago

Well spotted! You explain it clearly. This is the only g_socket_xxx function with this "skip" tag, which I have completely overlooked. Now I've devised a workaround:

local fd = sock:get_fd()
local channel = GLib.IOChannel.unix_new(fd)
GLib.io_add_watch(channel, 0, { GLib.IOCondition.IN },
    function(source, condition, user_data)
    -- do something
    end)

This works only for unix file descriptors, of course. For Windows, I'll try GLib.IOChannel.win32_new_socket(fd) and hope it works, too.