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