You are not logged in.

#1 2010-05-30 18:03:20

vkumar
Member
Registered: 2008-10-06
Posts: 166

First time with GLib & GIO: errors with GSocketService and friends

Hi,

I'm trying to become familiar with GLib and GIO because they seem like time-saving libraries. I'm working on an asynchronous UDP server, but I keep getting assertion failures and odd errors. I don't understand Glib signals, the class system, or subclassing so I'm sort of blind. Here's my code and the error I'm getting -- please let me know how I can fix it. Thanks;

#include <glib.h>
#include <gio/gio.h>
#include <stdint.h>

#define AUS_PORT    8080

static GInetAddress* get_localhost() {
    /* No clean way to handle IPV6, short of guess/check */
    GInetAddress* tmp = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
    if (!tmp) {
        tmp = g_inet_address_new_any(G_SOCKET_FAMILY_IPV6);
    }
    return tmp;
}

gboolean pseudo_blocking_fn(GThreadedSocketService *service,
            GSocketConnection *connection, GObject *source_object,
            gpointer user_data)
{
    uint64_t* conns = user_data;
    *conns += 1;
    g_print("Connection: %lu\n", *conns);
    return FALSE;    /* TRUE prevents signal handlers from being called */
}

int main() {
    g_type_init();    /* Apparently this is needed to use the type system */
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
    
    GSocketService* tgss = g_threaded_socket_service_new(16);
    GInetAddress* inet_addr = get_localhost();
    GSocketAddress* gsa = g_inet_socket_address_new(inet_addr, AUS_PORT);
    
    GError* err;
    GSocketAddress* effective_addr;
    if (!g_socket_listener_add_address(G_SOCKET_LISTENER(tgss),
        gsa, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL,
        &effective_addr, &err))
    {
        g_print("%s\n", err->message);
        return 1;
    }
    
    uint64_t conns = 0;
    g_signal_connect(tgss, "incoming", (GCallback) pseudo_blocking_fn, &conns);
    g_socket_service_start(tgss);
    
    g_main_loop_run(loop);
    g_main_loop_unref(loop);
    
    return 1;
}

[Desktop] $ gcc -O2 -Wall `pkg-config --libs --cflags gio-2.0` async-udp-server.c -o aus
[Desktop] $ ./aus
could not listen: Operation not supported

edit:
Using G_SOCKET_TYPE_STREAM and G_SOCKET_PROTOCOL_TCP makes g_socket_listener_add_address() successful, but the callback isn't run when I attempt to connect to the server. It's all very mysterious... (I tried TCP because gio appears to be using listen(), instead of recv().)
edit #2:
I've updated the code listing with the fixes.

Last edited by vkumar (2010-06-02 19:03:34)


div curl F = 0

Offline

#2 2010-06-01 12:12:56

PirateJonno
Forum Fellow
From: New Zealand
Registered: 2009-04-13
Posts: 372

Re: First time with GLib & GIO: errors with GSocketService and friends

I got it to work with 2 changes:
change g_inet_address_new_loopback to g_inet_address_new_any (or something else)
add a main loop, like this, roughly:

GMainLoop* loop = g_main_loop_new(NULL, FALSE);
...
g_main_loop_run(loop);
g_main_loop_unref(loop);

and remove the while loop.

I also have a few suggestions:
rename your async_callback to something else (async has a special meaning in GIO)
you might want to consider using GLib code conventions, which are basically what you've got but with spaces between function names and parameters.
also, you should change the C-style cast (GSocketListener*) to the GLib cast G_SOCKET_LISTENER(tgss)

Hope this helps


"You can watch for your administrator to install the latest kernel with watch uname -r" - From the watch man page

Offline

#3 2010-06-02 19:11:40

vkumar
Member
Registered: 2008-10-06
Posts: 166

Re: First time with GLib & GIO: errors with GSocketService and friends

Thanks, PirateJonno! I was able to get this program to work over TCP. I've updated the code listing above.

Unfortunately, the socket service isn't playing nice with UDP. I managed to use libevent and my own utility library to do what I wanted (with less code, ironically enough). Here's my version;

#include <event.h>
#include <cc/utils.h>
#define PORT    8080

void server(struct bufferevent* be, void* arg) {
    u64* conns = arg;
    *conns += 1;
    printf("Connection: %lu\n", *conns);
}

int main() {
    int sock = bsd_server(PORT, SOCK_DGRAM, NULL);
    event_init();
    u64 conns = 0;
    struct bufferevent* be = bufferevent_new(sock, server, NULL, NULL, &conns);
    bufferevent_enable(be, EV_READ);
    event_dispatch();
    return 0;
}

I wrote a small packet flood program to test the two servers (libevent+UDP and GIO+TCP);

[bin] $ flooder -d -p 8080 -t 8 -f 128 -m "Hello, world."
UDP Flood: on port 8080, with 8 thread(s) [each processing 16 frame(s)].
[bin] $ flooder -s -p 8080 -t 8 -f 128 -m "Hello, world."
TCP Flood: on port 8080, with 8 thread(s) [each processing 16 frame(s)].

The UDP-based server consistently responds to around 118 (out of 128) packets, whereas the TCP one responds to around 123.

Last edited by vkumar (2010-06-03 02:55:36)


div curl F = 0

Offline

#4 2010-06-03 06:02:09

PirateJonno
Forum Fellow
From: New Zealand
Registered: 2009-04-13
Posts: 372

Re: First time with GLib & GIO: errors with GSocketService and friends

Happy to help. I'm not sure where to go from there, but maybe GIO isn't the best solution for socket programming (unless you're using Gtk+ or whatever, in which case some consistency would be nice). If you really want to use it, maybe reconsider using g_socket_listener_add_address. I know client-side UDP is quite different to TCP, but I'm not sure what happens on the server side.


"You can watch for your administrator to install the latest kernel with watch uname -r" - From the watch man page

Offline

Board footer

Powered by FluxBB