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