490 lines
12 KiB
C
490 lines
12 KiB
C
/*
|
|
* libZRTP SDK library, implements the ZRTP secure VoIP protocol.
|
|
* Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
|
|
* Contact: http://philzimmermann.com
|
|
* For licensing and other legal details, see the file zrtp_legal.c.
|
|
*
|
|
* Viktor Krykun <v.krikun at zfoneproject.com>
|
|
*/
|
|
|
|
#include "zrtp.h"
|
|
|
|
#if (defined(ZRTP_USE_BUILTIN) && (ZRTP_USE_BUILTIN == 1))
|
|
|
|
/*============================================================================*/
|
|
/* Default realization of Mutexes synchronization routine */
|
|
/*============================================================================*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL)
|
|
#include <Ndis.h>
|
|
|
|
struct zrtp_mutex_t
|
|
{
|
|
NDIS_SPIN_LOCK mutex;
|
|
};
|
|
|
|
zrtp_status_t zrtp_mutex_init(zrtp_mutex_t **mutex)
|
|
{
|
|
zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t));
|
|
if (!new_mutex)
|
|
return zrtp_status_alloc_fail;
|
|
NdisAllocateSpinLock(&new_mutex->mutex);
|
|
*mutex = new_mutex;
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex)
|
|
{
|
|
NdisFreeSpinLock(&mutex->mutex);
|
|
zrtp_sys_free(mutex);
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex)
|
|
{
|
|
NdisAcquireSpinLock(&mutex->mutex);
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex)
|
|
{
|
|
NdisReleaseSpinLock(&mutex->mutex);
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#elif (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
|
|
#include <Windows.h>
|
|
|
|
struct zrtp_mutex_t
|
|
{
|
|
HANDLE mutex;
|
|
};
|
|
|
|
zrtp_status_t zrtp_mutex_init(zrtp_mutex_t** mutex)
|
|
{
|
|
zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t));
|
|
if (!new_mutex)
|
|
return zrtp_status_alloc_fail;
|
|
new_mutex->mutex = CreateMutex(NULL, FALSE, NULL);
|
|
if (!new_mutex->mutex) {
|
|
zrtp_sys_free(new_mutex);
|
|
return zrtp_status_fail;
|
|
}
|
|
*mutex = new_mutex;
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex)
|
|
{
|
|
zrtp_status_t s = (0 == CloseHandle(mutex->mutex)) ? zrtp_status_fail : zrtp_status_ok;
|
|
zrtp_sys_free(mutex);
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex)
|
|
{
|
|
return (WaitForSingleObject(mutex->mutex, INFINITE) == WAIT_FAILED) ? zrtp_status_fail : zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex)
|
|
{
|
|
return (0 == ReleaseMutex(mutex->mutex)) ? zrtp_status_fail : zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID)
|
|
|
|
#if defined ZRTP_HAVE_PTHREAD_H
|
|
# include <pthread.h>
|
|
#endif
|
|
|
|
struct zrtp_mutex_t
|
|
{
|
|
pthread_mutex_t mutex;
|
|
};
|
|
|
|
|
|
zrtp_status_t zrtp_mutex_init(zrtp_mutex_t** mutex)
|
|
{
|
|
zrtp_mutex_t* new_mutex = zrtp_sys_alloc(sizeof(zrtp_mutex_t));
|
|
if (new_mutex) {
|
|
zrtp_status_t s = pthread_mutex_init(&new_mutex->mutex, NULL) == 0 ? zrtp_status_ok : zrtp_status_fail;
|
|
if (s == zrtp_status_fail)
|
|
zrtp_sys_free(new_mutex);
|
|
else
|
|
*mutex = new_mutex;
|
|
return s;
|
|
}
|
|
return zrtp_status_alloc_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_destroy(zrtp_mutex_t* mutex)
|
|
{
|
|
zrtp_status_t s = (pthread_mutex_destroy(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
zrtp_sys_free(mutex);
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_lock(zrtp_mutex_t* mutex)
|
|
{
|
|
return (pthread_mutex_lock(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_mutex_unlock(zrtp_mutex_t* mutex)
|
|
{
|
|
return (pthread_mutex_unlock(&mutex->mutex) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*============================================================================*/
|
|
/* Default realization of Semaphores synchronization routine */
|
|
/*============================================================================*/
|
|
|
|
#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL)
|
|
|
|
struct zrtp_sem_t
|
|
{
|
|
KSEMAPHORE sem;
|
|
};
|
|
|
|
zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t val, uint32_t limit)
|
|
{
|
|
zrtp_sem_t *new_sem = zrtp_sys_alloc(sizeof(zrtp_sem_t));
|
|
if (NULL == new_sem) {
|
|
return zrtp_status_alloc_fail;
|
|
}
|
|
|
|
KeInitializeSemaphore(&new_sem->sem, val, limit);
|
|
*sem = new_sem;
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem)
|
|
{
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem)
|
|
{
|
|
return KeWaitForSingleObject(&sem->sem, Executive, KernelMode, FALSE, NULL) == STATUS_SUCCESS ?
|
|
zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem)
|
|
{
|
|
LARGE_INTEGER timeout;
|
|
timeout.QuadPart = 0;
|
|
|
|
return KeWaitForSingleObject(&sem->sem, Executive, KernelMode, FALSE, &timeout) == STATUS_SUCCESS ?
|
|
zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem)
|
|
{
|
|
KeReleaseSemaphore(&sem->sem, IO_NO_INCREMENT, 1, FALSE);
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
|
|
#elif (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
|
|
struct zrtp_sem_t
|
|
{
|
|
HANDLE sem;
|
|
};
|
|
|
|
zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t val, uint32_t limit)
|
|
{
|
|
zrtp_sem_t *new_sem = zrtp_sys_alloc(sizeof(zrtp_sem_t));
|
|
if (NULL == new_sem) {
|
|
return zrtp_status_alloc_fail;
|
|
}
|
|
|
|
new_sem->sem = CreateSemaphore(NULL, val, limit, NULL);
|
|
if (!new_sem->sem) {
|
|
zrtp_sys_free(new_sem);
|
|
return zrtp_status_fail;
|
|
}
|
|
*sem = new_sem;
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem)
|
|
{
|
|
zrtp_status_t s = (0 == CloseHandle(sem->sem)) ? zrtp_status_fail : zrtp_status_ok;
|
|
zrtp_sys_free(sem);
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem)
|
|
{
|
|
return (WaitForSingleObject(sem->sem, INFINITE) == WAIT_FAILED) ? zrtp_status_fail : zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem)
|
|
{
|
|
return (WaitForSingleObject(sem->sem, 0) == WAIT_OBJECT_0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem)
|
|
{
|
|
return (0 == ReleaseSemaphore(sem->sem, 1, NULL)) ? zrtp_status_fail : zrtp_status_ok;
|
|
}
|
|
|
|
#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID)
|
|
|
|
#if defined ZRTP_HAVE_STDIO_H
|
|
# include <stdio.h>
|
|
#endif
|
|
#if ZRTP_HAVE_SEMAPHORE_H
|
|
# include <semaphore.h>
|
|
#endif
|
|
#if ZRTP_HAVE_FCNTL_H
|
|
# include <fcntl.h>
|
|
#endif
|
|
#if ZRTP_HAVE_ERRNO_H
|
|
# include <errno.h>
|
|
#endif
|
|
|
|
|
|
#if (ZRTP_PLATFORM == ZP_DARWIN)
|
|
|
|
struct zrtp_sem_t
|
|
{
|
|
sem_t* sem;
|
|
};
|
|
|
|
zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit)
|
|
{
|
|
zrtp_status_t s = zrtp_status_ok;
|
|
char name_buff[48];
|
|
zrtp_time_t now = zrtp_time_now();
|
|
|
|
zrtp_sem_t *new_sem = (zrtp_sem_t*)zrtp_sys_alloc(sizeof(zrtp_sem_t));
|
|
if (0 == new_sem) {
|
|
return zrtp_status_alloc_fail;
|
|
}
|
|
|
|
/*
|
|
* This bogusness is to follow what appears to be the lowest common
|
|
* denominator in Posix semaphore naming:
|
|
* - start with '/'
|
|
* - be at most 15 chars
|
|
* - be unique and not match anything on the filesystem
|
|
* We suppose to generate unique name for every semaphore in the system.
|
|
*/
|
|
|
|
sprintf(name_buff, "/libzrtp.%llxZ%llx", now/1000, now);
|
|
new_sem->sem = sem_open(name_buff, O_CREAT | O_EXCL, S_IRUSR|S_IWUSR, value);
|
|
if ((sem_t *)SEM_FAILED == new_sem->sem) {
|
|
if (errno == ENAMETOOLONG) {
|
|
name_buff[13] = '\0';
|
|
} else if (errno == EEXIST) {
|
|
sprintf(name_buff, "/libzrtp.%llxZ%llx", now, now/1000);
|
|
} else {
|
|
s = zrtp_status_fail;
|
|
}
|
|
new_sem->sem = sem_open(name_buff, O_CREAT | O_EXCL, 0644, value);
|
|
}
|
|
|
|
if (new_sem->sem == (sem_t *)SEM_FAILED) {
|
|
s = zrtp_status_fail;
|
|
zrtp_sys_free(new_sem);
|
|
} else {
|
|
sem_unlink(name_buff);
|
|
*sem = new_sem;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem)
|
|
{
|
|
zrtp_status_t s = sem_close(sem->sem);
|
|
zrtp_sys_free(sem);
|
|
if (0 != s) {
|
|
s = zrtp_status_fail;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_wait(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_trywait(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_post(sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
#else
|
|
|
|
struct zrtp_sem_t
|
|
{
|
|
sem_t sem;
|
|
};
|
|
|
|
|
|
zrtp_status_t zrtp_sem_init(zrtp_sem_t** sem, uint32_t value, uint32_t limit)
|
|
{
|
|
zrtp_sem_t *new_sem = (zrtp_sem_t*)zrtp_sys_alloc(sizeof(zrtp_sem_t));
|
|
if (NULL == new_sem) {
|
|
return zrtp_status_alloc_fail;
|
|
}
|
|
|
|
if (sem_init(&new_sem->sem, 0, value) != 0) {
|
|
zrtp_sys_free(new_sem);
|
|
return zrtp_status_fail;
|
|
}
|
|
|
|
*sem = new_sem;
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_destroy(zrtp_sem_t* sem)
|
|
{
|
|
zrtp_status_t s = sem_destroy(&sem->sem) == 0 ? zrtp_status_ok : zrtp_status_fail;
|
|
zrtp_sys_free(sem);
|
|
return s;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_wait(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_wait(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_trtwait(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_trywait(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
zrtp_status_t zrtp_sem_post(zrtp_sem_t* sem)
|
|
{
|
|
return (sem_post(&sem->sem) == 0) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
#endif
|
|
|
|
|
|
/*============================================================================*/
|
|
/* Default realization of general routine */
|
|
/*============================================================================*/
|
|
|
|
#if defined ZRTP_HAVE_STRING_H
|
|
# include <string.h> /* for memset() and memcpy() */
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
#if (ZRTP_PLATFORM == ZP_WIN32_KERNEL)
|
|
|
|
void* zrtp_sys_alloc(unsigned int size)
|
|
{
|
|
void *VA;
|
|
return (NDIS_STATUS_SUCCESS != NdisAllocateMemoryWithTag(&VA, size, (ULONG)"zrtp")) ? NULL : VA;
|
|
}
|
|
|
|
void zrtp_sys_free(void* obj)
|
|
{
|
|
/* Length is 0 because memory was allocated with TAG */
|
|
NdisFreeMemory(obj, 0, 0);
|
|
}
|
|
|
|
void* zrtp_memcpy(void* dest, const void* src, unsigned int length)
|
|
{
|
|
return memcpy(dest,src,length);
|
|
}
|
|
|
|
void *zrtp_memset(void *s, int c, unsigned int n)
|
|
{
|
|
return memset(s, c, n);
|
|
}
|
|
|
|
zrtp_time_t zrtp_time_now()
|
|
{
|
|
LARGE_INTEGER ft;
|
|
KeQuerySystemTime(&ft);
|
|
|
|
ft.QuadPart -= 116444736000000000;
|
|
return (zrtp_time_t)(ft.QuadPart) / 10000;
|
|
}
|
|
#else
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
|
|
zrtp_time_t zrtp_time_now()
|
|
{
|
|
LONGLONG ft;
|
|
|
|
#if ZRTP_PLATFORM != ZP_WINCE
|
|
GetSystemTimeAsFileTime((LPFILETIME)&ft);
|
|
#else
|
|
SYSTEMTIME SystemTime;
|
|
GetSystemTime(&SystemTime);
|
|
SystemTimeToFileTime(&SystemTime, (LPFILETIME)&ft);
|
|
#endif
|
|
|
|
ft -= 116444736000000000;
|
|
return (zrtp_time_t)(ft) / 10000;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_SYMBIAN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID)
|
|
|
|
#if defined ZRTP_HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
#endif
|
|
|
|
zrtp_time_t zrtp_time_now()
|
|
{
|
|
struct timeval tv;
|
|
if (0 == gettimeofday(&tv, 0)) {
|
|
return (zrtp_time_t)(tv.tv_sec)*1000 + (zrtp_time_t)(tv.tv_usec)/1000;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
void *zrtp_memset(void *s, int c, unsigned int n)
|
|
{
|
|
memset(s, c, n);
|
|
return s;
|
|
}
|
|
|
|
void* zrtp_memcpy(void* dest, const void* src, unsigned int length)
|
|
{
|
|
memcpy(dest, src, (size_t)length);
|
|
return dest;
|
|
}
|
|
|
|
void* zrtp_sys_alloc(unsigned int size)
|
|
{
|
|
return malloc((size_t)size);
|
|
}
|
|
|
|
void zrtp_sys_free(void* obj)
|
|
{
|
|
free(obj);
|
|
}
|
|
|
|
#endif /* default platform-dependent components realizations */
|
|
|
|
#endif /*ZRTP_USE_BUILTIN*/
|