Fixed "Detected Host IP" notifications.
[udpgate.git] / src / network.c
index aaa0f47..00592eb 100644 (file)
 
 #include "network.h"
 #include "packet.h"
+#include "main.h"      /* for optarg_verbose */
 
 
 /* Config: */
 #define NETWORK_PATHNAME_PID "/var/run/udpgate.pid"
 #define SOCK_SOURCE_CHECK_EVENTS (G_IO_IN)     /* |G_IO_PRI */
 #define SOCK_SOURCE_CHECK_REVENTS (SOCK_SOURCE_CHECK_EVENTS)   /* |G_IO_ERR|G_IO_HUP|G_IO_NVAL */
+#define SERVER_INADDR 0x7F000001
+#undef  SERVER_INADDR
 #define SERVER_INADDR 0x511F02EA       /* paulina.vellum.cz = 81.31.2.234; host order */
 #define SERVER_PORT   9201     /* host order */
 #define PROBE_INADDR  SERVER_INADDR    /* host order */
@@ -52,7 +55,7 @@
 #define PROBE_TIMEOUT_SEC (5)
 
 
-void (*network_notify_hostip)(guint32 hostip_guint32,const gchar *hostip_string);
+void (*network_notify_hostip)(guint32 hostip_guint32);
 
 
 struct client {
@@ -129,6 +132,8 @@ static void client_timeout_remove(struct client *client)
        if (client->timeout_id) {
 gboolean errgboolean;
 
+               if (optarg_verbose)
+                       g_message(_("Client fd %d removed timeout id %d"),client->gpollfd.fd,client->timeout_id);
                errgboolean=g_source_remove(client->timeout_id);
                g_assert(errgboolean==TRUE);
                client->timeout_id=0;
@@ -147,6 +152,8 @@ static void client_touch(struct client *client)
                        (client==probe ? PROBE_TIMEOUT_SEC*1000 : CLIENT_TIMEOUT_SEC*1000),     /* interval; msec */
                        (GSourceFunc)client_touch_timeout,      /* function */
                        client);        /* data */
+       if (optarg_verbose)
+               g_message(_("Client fd %d new timeout id %d"),client->gpollfd.fd,client->timeout_id);
        g_assert(client->timeout_id!=0);
 }
 
@@ -157,17 +164,69 @@ static gboolean client_touch_timeout(struct client *client)
        g_return_val_if_fail(client!=NULL,FALSE);       /* FALSE=>should be removed */
        g_return_val_if_fail(client!=master,FALSE);     /* FALSE=>should be removed */
 
+       if (optarg_verbose)
+               g_message(_("Client fd %d timeout id %d occured/entered"),client->gpollfd.fd,client->timeout_id);
+
+       /* Do not destroy the timeout in client_destroy().
+        * It would crash GLib - we remove it be returning FALSE from here.
+        */
+       g_assert(client->timeout_id!=0);
+       client->timeout_id=0;
+
        if (client==probe) {
                network_stop();
-               if (network_notify_hostip)
-                       (*network_notify_hostip)(0,NULL);
+               /* Never destroy 'client' now - it has been destroyed by network_stop()! */
+               }
+       else {
+               client_destroy(client);
                }
 
-       client_destroy(client);
+       if (optarg_verbose)
+               g_message(_("Client timeout occurance finish"));
 
        return FALSE;   /* GSource should be removed */
 }
 
+static void handle_master_probe(const void *packet,size_t gotlen,const struct sockaddr_in *sockaddr_in_from)
+{
+GHashTable *got_hash;
+gpointer got_unique_gpointer;
+gpointer hostip_gpointer;
+guint32 hostip_guint32;
+
+       g_return_if_fail(packet!=NULL);
+       g_return_if_fail(sockaddr_in_from!=NULL);
+
+       if (!probe)
+               return;
+
+       if (!(got_hash=packet_disassembly(packet,gotlen)))
+               return;
+       if (!(g_hash_table_lookup_extended(
+                       got_hash,       /* hash_table */
+                       GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),        /* lookup_key */
+                       NULL,   /* orig_key */
+                       &got_unique_gpointer))) {
+err_packet_disassembly_destroy_got_hash:
+               packet_disassembly_destroy(got_hash);
+               return;
+               }
+       if (GPOINTER_TO_UINT(got_unique_gpointer)!=probe_unique)
+               goto err_packet_disassembly_destroy_got_hash;
+       if (!(g_hash_table_lookup_extended(
+                       got_hash,       /* hash_table */
+                       GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_INADDR),       /* lookup_key */
+                       NULL,   /* orig_key */
+                       &hostip_gpointer)))
+               goto err_packet_disassembly_destroy_got_hash;
+       hostip_guint32=GPOINTER_TO_UINT(hostip_gpointer);
+       packet_disassembly_destroy(got_hash);
+
+       client_destroy(probe);
+       if (network_notify_hostip)
+               (*network_notify_hostip)(hostip_guint32);
+}
+
 static struct client *client_new(void);
 
 static void handle_master(struct client *master)
@@ -193,6 +252,12 @@ GList *clientl;
 
                if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
                        continue;
+
+               if (packet_recognized(packet,gotlen)) {
+                       handle_master_probe(packet,gotlen,&sockaddr_in_from);
+                       continue;
+                       }
+
                /* FIXME: Performance: Ugly search... */
                for (clientl=sock_client_list;clientl;clientl=clientl->next) {
                        client=clientl->data;
@@ -241,43 +306,10 @@ socklen_t sockaddr_in_from_length;
                        0,      /* flags */
                        (struct sockaddr *)&sockaddr_in_from,   /* from */
                        &sockaddr_in_from_length))) {   /* fromlen */
-static GHashTable *got_hash;
-static gpointer got_unique_gpointer;
-static gpointer hostip_gpointer;
-static guint32 hostip_guint32;
-
                if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
                        continue;
-               if (!(got_hash=packet_disassembly(packet,gotlen)))
-                       continue;
-               if (!(g_hash_table_lookup_extended(
-                               got_hash,       /* hash_table */
-                               GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),        /* lookup_key */
-                               NULL,   /* orig_key */
-                               &got_unique_gpointer))) {
-err_packet_disassembly_destroy_got_hash:
-                       packet_disassembly_destroy(got_hash);
-                       continue;
-                       }
-               if (GPOINTER_TO_UINT(got_unique_gpointer)!=probe_unique)
-                       goto err_packet_disassembly_destroy_got_hash;
-               if (!(g_hash_table_lookup_extended(
-                               got_hash,       /* hash_table */
-                               GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_INADDR),       /* lookup_key */
-                               NULL,   /* orig_key */
-                               &hostip_gpointer)))
-                       goto err_packet_disassembly_destroy_got_hash;
-               hostip_guint32=GPOINTER_TO_UINT(hostip_gpointer);
-               packet_disassembly_destroy(got_hash);
 
-               client_destroy(probe);
-               if (network_notify_hostip)
-                       (*network_notify_hostip)(hostip_guint32,
-                                       udpgate_printf_alloca("%d.%d.%d.%d",
-                                                       (hostip_guint32>>24U)&0xFFU,
-                                                       (hostip_guint32>>16U)&0xFFU,
-                                                       (hostip_guint32>> 8U)&0xFFU,
-                                                       (hostip_guint32>> 0U)&0xFFU));
+               /* Probe socket should have no response; maybe some ICMP errors - ignored. */
                }
 }
 
@@ -436,6 +468,9 @@ int sock;
        sock_client_list=g_list_prepend(sock_client_list,client);
        g_source_add_poll(sock_gsource,&client->gpollfd);
 
+       if (optarg_verbose)
+               g_message(_("Client fd %d created"),client->gpollfd.fd);
+
        return client;
 }
 
@@ -446,6 +481,9 @@ static void client_destroy(struct client *client)
        if (!sock_gsource_new())
                return;
 
+       if (optarg_verbose)
+               g_message(_("Client fd %d timeout id %d destroy enter"),client->gpollfd.fd,client->timeout_id);
+
        if (client==master) {
                master=NULL;
                g_assert(client->timeout_id==0);
@@ -459,6 +497,10 @@ static void client_destroy(struct client *client)
        g_source_remove_poll(sock_gsource,&client->gpollfd);
        sock_client_list=g_list_remove(sock_client_list,client);
        close(client->gpollfd.fd);      /* errors ignored */
+
+       if (optarg_verbose)
+               g_message(_("Client fd %d timeout id %d destroy finish"),client->gpollfd.fd,client->timeout_id);
+
        g_free(client);
 }
 
@@ -518,7 +560,7 @@ struct sockaddr_in sockaddr_in;
        UDPGATE_MEMZERO(&sockaddr_in);
        sockaddr_in.sin_family=AF_INET;
        sockaddr_in.sin_port=htons(port);
-       sockaddr_in.sin_addr.s_addr=INADDR_ANY;
+       sockaddr_in.sin_addr.s_addr=htonl(INADDR_ANY);
        if (bind(master->gpollfd.fd,(struct sockaddr *)&sockaddr_in,sizeof(sockaddr_in))) {
                g_warning("bind(sock,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
 err_sock_gsource_destroy:
@@ -533,6 +575,8 @@ err_sock_gsource_destroy:
        client_touch(probe);    /* timeout */
 
        write_daemon_running(getpid());
+       if (network_notify_hostip)
+               (*network_notify_hostip)(0);
        return TRUE;
 }
 
@@ -547,7 +591,7 @@ int errno_save;
                }
        if (daemon_pid==getpid()) {
                sock_gsource_destroy();
-               return TRUE;
+               goto ok;
                }
        errno=0;
        kill(daemon_pid,SIGKILL);
@@ -557,5 +601,8 @@ int errno_save;
                                (int)daemon_pid,strerror(errno_save)));
                return FALSE;
                }
+ok:
+       if (network_notify_hostip)
+               (*network_notify_hostip)(0);
        return TRUE;
 }