cf3f4ffb8f729b5673c77371b63898fc82264421
[udpgate.git] / src / network.c
1 /* $Id$
2  * UDP Gateway utility network layer
3  * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include <glib/gmessages.h>
23 #include <glib/gmain.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <glib/glist.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <glib/giochannel.h>
33 #include <sys/ioctl.h>
34 #include <string.h>
35 #include <glib/galloca.h>
36 #include <glib/gprintf.h>
37 #include <glib/grand.h>
38
39 #include "network.h"
40 #include "packet.h"
41 #include "main.h"       /* for optarg_verbose */
42
43
44 /* Config: */
45 #define NETWORK_PATHNAME_PID "/var/run/udpgate.pid"
46 #define SOCK_SOURCE_CHECK_EVENTS (G_IO_IN)      /* |G_IO_PRI */
47 #define SOCK_SOURCE_CHECK_REVENTS (SOCK_SOURCE_CHECK_EVENTS)    /* |G_IO_ERR|G_IO_HUP|G_IO_NVAL */
48 #define SERVER_INADDR 0x511F02EA        /* paulina.vellum.cz = 81.31.2.234; host order */
49 #define SERVER_PORT   9201      /* host order */
50 #define PROBE_INADDR  SERVER_INADDR     /* host order */
51 #define PROBE_PORT    8201      /* host order */
52 #define CLIENT_TIMEOUT_SEC (5*60)
53 #define PROBE_TIMEOUT_SEC_BASE 5
54 #define PROBE_TIMEOUT_SEC_MAX 3500
55
56
57 void (*network_notify_hostip)(guint32 hostip_guint32);
58
59
60 struct client {
61         GPollFD gpollfd;
62         struct sockaddr_in sockaddr_in_from;
63         guint timeout_id;
64         };
65
66 static GSource *sock_gsource;
67
68 static GList *sock_client_list; /* of 'struct client *', incl. 'master' and 'probe' */
69 static struct client *master;   /* no 'timeout' permitted */
70 static struct client *probe;    /* 'timeout' permitted */
71 static guint32 probe_unique;
72 static guint probe_timeout_sec_now;
73 guint probe_timeout_sec_max=G_MAXUINT;
74 static gint port_local; /* for 'probe' resends */
75
76 static gboolean write_daemon_running(pid_t pid);
77
78 pid_t is_daemon_running(void)
79 {
80 FILE *f;
81 char buf[LINE_MAX],*got;
82 int pid_int;
83
84         if (sock_gsource)
85                 return getpid();
86
87         if (!(f=fopen(NETWORK_PATHNAME_PID,"r")))
88                 goto err;
89         got=fgets(buf,sizeof(buf),f);
90         fclose(f);      /* FIXME: error ignored */
91         if (got!=buf) {
92 err_unlink:
93                 write_daemon_running((pid_t)-1);        /* unlink */
94 err:
95                 return (pid_t)-1;
96                 }
97         pid_int=atoi(buf);
98         if (pid_int<=1)
99                 goto err_unlink;
100         if (kill((pid_t)pid_int,0)) {
101                 if (errno==ESRCH)
102                         goto err_unlink;
103                 goto err;
104                 }
105         return (pid_t)pid_int;
106 }
107
108 static gboolean write_daemon_running(pid_t pid)
109 {
110 FILE *f;
111
112         if (pid==(pid_t)-1) {
113                 if (unlink(NETWORK_PATHNAME_PID)) {
114                         if (errno!=ENOENT)
115                                 g_warning(_("Error removing PID file \"%s\": %m"),NETWORK_PATHNAME_PID);
116                         return FALSE;
117                         }
118                 return TRUE;
119                 }
120         if (!(f=fopen(NETWORK_PATHNAME_PID,"w"))) {
121                 g_warning(_("Error writing PID %d to \"%s\": %m"),(int)pid,NETWORK_PATHNAME_PID);
122                 return FALSE;
123                 }
124         fprintf(f,"%d\n",(int)pid);     /* errors ignored */
125         fclose(f);      /* FIXME: error ignored */
126         return TRUE;
127 }
128
129 static void client_timeout_remove(struct client *client)
130 {
131         g_return_if_fail(client!=NULL);
132         g_return_if_fail(client!=master);
133
134         if (client->timeout_id) {
135 gboolean errgboolean;
136
137                 if (optarg_verbose)
138                         g_message(_("Client fd %d removed timeout id %d"),client->gpollfd.fd,client->timeout_id);
139                 errgboolean=g_source_remove(client->timeout_id);
140                 g_assert(errgboolean==TRUE);
141                 client->timeout_id=0;
142                 }
143 }
144
145 static gboolean client_touch_timeout(struct client *client);
146
147 static void client_touch(struct client *client,guint timeout_sec)
148 {
149         g_return_if_fail(client!=NULL);
150         g_return_if_fail(client!=master);
151         g_return_if_fail(timeout_sec>0);
152
153         client_timeout_remove(client);
154         client->timeout_id=g_timeout_add(
155                         timeout_sec*1000,       /* interval; msec */
156                         (GSourceFunc)client_touch_timeout,      /* function */
157                         client);        /* data */
158         if (optarg_verbose)
159                 g_message(_("Client fd %d new timeout id %d"),client->gpollfd.fd,client->timeout_id);
160         g_assert(client->timeout_id!=0);
161 }
162
163 static void client_destroy(struct client *client);
164 static gboolean probe_send(struct client *probe,gint port_local);
165
166 static gboolean client_touch_timeout(struct client *client)
167 {
168         g_return_val_if_fail(client!=NULL,FALSE);       /* FALSE=>should be removed */
169         g_return_val_if_fail(client!=master,FALSE);     /* FALSE=>should be removed */
170
171         if (optarg_verbose)
172                 g_message(_("Client fd %d timeout id %d occured/entered"),client->gpollfd.fd,client->timeout_id);
173
174         /* Do not destroy the timeout in client_destroy().
175          * It would crash GLib - we remove it be returning FALSE from here.
176          */
177         g_assert(client->timeout_id!=0);
178         client->timeout_id=0;
179
180         if (client==probe) {
181                 if (probe_timeout_sec_now<probe_timeout_sec_max) {
182                         probe_timeout_sec_now*=PROBE_TIMEOUT_SEC_BASE;
183                         g_assert(probe_timeout_sec_max==G_MAXUINT || probe_timeout_sec_max<PROBE_TIMEOUT_SEC_MAX);
184                         probe_timeout_sec_now=MIN(probe_timeout_sec_now,probe_timeout_sec_max);
185                         probe_timeout_sec_now=MIN(probe_timeout_sec_now,PROBE_TIMEOUT_SEC_MAX);
186                         if (probe_send(probe,port_local)) {
187                                 client_touch(probe,probe_timeout_sec_now);      /* timeout */
188                                 return FALSE;   /* GSource should be removed */
189                                 }
190                         /* failure FALLTHRU */
191                         }
192                 network_stop();
193                 /* Never destroy 'client' now - it has been destroyed by network_stop()! */
194                 g_warning(_("No probe response from the server, stopping the daemon. Please check your public Internet connectivity."));
195                 }
196         else {
197                 client_destroy(client);
198                 }
199
200         if (optarg_verbose)
201                 g_message(_("Client timeout occurance finish"));
202
203         return FALSE;   /* GSource should be removed */
204 }
205
206 static void handle_master_probe(const void *packet,size_t gotlen,const struct sockaddr_in *sockaddr_in_from)
207 {
208 GHashTable *got_hash;
209 gpointer got_unique_gpointer;
210 gpointer hostip_gpointer;
211 guint32 hostip_guint32;
212
213         g_return_if_fail(packet!=NULL);
214         g_return_if_fail(sockaddr_in_from!=NULL);
215
216         if (!probe)
217                 return;
218
219         if (!(got_hash=packet_disassembly(packet,gotlen)))
220                 return;
221         if (!(g_hash_table_lookup_extended(
222                         got_hash,       /* hash_table */
223                         GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),        /* lookup_key */
224                         NULL,   /* orig_key */
225                         &got_unique_gpointer))) {
226 err_packet_disassembly_destroy_got_hash:
227                 packet_disassembly_destroy(got_hash);
228                 return;
229                 }
230         if (GPOINTER_TO_UINT(got_unique_gpointer)!=probe_unique)
231                 goto err_packet_disassembly_destroy_got_hash;
232         if (!(g_hash_table_lookup_extended(
233                         got_hash,       /* hash_table */
234                         GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_INADDR),       /* lookup_key */
235                         NULL,   /* orig_key */
236                         &hostip_gpointer)))
237                 goto err_packet_disassembly_destroy_got_hash;
238         hostip_guint32=GPOINTER_TO_UINT(hostip_gpointer);
239         packet_disassembly_destroy(got_hash);
240
241         client_destroy(probe);
242         if (network_notify_hostip)
243                 (*network_notify_hostip)(hostip_guint32);
244 }
245
246 static struct client *client_new(void);
247
248 static void handle_master(struct client *master)
249 {
250         g_return_if_fail(master!=NULL);
251
252         for (;;) {
253 char packet[0x10000];
254 ssize_t gotlen;
255 struct sockaddr_in sockaddr_in_from;
256 struct client *client=NULL      /* Prevent false positive: might be used uninitialized */;
257 struct sockaddr_in sockaddr_in_server;
258 socklen_t sockaddr_in_from_length;
259 GList *clientl;
260
261                 sockaddr_in_from_length=sizeof(sockaddr_in_from);
262                 if (-1==(gotlen=recvfrom(
263                                 master->gpollfd.fd,     /* s */
264                                 packet, /* buf */
265                                 sizeof(packet), /* len */
266                                 0,      /* flags */
267                                 (struct sockaddr *)&sockaddr_in_from,   /* from */
268                                 &sockaddr_in_from_length)))     /* fromlen */
269                         break;
270
271                 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
272                         continue;
273
274                 if (packet_recognized(packet,gotlen)) {
275                         handle_master_probe(packet,gotlen,&sockaddr_in_from);
276                         continue;
277                         }
278                 /* Not yet initialized by 'probe' reply - drop it. */
279                 if (probe)
280                         continue;
281
282                 /* FIXME: Performance: Ugly search... */
283                 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
284                         client=clientl->data;
285                         if (client==master)
286                                 continue;
287                         if (1
288                                         && client->sockaddr_in_from.sin_family     ==sockaddr_in_from.sin_family
289                                         && client->sockaddr_in_from.sin_port       ==sockaddr_in_from.sin_port
290                                         && client->sockaddr_in_from.sin_addr.s_addr==sockaddr_in_from.sin_addr.s_addr)
291                                 break;
292                         }
293                 if (!clientl) {
294                         client=client_new();
295                         client->sockaddr_in_from=sockaddr_in_from;
296                         }
297                 client_touch(client,CLIENT_TIMEOUT_SEC);
298                 UDPGATE_MEMZERO(&sockaddr_in_server);
299                 sockaddr_in_server.sin_family=AF_INET;
300                 sockaddr_in_server.sin_port=htons(SERVER_PORT);
301                 sockaddr_in_server.sin_addr.s_addr=htonl(SERVER_INADDR);
302                 /* FIXME: errors checking */
303                 sendto(
304                                 client->gpollfd.fd,     /* s */
305                                 packet, /* msg */
306                                 gotlen, /* len */
307                                 0,      /* flags */
308                                 (struct sockaddr *)&sockaddr_in_server, /* to */
309                                 sizeof(sockaddr_in_server));    /* tolen */
310                 }
311 }
312
313 static void handle_probe(struct client *probe)
314 {
315         g_return_if_fail(probe!=NULL);
316
317         for (;;) {
318 ssize_t gotlen;
319 struct sockaddr_in sockaddr_in_from;
320 char packet[0x10000];
321 socklen_t sockaddr_in_from_length;
322
323                 sockaddr_in_from_length=sizeof(sockaddr_in_from);
324                 if (-1==(gotlen=recvfrom(
325                                 master->gpollfd.fd,     /* s */
326                                 packet, /* buf */
327                                 sizeof(packet), /* len */
328                                 0,      /* flags */
329                                 (struct sockaddr *)&sockaddr_in_from,   /* from */
330                                 &sockaddr_in_from_length)))     /* fromlen */
331                         break;
332                 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
333                         continue;
334
335                 /* Probe socket should have no response; maybe some ICMP errors - ignored. */
336                 }
337 }
338
339 static void handle_client(struct client *client)
340 {
341         g_return_if_fail(client!=NULL);
342         g_return_if_fail(master!=NULL);
343
344         for (;;) {
345 ssize_t gotlen;
346 struct sockaddr_in sockaddr_in_from;
347 char packet [0x10000];
348 socklen_t sockaddr_in_from_length;
349
350                 sockaddr_in_from_length=sizeof(sockaddr_in_from);
351                 if (-1==(gotlen=recvfrom(
352                                 client->gpollfd.fd,     /* s */
353                                 packet, /* buf */
354                                 sizeof(packet), /* len */
355                                 0,      /* flags */
356                                 (struct sockaddr *)&sockaddr_in_from,   /* from */
357                                 &sockaddr_in_from_length)))     /* fromlen */
358                         break;
359                 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
360                         continue;
361                 client_touch(client,CLIENT_TIMEOUT_SEC);
362                 /* FIXME: errors checking */
363                 sendto(
364                                 master->gpollfd.fd,     /* s */
365                                 packet, /* msg */
366                                 gotlen, /* len */
367                                 0,      /* flags */
368                                 (struct sockaddr *)&client->sockaddr_in_from,   /* to */
369                                 sizeof(client->sockaddr_in_from));      /* tolen */
370                 }
371 }
372
373 static gboolean sock_source_callback(gpointer data /* unused */)
374 {
375 GList *clientl;
376
377         for (clientl=sock_client_list;clientl;clientl=clientl->next) {
378 struct client *client=clientl->data;
379
380                 if (client->gpollfd.revents&SOCK_SOURCE_CHECK_REVENTS) {
381                         /**/ if (client==master)
382                                 handle_master(client);
383                         else if (client==probe)
384                                 handle_probe(client);
385                         else
386                                 handle_client(client);
387                         }
388                 }
389
390         return TRUE; /* the source should be kept active */
391 }
392
393 static gboolean sock_source_prepare(GSource *source,gint *timeout)
394 {
395         *timeout=-1;
396
397         return FALSE;
398 }
399
400 static gboolean sock_source_check(GSource *source)
401 {
402 GList *clientl;
403
404         for (clientl=sock_client_list;clientl;clientl=clientl->next) {
405 struct client *client=clientl->data;
406
407                 if (client->gpollfd.revents&SOCK_SOURCE_CHECK_REVENTS)
408                         return TRUE;
409                 }
410         return FALSE;
411 }
412
413 static gboolean sock_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
414 {
415         g_assert(callback!=NULL);
416         return (*callback)(user_data);
417 }
418
419 static GSourceFuncs sock_source_watch_funcs={
420                 sock_source_prepare,
421                 sock_source_check,
422                 sock_source_dispatch,
423                 NULL, /* finalize */
424                 };
425
426 static void sock_gsource_destroy(void)
427 {
428         while (sock_client_list)
429                 client_destroy(sock_client_list->data);
430
431         g_assert(master==NULL);
432         g_assert(probe==NULL);
433
434         if (sock_gsource) {
435                 g_source_destroy(sock_gsource);
436                 sock_gsource=NULL;
437                 }
438
439         write_daemon_running((pid_t)-1);        /* unlink; errors ignored */
440 }
441
442 static gboolean sock_gsource_new(void)
443 {
444         if (sock_gsource)
445                 return TRUE;
446
447         g_assert(sock_client_list==NULL);
448
449         /* attach sock_source_callback() to watch for any abnormalities
450          * on our open pipe 'parentheart_fds' and terminate the child if parent dies.
451          */
452         if (!(sock_gsource=g_source_new(&sock_source_watch_funcs,sizeof(GSource)))) {
453                 g_warning("g_source_new(): %m");
454                 return FALSE;
455                 }
456         g_source_set_callback(
457                         sock_gsource,  /* source */
458                         sock_source_callback,  /* func */
459                         NULL, /* data */
460                         NULL);  /* notify */
461         if (!g_source_attach(   /* returns 'guint' id */
462                         sock_gsource,  /* source */
463                         NULL)) {        /* context; NULL means 'default context' */
464                 g_warning("g_source_attach(gsource,NULL): %m");
465                 sock_gsource_destroy();
466                 return FALSE;
467                 }
468         return TRUE;
469 }
470
471 static struct client *client_new(void)
472 {
473 struct client *client;
474 static unsigned long oneul=1;
475 int sock;
476
477         if (!sock_gsource_new())
478                 return FALSE;
479
480         if (-1==(sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))) {
481                 g_warning("socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP): %m");
482                 return NULL;
483                 }
484         if (ioctl(sock,FIONBIO,&oneul)) {       /* non-blocking mode */
485                 g_warning("ioctl(sock,FIONBIO,&1): %m");
486                 close(sock);    /* errors ignored */
487                 return NULL;
488                 }
489
490         udpgate_new(client);
491         client->gpollfd.fd=sock;
492         client->gpollfd.events=SOCK_SOURCE_CHECK_EVENTS;
493         client->gpollfd.revents=0;
494         client->timeout_id=0;
495         sock_client_list=g_list_prepend(sock_client_list,client);
496         g_source_add_poll(sock_gsource,&client->gpollfd);
497
498         if (optarg_verbose)
499                 g_message(_("Client fd %d created"),client->gpollfd.fd);
500
501         return client;
502 }
503
504 static void client_destroy(struct client *client)
505 {
506         g_return_if_fail(client!=NULL);
507
508         if (!sock_gsource_new())
509                 return;
510
511         if (optarg_verbose)
512                 g_message(_("Client fd %d timeout id %d destroy enter"),client->gpollfd.fd,client->timeout_id);
513
514         if (client==master) {
515                 master=NULL;
516                 g_assert(client->timeout_id==0);
517                 }
518         else {
519                 if (client==probe)
520                         probe=NULL;
521                 client_timeout_remove(client);
522                 }
523
524         g_source_remove_poll(sock_gsource,&client->gpollfd);
525         sock_client_list=g_list_remove(sock_client_list,client);
526         close(client->gpollfd.fd);      /* errors ignored */
527
528         if (optarg_verbose)
529                 g_message(_("Client fd %d timeout id %d destroy finish"),client->gpollfd.fd,client->timeout_id);
530
531         g_free(client);
532 }
533
534 static gboolean probe_send(struct client *probe,gint port_local)
535 {
536 struct sockaddr_in sockaddr_in_server;
537 GHashTable *probe_hash;
538 gpointer packet;
539 size_t packet_length;
540
541         g_return_val_if_fail(probe!=NULL,FALSE);
542
543         probe_unique=g_random_int();
544
545         probe_hash=g_hash_table_new(
546                         g_direct_hash,  /* hash_func */
547                         g_direct_equal);        /* key_equal_func */
548         g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_PORT) ,GUINT_TO_POINTER(port_local));
549         g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),GUINT_TO_POINTER(probe_unique));
550         packet=packet_assembly(&packet_length,probe_hash);
551         g_hash_table_destroy(probe_hash);
552         if (!packet)
553                 return FALSE;
554
555         UDPGATE_MEMZERO(&sockaddr_in_server);
556         sockaddr_in_server.sin_family=AF_INET;
557         sockaddr_in_server.sin_port=htons(PROBE_PORT);
558         sockaddr_in_server.sin_addr.s_addr=htonl(PROBE_INADDR);
559         /* FIXME: errors checking */
560         sendto(
561                         probe->gpollfd.fd,      /* s */
562                         packet, /* msg */
563                         packet_length,  /* len */
564                         0,      /* flags */
565                         (struct sockaddr *)&sockaddr_in_server, /* to */
566                         sizeof(sockaddr_in_server));    /* tolen */
567
568         return TRUE;
569 }
570
571 static gboolean master_start(gint port)
572 {
573 struct sockaddr_in sockaddr_in;
574
575         g_return_val_if_fail(port>=0,FALSE);
576         g_return_val_if_fail(master==NULL,FALSE);
577
578         /* Setup 'master': */
579         if (!(master=client_new()))
580                 return FALSE;
581         UDPGATE_MEMZERO(&sockaddr_in);
582         sockaddr_in.sin_family=AF_INET;
583         sockaddr_in.sin_port=htons(port);
584         sockaddr_in.sin_addr.s_addr=htonl(INADDR_ANY);
585         if (bind(master->gpollfd.fd,(struct sockaddr *)&sockaddr_in,sizeof(sockaddr_in))) {
586                 g_warning("bind(sock,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
587                 return FALSE;
588                 }
589         return TRUE;
590 }
591
592 static gboolean probe_start(gint port)
593 {
594         g_return_val_if_fail(port>=0,FALSE);
595         g_return_val_if_fail(probe==NULL,FALSE);
596
597         /* Setup 'probe': */
598         if (!(probe=client_new()))
599                 return FALSE;
600         port_local=port;
601         if (!probe_send(probe,port)) {
602                 client_destroy(probe);
603                 return FALSE;
604                 }
605         probe_timeout_sec_now=PROBE_TIMEOUT_SEC_BASE;
606         client_touch(probe,probe_timeout_sec_now);      /* timeout */
607         return TRUE;
608 }
609
610 gboolean network_start(gint port)
611 {
612 pid_t daemon_pid;
613
614         g_return_val_if_fail(port>=0,FALSE);
615
616         if ((pid_t)-1!=(daemon_pid=is_daemon_running())) {
617                 g_warning(_("Cannot start network daemon: Daemon is already running on PID %d"),(int)daemon_pid);
618                 return FALSE;
619                 }
620         if (!master_start(port)) {
621                 sock_gsource_destroy();
622                 return FALSE;
623                 }
624         if (!probe_start(port)) {
625                 sock_gsource_destroy();
626                 return FALSE;
627                 }
628         write_daemon_running(getpid()); /* errors ignored */
629         if (network_notify_hostip)
630                 (*network_notify_hostip)(0);
631         return TRUE;
632 }
633
634 gboolean optarg_port_set_string(const gchar *port_string)
635 {
636 char *endp;
637 long port_long;
638
639         g_return_val_if_fail(port_string!=NULL,FALSE);
640
641         port_long=strtol(port_string,&endp,0);
642         if (endp && *endp) {
643                 g_warning(_("Invalid port specification, offending string: %s"),endp);
644                 return FALSE;
645                 }
646         if (port_long<1 || port_long>=G_MAXINT || (endp && *endp)) {
647                 g_warning(_("Invalid port integer number specification (%ld)"),port_long);
648                 return FALSE;
649                 }
650         optarg_port=port_long;
651         return TRUE;
652 }
653
654 gboolean network_stop(void)
655 {
656 pid_t daemon_pid;
657 int errno_save;
658
659         if ((pid_t)-1==(daemon_pid=is_daemon_running())) {
660                 g_warning(_("Cannot stop network daemon: Daemon is not running"));
661                 return FALSE;
662                 }
663         if (daemon_pid==getpid()) {
664                 sock_gsource_destroy();
665                 goto ok;
666                 }
667         errno=0;
668         kill(daemon_pid,SIGKILL);
669         errno_save=errno;
670         write_daemon_running((pid_t)-1);        /* unlink; errors ignored */
671         if (errno_save)  {
672                 g_warning(udpgate_printf_alloca(_("Unable to stop the daemon at PID %d: %s"),
673                                 (int)daemon_pid,strerror(errno_save)));
674                 return FALSE;
675                 }
676 ok:
677         if (network_notify_hostip)
678                 (*network_notify_hostip)(0);
679         return TRUE;
680 }
681
682 static GMainLoop *gmainloop;
683 static void network_detach_network_notify_hostip(guint32 hostip_guint32)
684 {
685         if (!hostip_guint32)
686                 g_main_loop_quit(gmainloop);
687 }
688
689 gboolean network_detach(void)
690 {
691 pid_t daemon_pid,forked_pid;
692
693         if ((pid_t)-1==(daemon_pid=is_daemon_running()))
694                 return TRUE;
695         if (getpid()!=daemon_pid)
696                 return TRUE;
697         if (!optarg_no_fork) {
698                 if ((pid_t)-1==(forked_pid=fork())) {
699                         g_warning("fork(2): %m");
700                         return FALSE;
701                         }
702                 if (forked_pid) {
703                         /* parent */
704                         return TRUE;
705                         }
706                 write_daemon_running(getpid()); /* errors ignored */
707                 optarg_verbose=0;
708                 close(STDIN_FILENO);
709                 close(STDOUT_FILENO);
710                 close(STDERR_FILENO);
711                 setpgrp();
712                 setsid();
713                 }
714
715         network_notify_hostip=network_detach_network_notify_hostip;
716         gmainloop=g_main_loop_new(
717                         NULL,   /* context */
718                         TRUE);  /* is_running; ignored */
719         g_main_loop_run(gmainloop);     /* loop */
720         /* Unable to contact the server, aborting. */
721         return FALSE;
722 }