network_stop(): Fixed forgotten removal of a foreign PID file.
[udpgate.git] / src / network.c
index ad650b8..9bdc058 100644 (file)
@@ -176,8 +176,7 @@ static gboolean client_touch_timeout(struct client *client)
        if (client==probe) {
                network_stop();
                /* Never destroy 'client' now - it has been destroyed by network_stop()! */
-               if (network_notify_hostip)
-                       (*network_notify_hostip)(0);
+               g_warning(_("No probe response from the server, stopping the daemon. Please check your public Internet connectivity."));
                }
        else {
                client_destroy(client);
@@ -233,25 +232,27 @@ static struct client *client_new(void);
 
 static void handle_master(struct client *master)
 {
+       g_return_if_fail(master!=NULL);
+
+       for (;;) {
+char packet[0x10000];
 ssize_t gotlen;
 struct sockaddr_in sockaddr_in_from;
-char packet[0x10000];
 struct client *client;
 struct sockaddr_in sockaddr_in_server;
 socklen_t sockaddr_in_from_length;
-
-       g_return_if_fail(master!=NULL);
-
-       sockaddr_in_from_length=sizeof(sockaddr_in_from);
-       while (-1!=(gotlen=recvfrom(
-                       master->gpollfd.fd,     /* s */
-                       packet, /* buf */
-                       sizeof(packet), /* len */
-                       0,      /* flags */
-                       (struct sockaddr *)&sockaddr_in_from,   /* from */
-                       &sockaddr_in_from_length))) {   /* fromlen */
 GList *clientl;
 
+               sockaddr_in_from_length=sizeof(sockaddr_in_from);
+               if (-1==(gotlen=recvfrom(
+                               master->gpollfd.fd,     /* s */
+                               packet, /* buf */
+                               sizeof(packet), /* len */
+                               0,      /* flags */
+                               (struct sockaddr *)&sockaddr_in_from,   /* from */
+                               &sockaddr_in_from_length)))     /* fromlen */
+                       break;
+
                if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
                        continue;
 
@@ -293,21 +294,23 @@ GList *clientl;
 
 static void handle_probe(struct client *probe)
 {
+       g_return_if_fail(probe!=NULL);
+
+       for (;;) {
 ssize_t gotlen;
 struct sockaddr_in sockaddr_in_from;
 char packet[0x10000];
 socklen_t sockaddr_in_from_length;
 
-       g_return_if_fail(probe!=NULL);
-
-       sockaddr_in_from_length=sizeof(sockaddr_in_from);
-       while (-1!=(gotlen=recvfrom(
-                       master->gpollfd.fd,     /* s */
-                       packet, /* buf */
-                       sizeof(packet), /* len */
-                       0,      /* flags */
-                       (struct sockaddr *)&sockaddr_in_from,   /* from */
-                       &sockaddr_in_from_length))) {   /* fromlen */
+               sockaddr_in_from_length=sizeof(sockaddr_in_from);
+               if (-1==(gotlen=recvfrom(
+                               master->gpollfd.fd,     /* s */
+                               packet, /* buf */
+                               sizeof(packet), /* len */
+                               0,      /* flags */
+                               (struct sockaddr *)&sockaddr_in_from,   /* from */
+                               &sockaddr_in_from_length)))     /* fromlen */
+                       break;
                if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
                        continue;
 
@@ -317,21 +320,24 @@ socklen_t sockaddr_in_from_length;
 
 static void handle_client(struct client *client)
 {
+       g_return_if_fail(client!=NULL);
+       g_return_if_fail(master!=NULL);
+
+       for (;;) {
 ssize_t gotlen;
 struct sockaddr_in sockaddr_in_from;
 char packet [0x10000];
 socklen_t sockaddr_in_from_length;
 
-       g_return_if_fail(client!=NULL);
-       g_return_if_fail(master!=NULL);
-
-       while (-1!=(gotlen=recvfrom(
-                       client->gpollfd.fd,     /* s */
-                       packet, /* buf */
-                       sizeof(packet), /* len */
-                       0,      /* flags */
-                       (struct sockaddr *)&sockaddr_in_from,   /* from */
-                       &sockaddr_in_from_length))) {   /* fromlen */
+               sockaddr_in_from_length=sizeof(sockaddr_in_from);
+               if (-1==(gotlen=recvfrom(
+                               client->gpollfd.fd,     /* s */
+                               packet, /* buf */
+                               sizeof(packet), /* len */
+                               0,      /* flags */
+                               (struct sockaddr *)&sockaddr_in_from,   /* from */
+                               &sockaddr_in_from_length)))     /* fromlen */
+                       break;
                if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
                        continue;
                client_touch(client);
@@ -411,7 +417,7 @@ static void sock_gsource_destroy(void)
                sock_gsource=NULL;
                }
 
-       write_daemon_running((pid_t)-1);        /* unlink */
+       write_daemon_running((pid_t)-1);        /* unlink; errors ignored */
 }
 
 static gboolean sock_gsource_new(void)
@@ -452,8 +458,8 @@ int sock;
        if (!sock_gsource_new())
                return FALSE;
 
-       if (-1==(sock=socket(AF_INET,SOCK_DGRAM,0))) {
-               g_warning("socket(AF_INET,SOCK_DGRAM): %m");
+       if (-1==(sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))) {
+               g_warning("socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP): %m");
                return NULL;
                }
        if (ioctl(sock,FIONBIO,&oneul)) {       /* non-blocking mode */
@@ -576,7 +582,29 @@ err_sock_gsource_destroy:
        probe_send(probe,port);
        client_touch(probe);    /* timeout */
 
-       write_daemon_running(getpid());
+       write_daemon_running(getpid()); /* errors ignored */
+       if (network_notify_hostip)
+               (*network_notify_hostip)(0);
+       return TRUE;
+}
+
+gboolean optarg_port_set_string(const gchar *port_string)
+{
+char *endp;
+long port_long;
+
+       g_return_val_if_fail(port_string!=NULL,FALSE);
+
+       port_long=strtol(port_string,&endp,0);
+       if (endp && *endp) {
+               g_warning(_("Invalid port specification, offending string: %s"),endp);
+               return FALSE;
+               }
+       if (port_long<1 || port_long>=G_MAXINT || (endp && *endp)) {
+               g_warning(_("Invalid port integer number specification (%ld)"),port_long);
+               return FALSE;
+               }
+       optarg_port=port_long;
        return TRUE;
 }
 
@@ -591,15 +619,61 @@ int errno_save;
                }
        if (daemon_pid==getpid()) {
                sock_gsource_destroy();
-               return TRUE;
+               goto ok;
                }
        errno=0;
        kill(daemon_pid,SIGKILL);
        errno_save=errno;
+       write_daemon_running((pid_t)-1);        /* unlink; errors ignored */
        if (errno_save)  {
                g_warning(udpgate_printf_alloca(_("Unable to stop the daemon at PID %d: %s"),
                                (int)daemon_pid,strerror(errno_save)));
                return FALSE;
                }
+ok:
+       if (network_notify_hostip)
+               (*network_notify_hostip)(0);
        return TRUE;
 }
+
+static GMainLoop *gmainloop;
+static void network_detach_network_notify_hostip(guint32 hostip_guint32)
+{
+       if (!hostip_guint32)
+               g_main_loop_quit(gmainloop);
+}
+
+gboolean network_detach(void)
+{
+pid_t daemon_pid,forked_pid;
+
+       if ((pid_t)-1==(daemon_pid=is_daemon_running()))
+               return TRUE;
+       if (getpid()!=daemon_pid)
+               return TRUE;
+       if (!optarg_no_fork) {
+               if ((pid_t)-1==(forked_pid=fork())) {
+                       g_warning("fork(2): %m");
+                       return FALSE;
+                       }
+               if (forked_pid) {
+                       /* parent */
+                       return TRUE;
+                       }
+               write_daemon_running(getpid()); /* errors ignored */
+               optarg_verbose=0;
+               close(STDIN_FILENO);
+               close(STDOUT_FILENO);
+               close(STDERR_FILENO);
+               setpgrp();
+               setsid();
+               }
+
+       network_notify_hostip=network_detach_network_notify_hostip;
+       gmainloop=g_main_loop_new(
+                       NULL,   /* context */
+                       TRUE);  /* is_running; ignored */
+       g_main_loop_run(gmainloop);     /* loop */
+       /* Unable to contact the server, aborting. */
+       return FALSE;
+}