TCP port forwarding implemented.
authorshort <>
Sun, 13 Nov 2005 15:09:06 +0000 (15:09 +0000)
committershort <>
Sun, 13 Nov 2005 15:09:06 +0000 (15:09 +0000)
 - FIXME: Probing is not performed for the TCP port!
 - FIXME: 'struct client' is ugly.

src/network.c

index 07a3061..40c2bf8 100644 (file)
@@ -44,8 +44,7 @@
 
 
 /* Config: */
-#define SOCK_SOURCE_CHECK_EVENTS (G_IO_IN)     /* |G_IO_PRI */
-#define SOCK_SOURCE_CHECK_REVENTS (SOCK_SOURCE_CHECK_EVENTS)   /* |G_IO_ERR|G_IO_HUP|G_IO_NVAL */
+#define SOCK_SOURCE_CHECK_REVENTS (G_IO_IN|G_IO_OUT)   /* |G_IO_ERR|G_IO_HUP|G_IO_NVAL */
 #define SERVER_INADDR 0xC37AD054       /* mms2.org = 195.122.208.84; host order */
 #define SERVER_PORT   9201     /* host order */
 #define PROBE_INADDR  SERVER_INADDR    /* host order */
@@ -53,6 +52,8 @@
 #define CLIENT_TIMEOUT_SEC (5*60)
 #define PROBE_TIMEOUT_SEC_BASE 5
 #define PROBE_TIMEOUT_SEC_MAX 3500
+#define TCP_BACKLOG 5
+#define GSTRING_TO_SEND_MAX 1500*6     /* maximum data buffered per TCP client */
 
 
 void (*network_notify_hostip)(guint32 hostip_guint32);
@@ -77,12 +78,18 @@ struct client {
        GPollFD gpollfd;
        struct sockaddr_in sockaddr_in_from;
        guint timeout_id;
+       struct client *bound;
+       unsigned connect_pending:1;     /* for TCP connection to the server; activated by: G_IO_OUT */
+       unsigned server_only:1; /* nonimportant connect - the server side */
+       unsigned done:1;        /* temporary marker */
+       GString *gstring_to_send;       /* for TCP connections; data to be sent to this socket */
        };
 
 static GSource *sock_gsource;
 
 static GList *sock_client_list;        /* of 'struct client *', incl. 'master' and 'probe' */
-static struct client *master;  /* no 'timeout' permitted */
+static struct client *master_udp;      /* no 'timeout' permitted */
+static struct client *master_tcp;      /* no 'timeout' permitted */
 static struct client *probe;   /* 'timeout' permitted */
 static guint32 probe_unique;
 static guint probe_timeout_sec_now;
@@ -150,7 +157,8 @@ static gboolean once=TRUE;
 static void client_timeout_remove(struct client *client)
 {
        g_return_if_fail(client!=NULL);
-       g_return_if_fail(client!=master);
+       g_return_if_fail(client!=master_udp);
+       g_return_if_fail(client!=master_tcp);
 
        if (client->timeout_id) {
 gboolean errgboolean;
@@ -168,7 +176,8 @@ static gboolean client_touch_timeout(struct client *client);
 static void client_touch(struct client *client,guint timeout_sec)
 {
        g_return_if_fail(client!=NULL);
-       g_return_if_fail(client!=master);
+       g_return_if_fail(client!=master_udp);
+       g_return_if_fail(client!=master_tcp);
        g_return_if_fail(timeout_sec>0);
 
        client_timeout_remove(client);
@@ -187,7 +196,8 @@ static gboolean probe_send(struct client *probe,gint port_local);
 static gboolean client_touch_timeout(struct client *client)
 {
        g_return_val_if_fail(client!=NULL,FALSE);       /* FALSE=>should be removed */
-       g_return_val_if_fail(client!=master,FALSE);     /* FALSE=>should be removed */
+       g_return_val_if_fail(client!=master_udp,FALSE); /* FALSE=>should be removed */
+       g_return_val_if_fail(client!=master_tcp,FALSE); /* FALSE=>should be removed */
 
        if (optarg_verbose)
                g_message(_("Client fd %d timeout id %d occured/entered"),client->gpollfd.fd,client->timeout_id);
@@ -264,24 +274,60 @@ err_packet_disassembly_destroy_got_hash:
                (*network_notify_hostip)(hostip_guint32);
 }
 
-static struct client *client_new(void);
+enum client_new_type {
+       CLIENT_NEW_TYPE_UDP,
+       CLIENT_NEW_TYPE_TCP,
+       };
+
+static struct client *client_new(enum client_new_type type);
+static struct client *client_new_from_sock(int sock);
+
+static void clients_bind(struct client *client0,struct client *client1)
+{
+       g_return_if_fail(client0!=NULL);
+       g_return_if_fail(client0->bound==NULL);
+       g_return_if_fail(client0->gstring_to_send==NULL);
+       g_return_if_fail(client1!=NULL);
+       g_return_if_fail(client1->bound==NULL);
+       g_return_if_fail(client1->gstring_to_send==NULL);
+       g_return_if_fail(client0!=client1);
+
+       client0->bound=client1;
+       client1->bound=client0;
+
+       client0->gstring_to_send=g_string_sized_new(GSTRING_TO_SEND_MAX);
+       client1->gstring_to_send=g_string_sized_new(GSTRING_TO_SEND_MAX);
+}
+
+static void client_split(struct client *client)
+{
+       g_return_if_fail(client!=NULL);
+       g_return_if_fail(client->bound!=NULL);
+       g_return_if_fail(client->bound!=client);
+       g_return_if_fail(client->bound->bound==client);
+       g_return_if_fail(client->gstring_to_send!=NULL);
+
+       client->bound->bound=NULL;
+       client->bound=NULL;
+}
 
-static void handle_master(struct client *master)
+static struct sockaddr_in sockaddr_in_server;
+
+static void handle_master_udp(struct client *master_udp)
 {
-       g_return_if_fail(master!=NULL);
+       g_return_if_fail(master_udp!=NULL);
 
        for (;;) {
 char packet[0x10000];
 ssize_t gotlen;
 struct sockaddr_in sockaddr_in_from;
 struct client *client=NULL     /* Prevent false positive: might be used uninitialized */;
-struct sockaddr_in sockaddr_in_server;
 socklen_t sockaddr_in_from_length;
 GList *clientl;
 
                sockaddr_in_from_length=sizeof(sockaddr_in_from);
                if (-1==(gotlen=recvfrom(
-                               master->gpollfd.fd,     /* s */
+                               master_udp->gpollfd.fd, /* s */
                                packet, /* buf */
                                sizeof(packet), /* len */
                                0,      /* flags */
@@ -307,7 +353,7 @@ GList *clientl;
                /* FIXME: Performance: Ugly search... */
                for (clientl=sock_client_list;clientl;clientl=clientl->next) {
                        client=clientl->data;
-                       if (client==master)
+                       if (client==master_udp)
                                continue;
                        if (1
                                        && client->sockaddr_in_from.sin_family     ==sockaddr_in_from.sin_family
@@ -316,14 +362,10 @@ GList *clientl;
                                break;
                        }
                if (!clientl) {
-                       client=client_new();
+                       client=client_new(CLIENT_NEW_TYPE_UDP);
                        client->sockaddr_in_from=sockaddr_in_from;
                        }
                client_touch(client,CLIENT_TIMEOUT_SEC);
-               UDPGATE_MEMZERO(&sockaddr_in_server);
-               sockaddr_in_server.sin_family=AF_INET;
-               sockaddr_in_server.sin_port=htons(SERVER_PORT);
-               sockaddr_in_server.sin_addr.s_addr=htonl(SERVER_INADDR);
                /* FIXME: errors checking */
                sendto(
                                client->gpollfd.fd,     /* s */
@@ -335,6 +377,65 @@ GList *clientl;
                }
 }
 
+static void handle_master_tcp(struct client *master_tcp)
+{
+       g_return_if_fail(master_tcp!=NULL);
+
+       for (;;) {
+int sock_new;
+struct sockaddr_in sockaddr_in_from;
+struct client *client=NULL     /* Prevent false positive: might be used uninitialized */;
+socklen_t sockaddr_in_from_length;
+int connect_got;
+struct client *server;
+
+               sockaddr_in_from_length=sizeof(sockaddr_in_from);
+               if (-1==(sock_new=accept(
+                               master_tcp->gpollfd.fd, /* s */
+                               (struct sockaddr *)&sockaddr_in_from,   /* from */
+                               &sockaddr_in_from_length)))     /* fromlen */
+                       break;
+
+               if (sockaddr_in_from_length!=sizeof(sockaddr_in_from))  /* FIXME: errors reporting */
+                       continue;
+
+               /* Not yet initialized by 'probe' reply - drop it. */
+               if (probe) {
+                       if (optarg_verbose)
+                               g_message(_("Incoming connection received from %s but no probe reply yet; dropping connection."),
+                                               SOCKADDR_IN_TO_STRING(&sockaddr_in_from));
+                       close(sock_new);        /* FIXME: errors reporting */
+                       continue;
+                       }
+
+               if (!(client=client_new_from_sock(sock_new)))
+                       continue;
+               client->sockaddr_in_from=sockaddr_in_from;
+
+               if (!(server=client_new(CLIENT_NEW_TYPE_TCP))) {
+                       client_destroy(client);
+                       continue;
+                       }
+               server->server_only=1;
+               server->sockaddr_in_from=sockaddr_in_server;
+               clients_bind(client,server);
+               /* Currently only one of 'client' or 'server' needs to be destroyed. */
+
+               errno=0;
+               connect_got=connect(
+                               server->gpollfd.fd,     /* sockfd */
+                               (struct sockaddr *)&sockaddr_in_server, /* to */
+                               sizeof(sockaddr_in_server));    /* tolen */
+               if (connect_got!=-1 || errno!=EINPROGRESS) {
+                       g_warning(_("Error establishing server TCP connection: %m"));
+                       client_destroy(server);
+                       continue;
+                       }
+               g_assert(!server->connect_pending);
+               server->connect_pending=1;
+               }
+}
+
 static void handle_probe(struct client *probe)
 {
        g_return_if_fail(probe!=NULL);
@@ -347,7 +448,7 @@ socklen_t sockaddr_in_from_length;
 
                sockaddr_in_from_length=sizeof(sockaddr_in_from);
                if (-1==(gotlen=recvfrom(
-                               master->gpollfd.fd,     /* s */
+                               master_udp->gpollfd.fd, /* s */
                                packet, /* buf */
                                sizeof(packet), /* len */
                                0,      /* flags */
@@ -361,15 +462,15 @@ socklen_t sockaddr_in_from_length;
                }
 }
 
-static void handle_client(struct client *client)
+static void handle_client_udp(struct client *client)
 {
        g_return_if_fail(client!=NULL);
-       g_return_if_fail(master!=NULL);
+       g_return_if_fail(master_udp!=NULL);
 
        for (;;) {
 ssize_t gotlen;
 struct sockaddr_in sockaddr_in_from;
-char packet [0x10000];
+char packet[0x10000];
 socklen_t sockaddr_in_from_length;
 
                sockaddr_in_from_length=sizeof(sockaddr_in_from);
@@ -386,7 +487,7 @@ socklen_t sockaddr_in_from_length;
                client_touch(client,CLIENT_TIMEOUT_SEC);
                /* FIXME: errors checking */
                sendto(
-                               master->gpollfd.fd,     /* s */
+                               master_udp->gpollfd.fd, /* s */
                                packet, /* msg */
                                gotlen, /* len */
                                0,      /* flags */
@@ -395,21 +496,156 @@ socklen_t sockaddr_in_from_length;
                }
 }
 
+static void handle_client_tcp_connect(struct client *server)
+{
+       g_return_if_fail(server!=NULL);
+       g_return_if_fail(server->connect_pending);
+       g_return_if_fail(master_tcp!=NULL);
+
+       errno=0;
+       if (connect(
+                       server->gpollfd.fd,     /* sockfd */
+                       (struct sockaddr *)&sockaddr_in_server, /* to */
+                       sizeof(sockaddr_in_server))) {  /* tolen */
+               g_warning(_("Error establishing server TCP connection: %m"));
+               client_destroy(server);
+               return;
+               }
+       g_assert(server->connect_pending);
+       server->connect_pending=0;
+}
+
+/* Read from client->gpollfd.fd the data for client->bound->gstring_to_send. */
+static void handle_client_tcp_read(struct client *client)
+{
+       g_return_if_fail(client!=NULL);
+       g_return_if_fail(client->bound!=NULL);
+       g_return_if_fail(!client->connect_pending);
+       g_return_if_fail(master_tcp!=NULL);
+
+       for (;;) {
+ssize_t gotlen;
+size_t read_max;
+char buf[GSTRING_TO_SEND_MAX];
+
+               read_max=sizeof(buf)-client->bound->gstring_to_send->len;
+               g_assert(read_max>=0);
+               if (read_max<=0)        /* In fact it initially should not happen, there would be no: G_IO_IN */
+                       break;
+               gotlen=read(client->gpollfd.fd,buf,read_max);
+               if (gotlen==-1) {
+                       if (errno==EAGAIN)
+                               break;
+                       g_warning(_("Error reading data from %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
+                       client_destroy(client);
+                       return;
+                       }
+               if (gotlen==0) {
+                       /* Successful close; leave the bound peer's 'gstring_to_send' to be written there. */
+                       if (client->server_only && client->bound->gstring_to_send->len)
+                               client_split(client);
+                       client_destroy(client);
+                       return;
+                       }
+               g_assert(gotlen>0);
+               g_assert((size_t)gotlen<=read_max);
+               g_string_append_len(client->bound->gstring_to_send,buf,gotlen);
+               }
+}
+
+/* Write to client->gpollfd.fd the data from client->gstring_to_send. */
+static void handle_client_tcp_write(struct client *client)
+{
+       g_return_if_fail(client!=NULL);
+       g_return_if_fail(!client->connect_pending);
+       g_return_if_fail(master_tcp!=NULL);
+
+       for (;;) {
+ssize_t gotlen;
+
+               if (client->gstring_to_send->len<=0)    /* In fact it initially should not happen, there would be no: G_IO_OUT */
+                       break;
+               gotlen=write(client->gpollfd.fd,client->gstring_to_send->str,client->gstring_to_send->len);
+               if (gotlen==-1) {
+                       if (errno==EAGAIN)
+                               break;
+                       g_warning(_("Error writing data to %s"),SOCKADDR_IN_TO_STRING(&client->sockaddr_in_from));
+                       client_destroy(client);
+                       return;
+                       }
+               if (gotlen<=0)
+                       break;
+               g_assert((size_t)gotlen<=client->gstring_to_send->len);
+               g_string_erase(client->gstring_to_send,0,gotlen);
+               }
+
+       /* Nothing left to do for such client. */
+       if (!client->gstring_to_send->len && !client->bound)
+               client_destroy(client);
+}
+
 static gboolean sock_source_callback(gpointer data /* unused */)
 {
 GList *clientl;
 
+       /* FIXME: Quadratic 'done' marking to not to stick on stale entry! */
+
+       for (clientl=sock_client_list;clientl;clientl=clientl->next) {
+struct client *client=clientl->data;
+
+               client->done=0;
+               }
+retry_in:
        for (clientl=sock_client_list;clientl;clientl=clientl->next) {
 struct client *client=clientl->data;
 
-               if (client->gpollfd.revents&SOCK_SOURCE_CHECK_REVENTS) {
-                       /**/ if (client==master)
-                               handle_master(client);
+               if (client->done)
+                       continue;
+               client->done=1;
+               if (client->gpollfd.revents&G_IO_IN) {
+                       /**/ if (client==master_udp)
+                               handle_master_udp(client);
+                       else if (client==master_tcp)
+                               handle_master_tcp(client);
                        else if (client==probe)
                                handle_probe(client);
+                       else if (client->connect_pending)
+                               g_assert_not_reached();
+                       else if (client->bound)
+                               handle_client_tcp_read(client);
+                       else
+                               handle_client_udp(client);
+                       }
+               goto retry_in;
+               }
+
+       for (clientl=sock_client_list;clientl;clientl=clientl->next) {
+struct client *client=clientl->data;
+
+               client->done=0;
+               }
+retry_out:
+       for (clientl=sock_client_list;clientl;clientl=clientl->next) {
+struct client *client=clientl->data;
+
+               if (client->done)
+                       continue;
+               client->done=1;
+               if (client->gpollfd.revents&G_IO_OUT) {
+                       /**/ if (client==master_udp)
+                               g_assert_not_reached();
+                       else if (client==master_tcp)
+                               g_assert_not_reached();
+                       else if (client==probe)
+                               g_assert_not_reached();
+                       else if (client->connect_pending)
+                               handle_client_tcp_connect(client);
+                       else if (client->gstring_to_send)
+                               handle_client_tcp_write(client);
                        else
-                               handle_client(client);
+                               g_assert_not_reached();
                        }
+               goto retry_out;
                }
 
        return TRUE; /* the source should be kept active */
@@ -417,8 +653,28 @@ struct client *client=clientl->data;
 
 static gboolean sock_source_prepare(GSource *source,gint *timeout)
 {
+GList *clientl;
+
        *timeout=-1;
 
+       for (clientl=sock_client_list;clientl;clientl=clientl->next) {
+struct client *client=clientl->data;
+
+               client->gpollfd.events=G_IO_IN;
+               if (!client->bound && client->gstring_to_send)
+                       client->gpollfd.events&=~G_IO_IN;
+               if (client->bound && client->bound->gstring_to_send->len>=GSTRING_TO_SEND_MAX)
+                       client->gpollfd.events&=~G_IO_IN;
+               if (client->connect_pending)
+                       client->gpollfd.events&=~G_IO_IN;
+               if (client->bound && client->bound->connect_pending)
+                       client->gpollfd.events&=~G_IO_IN;
+               if (client->connect_pending)
+                       client->gpollfd.events|=G_IO_OUT;
+               if (client->gstring_to_send && client->gstring_to_send->len>0)
+                       client->gpollfd.events|=G_IO_OUT;
+               g_assert(!(client->gpollfd.events&~SOCK_SOURCE_CHECK_REVENTS));
+               }
        return FALSE;
 }
 
@@ -453,7 +709,8 @@ static void sock_gsource_destroy(void)
        while (sock_client_list)
                client_destroy(sock_client_list->data);
 
-       g_assert(master==NULL);
+       g_assert(master_udp==NULL);
+       g_assert(master_tcp==NULL);
        g_assert(probe==NULL);
 
        if (sock_gsource) {
@@ -493,19 +750,16 @@ static gboolean sock_gsource_new(void)
        return TRUE;
 }
 
-static struct client *client_new(void)
+static struct client *client_new_from_sock(int sock)
 {
 struct client *client;
 static unsigned long oneul=1;
-int sock;
+
+       g_return_val_if_fail(sock>=0,NULL);
 
        if (!sock_gsource_new())
                return FALSE;
 
-       if (-1==(sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))) {
-               g_warning("socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP): %m");
-               return NULL;
-               }
        if (ioctl(sock,FIONBIO,&oneul)) {       /* non-blocking mode */
                g_warning("ioctl(sock,FIONBIO,&1): %m");
                close(sock);    /* errors ignored */
@@ -514,9 +768,13 @@ int sock;
 
        udpgate_new(client);
        client->gpollfd.fd=sock;
-       client->gpollfd.events=SOCK_SOURCE_CHECK_EVENTS;
-       client->gpollfd.revents=0;
+       client->gpollfd.events=0;       /* Initialized later. */
+       client->gpollfd.revents=0;      /* Probably does not need to be initialized. */
        client->timeout_id=0;
+       client->bound=NULL;
+       client->connect_pending=0;
+       client->server_only=0;
+       client->gstring_to_send=0;
        sock_client_list=g_list_prepend(sock_client_list,client);
        g_source_add_poll(sock_gsource,&client->gpollfd);
 
@@ -526,8 +784,33 @@ int sock;
        return client;
 }
 
+static struct client *client_new(enum client_new_type type)
+{
+int sock;
+
+       switch (type) {
+               case CLIENT_NEW_TYPE_UDP:
+                       if (-1==(sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP))) {
+                               g_warning("socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP): %m");
+                               return NULL;
+                               }
+                       break;
+               case CLIENT_NEW_TYPE_TCP:
+                       if (-1==(sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))) {
+                               g_warning("socket(PF_INET,SOCK_STREAM,IPPROTO_TCP): %m");
+                               return NULL;
+                               }
+                       break;
+               default: g_assert_not_reached();
+               }
+
+       return client_new_from_sock(sock);
+}
+
 static void client_destroy(struct client *client)
 {
+struct client *bound;
+
        g_return_if_fail(client!=NULL);
 
        if (!sock_gsource_new())
@@ -536,8 +819,12 @@ static void client_destroy(struct client *client)
        if (optarg_verbose)
                g_message(_("Client fd %d timeout id %d destroy enter"),client->gpollfd.fd,client->timeout_id);
 
-       if (client==master) {
-               master=NULL;
+       if (client==master_udp) {
+               master_udp=NULL;
+               g_assert(client->timeout_id==0);
+               }
+       else if (client==master_tcp) {
+               master_tcp=NULL;
                g_assert(client->timeout_id==0);
                }
        else {
@@ -550,15 +837,27 @@ static void client_destroy(struct client *client)
        sock_client_list=g_list_remove(sock_client_list,client);
        close(client->gpollfd.fd);      /* errors ignored */
 
+       if (client->gstring_to_send)
+               g_string_free(client->gstring_to_send,TRUE);
+
        if (optarg_verbose)
                g_message(_("Client fd %d timeout id %d destroy finish"),client->gpollfd.fd,client->timeout_id);
 
+       bound=client->bound;
        g_free(client);
+
+       if (bound) {
+               g_assert(bound!=client);
+               g_assert(bound->bound==client);
+               client->bound=NULL;
+               bound->bound=NULL;
+               client_destroy(bound);
+               }
 }
 
 static gboolean probe_send(struct client *probe,gint port_local)
 {
-struct sockaddr_in sockaddr_in_server;
+struct sockaddr_in sockaddr_in_probe;
 GHashTable *probe_hash;
 gpointer packet;
 size_t packet_length;
@@ -577,19 +876,55 @@ size_t packet_length;
        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);
+       UDPGATE_MEMZERO(&sockaddr_in_probe);
+       sockaddr_in_probe.sin_family=AF_INET;
+       sockaddr_in_probe.sin_port=htons(PROBE_PORT);
+       sockaddr_in_probe.sin_addr.s_addr=htonl(PROBE_INADDR);
        /* FIXME: errors checking */
        sendto(
                        probe->gpollfd.fd,      /* s */
                        packet, /* msg */
                        packet_length,  /* len */
                        0,      /* flags */
-                       (struct sockaddr *)&sockaddr_in_server, /* to */
-                       sizeof(sockaddr_in_server));    /* tolen */
+                       (struct sockaddr *)&sockaddr_in_probe,  /* to */
+                       sizeof(sockaddr_in_probe));     /* tolen */
+
+       return TRUE;
+}
+
+static gboolean master_udp_start(gint port,const struct sockaddr_in *sockaddr_in_pointer)
+{
+       g_return_val_if_fail(master_udp==NULL,FALSE);
 
+       if (!(master_udp=client_new(CLIENT_NEW_TYPE_UDP)))
+               return FALSE;
+       if (bind(master_udp->gpollfd.fd,(struct sockaddr *)sockaddr_in_pointer,sizeof(*sockaddr_in_pointer))) {
+               g_warning("bind(sock_udp,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
+               return FALSE;
+               }
+       return TRUE;
+}
+
+static gboolean master_tcp_start(gint port,const struct sockaddr_in *sockaddr_in_pointer)
+{
+static int onei=1;
+
+       g_return_val_if_fail(master_tcp==NULL,FALSE);
+
+       if (!(master_tcp=client_new(CLIENT_NEW_TYPE_TCP)))
+               return FALSE;
+       if (setsockopt(master_tcp->gpollfd.fd,SOL_SOCKET,SO_REUSEADDR,&onei,sizeof(onei))) {
+               g_warning("setsockopt(sock_tcp,SOL_SOCKET,SO_REUSEADDR,1): %m");
+               return FALSE;
+               }
+       if (bind(master_tcp->gpollfd.fd,(struct sockaddr *)sockaddr_in_pointer,sizeof(*sockaddr_in_pointer))) {
+               g_warning("bind(sock_tcp,{AF_INET,INADDR_ANY:%d}): %m",(int)port);
+               return FALSE;
+               }
+       if (listen(master_tcp->gpollfd.fd,TCP_BACKLOG)) {
+               g_warning("listen(sock_tcp,%d): %m",TCP_BACKLOG);
+               return FALSE;
+               }
        return TRUE;
 }
 
@@ -599,23 +934,23 @@ struct sockaddr_in sockaddr_in;
 uint16_t port_use;
 
        g_return_val_if_fail(port>=0,FALSE);
-       g_return_val_if_fail(master==NULL,FALSE);
+       g_return_val_if_fail(master_udp==NULL,FALSE);
+       g_return_val_if_fail(master_tcp==NULL,FALSE);
 
        port_use=port;
        if (port < 0 || port_use != port) {
                g_warning(_("Port value %d is not valid for IPv4!"),(int)port);
                return FALSE;
                }
-
-       /* Setup 'master': */
-       if (!(master=client_new()))
-               return FALSE;
        UDPGATE_MEMZERO(&sockaddr_in);
        sockaddr_in.sin_family=AF_INET;
        sockaddr_in.sin_port=htons(port_use);
        sockaddr_in.sin_addr.s_addr=htonl(INADDR_ANY);
-       if (bind(master->gpollfd.fd,(struct sockaddr *)&sockaddr_in,sizeof(sockaddr_in))) {
-               g_warning("bind(sock,{AF_INET,INADDR_ANY:%u}): %m",(unsigned)port_use);
+
+       if (!master_udp_start(port,&sockaddr_in))
+               return FALSE;
+       if (!master_tcp_start(port,&sockaddr_in)) {
+               client_destroy(master_udp);
                return FALSE;
                }
        return TRUE;
@@ -627,7 +962,7 @@ static gboolean probe_start(gint port)
        g_return_val_if_fail(probe==NULL,FALSE);
 
        /* Setup 'probe': */
-       if (!(probe=client_new()))
+       if (!(probe=client_new(CLIENT_NEW_TYPE_UDP)))
                return FALSE;
        port_local=port;
        if (!probe_send(probe,port)) {
@@ -645,6 +980,11 @@ pid_t daemon_pid;
 
        g_return_val_if_fail(port>=0,FALSE);
 
+       UDPGATE_MEMZERO(&sockaddr_in_server);
+       sockaddr_in_server.sin_family=AF_INET;
+       sockaddr_in_server.sin_port=htons(SERVER_PORT);
+       sockaddr_in_server.sin_addr.s_addr=htonl(SERVER_INADDR);
+
        if ((pid_t)-1!=(daemon_pid=is_daemon_running())) {
                g_warning(_("Cannot start network daemon: Daemon is already running on PID %d"),(int)daemon_pid);
                return FALSE;