syslog_in_unix.c
author viric@llimona
Tue, 30 May 2006 12:57:31 +0200
changeset 58 c03287b2c3c1
parent 53 667cd5966695
permissions -rw-r--r--
Now the tcp_server handles well the situation where there isn't a log file.

#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 <sys/types.h>  // Per crides de fitxer
#include <sys/socket.h>  // Per les macros bool,true,false
#include <sys/un.h>  // Per les estructures dels unix sockets
#include <assert.h> // Per assert()
#include <stdbool.h>
#include <signal.h> // per SIGTERM i similars
#include <sys/select.h> // per select()

#include "rfc3164.h"
#include "syslog.h"


static bool finish = false;

void show_help(const char * restrict program)
{
	printf("Usage: %s <unix_socket>\n", program);
}


int listen_unix(const char * restrict socketname)
{
	int socket_unix;
	struct sockaddr_un source_unix;
	int result;
	int sockopt;


	socket_unix = socket(PF_UNIX, SOCK_DGRAM, 0 );
	if (socket_unix == -1)
	{
		printf("Unix socket creation error: %s\n", strerror(errno));
		abort();
	}

	/* Allow socket reuse */
	sockopt = 1;
	result = setsockopt(socket_unix, SOL_SOCKET, SO_REUSEADDR, &sockopt,
		sizeof(sockopt));
	assert(result == 0);

	/* Unix socket listen address */
	memset(&source_unix, 0, sizeof(source_unix));
	source_unix.sun_family = AF_UNIX;
	strcpy(source_unix.sun_path, socketname);
	result = bind(socket_unix, (struct sockaddr *) &source_unix,
		sizeof(source_unix));
	assert(result == 0);

	/* Here we should take care of the socket permissions */

	return socket_unix;
}

void server_loop(const char * restrict socketname)
{
	int socket_unix;
	int result;
	char message[MESSAGE_LENGTH+1];
	fd_set read_fd_set;
	struct timeval read_timeout;

	socket_unix = listen_unix(socketname);

	FD_ZERO(&read_fd_set);

	while (finish == false)
	{
		if (FD_ISSET(socket_unix, &read_fd_set))
		{
			result = recv(socket_unix, message, MESSAGE_LENGTH, 0);
			if(result >= 0)
			{
				process_message(message);
				/* Debug */
				if(!strcmp(message,"close"))
					break;
				write(1, message, result);
			} else if (result == -1)
			{
				if (errno != EINTR)
					break;
			}
		}

		/* Prepare the fd_set */
		FD_ZERO(&read_fd_set);
		FD_SET(socket_unix, &read_fd_set);
		/* We set the timeout in order to save us easily from the race
		 * condition for signal receiving (select/pselect) */
		read_timeout.tv_sec = 5;
		read_timeout.tv_usec = 0;
		result = select(socket_unix+1, &read_fd_set, NULL, NULL,
				&read_timeout);
		if (result == -1)
			FD_ZERO(&read_fd_set);
		assert( !(result == -1 && errno != EINTR) );
	}

	result = close(socket_unix);
	if (result == -1)
	{
		printf("Unix socket close error: %s\n", strerror(errno));
		abort();
	}
	result = unlink(socketname);
	if (result == -1)
	{
		printf("Unix socket unlink error: %s\n", strerror(errno));
		abort();
	}

}

static void term_handler(int parameter)
{
	finish=true;
}


int main(int argn, char **argv)
{
	/* Processem els parĂ metres d'entrada */
	if (argn != 2) {
		show_help(argv[0]);
		return 2;
	}

	program_ignore_hup();
	program_handler(SIGTERM, term_handler);

	/* If Ctrl-C is typed in a xterm, it will send SIGINT to the
	group process running in it. So even if we only run the kernel,
	this son will receive the xterm's SIGINT. We must handle that,
	as this program should unlink the socket, and not only close it. */
	program_handler(SIGINT, term_handler);

	server_loop(argv[1]);

	return 0;
}