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