Author: ArcRiley Date: 2009-01-04 00:03:50 -0500 (Sun, 04 Jan 2009) New Revision: 1417
Modified: trunk/concordance/src/Core.c trunk/concordance/src/Core.h Log: Added basic GMainLoop functionality Modified: trunk/concordance/src/Core.c =================================================================== --- trunk/concordance/src/Core.c 2009-01-04 00:09:52 UTC (rev 1416) +++ trunk/concordance/src/Core.c 2009-01-04 05:03:50 UTC (rev 1417) @@ -26,7 +26,9 @@ #include "Core.h" -static int opensocket(conSocket sock); +static gpointer conCore_loop (gpointer); +static int conCore_listenChannel (conCoreObject*, conSocket*); +static gboolean conCore_listenNew (GIOChannel*, GIOCondition, gpointer); /*\ cdef class Core : \*/ static char conCore_Doc[] = "Test"; @@ -41,6 +43,8 @@ if (self) { self->c2s.sock = -1; self->s2s.sock = -1; + self->context = NULL; + self->mainloop = NULL; } return (PyObject*) self; } @@ -110,31 +114,39 @@ &self->c2s.addr, &self->c2s.port, &self->s2s.addr, &self->s2s.port)) return -1; - - /* open the listening sockets (self->c2s->sock and self->s2s->sock) - Note that these default to -1 and remain -1 on failure, the dealloc - function uses this (if != -1) to close open all sockets. + /* We use a non-default context to avoid conflict with other glib-based + Python packages which may have their own GMainLoop in other threads. - opensocket (see below) will set the Python error message on failure. + GMainContext* g_main_context_new (void); */ - if (!opensocket(self->c2s)) + self->context = g_main_context_new(); + + /* open the listening channels + + Note that the sockets default to -1 and remain -1 on failure, the + dealloc function uses this (if != -1) to close open all sockets. + + listenchannel (see below) will set the Python error message on failure. + */ + if (!conCore_listenChannel(self, &self->c2s)) return -1; - if (!opensocket(self->s2s)) + if (!conCore_listenChannel(self, &self->s2s)) return -1; -/* -#ifdef MS_WINDOWS - sock.chan = g_io_channel_win32_new_socket(sock.sock); -#else - sock.chan = g_io_channel_unix_new(sock.sock); -#endif - g_io_add_watch(sock.chan, G_IO_IN, callback, NULL); -*/ + /* launch GMainLoop thread before returning + GThread* g_thread_create (GThreadFunc func, + gpointer data, + gboolean joinable, + GError **error); + */ + self->thread = g_thread_create((GThreadFunc) conCore_loop, + (gpointer) self, 0, NULL); return 0; } + static void conCore_dealloc(conCoreObject* self) { /*\ cdef : \*/ @@ -146,10 +158,166 @@ PyObject_Del(self); } + + static gpointer + conCore_loop(gpointer s) { /*\ + cdef : \*/ + conCoreObject* self = (conCoreObject*) s; + /* create and run the GMainLoop, terminates thread on g_main_loop_quit() + + GMainLoop* g_main_loop_new (GMainContext *context, + gboolean is_running); + void g_main_loop_run (GMainLoop *loop); + */ + self->mainloop = g_main_loop_new(self->context, 0); + g_main_loop_run(self->mainloop); + return NULL; + } + + + static int + conCore_listenChannel(conCoreObject* self, conSocket* sock) { /*\ + cdef : \*/ + int ret; + struct addrinfo* resinfo = NULL; + GSource* source; + + /* Get address family and struct + + int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res); + getaddrinfo() returns 0 if it succeeds, or non-zero on failure. + */ + ret = getaddrinfo(sock->addr, NULL, NULL, &resinfo); + if (ret != 0) { + switch (ret) { + case EAI_AGAIN : + /* EAI_AGAIN + The name server returned a temporary failure indication. + Try again later. */ + PyErr_SetString(PyExc_OSError, "temporary dns failure"); + case EAI_FAIL : + /* EAI_FAIL + The name server returned a permanent failure indication. */ + PyErr_SetString(PyExc_OSError, "permanent dns failure"); + case EAI_FAMILY : + /* EAI_FAMILY + The requested address family is not supported. */ + PyErr_SetString(PyExc_OSError, "address family not supported"); + case EAI_MEMORY : + /* EAI_MEMORY + Out of memory. */ + PyErr_SetString(PyExc_MemoryError, "out of memory on getaddrinfo"); + case EAI_NODATA : + /* EAI_NODATA + The specified network host exists, but does not have any + network addresses defined. */ + PyErr_SetString(PyExc_AttributeError, "host lacks IP address"); + default : + PyErr_SetString(PyExc_AttributeError, "invalid address/hostname"); + } + return 0; + } + + /* Copy port into sockaddr struct + + uint16_t htons(uint16_t hostshort); + The htons() function converts the unsigned short integer hostshort + from host byte order to network byte order. + */ + ((struct sockaddr_in*) resinfo->ai_addr)->sin_port = htons(sock->port); + + /* Open new socket of the appropriate family (AF_INET or AF_INET6) + + int socket(int domain, int type, int protocol); + */ + sock->sock = socket(resinfo->ai_family, SOCK_STREAM, 0); + + /* If successful continue to bind/listen, else set error message */ + if (sock->sock > -1) { + /* Bind and Listen to opened socket + + int bind(int fd, const struct sockaddr *addr, + socklen_t addrlen); + On success, zero is returned. On error, -1 is returned. + + int listen(int fd, int backlog); + On success, zero is returned. On error, -1 is returned. + */ + if (bind(sock->sock, resinfo->ai_addr, resinfo->ai_addrlen) == 0 && + listen(sock->sock, 16) == 0 ) { + + /* create new channel using an OS-dependent function + + GIOChannel* g_io_channel_win32_new_fd (gint fd); + GIOChannel* g_io_channel_unix_new (gint fd); + */ + #ifdef MS_WINDOWS + sock->chan = g_io_channel_win32_new_socket(sock->sock); + #else + sock->chan = g_io_channel_unix_new(sock->sock); + #endif + + /* add channel to our context watch + + Note that this block is a replacement for g_io_add_watch() which + uses our own context rather than the default context. + + GSource * g_io_create_watch (GIOChannel *channel, + GIOCondition condition); + void g_source_set_callback (GSource *source, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); + guint g_source_attach (GSource *source, + GMainContext *context); + */ + source = g_io_create_watch (sock->chan, G_IO_IN); + g_source_set_callback(source, (GSourceFunc)conCore_listenNew, + (gpointer) self, NULL); + g_source_attach(source, self->context); + ret = 1; + } + else { + PyErr_SetString(PyExc_OSError, "unable to bind listening socket"); + ret = 0; + } + } + else { + PyErr_SetString(PyExc_OSError, "unable to bind listening socket"); + ret = 0; + } + + /* before returning, free the previously created resinfo struct + + void freeaddrinfo(struct addrinfo *res); + */ + if (resinfo) + freeaddrinfo(resinfo); + + return ret; + } + + + static gboolean + conCore_listenNew(GIOChannel* source, GIOCondition condition, + gpointer s) { /*\ + cdef : \*/ + conCoreObject* self = (conCoreObject*) s; + if (source == self->s2s.chan) + printf("new server\n"); + else + printf("new client\n"); + return 1; + } + + static PyMethodDef conCore_methods[] = { { NULL, NULL }, }; + PyTypeObject conCore_Type = { PyVarObject_HEAD_INIT(NULL, 0) "concordance.Core", /*tp_name*/ @@ -194,99 +362,3 @@ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; - - - -/***************************************************************************\ - * Core helper functions */ - -static int opensocket(conSocket sock) { /*\ - cdef : \*/ - int ret; - struct addrinfo* resinfo = NULL; - - /* Get address family and struct - - int getaddrinfo(const char *node, const char *service, - const struct addrinfo *hints, - struct addrinfo **res); - getaddrinfo() returns 0 if it succeeds, or non-zero on failure. - */ - ret = getaddrinfo(sock.addr, NULL, NULL, &resinfo); - if (ret != 0) { - switch (ret) { - case EAI_AGAIN : - /* EAI_AGAIN - The name server returned a temporary failure indication. - Try again later. */ - PyErr_SetString(PyExc_OSError, "temporary dns failure"); - case EAI_FAIL : - /* EAI_FAIL - The name server returned a permanent failure indication. */ - PyErr_SetString(PyExc_OSError, "permanent dns failure"); - case EAI_FAMILY : - /* EAI_FAMILY - The requested address family is not supported. */ - PyErr_SetString(PyExc_OSError, "address family not supported"); - case EAI_MEMORY : - /* EAI_MEMORY - Out of memory. */ - PyErr_SetString(PyExc_MemoryError, "out of memory on getaddrinfo"); - case EAI_NODATA : - /* EAI_NODATA - The specified network host exists, but does not have any - network addresses defined. */ - PyErr_SetString(PyExc_AttributeError, "host lacks IP address"); - default : - PyErr_SetString(PyExc_AttributeError, "invalid address/hostname"); - } - return 0; - } - - /* Copy port into sockaddr struct - - uint16_t htons(uint16_t hostshort); - The htons() function converts the unsigned short integer hostshort - from host byte order to network byte order. - */ - ((struct sockaddr_in*) resinfo->ai_addr)->sin_port = htons(sock.port); - - /* Open new socket of the appropriate family (AF_INET or AF_INET6) - - int socket(int domain, int type, int protocol); - */ - sock.sock = socket(resinfo->ai_family, SOCK_STREAM, 0); - - /* If successful continue to bind/listen, else set error message */ - if (sock.sock > -1) { - /* Bind and Listen to opened socket - - int bind(int sockfd, const struct sockaddr *addr, - socklen_t addrlen); - On success, zero is returned. On error, -1 is returned. - - int listen(int sockfd, int backlog); - On success, zero is returned. On error, -1 is returned. - */ - if (bind(sock.sock, resinfo->ai_addr, resinfo->ai_addrlen) == 0 && - listen(sock.sock, 16) == 0 ) - ret = 1; - else { - PyErr_SetString(PyExc_OSError, "unable to bind listening socket"); - ret = 0; - } - } - else { - PyErr_SetString(PyExc_OSError, "unable to bind listening socket"); - ret = 0; - } - - /* before returning, free the previously created resinfo struct - - void freeaddrinfo(struct addrinfo *res); - */ - if (resinfo) - freeaddrinfo(resinfo); - - return ret; -} Modified: trunk/concordance/src/Core.h =================================================================== --- trunk/concordance/src/Core.h 2009-01-04 00:09:52 UTC (rev 1416) +++ trunk/concordance/src/Core.h 2009-01-04 05:03:50 UTC (rev 1417) @@ -31,8 +31,11 @@ typedef struct { PyObject_HEAD - conSocket c2s; - conSocket s2s; + conSocket c2s; + conSocket s2s; + GThread* thread; + GMainContext* context; + GMainLoop* mainloop; } conCoreObject; PyTypeObject conCore_Type; _______________________________________________ PySoy-SVN mailing list PySoy-SVN@pysoy.org http://www.pysoy.org/mailman/listinfo/pysoy-svn