2 * UDP Gateway utility network layer
3 * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
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
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.
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
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>
29 #include <sys/types.h>
32 #include <glib/giochannel.h>
33 #include <sys/ioctl.h>
35 #include <glib/galloca.h>
36 #include <glib/gprintf.h>
37 #include <glib/grand.h>
38 #include <glib/gutils.h>
42 #include "main.h" /* for optarg_verbose */
47 #define SOCK_SOURCE_CHECK_REVENTS (G_IO_IN|G_IO_OUT) /* |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
56 #define GSTRING_TO_SEND_MAX 1500*6 /* maximum data buffered per TCP client */
59 void (*network_notify_hostip)(guint32 hostip_guint32);
62 static G_CONST_RETURN gchar *pid_pathname(void)
64 static const gchar *static_pathname;
65 static const char *user_val;
68 user_val=g_get_user_name();
69 return pathname_find(&static_pathname,
70 G_STRINGIFY(LOCALSTATEDIR) "/run",PACKAGE ".pid",
71 (!user_val ? NULL : g_get_tmp_dir()),
72 (!user_val ? NULL : udpgate_printf_alloca(".%s-%s.pid",user_val,PACKAGE)),
79 struct sockaddr_in sockaddr_in_from;
82 unsigned connect_pending:1; /* for TCP connection to the server; activated by: G_IO_OUT */
83 unsigned server_only:1; /* nonimportant connect - the server side */
84 unsigned done:1; /* temporary marker */
85 GString *gstring_to_send; /* for TCP connections; data to be sent to this socket */
88 static GSource *sock_gsource;
90 static GList *sock_client_list; /* of 'struct client *', incl. 'master' and 'probe' */
91 static struct client *master_udp; /* no 'timeout' permitted */
92 static struct client *master_tcp; /* no 'timeout' permitted */
93 static struct client *probe; /* 'timeout' permitted */
94 static guint32 probe_unique;
95 static guint probe_timeout_sec_now;
96 guint probe_timeout_sec_max=G_MAXUINT;
97 static gint port_local; /* for 'probe' resends */
99 static gboolean write_daemon_running(pid_t pid);
101 pid_t is_daemon_running(void)
104 char buf[LINE_MAX],*got;
110 if (!(f=fopen(pid_pathname(),"r")))
112 got=fgets(buf,sizeof(buf),f);
113 fclose(f); /* FIXME: error ignored */
116 write_daemon_running((pid_t)-1); /* unlink */
123 if (kill((pid_t)pid_int,0)) {
128 return (pid_t)pid_int;
131 static gboolean write_daemon_running(pid_t pid)
135 if (pid==(pid_t)-1) {
136 if (unlink(pid_pathname())) {
138 g_warning(_("Error removing PID file \"%s\": %m"),pid_pathname());
143 if (!(f=fopen(pid_pathname(),"w"))) {
144 static gboolean once=TRUE;
148 g_warning(_("Error writing PID %d to \"%s\": %m"),(int)pid,pid_pathname());
152 fprintf(f,"%d\n",(int)pid); /* errors ignored */
153 fclose(f); /* FIXME: error ignored */
157 static void client_timeout_remove(struct client *client)
159 g_return_if_fail(client!=NULL);
160 g_return_if_fail(client!=master_udp);
161 g_return_if_fail(client!=master_tcp);
163 if (client->timeout_id) {
164 gboolean errgboolean;
167 g_message(_("Client fd %d removed timeout id %d"),client->gpollfd.fd,client->timeout_id);
168 errgboolean=g_source_remove(client->timeout_id);
169 g_assert(errgboolean==TRUE);
170 client->timeout_id=0;
174 static gboolean client_touch_timeout(struct client *client);
176 static void client_touch(struct client *client,guint timeout_sec)
178 g_return_if_fail(client!=NULL);
179 g_return_if_fail(client!=master_udp);
180 g_return_if_fail(client!=master_tcp);
181 g_return_if_fail(timeout_sec>0);
183 client_timeout_remove(client);
184 client->timeout_id=g_timeout_add(
185 timeout_sec*1000, /* interval; msec */
186 (GSourceFunc)client_touch_timeout, /* function */
189 g_message(_("Client fd %d new timeout id %d"),client->gpollfd.fd,client->timeout_id);
190 g_assert(client->timeout_id!=0);
193 static void client_destroy(struct client *client);
194 static gboolean probe_send(struct client *probe,gint port_local);
196 static gboolean client_touch_timeout(struct client *client)
198 g_return_val_if_fail(client!=NULL,FALSE); /* FALSE=>should be removed */
199 g_return_val_if_fail(client!=master_udp,FALSE); /* FALSE=>should be removed */
200 g_return_val_if_fail(client!=master_tcp,FALSE); /* FALSE=>should be removed */
203 g_message(_("Client fd %d timeout id %d occured/entered"),client->gpollfd.fd,client->timeout_id);
205 /* Do not destroy the timeout in client_destroy().
206 * It would crash GLib - we remove it be returning FALSE from here.
208 g_assert(client->timeout_id!=0);
209 client->timeout_id=0;
212 if (probe_timeout_sec_now<probe_timeout_sec_max) {
213 probe_timeout_sec_now*=PROBE_TIMEOUT_SEC_BASE;
214 g_assert(probe_timeout_sec_max==G_MAXUINT || probe_timeout_sec_max<PROBE_TIMEOUT_SEC_MAX);
215 probe_timeout_sec_now=MIN(probe_timeout_sec_now,probe_timeout_sec_max);
216 probe_timeout_sec_now=MIN(probe_timeout_sec_now,PROBE_TIMEOUT_SEC_MAX);
217 if (probe_send(probe,port_local)) {
218 client_touch(probe,probe_timeout_sec_now); /* timeout */
219 return FALSE; /* GSource should be removed */
221 /* failure FALLTHRU */
224 /* Never destroy 'client' now - it has been destroyed by network_stop()! */
225 g_warning(_("No probe response from the server, stopping the daemon. Please check your public Internet connectivity."));
228 client_destroy(client);
232 g_message(_("Client timeout occurance finish"));
234 return FALSE; /* GSource should be removed */
237 static void handle_master_probe(const void *packet,size_t gotlen,const struct sockaddr_in *sockaddr_in_from)
239 GHashTable *got_hash;
240 gpointer got_unique_gpointer;
241 gpointer hostip_gpointer;
242 guint32 hostip_guint32;
244 g_return_if_fail(packet!=NULL);
245 g_return_if_fail(sockaddr_in_from!=NULL);
250 if (!(got_hash=packet_disassembly(packet,gotlen)))
252 if (!(g_hash_table_lookup_extended(
253 got_hash, /* hash_table */
254 GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32), /* lookup_key */
256 &got_unique_gpointer))) {
257 err_packet_disassembly_destroy_got_hash:
258 packet_disassembly_destroy(got_hash);
261 if (GPOINTER_TO_UINT(got_unique_gpointer)!=probe_unique)
262 goto err_packet_disassembly_destroy_got_hash;
263 if (!(g_hash_table_lookup_extended(
264 got_hash, /* hash_table */
265 GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_INADDR), /* lookup_key */
268 goto err_packet_disassembly_destroy_got_hash;
269 hostip_guint32=GPOINTER_TO_UINT(hostip_gpointer);
270 packet_disassembly_destroy(got_hash);
272 client_destroy(probe);
273 if (network_notify_hostip)
274 (*network_notify_hostip)(hostip_guint32);
277 enum client_new_type {
282 static struct client *client_new(enum client_new_type type);
283 static struct client *client_new_from_sock(int sock);
285 static void clients_bind(struct client *client0,struct client *client1)
287 g_return_if_fail(client0!=NULL);
288 g_return_if_fail(client0->bound==NULL);
289 g_return_if_fail(client0->gstring_to_send==NULL);
290 g_return_if_fail(client1!=NULL);
291 g_return_if_fail(client1->bound==NULL);
292 g_return_if_fail(client1->gstring_to_send==NULL);
293 g_return_if_fail(client0!=client1);
295 client0->bound=client1;
296 client1->bound=client0;
298 client0->gstring_to_send=g_string_sized_new(GSTRING_TO_SEND_MAX);
299 client1->gstring_to_send=g_string_sized_new(GSTRING_TO_SEND_MAX);
302 static void client_split(struct client *client)
304 g_return_if_fail(client!=NULL);
305 g_return_if_fail(client->bound!=NULL);
306 g_return_if_fail(client->bound!=client);
307 g_return_if_fail(client->bound->bound==client);
308 g_return_if_fail(client->gstring_to_send!=NULL);
310 client->bound->bound=NULL;
314 static struct sockaddr_in sockaddr_in_server;
316 static void handle_master_udp(struct client *master_udp)
318 g_return_if_fail(master_udp!=NULL);
321 char packet[0x10000];
323 struct sockaddr_in sockaddr_in_from;
324 struct client *client=NULL /* Prevent false positive: might be used uninitialized */;
325 socklen_t sockaddr_in_from_length;
328 sockaddr_in_from_length=sizeof(sockaddr_in_from);
329 if (-1==(gotlen=recvfrom(
330 master_udp->gpollfd.fd, /* s */
332 sizeof(packet), /* len */
334 (struct sockaddr *)&sockaddr_in_from, /* from */
335 &sockaddr_in_from_length))) /* fromlen */
338 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
341 if (packet_recognized(packet,gotlen)) {
342 handle_master_probe(packet,gotlen,&sockaddr_in_from);
345 /* Not yet initialized by 'probe' reply - drop it. */
348 g_message(_("Data packet received from %s but no probe reply yet; dropping packet."),
349 SOCKADDR_IN_TO_STRING(&sockaddr_in_from));
353 /* FIXME: Performance: Ugly search... */
354 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
355 client=clientl->data;
356 if (client==master_udp)
359 && client->sockaddr_in_from.sin_family ==sockaddr_in_from.sin_family
360 && client->sockaddr_in_from.sin_port ==sockaddr_in_from.sin_port
361 && client->sockaddr_in_from.sin_addr.s_addr==sockaddr_in_from.sin_addr.s_addr)
365 client=client_new(CLIENT_NEW_TYPE_UDP);
366 client->sockaddr_in_from=sockaddr_in_from;
368 client_touch(client,CLIENT_TIMEOUT_SEC);
369 /* FIXME: errors checking */
371 client->gpollfd.fd, /* s */
375 (struct sockaddr *)&sockaddr_in_server, /* to */
376 sizeof(sockaddr_in_server)); /* tolen */
380 static void handle_master_tcp(struct client *master_tcp)
382 g_return_if_fail(master_tcp!=NULL);
386 struct sockaddr_in sockaddr_in_from;
387 struct client *client=NULL /* Prevent false positive: might be used uninitialized */;
388 socklen_t sockaddr_in_from_length;
390 struct client *server;
392 sockaddr_in_from_length=sizeof(sockaddr_in_from);
393 if (-1==(sock_new=accept(
394 master_tcp->gpollfd.fd, /* s */
395 (struct sockaddr *)&sockaddr_in_from, /* from */
396 &sockaddr_in_from_length))) /* fromlen */
399 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
402 /* Not yet initialized by 'probe' reply - drop it. */
405 g_message(_("Incoming connection received from %s but no probe reply yet; dropping connection."),
406 SOCKADDR_IN_TO_STRING(&sockaddr_in_from));
407 close(sock_new); /* FIXME: errors reporting */
411 if (!(client=client_new_from_sock(sock_new)))
413 client->sockaddr_in_from=sockaddr_in_from;
415 if (!(server=client_new(CLIENT_NEW_TYPE_TCP))) {
416 client_destroy(client);
419 server->server_only=1;
420 server->sockaddr_in_from=sockaddr_in_server;
421 clients_bind(client,server);
422 /* Currently only one of 'client' or 'server' needs to be destroyed. */
426 server->gpollfd.fd, /* sockfd */
427 (struct sockaddr *)&sockaddr_in_server, /* to */
428 sizeof(sockaddr_in_server)); /* tolen */
429 if (connect_got!=-1 || errno!=EINPROGRESS) {
430 g_warning(_("Error establishing server TCP connection: %m"));
431 client_destroy(server);
434 g_assert(!server->connect_pending);
435 server->connect_pending=1;
439 static void handle_probe(struct client *probe)
441 g_return_if_fail(probe!=NULL);
445 struct sockaddr_in sockaddr_in_from;
446 char packet[0x10000];
447 socklen_t sockaddr_in_from_length;
449 sockaddr_in_from_length=sizeof(sockaddr_in_from);
450 if (-1==(gotlen=recvfrom(
451 master_udp->gpollfd.fd, /* s */
453 sizeof(packet), /* len */
455 (struct sockaddr *)&sockaddr_in_from, /* from */
456 &sockaddr_in_from_length))) /* fromlen */
458 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
461 /* Probe socket should have no response; maybe some ICMP errors - ignored. */
465 static void handle_client_udp(struct client *client)
467 g_return_if_fail(client!=NULL);
468 g_return_if_fail(master_udp!=NULL);
472 struct sockaddr_in sockaddr_in_from;
473 char packet[0x10000];
474 socklen_t sockaddr_in_from_length;
476 sockaddr_in_from_length=sizeof(sockaddr_in_from);
477 if (-1==(gotlen=recvfrom(
478 client->gpollfd.fd, /* s */
480 sizeof(packet), /* len */
482 (struct sockaddr *)&sockaddr_in_from, /* from */
483 &sockaddr_in_from_length))) /* fromlen */
485 if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
487 client_touch(client,CLIENT_TIMEOUT_SEC);
488 /* FIXME: errors checking */
490 master_udp->gpollfd.fd, /* s */
494 (struct sockaddr *)&client->sockaddr_in_from, /* to */
495 sizeof(client->sockaddr_in_from)); /* tolen */
499 static void handle_client_tcp_connect(struct client *server)
501 g_return_if_fail(server!=NULL);
502 g_return_if_fail(server->connect_pending);
503 g_return_if_fail(master_tcp!=NULL);
507 server->gpollfd.fd, /* sockfd */
508 (struct sockaddr *)&sockaddr_in_server, /* to */
509 sizeof(sockaddr_in_server))) { /* tolen */
510 g_warning(_("Error establishing server TCP connection: %m"));
511 client_destroy(server);
514 g_assert(server->connect_pending);
515 server->connect_pending=0;
518 /* Read from client->gpollfd.fd the data for client->bound->gstring_to_send. */
519 static void handle_client_tcp_read(struct client *client)
521 g_return_if_fail(client!=NULL);
522 g_return_if_fail(client->bound!=NULL);
523 g_return_if_fail(!client->connect_pending);
524 g_return_if_fail(master_tcp!=NULL);
529 char buf[GSTRING_TO_SEND_MAX];
531 read_max=sizeof(buf)-client->bound->gstring_to_send->len;
532 g_assert(read_max>=0);
533 if (read_max<=0) /* In fact it initially should not happen, there would be no: G_IO_IN */
535 gotlen=read(client->gpollfd.fd,buf,read_max);
539 g_warning(_("Error reading data from %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
540 client_destroy(client);
544 /* Successful close; leave the bound peer's 'gstring_to_send' to be written there. */
545 if (client->server_only && client->bound->gstring_to_send->len)
546 client_split(client);
547 client_destroy(client);
551 g_assert((size_t)gotlen<=read_max);
552 g_string_append_len(client->bound->gstring_to_send,buf,gotlen);
556 /* Write to client->gpollfd.fd the data from client->gstring_to_send. */
557 static void handle_client_tcp_write(struct client *client)
559 g_return_if_fail(client!=NULL);
560 g_return_if_fail(!client->connect_pending);
561 g_return_if_fail(master_tcp!=NULL);
566 if (client->gstring_to_send->len<=0) /* In fact it initially should not happen, there would be no: G_IO_OUT */
568 gotlen=write(client->gpollfd.fd,client->gstring_to_send->str,client->gstring_to_send->len);
572 g_warning(_("Error writing data to %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
573 client_destroy(client);
578 g_assert((size_t)gotlen<=client->gstring_to_send->len);
579 g_string_erase(client->gstring_to_send,0,gotlen);
582 /* Nothing left to do for such client. */
583 if (!client->gstring_to_send->len && !client->bound)
584 client_destroy(client);
587 static gboolean sock_source_callback(gpointer data /* unused */)
591 /* FIXME: Quadratic 'done' marking to not to stick on stale entry! */
593 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
594 struct client *client=clientl->data;
599 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
600 struct client *client=clientl->data;
605 if (client->gpollfd.revents&G_IO_IN) {
606 /**/ if (client==master_udp)
607 handle_master_udp(client);
608 else if (client==master_tcp)
609 handle_master_tcp(client);
610 else if (client==probe)
611 handle_probe(client);
612 else if (client->connect_pending)
613 g_assert_not_reached();
614 else if (client->bound)
615 handle_client_tcp_read(client);
617 handle_client_udp(client);
622 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
623 struct client *client=clientl->data;
628 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
629 struct client *client=clientl->data;
634 if (client->gpollfd.revents&G_IO_OUT) {
635 /**/ if (client==master_udp)
636 g_assert_not_reached();
637 else if (client==master_tcp)
638 g_assert_not_reached();
639 else if (client==probe)
640 g_assert_not_reached();
641 else if (client->connect_pending)
642 handle_client_tcp_connect(client);
643 else if (client->gstring_to_send)
644 handle_client_tcp_write(client);
646 g_assert_not_reached();
651 return TRUE; /* the source should be kept active */
654 static gboolean sock_source_prepare(GSource *source,gint *timeout)
660 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
661 struct client *client=clientl->data;
663 client->gpollfd.events=G_IO_IN;
664 if (!client->bound && client->gstring_to_send)
665 client->gpollfd.events&=~G_IO_IN;
666 if (client->bound && client->bound->gstring_to_send->len>=GSTRING_TO_SEND_MAX)
667 client->gpollfd.events&=~G_IO_IN;
668 if (client->connect_pending)
669 client->gpollfd.events&=~G_IO_IN;
670 if (client->bound && client->bound->connect_pending)
671 client->gpollfd.events&=~G_IO_IN;
672 if (client->connect_pending)
673 client->gpollfd.events|=G_IO_OUT;
674 if (client->gstring_to_send && client->gstring_to_send->len>0)
675 client->gpollfd.events|=G_IO_OUT;
676 g_assert(!(client->gpollfd.events&~SOCK_SOURCE_CHECK_REVENTS));
681 static gboolean sock_source_check(GSource *source)
685 for (clientl=sock_client_list;clientl;clientl=clientl->next) {
686 struct client *client=clientl->data;
688 if (client->gpollfd.revents&SOCK_SOURCE_CHECK_REVENTS)
694 static gboolean sock_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
696 g_assert(callback!=NULL);
697 return (*callback)(user_data);
700 static GSourceFuncs sock_source_watch_funcs={
703 sock_source_dispatch,
707 static void sock_gsource_destroy(void)
709 while (sock_client_list)
710 client_destroy(sock_client_list->data);
712 g_assert(master_udp==NULL);
713 g_assert(master_tcp==NULL);
714 g_assert(probe==NULL);
717 g_source_destroy(sock_gsource);
721 write_daemon_running((pid_t)-1); /* unlink; errors ignored */
724 static gboolean sock_gsource_new(void)
729 g_assert(sock_client_list==NULL);
731 /* attach sock_source_callback() to watch for any abnormalities
732 * on our open pipe 'parentheart_fds' and terminate the child if parent dies.
734 if (!(sock_gsource=g_source_new(&sock_source_watch_funcs,sizeof(GSource)))) {
735 g_warning("g_source_new(): %m");
738 g_source_set_callback(
739 sock_gsource, /* source */
740 sock_source_callback, /* func */
743 if (!g_source_attach( /* returns 'guint' id */
744 sock_gsource, /* source */
745 NULL)) { /* context; NULL means 'default context' */
746 g_warning("g_source_attach(gsource,NULL): %m");
747 sock_gsource_destroy();
753 static struct client *client_new_from_sock(int sock)
755 struct client *client;
756 static unsigned long oneul=1;
758 g_return_val_if_fail(sock>=0,NULL);
760 if (!sock_gsource_new())
763 if (ioctl(sock,FIONBIO,&oneul)) { /* non-blocking mode */
764 g_warning("ioctl(sock,FIONBIO,&1): %m");
765 close(sock); /* errors ignored */
770 client->gpollfd.fd=sock;
771 client->gpollfd.events=0; /* Initialized later. */
772 client->gpollfd.revents=0; /* Probably does not need to be initialized. */
773 client->timeout_id=0;
775 client->connect_pending=0;
776 client->server_only=0;
777 client->gstring_to_send=0;
778 sock_client_list=g_list_prepend(sock_client_list,client);
779 g_source_add_poll(sock_gsource,&client->gpollfd);
782 g_message(_("Client fd %d created"),client->gpollfd.fd);
787 static struct client *client_new(enum client_new_type type)
792 case CLIENT_NEW_TYPE_UDP:
793 if (-1==(sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP))) {
794 g_warning("socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP): %m");
798 case CLIENT_NEW_TYPE_TCP:
799 if (-1==(sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))) {
800 g_warning("socket(PF_INET,SOCK_STREAM,IPPROTO_TCP): %m");
804 default: g_assert_not_reached();
807 return client_new_from_sock(sock);
810 static void client_destroy(struct client *client)
812 struct client *bound;
814 g_return_if_fail(client!=NULL);
816 if (!sock_gsource_new())
820 g_message(_("Client fd %d timeout id %d destroy enter"),client->gpollfd.fd,client->timeout_id);
822 if (client==master_udp) {
824 g_assert(client->timeout_id==0);
826 else if (client==master_tcp) {
828 g_assert(client->timeout_id==0);
833 client_timeout_remove(client);
836 g_source_remove_poll(sock_gsource,&client->gpollfd);
837 sock_client_list=g_list_remove(sock_client_list,client);
838 close(client->gpollfd.fd); /* errors ignored */
840 if (client->gstring_to_send)
841 g_string_free(client->gstring_to_send,TRUE);
844 g_message(_("Client fd %d timeout id %d destroy finish"),client->gpollfd.fd,client->timeout_id);
850 g_assert(bound!=client);
851 g_assert(bound->bound==client);
854 client_destroy(bound);
858 static gboolean probe_send(struct client *probe,gint port_local)
860 struct sockaddr_in sockaddr_in_probe;
861 GHashTable *probe_hash;
863 size_t packet_length;
865 g_return_val_if_fail(probe!=NULL,FALSE);
867 probe_unique=g_random_int();
869 probe_hash=g_hash_table_new(
870 g_direct_hash, /* hash_func */
871 g_direct_equal); /* key_equal_func */
872 g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_PORT) ,GUINT_TO_POINTER(port_local));
873 g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),GUINT_TO_POINTER(probe_unique));
874 packet=packet_assembly(&packet_length,probe_hash);
875 g_hash_table_destroy(probe_hash);
879 UDPGATE_MEMZERO(&sockaddr_in_probe);
880 sockaddr_in_probe.sin_family=AF_INET;
881 sockaddr_in_probe.sin_port=htons(PROBE_PORT);
882 sockaddr_in_probe.sin_addr.s_addr=htonl(PROBE_INADDR);
883 /* FIXME: errors checking */
885 probe->gpollfd.fd, /* s */
887 packet_length, /* len */
889 (struct sockaddr *)&sockaddr_in_probe, /* to */
890 sizeof(sockaddr_in_probe)); /* tolen */
895 static gboolean master_udp_start(gint port,const struct sockaddr_in *sockaddr_in_pointer)
897 g_return_val_if_fail(master_udp==NULL,FALSE);
899 if (!(master_udp=client_new(CLIENT_NEW_TYPE_UDP)))
901 if (bind(master_udp->gpollfd.fd,(struct sockaddr *)sockaddr_in_pointer,sizeof(*sockaddr_in_pointer))) {
902 g_warning("bind(sock_udp,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
908 static gboolean master_tcp_start(gint port,const struct sockaddr_in *sockaddr_in_pointer)
912 g_return_val_if_fail(master_tcp==NULL,FALSE);
914 if (!(master_tcp=client_new(CLIENT_NEW_TYPE_TCP)))
916 if (setsockopt(master_tcp->gpollfd.fd,SOL_SOCKET,SO_REUSEADDR,&onei,sizeof(onei))) {
917 g_warning("setsockopt(sock_tcp,SOL_SOCKET,SO_REUSEADDR,1): %m");
920 if (bind(master_tcp->gpollfd.fd,(struct sockaddr *)sockaddr_in_pointer,sizeof(*sockaddr_in_pointer))) {
921 g_warning("bind(sock_tcp,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
924 if (listen(master_tcp->gpollfd.fd,TCP_BACKLOG)) {
925 g_warning("listen(sock_tcp,%d): %m",TCP_BACKLOG);
931 static gboolean master_start(gint port)
933 struct sockaddr_in sockaddr_in;
936 g_return_val_if_fail(port>=0,FALSE);
937 g_return_val_if_fail(master_udp==NULL,FALSE);
938 g_return_val_if_fail(master_tcp==NULL,FALSE);
941 if (port < 0 || port_use != port) {
942 g_warning(_("Port value %d is not valid for IPv4!"),(int)port);
945 UDPGATE_MEMZERO(&sockaddr_in);
946 sockaddr_in.sin_family=AF_INET;
947 sockaddr_in.sin_port=htons(port_use);
948 sockaddr_in.sin_addr.s_addr=htonl(INADDR_ANY);
950 if (!master_udp_start(port,&sockaddr_in))
952 if (!master_tcp_start(port,&sockaddr_in)) {
953 client_destroy(master_udp);
959 static gboolean probe_start(gint port)
961 g_return_val_if_fail(port>=0,FALSE);
962 g_return_val_if_fail(probe==NULL,FALSE);
965 if (!(probe=client_new(CLIENT_NEW_TYPE_UDP)))
968 if (!probe_send(probe,port)) {
969 client_destroy(probe);
972 probe_timeout_sec_now=PROBE_TIMEOUT_SEC_BASE;
973 client_touch(probe,probe_timeout_sec_now); /* timeout */
977 gboolean network_start(gint port)
981 g_return_val_if_fail(port>=0,FALSE);
983 UDPGATE_MEMZERO(&sockaddr_in_server);
984 sockaddr_in_server.sin_family=AF_INET;
985 sockaddr_in_server.sin_port=htons(SERVER_PORT);
986 sockaddr_in_server.sin_addr.s_addr=htonl(SERVER_INADDR);
988 if ((pid_t)-1!=(daemon_pid=is_daemon_running())) {
989 g_warning(_("Cannot start network daemon: Daemon is already running on PID %d"),(int)daemon_pid);
992 if (!master_start(port)) {
993 sock_gsource_destroy();
996 if (!probe_start(port)) {
997 sock_gsource_destroy();
1000 write_daemon_running(getpid()); /* errors ignored */
1001 if (network_notify_hostip)
1002 (*network_notify_hostip)(0);
1006 gboolean optarg_port_set_string(const gchar *port_string)
1011 g_return_val_if_fail(port_string!=NULL,FALSE);
1013 port_long=strtol(port_string,&endp,0);
1014 if (endp && *endp) {
1015 g_warning(_("Invalid port specification, offending string: %s"),endp);
1018 if (port_long<1 || port_long>=G_MAXINT || (endp && *endp)) {
1019 g_warning(_("Invalid port integer number specification (%ld)"),port_long);
1022 optarg_port=port_long;
1026 gboolean network_stop(void)
1031 if ((pid_t)-1==(daemon_pid=is_daemon_running())) {
1032 g_warning(_("Cannot stop network daemon: Daemon is not running"));
1035 if (daemon_pid==getpid()) {
1036 sock_gsource_destroy();
1040 kill(daemon_pid,SIGKILL);
1042 write_daemon_running((pid_t)-1); /* unlink; errors ignored */
1044 g_warning(udpgate_printf_alloca(_("Unable to stop the daemon at PID %d: %s"),
1045 (int)daemon_pid,strerror(errno_save)));
1049 if (network_notify_hostip)
1050 (*network_notify_hostip)(0);
1054 static GMainLoop *gmainloop;
1055 static void network_detach_network_notify_hostip(guint32 hostip_guint32)
1057 if (!hostip_guint32)
1058 g_main_loop_quit(gmainloop);
1061 gboolean network_detach(void)
1063 pid_t daemon_pid,forked_pid;
1065 if ((pid_t)-1==(daemon_pid=is_daemon_running()))
1067 if (getpid()!=daemon_pid)
1069 if (!optarg_no_fork) {
1070 if ((pid_t)-1==(forked_pid=fork())) {
1071 g_warning("fork(2): %m");
1078 write_daemon_running(getpid()); /* errors ignored */
1080 close(STDIN_FILENO);
1081 close(STDOUT_FILENO);
1082 close(STDERR_FILENO);
1087 network_notify_hostip=network_detach_network_notify_hostip;
1088 gmainloop=g_main_loop_new(
1090 TRUE); /* is_running; ignored */
1091 g_main_loop_run(gmainloop); /* loop */
1092 /* Unable to contact the server, aborting. */