Windows g_socket_create_source problem

View: New views
3 Messages — Rating Filter:   Alert me  

Windows g_socket_create_source problem

by Daan Nusman :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi everyone.

I am having some trouble combining Lua Sockets with GTK+. I'm interested
in integrating waiting for socket events in the main event loop, which
means using a GSocket-type GSource.

I think I am on the right track: I'm creating a Lua Socket, getting the
file descriptor (which is a normal fd/SOCKET), create a new GSocket
using g_socket_create_source, and attaching a callback that should fire
on data available on the socket.

The problem is that once the callback fires (i.e., when I send something
to the socket), it keeps on firing like craaayzaay, even if no data is
present on the socket. This means that the second time the callback is
called, the blocking socket will block the main thread. If I return
FALSE instead of TRUE from the callback, the first event is received
correctly, the gsource is cleaned up, but of course no other events will
be received after that.

Am I missing something or have I hit some winsock-related bug? This is
my first foray into GTK+/GLib territory, so one might never know :)

I'm using the GTK+ Windows binaries found at gtk.org (GLib 2.22.2).

Thanks,
Daan Nusman



PS. here's some source code. The addSocket function is called from Lua with
the file descriptor of the socket as argument.

//================================================
// GTK+ networking bridge


// data associated with GSource callback
struct LuaSocketData
{
    lua_State* L;       // the lua state that owns the callback function
    int m_CallbackRef;  // this is a reference to a Lua function
};

// destroys the LuaSocketData (assumes lua state still exists..)
static void LuaSocketData_destroy(gpointer data)
{
    LuaSocketData* luaSocket = (LuaSocketData*)data;
    luaL_unref(luaSocket->L, LUA_REGISTRYINDEX, luaSocket->m_CallbackRef);
}


// called when new data (or error) arrives on a Lua Socket.
gboolean __cdecl onLuaSocketReady(GSocket *socket,
                                  GIOCondition condition,  gpointer
user_data)
{
    LuaSocketData* luaSocket = (LuaSocketData*)user_data;
    lua_State* L = luaSocket->L;

    if(condition == G_IO_IN)
    {
        printf("callback to lref#%d\n", luaSocket->m_CallbackRef);
        lua_getref(L, luaSocket->m_CallbackRef);

        // this calls Lua, which does a recv on the socket.
        if(lua_pcall(L, 0, 0, 0))
        {
            printf("callback error: %s\n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
    }
    else
    {
        __asm int 3 //DebugBreak();  TODO
    }

    return TRUE;   // continue receiving events
}


/*
Lua function that inserts a socket into the GTK+ event loop.

Lua params:
    - 1) socket fd  (use mySocket:getfd())
    - 2) callback function, to be called when new data is available on
the socket
*/
static int addSocket(lua_State* L)
{
    int sockFD = luaL_checkint(L, 1);

    // what condition to call the callback on
    GIOCondition condition = G_IO_IN;

    // create new socket from the lua socket/fd
    GError* err = 0;
    GSocket* gSock = g_socket_new_from_fd(sockFD, &err);
    if(err) luaL_error(L, "%s", err->message);  // fixme: memleak

    // Insert notifications into message loop,
    // with special user data remembering the callback.
    GSource* socketMessageSource =
        g_socket_create_source(gSock, condition, NULL);
    LuaSocketData* luasocketdata =
        (LuaSocketData*)g_malloc(sizeof(LuaSocketData));
    lua_pushvalue(L, 2);    
    luasocketdata->m_CallbackRef =
        luaL_ref(L, LUA_REGISTRYINDEX); // store function
    luasocketdata->L = lua_getmainthreadstate(L);

    g_source_set_callback (socketMessageSource,
        (GSourceFunc) onLuaSocketReady,
        luasocketdata, g_free);
    g_source_attach (socketMessageSource, NULL);  // add source to "main
context"
    g_source_unref (socketMessageSource);

    return 0;
}



_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@...
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Windows g_socket_create_source problem

by Tor Lillqvist :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> I think I am on the right track: I'm creating a Lua Socket, getting the file
> descriptor (which is a normal fd/SOCKET), create a new GSocket using
> g_socket_create_source, and attaching a callback that should fire on data
> available on the socket.

Please note that the GSocket API is quite new, and it is possible you
are the first person to ever try it seriously on Windows. Problems are
to be expected. Then throw in a weird language biinding in the mix
(which might, or might not, be partly to blame), and the number of
people able to help you goes way down. You should file a bug, and
attach a *minimal* but *complete* free-standing sample program in
plain C (i.e. no Lua stuff).

--tml

P.S. Does the gtk-win32-list still exist? I thought the consensus was
that it is unnecessary and can be dropped.
_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@...
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Windows g_socket_create_source problem

by Daan Nusman :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Tor,

thanks for your speedy reply.

Tor Lillqvist wrote:

>> I think I am on the right track: I'm creating a Lua Socket, getting the file
>> descriptor (which is a normal fd/SOCKET), create a new GSocket using
>> g_socket_create_source, and attaching a callback that should fire on data
>> available on the socket.
>>    
>
> Please note that the GSocket API is quite new, and it is possible you
> are the first person to ever try it seriously on Windows. Problems are
> to be expected. Then throw in a weird language biinding in the mix
> (which might, or might not, be partly to blame), and the number of
> people able to help you goes way down. You should file a bug, and
> attach a *minimal* but *complete* free-standing sample program in
> plain C (i.e. no Lua stuff).
>  
I've followed your advice, and in the process created a test app that
can run using both native GSocket sockets and low-level sockets. The
GSocket sockets work! However the low-level sockets (and, by extension,
all sockets from other socket libraries) do not. I have a feeling that
this is because of the

win32_unset_event_mask (socket, FD_READ);

call in g_socket_receive() in gsocket.c(1651).

However, I cannot call that function from my own code because it is
private to GSocket. Windows itself automatically resets the associated
windows event handle selected with WSAEventSelect when recv is called,
so that should not be the problem.

A solution might be to clear those GSocket flags after the callback has
returned instead of the g_socket_receive function?

For now, I think I will just use the GSocket recv and pass that data on
to Lua, instead of having Lua do the recv call.


Anyway, the test app can be found here:  
http://matrix.re-lion.com/temp/main.cpp
It waits for UDP messages on port 26632. I've only tested/ran it under
Windows. It has these options:

#define USE_GSOCKET_FOR_RECV      0
#define USE_GSOCKET_NEW           1
// setting USE_GSOCKET_FOR_RECV to 0 and USE_GSOCKET_NEW to 1 causes a
low-level recv() to be used on a GSocket (does not work)
// setting USE_GSOCKET_FOR_RECV to 1 and USE_GSOCKET_NEW to 0 causes a
g_socket_new_from_fd to be created and a g_socket_receive for receiving
(works!)
// setting USE_GSOCKET_FOR_RECV to 0 and USE_GSOCKET_NEW to 0 causes a
g_socket_new_from_fd to be created and low-level recv(does not work)
(this would be the main case for using other socket libs)
// setting USE_GSOCKET_FOR_RECV to 1 and USE_GSOCKET_NEW to 1 results in
an all-GLib socket implementation (works)

Presumably, all combinations do work under Linux?
The output for the non-working cases is:
--------------
Send a UDP message to localhost:26632 or do a UDP broadcast...
callback! condition: 1. got data: 114 bytes: FEAR ME FOR I AM A UDP PACKET
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
callback! condition: 1. WSA error: 10035
...etc
--------------
(WSA error 10035 is WSAEWOULDBLOCK)

>
> P.S. Does the gtk-win32-list still exist? I thought the consensus was
> that it is unnecessary and can be dropped.
>
>  
No idea, it's still there on the site
(http://mail.gnome.org/mailman/listinfo/gtk-win32-list) though. I'll
just remove it from the Cc list then.

Thanks for your time,
Daan

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@...
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list