#include <string.h>
#include <glib/galloca.h>
#include <glib/gprintf.h>
+#include <glib/grand.h>
#include "network.h"
+#include "packet.h"
/* Config: */
#define PROBE_TIMEOUT_SEC (5)
+void (*network_notify_hostip)(guint32 hostip_guint32,const gchar *hostip_string);
+
+
struct client {
GPollFD gpollfd;
struct sockaddr_in sockaddr_in_from;
static GSource *sock_gsource;
static GList *sock_client_list; /* of 'struct client *', incl. 'master' and 'probe' */
-struct client *master; /* no 'timeout' permitted */
-struct client *probe; /* 'timeout' permitted */
+static struct client *master; /* no 'timeout' permitted */
+static struct client *probe; /* 'timeout' permitted */
+static guint32 probe_unique;
static gboolean write_daemon_running(pid_t pid);
g_return_val_if_fail(client!=NULL,FALSE); /* FALSE=>should be removed */
g_return_val_if_fail(client!=master,FALSE); /* FALSE=>should be removed */
+ if (client==probe) {
+ network_stop();
+ if (network_notify_hostip)
+ (*network_notify_hostip)(0,NULL);
+ }
+
client_destroy(client);
return FALSE; /* GSource should be removed */
char packet[0x10000];
struct client *client;
struct sockaddr_in sockaddr_in_server;
-socklen_t sockaddr_in_from_len;
+socklen_t sockaddr_in_from_length;
g_return_if_fail(master!=NULL);
- sockaddr_in_from_len=sizeof(sockaddr_in_from);
+ sockaddr_in_from_length=sizeof(sockaddr_in_from);
while (-1!=(gotlen=recvfrom(
master->gpollfd.fd, /* s */
packet, /* buf */
sizeof(packet), /* len */
0, /* flags */
(struct sockaddr *)&sockaddr_in_from, /* from */
- &sockaddr_in_from_len))) { /* fromlen */
+ &sockaddr_in_from_length))) { /* fromlen */
GList *clientl;
- if (sockaddr_in_from_len!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
+ if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
continue;
/* FIXME: Performance: Ugly search... */
for (clientl=sock_client_list;clientl;clientl=clientl->next) {
ssize_t gotlen;
struct sockaddr_in sockaddr_in_from;
char packet[0x10000];
-socklen_t sockaddr_in_from_len;
+socklen_t sockaddr_in_from_length;
g_return_if_fail(probe!=NULL);
- sockaddr_in_from_len=sizeof(sockaddr_in_from);
+ sockaddr_in_from_length=sizeof(sockaddr_in_from);
while (-1!=(gotlen=recvfrom(
master->gpollfd.fd, /* s */
packet, /* buf */
sizeof(packet), /* len */
0, /* flags */
(struct sockaddr *)&sockaddr_in_from, /* from */
- &sockaddr_in_from_len))) { /* fromlen */
+ &sockaddr_in_from_length))) { /* fromlen */
+static GHashTable *got_hash;
+static gpointer got_unique_gpointer;
+static gpointer hostip_gpointer;
+static guint32 hostip_guint32;
- if (sockaddr_in_from_len!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
+ if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
+ continue;
+ if (!(got_hash=packet_disassembly(packet,gotlen)))
+ continue;
+ if (!(g_hash_table_lookup_extended(
+ got_hash, /* hash_table */
+ GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32), /* lookup_key */
+ NULL, /* orig_key */
+ &got_unique_gpointer))) {
+err_packet_disassembly_destroy_got_hash:
+ packet_disassembly_destroy(got_hash);
continue;
+ }
+ if (GPOINTER_TO_UINT(got_unique_gpointer)!=probe_unique)
+ goto err_packet_disassembly_destroy_got_hash;
+ if (!(g_hash_table_lookup_extended(
+ got_hash, /* hash_table */
+ GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_INADDR), /* lookup_key */
+ NULL, /* orig_key */
+ &hostip_gpointer)))
+ goto err_packet_disassembly_destroy_got_hash;
+ hostip_guint32=GPOINTER_TO_UINT(hostip_gpointer);
+ packet_disassembly_destroy(got_hash);
+
+ client_destroy(probe);
+ if (network_notify_hostip)
+ (*network_notify_hostip)(hostip_guint32,
+ udpgate_printf_alloca("%d.%d.%d.%d",
+ (hostip_guint32>>24U)&0xFFU,
+ (hostip_guint32>>16U)&0xFFU,
+ (hostip_guint32>> 8U)&0xFFU,
+ (hostip_guint32>> 0U)&0xFFU));
}
}
ssize_t gotlen;
struct sockaddr_in sockaddr_in_from;
char packet [0x10000];
-socklen_t sockaddr_in_from_len;
+socklen_t sockaddr_in_from_length;
g_return_if_fail(client!=NULL);
g_return_if_fail(master!=NULL);
sizeof(packet), /* len */
0, /* flags */
(struct sockaddr *)&sockaddr_in_from, /* from */
- &sockaddr_in_from_len))) { /* fromlen */
- if (sockaddr_in_from_len!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
+ &sockaddr_in_from_length))) { /* fromlen */
+ if (sockaddr_in_from_length!=sizeof(sockaddr_in_from)) /* FIXME: errors reporting */
continue;
client_touch(client);
/* FIXME: errors checking */
master=NULL;
g_assert(client->timeout_id==0);
}
- else
+ else {
+ if (client==probe)
+ probe=NULL;
client_timeout_remove(client);
+ }
g_source_remove_poll(sock_gsource,&client->gpollfd);
sock_client_list=g_list_remove(sock_client_list,client);
g_free(client);
}
-static gboolean probe_send(struct client *probe)
+static gboolean probe_send(struct client *probe,gint port_local)
{
struct sockaddr_in sockaddr_in_server;
+GHashTable *probe_hash;
+gpointer packet;
+size_t packet_length;
g_return_val_if_fail(probe!=NULL,FALSE);
+ probe_unique=g_random_int();
+
+ probe_hash=g_hash_table_new(
+ g_int_hash, /* hash_func */
+ g_int_equal); /* key_equal_func */
+ g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_CLIENT_PORT) ,GUINT_TO_POINTER(port_local));
+ g_hash_table_insert(probe_hash,GUINT_TO_POINTER(PACKET_ELEM_TYPE_DATA_GUINT32),GUINT_TO_POINTER(probe_unique));
+ packet=packet_assembly(&packet_length,probe_hash);
+ g_hash_table_destroy(probe_hash);
+ if (!packet)
+ return FALSE;
+
UDPGATE_MEMZERO(&sockaddr_in_server);
sockaddr_in_server.sin_family=AF_INET;
sockaddr_in_server.sin_port=htons(PROBE_PORT);
sockaddr_in_server.sin_addr.s_addr=htonl(PROBE_INADDR);
/* FIXME: errors checking */
-#if 0
sendto(
probe->gpollfd.fd, /* s */
packet, /* msg */
- gotlen, /* len */
+ packet_length, /* len */
0, /* flags */
(struct sockaddr *)&sockaddr_in_server, /* to */
sizeof(sockaddr_in_server)); /* tolen */
-#endif
return TRUE;
}
-
gboolean network_start(gint port)
{
pid_t daemon_pid;
/* Setup 'probe': */
if (!(probe=client_new()))
goto err_sock_gsource_destroy;
- probe_send(probe);
+ probe_send(probe,port);
client_touch(probe); /* timeout */
write_daemon_running(getpid());
{
size_t string_length;
#ifndef G_DISABLE_ASSERT
-size_t gstring_len_orig;
+size_t gstring_length_orig;
#endif /* !G_DISABLE_ASSERT */
g_return_if_fail(gstring!=NULL);
string_length=strlen(string);
packet_assembly_guint32(gstring,string_length);
#ifndef G_DISABLE_ASSERT
- gstring_len_orig=gstring->len;
+ gstring_length_orig=gstring->len;
#endif /* !G_DISABLE_ASSERT */
g_string_append(gstring,string);
#ifndef G_DISABLE_ASSERT
- g_assert(gstring_len_orig+string_length==gstring->len);
+ g_assert(gstring_length_orig+string_length==gstring->len);
#endif /* !G_DISABLE_ASSERT */
}
}
}
-void *packet_assembly(size_t *packet_len_pointer,GHashTable *values)
+void *packet_assembly(size_t *packet_length_pointer,GHashTable *values)
{
GString *gstring;
- g_return_val_if_fail(packet_len_pointer!=NULL,NULL);
+ g_return_val_if_fail(packet_length_pointer!=NULL,NULL);
g_return_val_if_fail(values!=NULL,NULL);
gstring=g_string_new(NULL);
(GHFunc)packet_assembly_foreach, /* func */
gstring); /* user_data */
- *packet_len_pointer=gstring->len;
+ *packet_length_pointer=gstring->len;
return g_string_free(gstring,
FALSE); /* free_segment */
}
return TRUE;
}
-GHashTable *packet_disassembly(gconstpointer packet,size_t packet_len)
+GHashTable *packet_disassembly(gconstpointer packet,size_t packet_length)
{
GHashTable *r;
gconstpointer packet_end;
g_int_equal, /* key_equal_func */
NULL, /* key_destroy_func */
packet_disassembly_value_destroy_func); /* value_destroy_func */
- packet_end=packet+packet_len;
+ packet_end=packet+packet_length;
if (packet+strlen(PACKET_HEADER)>packet_end) {
err_g_hash_table_destroy_r: