view waaad/utils.h @ 387:43c0e3f67958

Simplified macro
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 29 May 2009 12:57:22 +0900
parents e86dba02630a
children
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2009, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

/* Useful functions.
 * 
 * This file provides some general-purpose functions that are useful in several modules.
 */
 
#ifndef _UTILS_H
#define _UTILS_H

#include "waaad-host.h"

#include <stdio.h>

#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>

/********************************************************************************************************/
/* Some debug stuff */
#include <assert.h>

#ifndef ASSERT
#define ASSERT(x) assert(x)
#endif /* ASSERT */

/********************************************************************************************************/
/* Sets of useful macros */

/* Helper for tracing the CHECK_* macros bellow */
#define TRACE_DEBUG_ALL( str ) 	\
	TRACE_DEBUG(CALL, str );


/* Macros to check a return value and branch out in case of error.
 * These macro are to be used only when errors are highly improbable, not for expected errors.
 */

/* Check the return value of a system function and execute fallback in case of error */
#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
	int __ret__;									\
	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
	__ret__ = (__call__);								\
	if (__ret__ < 0) {								\
		int __err__ = errno;	/* We may handle EINTR here */			\
		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
			strerror(__err__));						\
		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
		__fallback__;								\
	}										\
}
/* Check the return value of a system function, return error code on error */
#define CHECK_SYS( __call__  ) { 							\
	int __ret__;									\
	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
	__ret__ = (__call__);								\
	if (__ret__ < 0) {								\
		int __err__ = errno;	/* We may handle EINTR here */			\
		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
			strerror(__err__));						\
		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
		return __err__;								\
	}										\
}

/* Check the return value of a POSIX function and execute fallback in case of error or special value */
#define CHECK_POSIX_DO2( __call__, __val__, __fallback1__, __fallback2__ ) {			\
	int __ret__;										\
	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
	__ret__ = (__call__);									\
	if (__ret__ != 0) {									\
		if (__ret__ == (__val__)) {							\
			__fallback1__;								\
		} else {									\
			log_error("An unexpected error, see log for detail\n");			\
			TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
			__fallback2__;								\
		}										\
	}											\
}

/* Check the return value of a POSIX function and execute fallback in case of error */
#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );

/* Check the return value of a POSIX function and return it if error */
#define CHECK_POSIX( __call__ ) { 							\
	int __v__;									\
	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
}

/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
	void *  __ret__;								\
	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
	__ret__ = (void *)( __call__ );							\
	if (__ret__ == NULL) {								\
		int __err__ = errno;							\
		log_error("Memory allocation failed: %s\n", strerror(__err__));		\
		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
		__fallback__;								\
	}										\
}

/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
#define CHECK_MALLOC( __call__ )							\
	CHECK_MALLOC_DO( __call__, return ENOMEM );


/* The next functions can be used also for expected errors */

/* Check parameters at function entry, execute fallback on error */
#define CHECK_PARAMS_DO( __bool__, __fallback__ )					\
	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );					\
	if ( ! (__bool__) ) {								\
		TRACE_DEBUG(INFO, "Invalid parameter received in " #__bool__ );		\
		__fallback__;								\
	}
/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
#define CHECK_PARAMS( __bool__ )							\
	CHECK_PARAMS_DO( __bool__, return EINVAL );

/* Check the return value of an internal function, log and propagate */
#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
	int __ret__;									\
	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
	__ret__ = (__call__);								\
	if (__ret__ != 0) {								\
		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
		__fallback__;								\
	}										\
}
/* Check the return value of a function call, return any error code */
#define CHECK_FCT( __call__ ) {								\
	int __v__;									\
	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
}
		

/*
 * Manipulating network addresses 
 */

/* Some aliases to socket addresses structures */
#ifndef sSA_ALIASES
#define sSS	struct sockaddr_storage
#define sSA	struct sockaddr
#define sSA4	struct sockaddr_in
#define sSA6	struct sockaddr_in6
#define sSA_ALIASES
#endif /* sSA_ALIASES */

/* Dump one sockaddr */
#define sSA_DUMP( level, text, sa ) {				\
	sSA * __sa = (sSA *)(sa);				\
	char *__str, __addrbuf[INET6_ADDRSTRLEN];		\
	if (__sa) {						\
	  int __rc = getnameinfo(__sa, 				\
	  		sizeof(sSS),				\
			__addrbuf,				\
			sizeof(__addrbuf),			\
			NULL,					\
			0,					\
			0);					\
	  if (__rc)						\
	  	__str = (char *)gai_strerror(__rc);		\
	  else							\
	  	__str = &__addrbuf[0];				\
	} else {						\
		__str = "(NULL / ANY)";				\
	}							\
	TRACE_DEBUG(level, text "%s", __str);			\
}

/* Dump an array of sSS for debug. Last element has a value of 0 for ss_family */
#define sSS_DUMP_ARRAY( level, text, ss ) {			\
	sSS * __ss = (sSS *)(ss);				\
	if (__ss == NULL) {					\
		TRACE_DEBUG(level, text "empty array.");	\
	} else {						\
		while (__ss->ss_family != 0) {			\
			sSA_DUMP(level, text, __ss );		\
			__ss++;					\
		}						\
	}							\
}

/* Dump a list of sockaddr structures. The number of elements is given in cnt */
#define sSA_DUMP_ARRAY( level, text, sa, cnt ) {		\
	sSA * __sa = (sSA *)(sa);				\
	int __cnt = (cnt), __i = 0;				\
	while (__i < __cnt) {					\
		switch (__sa->sa_family) {			\
		case AF_INET:					\
		{						\
			char buf[INET_ADDRSTRLEN];		\
			sSA4 *__sin = (sSA4 *)__sa;		\
			TRACE_DEBUG(level, text "IP: %s", 	\
				inet_ntop(AF_INET, 		\
					&__sin->sin_addr.s_addr,\
					 buf, sizeof(buf)));	\
			__sa = (sSA *)(__sin + 1); 		\
		}						\
		break;						\
		case AF_INET6:					\
		{						\
			char buf[INET6_ADDRSTRLEN];		\
			sSA6 *__si6 = (sSA6 *)__sa;		\
			TRACE_DEBUG(level, text "IPv6: %s", 	\
				inet_ntop(AF_INET6, 		\
					&__si6->sin6_addr.s6_addr,\
					 buf, sizeof(buf)));	\
			__sa = (sSA *)(__si6 + 1); 		\
		}						\
		break;						\
		default:					\
			TRACE_DEBUG(level, text "Unknown AF %d",\
				__sa->sa_family);		\
			__sa++;					\
		}						\
		__i++;						\
	}							\
}

/* The sockaddr length of a sSS structure */
#define sSSlen( _ss_ )	\
	( (socklen_t) ( ((_ss_)->ss_family == AF_INET) ? (sizeof(sSA4)) :		\
				(((_ss_)->ss_family == AF_INET6) ? (sizeof(sSA6)) :	\
					0 ) ) )

/* Define the value of IP loopback address */
#ifndef INADDR_LOOPBACK 
#define INADDR_LOOPBACK	inet_addr("127.0.0.1")
#endif /* INADDR_LOOPBACK */

/* create a V4MAPPED address */
#define IN6_ADDR_V4MAP( a6, a4 ) {			\
	((uint32_t *)(a6))[0] = 0;			\
	((uint32_t *)(a6))[1] = 0;			\
	((uint32_t *)(a6))[2] = htonl(0xffff);		\
	((uint32_t *)(a6))[3] = (uint32_t)(a4);		\
}

/* Retrieve a v4 value from V4MAPPED address ( takes a s6_addr as param) */
#define IN6_ADDR_V4UNMAP( a6 ) 				\
	(((in_addr_t *)(a6))[3])

/* We provide macros to convert 64 bit values to and from network byte-order, on systems where it is not already provided. */
#ifndef HAVE_NTOHLL	/* Defined in config.h, if the ntohll symbol is defined on the system */
# if HOST_BIG_ENDIAN
    /* In big-endian systems, we don't have to change the values, since the order is the same as network */
#   define ntohll(x) (x)
#   define htonll(x) (x)
# else /* HOST_BIG_ENDIAN */
    /* For these systems, we must reverse the bytes. Use ntohl and htonl on sub-32 blocs, and inverse these blocs. */
#   define ntohll(x) (typeof (x))( (((uint64_t)ntohl( (uint32_t)(x))) << 32 ) | ((uint64_t) ntohl( ((uint64_t)(x)) >> 32 ))) 
#   define htonll(x) (typeof (x))( (((uint64_t)htonl( (uint32_t)(x))) << 32 ) | ((uint64_t) htonl( ((uint64_t)(x)) >> 32 ))) 
# endif /* HOST_BIG_ENDIAN */
#endif /* HAVE_NTOHLL */


/*
 * Other macros 
 */

/* This macro will pad a size to the next multiple of 4. */
#define PAD4(_x) ((_x) + ( (4 - (_x)) & 3 ) )

/* Useful to display as ASCII some bytes values */
#define ASCII(_c) ( ((_c < 32) || (_c > 127)) ? ( _c ? '?' : ' ' ) : _c )

/* Compare timespec structures */
#define TS_IS_INFERIOR( ts1, ts2 ) 		\
	(    ((ts1)->tv_sec  < (ts2)->tv_sec ) 	\
	  || ((ts1)->tv_nsec < (ts2)->tv_nsec) )



/* Terminate a thread */
static __inline__ int _thread_term(pthread_t * th)
{
	int ret = 0;
	void * th_ret = NULL;
	
	CHECK_PARAMS(th);
	
	/* Test if it was already terminated */
	if (*th == (pthread_t)NULL)
		return 0;
	
	/* Cancel the thread if it is still running - ignore error if it was already terminated */
	(void) pthread_cancel(*th);
	
	/* Then join the thread */
	CHECK_POSIX_DO( ret = pthread_join(*th, &th_ret), /* continue */ );
	
	if (th_ret != NULL) {
		TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret);
	}
	
	/* Clean the location */
	*th = (pthread_t)NULL;
	
	return ret;
}

/* Cleanups for cancellation */
void cleanup_mutex( void * mutex );
void cleanup_rwlock( void * rwlock );
void cleanup_msg( void * msg );
void cleanup_msg_i( void * pmsg );
void cleanup_buffer( void * buffer );
void cleanup_buffer_i( void * pbuffer );

/********************************************************************************************************/
/*
 * Lists
 * 
 * -- some modules will access directly to the content of this structure...
 */
typedef struct _uti_list {
	struct _uti_list *next;	/* next element in the list */
	struct _uti_list *prev; /* previous element in the list */
	struct _uti_list *head; /* head of the list */
	void		 *o;    /* pointer for use by the client module, either for head of the object or other */
} uti_list_t;

#define _LIST( _li ) ((uti_list_t *)( _li ))

/* Initialize a list element */
void uti_list_init ( uti_list_t * list, void *obj );

/* Return boolean, true if the list is empty */
#define IS_LIST_EMPTY( _list ) ( ((_list)->head == (_list)) && ((_list)->next == (_list)))

/* Insert an item in a list at known position */
void uti_list_insert_after  ( uti_list_t * ref, uti_list_t * item );
void uti_list_insert_before ( uti_list_t * ref, uti_list_t * item );

/* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
int uti_list_insert_ordered( uti_list_t * head, uti_list_t * item, int (*cmp_fct)(void *, void *), void ** ref_duplicate);

/* Unlink an object */
void uti_list_unlink ( uti_list_t * item );

/********************************************************************************************************/
/*
 * Hash tables
 *
 */

/* Compute a hash value of a string (session id, diameter id, ...) */
uint32_t uti_hash ( char * string, size_t len );

/********************************************************************************************************/
/*
 * Events
 *
 */

/* The waaad daemon events */
typedef enum {
	WDE_SIGTERM = 1,/* The daemon received signal SIGTERM */
	WDE_SIGINT,	/* The daemon received signal SIGINT */
	
	WDE_ERROR,	/* An unrecoverable error occurred */
	
	WDE_MAX		/* The last defined event code */
} uti_event_t;

/* send an event to the daemon */
int uti_event_send(uti_event_t event);

/* block and wait for the next event */
int uti_event_receive(uti_event_t * event);

/********************************************************************************************************/



#endif /* _UTILS_H */
"Welcome to our mercurial repository"