Mercurial > hg > waaad
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 */