syslog_in_udp.c
author viric@llimona
Tue, 30 May 2006 13:07:54 +0200
changeset 60 07f049b2c1b6
parent 53 667cd5966695
child 62 39bf7ecd7b21
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 <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <assert.h> // Per assert()
#include <sys/select.h> // Pel select()

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

#define LISTEN_QUEUE = 10;

void show_help(const char * restrict program)
{
	printf("Usage: %s <udp_port> (negative for enable ipv6)\n", program);
}

int listen_ipv6(int port)
{
	int socket_ipv6;
	struct sockaddr_in6 source_ipv6;
	int result;
	int on=1;



	socket_ipv6 = socket(PF_INET6, SOCK_DGRAM, 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();
	}
	

	/* 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, const_listen_queue);
	if (result != 0)
	{
		printf("Error in listen() ipv6: %s\n", strerror(errno));
		abort();
	}
	*/

	return socket_ipv6;
}

int listen_ipv4(int port)
{
	int socket_ipv4;
	struct sockaddr_in source_ipv4;
	int result;
	int on=1;


	socket_ipv4 = socket(PF_INET, SOCK_DGRAM, 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();
	}

	/* 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, const_listen_queue);
	if (result != 0)
	{
		printf("Error in listen() ipv4: %s\n", strerror(errno));
		abort();
	}
	*/

	return socket_ipv4;
}

void server_loop(const int port, const bool ipv6enabled)
{
	int socket_ipv6, socket_ipv4;
	fd_set listen_sockets;
	struct timeval wait_time;
	int result;
	int size;
	int high_socket;
	char message[MESSAGE_LENGTH+1];


	socket_ipv4 = listen_ipv4(port);
	if (ipv6enabled)
		socket_ipv6 = listen_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);

		/* Establim el temporitzador pel select() */
		wait_time.tv_sec = 5;
		wait_time.tv_usec = 0;

		result = select(high_socket, &listen_sockets, NULL, NULL,
			&wait_time);
		if (result == 0)
			continue;
		else if (result == -1)
		{
			fprintf(stderr, "Error in select(): %s\n",
				strerror(errno));
			abort();
		}

		/* Algun FD té dades... */
		if (FD_ISSET(socket_ipv4, &listen_sockets))
		{
			size = recv(socket_ipv4, message, MESSAGE_LENGTH, 0);
			process_message(message);
			/* Debug */
			if(!strcmp(message,"close"))
				break;
			write(1, message, size);
		}

		if (ipv6enabled && FD_ISSET(socket_ipv6, &listen_sockets))
		{
			size = recv(socket_ipv6, message, MESSAGE_LENGTH, 0);
			process_message(message);
			/* Debug */
			if(!strcmp(message,"close"))
				break;
			write(1, message, size);
		}
	}

	/* Closing sockets at the end */
	close(socket_ipv4);
	if (ipv6enabled)
		close(socket_ipv6);
}


int main(int argn, char **argv)
{
	int port;
	bool use_ipv6 = false;

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

	port=atoi(argv[1]);
	/* If a port number is typed as negative, it will start
	 * also the ipv6 server */
	if(port < 0)
	{
		port = -port;
		use_ipv6 = true;
	}

	if (port < 0 || port >65535)
	{
		show_help(argv[0]);
		return 2;
	}

	program_ignore_hup();

	server_loop(port, use_ipv6);

	return 0;
}