The tcp server listen() started working. By now the connections are closed at once.
authorviric@llimona
Tue, 30 May 2006 00:32:32 +0200
changeset 51 a01abd65856a
parent 50 6958ce45aa83
child 52 3af277b9f73b
The tcp server listen() started working. By now the connections are closed at once. A bug was corrected in syslog_kernel, about EOF from read(). Added debug to term_childs().
Makefile.common
childs.c
syslog.conf
syslog.h
syslog_kernel.c
tcp_server.c
--- a/Makefile.common	Tue May 30 00:04:18 2006 +0200
+++ b/Makefile.common	Tue May 30 00:32:32 2006 +0200
@@ -20,6 +20,7 @@
 out_file.o: out_file.c syslog.h
 signals.o: signals.c syslog.h
 unix_writer.o: unix_writer.c rfc3164.h
+tcp_server.o: tcp_server.c rfc3164.h
 childs.o: childs.c syslog.h
 
 syslog_in_npipe: syslog_in_npipe.o rfc3164.a signals.o
@@ -27,7 +28,7 @@
 syslog_in_unix: syslog_in_unix.o rfc3164.a signals.o
 unix_writer: unix_writer.o
 syslog_kernel: syslog_kernel.o config.o rfc3164.a signals.o out_udp.o \
-               out_file.o childs.o
+               out_file.o childs.o tcp_server.o
 
 clean:
 	rm -f *.o *.a
--- a/childs.c	Tue May 30 00:04:18 2006 +0200
+++ b/childs.c	Tue May 30 00:32:32 2006 +0200
@@ -35,6 +35,7 @@
 	for(i=0;i<childs_alive;i++)
 	{
 		res = kill(child[i], SIGTERM);
+		fprintf(stderr, "Sent SIGTERM to %i\n", child[i]);
 		/* Accepting the res == -1 && errno == ESRCH saves us
 		 * from the race condition possible kill error */
 		if (res == -1)
--- a/syslog.conf	Tue May 30 00:04:18 2006 +0200
+++ b/syslog.conf	Tue May 30 00:32:32 2006 +0200
@@ -1,4 +1,5 @@
 from_unix=patata
 to_udp_host=localhost
 to_udp_port=8000
+tcp_manager=3000
 log_file=prova.log
--- a/syslog.h	Tue May 30 00:04:18 2006 +0200
+++ b/syslog.h	Tue May 30 00:32:32 2006 +0200
@@ -1,5 +1,6 @@
 enum {
 	MAX_STRING=255,
+	TCP_LISTEN_QUEUE=10,
 	MAX_CHILDS=15
 };
 
@@ -42,6 +43,9 @@
 int write_out_file(const char * restrict buf, const int len);
 int close_out_file();
 
+/* tcp_server.c */
+int init_tcp_server();
+
 /* childs.c */
 void term_childs();
 void wait_childs_die();
--- a/syslog_kernel.c	Tue May 30 00:04:18 2006 +0200
+++ b/syslog_kernel.c	Tue May 30 00:32:32 2006 +0200
@@ -148,6 +148,9 @@
 				fprintf(stderr, "Received: %s\n",missatge);
 				
 				output_message(missatge, res);
+			} else if (res == 0) /* EOF */
+			{
+				break;
 			}
 		}
 
@@ -207,6 +210,8 @@
 		else if (res == -1)
 			fprintf(stderr, "error setting up the File output.\n");
 
+		init_tcp_server();
+
 		kernel_loop();
 
 		if (reconfig == true)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcp_server.c	Tue May 30 00:32:32 2006 +0200
@@ -0,0 +1,246 @@
+#include <unistd.h> // Per les crides a fitxer
+#include <stdio.h>  // Per l'I/O de stdin/stdout
+#include <errno.h>  // Pels errors de les crides a fitxer
+#include <string.h> // Per strerror()
+#include <stdlib.h> // Per abort()
+#include <fcntl.h> // Per fcntl()
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdbool.h>
+#include <assert.h> // Per assert()
+#include <sys/select.h> // Pel select()
+
+#include "syslog.h"
+
+/* Prototypes */
+static void listen_tcp(const int port, const bool ipv6enabled);
+static int listen_tcp_ipv6(int port);
+static int listen_tcp_ipv4(int port);
+static int accept_connection(int socket);
+
+/* Returns 0 on success. Returns -1 on error. */
+int init_tcp_server()
+{
+	int pid;
+	int port;
+	char service[MAX_STRING];
+	enum {
+		SUCCESS=0,
+		ERROR=-1,
+		DISABLED=-2
+	} ret;
+
+	
+	/* Get the configuration */
+	get_config(TCP_MANAGER, service, MAX_STRING);
+	if (strncmp(service, "disabled", MAX_STRING) == 0)
+		return DISABLED;
+
+	/* Check the configuration */
+	port = atoi(service);
+	if (port < -65535 || port > 65535)
+		return ERROR;
+
+	/* Create the server process */
+	pid = child_fork();
+
+	if (pid == 0)
+	{
+		/* Child */
+		close(0);
+		close(1);
+		//close(2);
+		if(port < 0)
+		{
+			listen_tcp(-port, true);
+		} else
+		{
+			listen_tcp(port, false);
+		}
+		/* Should be Not reachable */
+		exit(0);
+	} else if (pid > 0)
+	{
+		/* Parent */
+		fprintf(stderr, "Child forked (tcp server on port %i): %i\n",
+			port, pid);
+		ret = SUCCESS;
+	} else
+	{
+		ret = ERROR;
+	}
+
+	return ret;
+}
+
+
+static void listen_tcp(const int port, const bool ipv6enabled)
+{
+	int socket_ipv6, socket_ipv4;
+	fd_set listen_sockets;
+	int result;
+	int high_socket;
+
+	socket_ipv4 = listen_tcp_ipv4(port);
+
+	if (ipv6enabled)
+		socket_ipv6 = listen_tcp_ipv6(port);
+
+	/* Mirem quin és el socket més alt pel select() */
+	high_socket = socket_ipv4;
+	if (ipv6enabled && (high_socket < socket_ipv6) )
+		high_socket = socket_ipv6;
+		
+	high_socket += 1;
+
+	result = 0;
+	while (result >= 0)
+	{
+		/* Establim els FDs que volem esperar al select() */
+		FD_ZERO(&listen_sockets);
+		if (ipv6enabled)
+			FD_SET(socket_ipv6, &listen_sockets);
+		FD_SET(socket_ipv4, &listen_sockets);
+
+		result = select(high_socket, &listen_sockets, NULL, NULL,
+			NULL);
+		if (result == 0)
+		{
+			/* Això no hauria de passar, no tenim timeout fixat. */
+			continue;
+		}
+		else if (result == -1 && errno != EINTR)
+		{
+			fprintf(stderr, "Error in select(): %s\n",
+				strerror(errno));
+			abort();
+		}
+
+		/* Algun FD té dades... */
+		if (FD_ISSET(socket_ipv4, &listen_sockets))
+		{
+			accept_connection(socket_ipv4);
+		}
+
+		if (ipv6enabled && FD_ISSET(socket_ipv6, &listen_sockets))
+		{
+			accept_connection(socket_ipv6);
+		}
+	}
+}
+
+
+static int listen_tcp_ipv6(int port)
+{
+	int socket_ipv6;
+	struct sockaddr_in6 source_ipv6;
+	int result;
+	int on=1;
+
+
+	socket_ipv6 = socket(PF_INET6, SOCK_STREAM, 0);
+	if (socket_ipv6 == -1)
+	{
+		fprintf(stderr, "IPv6 socket failed.\n");
+		abort();
+	}
+
+	/* Fem que poguem reutilitzar l'adreça encara que no s'hagi acabat
+	   el timeout després de tancar-se la connexió */
+	if (setsockopt(socket_ipv6, SOL_SOCKET, SO_REUSEADDR,
+	                         (char *)&on,sizeof(on)) < 0)
+	{
+		fprintf(stderr, "IPv6 setsockopt() failed: %s.\n",
+			strerror(errno));
+		abort();
+	}
+
+	/* No volem que aquest socket bloquegi. */
+	if (fcntl(socket_ipv6, F_SETFL, O_NONBLOCK) == -1)
+	{
+		fprintf(stderr, "IPv6 fcntl() failed: %s.\n",
+			strerror(errno));
+		abort();
+	}
+
+	/* IPv6 listen address */
+	memset(&source_ipv6, 0, sizeof(source_ipv6));
+	source_ipv6.sin6_family = AF_INET6;
+	source_ipv6.sin6_flowinfo = 0;
+	source_ipv6.sin6_port = htons(port);
+	source_ipv6.sin6_addr = in6addr_any;
+	result = bind(socket_ipv6, (struct sockaddr *) &source_ipv6,
+		sizeof(source_ipv6));
+	assert(result == 0);
+
+	result = listen(socket_ipv6, TCP_LISTEN_QUEUE);
+	if (result != 0)
+	{
+		fprintf(stderr,"Error in listen() ipv6: %s\n", strerror(errno));
+		abort();
+	}
+
+	return socket_ipv6;
+}
+
+static int listen_tcp_ipv4(int port)
+{
+	int socket_ipv4;
+	struct sockaddr_in source_ipv4;
+	int result;
+	int on=1;
+
+
+	socket_ipv4 = socket(PF_INET, SOCK_STREAM, 0);
+	if (socket_ipv4 == -1)
+	{
+		fprintf(stderr, "IPv4 socket not supported.\n");
+		abort();
+	}
+
+	/* Fem que poguem reutilitzar l'adreça encara que no s'hagi acabat
+	   el timeout després de tancar-se la connexió */
+	if (setsockopt(socket_ipv4, SOL_SOCKET, SO_REUSEADDR,
+	                         (char *)&on,sizeof(on)) < 0)
+	{
+		fprintf(stderr, "IPv4 setsockopt() failed: %s.\n",
+			strerror(errno));
+		abort();
+	}
+
+	/* No volem que aquest socket bloquegi. */
+	if (fcntl(socket_ipv4, F_SETFL, O_NONBLOCK) == -1)
+	{
+		fprintf(stderr, "IPv6 fcntl() failed: %s.\n",
+			strerror(errno));
+		abort();
+	}
+
+	/* IPv4 listen address */
+	memset(&source_ipv4, 0, sizeof(source_ipv4));
+	source_ipv4.sin_family = AF_INET;
+	source_ipv4.sin_port = htons(port);
+	source_ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+	result = bind(socket_ipv4, (struct sockaddr *) &source_ipv4,
+		sizeof(source_ipv4));
+	assert(result == 0);
+
+	result = listen(socket_ipv4, TCP_LISTEN_QUEUE);
+	if (result != 0)
+	{
+		fprintf(stderr,"Error in listen() ipv4: %s\n", strerror(errno));
+		abort();
+	}
+
+	return socket_ipv4;
+}
+
+
+static int accept_connection(int socket)
+{
+	int res;
+
+	res = accept(socket, NULL, NULL);
+	close(res);
+	return res;
+}