/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #ifdef CLOCK_MONOTONIC #include #endif static int no_monotonic_pthread_clock; /* * translates errno to DirectResult */ DirectResult errno2result( int erno ) { switch (erno) { case 0: return DR_OK; case ENOENT: return DR_FILENOTFOUND; case EACCES: case EPERM: return DR_ACCESSDENIED; case EBUSY: case EAGAIN: return DR_BUSY; case ECONNREFUSED: return DR_ACCESSDENIED; case ENODEV: case ENXIO: #ifdef ENOTSUP /* ENOTSUP is not defined on NetBSD */ case ENOTSUP: #endif return DR_UNSUPPORTED; } return DR_FAILURE; } const char * DirectResultString( DirectResult result ) { if (!D_RESULT_TYPE_IS( result, 0, 0, 0 )) return "UNKNOWN RESULT CODE TYPE!"; switch (result) { case DR_OK: return "OK"; case DR_FAILURE: return "General failure!"; case DR_INIT: return "Initialization error!"; case DR_BUG: return "Internal bug!"; case DR_DEAD: return "Interface was released!"; case DR_UNSUPPORTED: return "Not supported!"; case DR_UNIMPLEMENTED: return "Not implemented!"; case DR_ACCESSDENIED: return "Access denied!"; case DR_INVARG: return "Invalid argument!"; case DR_NOLOCALMEMORY: return "Out of memory!"; case DR_LOCKED: return "Resource is locked!"; case DR_BUFFEREMPTY: return "Buffer is empty!"; case DR_FILENOTFOUND: return "File not found!"; case DR_IO: return "General I/O error!"; case DR_NOIMPL: return "No (suitable) implementation found!"; case DR_TIMEOUT: return "Operation timed out!"; case DR_BUSY: return "Resource is busy!"; case DR_THIZNULL: return "'thiz' argument is NULL!"; case DR_IDNOTFOUND: return "Requested ID not found!"; case DR_INVAREA: return "Invalid area present!"; case DR_DESTROYED: return "Resource was destroyed!"; case DR_FUSION: return "Fusion IPC error detected!"; case DR_BUFFERTOOLARGE: return "Buffer is too large!"; case DR_INTERRUPTED: return "Operation has been interrupted!"; case DR_NOCONTEXT: return "No context available!"; case DR_TEMPUNAVAIL: return "Resource temporarily unavailable!"; case DR_LIMITEXCEEDED: return "Limit has been exceeded!"; case DR_NOSUCHMETHOD: return "No such (remote) method!"; case DR_NOSUCHINSTANCE: return "No such (remote) instance!"; case DR_ITEMNOTFOUND: return "Appropriate item not found!"; case DR_VERSIONMISMATCH: return "Some versions didn't match!"; case DR_NOSHAREDMEMORY: return "Out of shared memory!"; case DR_EOF: return "End of file!"; case DR_SUSPENDED: return "Object is suspended!"; case DR_INCOMPLETE: return "Operation incomplete!"; case DR_NOCORE: return "No core (loaded)!"; default: break; } return "UNKNOWN RESULT CODE!"; } int direct_safe_dup( int fd ) { int n = 0; int fc[3]; while (fd >= 0 && fd <= 2) { fc[n++] = fd; fd = dup (fd); } while (n) close (fc[--n]); return fd; } int direct_try_open( const char *name1, const char *name2, int flags, bool error_msg ) { int fd; fd = open (name1, flags); if (fd >= 0) return direct_safe_dup (fd); if (errno != ENOENT) { if (error_msg) D_PERROR( "Direct/Util: opening '%s' failed\n", name1 ); return -1; } fd = open (name2, flags); if (fd >= 0) return direct_safe_dup (fd); if (error_msg) { if (errno == ENOENT) D_PERROR( "Direct/Util: opening '%s' and '%s' failed\n", name1, name2 ); else D_PERROR( "Direct/Util: opening '%s' failed\n", name2 ); } return -1; } void direct_trim( char **s ) { int i; int len = strlen( *s ); for (i = len-1; i >= 0; i--) if ((*s)[i] <= ' ') (*s)[i] = 0; else break; while (**s) if (**s <= ' ') (*s)++; else return; } /* * Utility function to initialize recursive mutexes. */ int direct_util_recursive_pthread_mutex_init( pthread_mutex_t *mutex ) { int ret; pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); #if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); #endif ret = pthread_mutex_init( mutex, &attr ); if (ret) D_PERROR( "Direct/Lock: Could not initialize recursive mutex!\n" ); pthread_mutexattr_destroy( &attr ); return ret; } /* * Utility function to initialize monotonic condition. */ int direct_util_monotonic_pthread_cond_init( pthread_cond_t *cond ) { #if defined(CLOCK_MONOTONIC) && !defined(DIRECT_BUILD_NO_PTHREAD_CONDATTR) int ret; pthread_condattr_t attr; struct timespec dummy; pthread_condattr_init( &attr ); if(!no_monotonic_pthread_clock) { if((syscall( __NR_clock_getres, CLOCK_MONOTONIC, &dummy ) == 0) && (pthread_condattr_setclock( &attr, CLOCK_MONOTONIC ) == 0)) ; else no_monotonic_pthread_clock = 1; } ret = pthread_cond_init( cond, &attr ); if (ret) D_PERROR( "Direct/Lock: Could not initialize monotonic condition!\n" ); pthread_condattr_destroy( &attr ); return ret; #else pthread_cond_init( cond, NULL ); return 0; #endif } /* * Utility function to calibrate timeout for monotonic condition. */ void direct_util_get_monotonic_pthread_timeout( struct timespec *timeout, int seconds, int nano_seconds ) { struct timeval now; if(no_monotonic_pthread_clock) gettimeofday( &now, NULL ); else direct_monotonic_gettimeofday( &now ); timeout->tv_sec = now.tv_sec + seconds; timeout->tv_nsec = (now.tv_usec * 1000) + nano_seconds; timeout->tv_sec += timeout->tv_nsec / 1000000000; timeout->tv_nsec %= 1000000000; } /* * Encode/Decode Base-64. */ char* direct_base64_encode( const void *data, int size ) { static const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/="; const unsigned char *src = (const unsigned char*)data; char *ret; char *buf; D_ASSERT( data != NULL ); buf = ret = D_MALLOC( (size + 2) / 3 * 4 + 1 ); if (!ret) return NULL; for (; size >= 3; size -= 3) { buf[0] = enc[((src[0] & 0xfc) >> 2)]; buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; buf[2] = enc[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)]; buf[3] = enc[((src[2] & 0x3f))]; buf += 4; src += 3; } if (size > 0) { buf[0] = enc[(src[0] & 0xfc) >> 2]; if (size > 1) { buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; buf[2] = enc[((src[1] & 0x0f) << 2)]; } else { buf[1] = enc[(src[0] & 0x03) << 4]; buf[2] = '='; } buf[3] = '='; buf += 4; } *buf = '\0'; return ret; } void* direct_base64_decode( const char *string, int *ret_size ) { unsigned char dec[256]; unsigned char *ret; unsigned char *buf; int len; int i, j; D_ASSERT( string != NULL ); len = strlen( string ); buf = ret = D_MALLOC( len * 3 / 4 + 3 ); if (!ret) return NULL; /* generate decode table */ for (i = 0; i < 255; i++) dec[i] = 0x80; for (i = 'A'; i <= 'Z'; i++) dec[i] = 0 + (i - 'A'); for (i = 'a'; i <= 'z'; i++) dec[i] = 26 + (i - 'a'); for (i = '0'; i <= '9'; i++) dec[i] = 52 + (i - '0'); dec['+'] = 62; dec['/'] = 63; dec['='] = 0; /* decode */ for (j = 0; j < len; j += 4) { unsigned char a[4], b[4]; for (i = 0; i < 4; i++) { int c = string[i+j]; a[i] = c; b[i] = dec[c]; } *buf++ = (b[0] << 2) | (b[1] >> 4); *buf++ = (b[1] << 4) | (b[2] >> 2); *buf++ = (b[2] << 6) | (b[3] ); if (a[2] == '=' || a[3] == '=') break; } *buf = '\0'; if (ret_size) *ret_size = buf - ret; return ret; } /* * Compute MD5 sum. */ static const u8 S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */ { 5, 9, 14, 20 }, /* Round 2 */ { 4, 11, 16, 23 }, /* Round 3 */ { 6, 10, 15, 21 } /* Round 4 */ }; static const u32 T[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void md5_hash( u32 ABCD[4], u32 X[16] ) { u32 a = ABCD[3]; u32 b = ABCD[2]; u32 c = ABCD[1]; u32 d = ABCD[0]; int t; int i; #ifdef WORDS_BIGENDIAN for (i = 0; i < 16; i++) X[i] = BSWAP32(X[i]); #endif for (i = 0; i < 64; i++) { t = S[i>>4][i&3]; a += T[i]; switch (i>>4) { case 0: a += (d ^ (b&(c^d))) + X[ i &15]; break; case 1: a += (c ^ (d&(c^b))) + X[(1+5*i)&15]; break; case 2: a += (b^c^d) + X[(5+3*i)&15]; break; case 3: a += (c^(b|~d)) + X[( 7*i)&15]; break; } a = b + ((a << t) | (a >> (32 - t))); t = d; d = c; c = b; b = a; a = t; } ABCD[0] += d; ABCD[1] += c; ABCD[2] += b; ABCD[3] += a; } void direct_md5_sum( void *dst, const void *src, const int len ) { u8 block[64]; u32 ABCD[4]; int i, j; D_ASSERT( dst != NULL ); D_ASSERT( src != NULL ); ABCD[0] = 0x10325476; ABCD[1] = 0x98badcfe; ABCD[2] = 0xefcdab89; ABCD[3] = 0x67452301; for (i = 0, j = 0; i < len; i++) { block[j++] = ((const u8*)src)[i]; if (j == 64) { md5_hash( ABCD, (u32*)block ); j = 0; } } block[j++] = 0x80; memset( &block[j], 0, 64-j ); if (j > 56) { md5_hash( ABCD, (u32*)block ); memset( block, 0, 64 ); } for (i = 0; i < 8; i++) block[56+i] = ((u64)len << 3) >> (i << 3); md5_hash( ABCD, (u32*)block ); for (i = 0; i < 4; i++) #ifdef WORDS_BIGENDIAN ((u32*)dst)[i] = BSWAP32(ABCD[3-i]); #else ((u32*)dst)[i] = ABCD[3-i]; #endif }