syslog_in_unix.c
author viric@llimona
Tue, 30 May 2006 13:07:54 +0200
changeset 60 07f049b2c1b6
parent 53 667cd5966695
permissions -rw-r--r--
Added tag 3a_entrega for changeset a8776c046a530bf7665426108b6b501e2944645a

#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;
}