blob: fcf6b09fe00dbe3c0017f1c473c913251cb5bb97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Wind River Systems - initial API and implementation
* Nokia - Symbian support
*******************************************************************************/
/*
* Machine and OS dependent definitions.
* This module implements host OS abstraction layer that helps make
* agent code portable between Linux, Windows, VxWorks and potentially other OSes.
*/
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <framework/myalloc.h>
#include <framework/errors.h>
pthread_attr_t pthread_create_attr;
#if defined(WIN32)
#include <process.h>
#include <fcntl.h>
#include <MSWSock.h>
/*********************************************************************
Support of pthreads on Windows is implemented according to
recommendations from the paper:
Strategies for Implementing POSIX Condition Variables on Win32
C++ Report, SIGS, Vol. 10, No. 5, June, 1998
Douglas C. Schmidt and Irfan Pyarali
Department of Computer Science
Washington University, St. Louis, Missouri
**********************************************************************/
typedef struct {
int waiters_count;
CRITICAL_SECTION waiters_count_lock;
HANDLE sema;
HANDLE waiters_done;
size_t was_broadcast;
} PThreadCond;
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) {
assert(attr == NULL);
*mutex = (pthread_mutex_t)CreateMutex(NULL, FALSE, NULL);
if (*mutex == NULL) return set_win32_errno(GetLastError());
return 0;
}
int pthread_mutex_lock(pthread_mutex_t * mutex) {
assert(mutex != NULL);
assert(*mutex != NULL);
if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) return set_win32_errno(GetLastError());
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t * mutex) {
assert(mutex != NULL);
assert(*mutex != NULL);
if (!ReleaseMutex(*mutex)) return set_win32_errno(GetLastError());
return 0;
}
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) {
PThreadCond * p = (PThreadCond *)loc_alloc_zero(sizeof(PThreadCond));
assert(attr == NULL);
p->waiters_count = 0;
p->was_broadcast = 0;
p->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
if (p->sema == NULL) return set_win32_errno(GetLastError());
InitializeCriticalSection(&p->waiters_count_lock);
p->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL);
if (p->waiters_done == NULL) return set_win32_errno(GetLastError());
*cond = (pthread_cond_t)p;
return 0;
}
int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) {
DWORD res = 0;
int last_waiter = 0;
PThreadCond * p = (PThreadCond *)*cond;
EnterCriticalSection(&p->waiters_count_lock);
p->waiters_count++;
LeaveCriticalSection(&p->waiters_count_lock);
/* This call atomically releases the mutex and waits on the */
/* semaphore until <pthread_cond_signal> or <pthread_cond_broadcast> */
/* are called by another thread. */
res = SignalObjectAndWait(*mutex, p->sema, INFINITE, FALSE);
if (res == WAIT_FAILED) return set_win32_errno(GetLastError());
/* Re-acquire lock to avoid race conditions. */
EnterCriticalSection(&p->waiters_count_lock);
/* We're no longer waiting... */
p->waiters_count--;
/* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
last_waiter = p->was_broadcast && p->waiters_count == 0;
LeaveCriticalSection(&p->waiters_count_lock);
/* If we're the last waiter thread during this particular broadcast */
/* then let all the other threads proceed. */
if (last_waiter) {
/* This call atomically signals the <waiters_done_> event and waits until */
/* it can acquire the <mutex>. This is required to ensure fairness. */
DWORD err = SignalObjectAndWait(p->waiters_done, *mutex, INFINITE, FALSE);
if (err == WAIT_FAILED) return set_win32_errno(GetLastError());
}
else {
/* Always regain the external mutex since that's the guarantee we */
/* give to our callers. */
DWORD err = WaitForSingleObject(*mutex, INFINITE);
if (err == WAIT_FAILED) return set_win32_errno(GetLastError());
}
assert(res == WAIT_OBJECT_0);
return 0;
}
int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) {
DWORD res = 0;
int last_waiter = 0;
PThreadCond * p = (PThreadCond *)*cond;
DWORD timeout = 0;
struct timespec timenow;
if (clock_gettime(CLOCK_REALTIME, &timenow)) return errno;
if (abstime->tv_sec < timenow.tv_sec) return ETIMEDOUT;
if (abstime->tv_sec == timenow.tv_sec) {
if (abstime->tv_nsec <= timenow.tv_nsec) return ETIMEDOUT;
}
timeout = (DWORD)((abstime->tv_sec - timenow.tv_sec) * 1000 + (abstime->tv_nsec - timenow.tv_nsec) / 1000000 + 5);
EnterCriticalSection(&p->waiters_count_lock);
p->waiters_count++;
LeaveCriticalSection(&p->waiters_count_lock);
/* This call atomically releases the mutex and waits on the */
/* semaphore until <pthread_cond_signal> or <pthread_cond_broadcast> */
/* are called by another thread. */
res = SignalObjectAndWait(*mutex, p->sema, timeout, FALSE);
if (res == WAIT_FAILED) return set_win32_errno(GetLastError());
/* Re-acquire lock to avoid race conditions. */
EnterCriticalSection(&p->waiters_count_lock);
/* We're no longer waiting... */
p->waiters_count--;
/* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
last_waiter = p->was_broadcast && p->waiters_count == 0;
LeaveCriticalSection(&p->waiters_count_lock);
/* If we're the last waiter thread during this particular broadcast */
/* then let all the other threads proceed. */
if (last_waiter) {
/* This call atomically signals the <waiters_done> event and waits until */
/* it can acquire the <mutex>. This is required to ensure fairness. */
DWORD err = SignalObjectAndWait(p->waiters_done, *mutex, INFINITE, FALSE);
if (err == WAIT_FAILED) return set_win32_errno(GetLastError());
}
else {
/* Always regain the external mutex since that's the guarantee we */
/* give to our callers. */
DWORD err = WaitForSingleObject(*mutex, INFINITE);
if (err == WAIT_FAILED) return set_win32_errno(GetLastError());
}
if (res == WAIT_TIMEOUT) return errno = ETIMEDOUT;
assert(res == WAIT_OBJECT_0);
return 0;
}
int pthread_cond_signal(pthread_cond_t * cond) {
int have_waiters = 0;
PThreadCond * p = (PThreadCond *)*cond;
EnterCriticalSection(&p->waiters_count_lock);
have_waiters = p->waiters_count > 0;
LeaveCriticalSection(&p->waiters_count_lock);
/* If there aren't any waiters, then this is a no-op. */
if (have_waiters) {
if (!ReleaseSemaphore(p->sema, 1, 0)) return set_win32_errno(GetLastError());
}
return 0;
}
int pthread_cond_broadcast(pthread_cond_t * cond) {
int have_waiters = 0;
PThreadCond * p = (PThreadCond *)*cond;
/* This is needed to ensure that <waiters_count_> and <was_broadcast_> are */
/* consistent relative to each other. */
EnterCriticalSection(&p->waiters_count_lock);
if (p->waiters_count > 0) {
/* We are broadcasting, even if there is just one waiter... */
/* Record that we are broadcasting, which helps optimize */
/* <pthread_cond_wait> for the non-broadcast case. */
p->was_broadcast = 1;
have_waiters = 1;
}
if (have_waiters) {
/* Wake up all the waiters atomically. */
if (!ReleaseSemaphore(p->sema, p->waiters_count, 0)) return set_win32_errno(GetLastError());
LeaveCriticalSection(&p->waiters_count_lock);
/* Wait for all the awakened threads to acquire the counting */
/* semaphore. */
if (WaitForSingleObject(p->waiters_done, INFINITE) == WAIT_FAILED) return set_win32_errno(GetLastError());
/* This assignment is okay, even without the <waiters_count_lock_> held */
/* because no other waiter threads can wake up to access it. */
p->was_broadcast = 0;
}
else {
LeaveCriticalSection(&p->waiters_count_lock);
}
return 0;
}
int pthread_cond_destroy(pthread_cond_t * cond) {
PThreadCond * p = (PThreadCond *)*cond;
DeleteCriticalSection(&p->waiters_count_lock);
if (!CloseHandle(p->sema)) return set_win32_errno(GetLastError());
if (!CloseHandle(p->waiters_done)) return set_win32_errno(GetLastError());
loc_free(p);
*cond = NULL;
return 0;
}
typedef struct ThreadArgs ThreadArgs;
struct ThreadArgs {
void * (*start)(void *);
void * args;
};
static void start_thread(void * x) {
ThreadArgs a = *(ThreadArgs *)x;
loc_free(x);
ExitThread((DWORD)a.start(a.args));
}
int pthread_create(pthread_t * res, const pthread_attr_t * attr,
void * (*start)(void *), void * args) {
HANDLE thread = NULL;
DWORD thread_id = 0;
ThreadArgs * a = (ThreadArgs *)loc_alloc(sizeof(ThreadArgs));
a->start = start;
a->args = args;
thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)start_thread, a, 0, &thread_id);
if (thread == NULL) {
int err = set_win32_errno(GetLastError());
loc_free(a);
return errno = err;
}
if (!CloseHandle(thread)) return set_win32_errno(GetLastError());
*res = (pthread_t)thread_id;
return 0;
}
int pthread_join(pthread_t thread_id, void ** value_ptr) {
int error = 0;
HANDLE thread = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, (DWORD)thread_id);
if (thread == NULL) return set_win32_errno(GetLastError());
if (WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) error = set_win32_errno(GetLastError());
if (!error && value_ptr != NULL && !GetExitCodeThread(thread, (LPDWORD)value_ptr)) error = set_win32_errno(GetLastError());
if (!CloseHandle(thread) && !error) error = set_win32_errno(GetLastError());
return error;
}
pthread_t pthread_self(void) {
return (pthread_t)GetCurrentThreadId();
}
int pthread_equal(pthread_t thread1, pthread_t thread2) {
return thread1 == thread2;
}
int pthread_attr_init(pthread_attr_t * attr) {
*attr = NULL;
return 0;
}
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
#ifndef SIO_UDP_NETRESET
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR,15)
#endif
#undef socket
int wsa_socket(int af, int type, int protocol) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = socket(af, type, protocol);
if (res < 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
if (type == SOCK_DGRAM && protocol == IPPROTO_UDP) {
DWORD dw = 0;
BOOL b = FALSE;
WSAIoctl(res, SIO_UDP_CONNRESET, &b, sizeof(b), NULL, 0, &dw, NULL, NULL);
WSAIoctl(res, SIO_UDP_NETRESET, &b, sizeof(b), NULL, 0, &dw, NULL, NULL);
}
return res;
}
#undef connect
int wsa_connect(int socket, const struct sockaddr * addr, int addr_size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = connect(socket, addr, addr_size);
if (res != 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return 0;
}
#undef bind
int wsa_bind(int socket, const struct sockaddr * addr, int addr_size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = bind(socket, addr, addr_size);
if (res != 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return 0;
}
#undef listen
int wsa_listen(int socket, int size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = listen(socket, size);
if (res != 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return 0;
}
#undef recv
int wsa_recv(int socket, void * buf, size_t size, int flags) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = recv(socket, (char *)buf, size, flags);
if (res < 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return res;
}
#undef recvfrom
int wsa_recvfrom(int socket, void * buf, size_t size, int flags,
struct sockaddr * addr, socklen_t * addr_size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = recvfrom(socket, (char *)buf, size, flags, addr, addr_size);
if (res < 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return res;
}
#undef send
int wsa_send(int socket, const void * buf, size_t size, int flags) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = send(socket, (char *)buf, size, flags);
if (res < 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return res;
}
#undef sendto
int wsa_sendto(int socket, const void * buf, size_t size, int flags,
const struct sockaddr * dest_addr, socklen_t dest_size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = sendto(socket, (char *)buf, size, flags, dest_addr, dest_size);
if (res < 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return res;
}
#undef setsockopt
int wsa_setsockopt(int socket, int level, int opt, const char * value, int size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = setsockopt(socket, level, opt, value, size);
if (res != 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return 0;
}
#undef getsockname
int wsa_getsockname(int socket, struct sockaddr * name, int * size) {
int res = 0;
SetLastError(0);
WSASetLastError(0);
res = getsockname(socket, name, size);
if (res != 0) {
set_win32_errno(WSAGetLastError());
return -1;
}
return 0;
}
/* inet_ntop()/inet_pton() are not available before Windows Vista */
const char * inet_ntop(int af, const void * src, char * dst, socklen_t size) {
char * str = NULL;
if (af != AF_INET) {
#ifdef EAFNOSUPPORT
errno = EAFNOSUPPORT;
#else
errno = EINVAL;
#endif
return NULL;
}
str = inet_ntoa(*(struct in_addr *)src);
if ((socklen_t)strlen(str) >= size) {
errno = ENOSPC;
return NULL;
}
return strcpy(dst, str);
}
int inet_pton(int af, const char * src, void * dst) {
if (af != AF_INET) {
#ifdef EAFNOSUPPORT
errno = EAFNOSUPPORT;
#else
errno = EINVAL;
#endif
return -1;
}
if (src == NULL || *src == 0) return 0;
if ((((struct in_addr *)dst)->s_addr = inet_addr(src)) == INADDR_NONE) return 0;
return 1;
}
#endif /* WIN32 */
#if defined(WIN32) && !defined(__CYGWIN__)
static __int64 file_time_to_unix_time(const FILETIME * ft) {
__int64 res = (__int64)ft->dwHighDateTime << 32;
res |= ft->dwLowDateTime;
res /= 10; /* from 100 nano-sec periods to usec */
res -= 11644473600000000ull; /* from Win epoch to Unix epoch */
return res;
}
int clock_gettime(clockid_t clock_id, struct timespec * tp) {
FILETIME ft;
__int64 tim;
assert(clock_id == CLOCK_REALTIME);
if (!tp) {
errno = EINVAL;
return -1;
}
GetSystemTimeAsFileTime(&ft);
tim = file_time_to_unix_time(&ft);
tp->tv_sec = (long)(tim / 1000000L);
tp->tv_nsec = (long)(tim % 1000000L) * 1000;
return 0;
}
void usleep(useconds_t useconds) {
Sleep(useconds / 1000);
}
int truncate(const char * path, int64_t size) {
int res = 0;
int f = open(path, _O_RDWR | _O_BINARY, 0);
if (f < 0) return -1;
res = ftruncate(f, size);
_close(f);
return res;
}
int ftruncate(int fd, int64_t size) {
int64_t cur, pos;
BOOL ret = FALSE;
HANDLE handle = (HANDLE)_get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
}
/* save the current file pointer */
cur = _lseeki64(fd, 0, SEEK_CUR);
if (cur >= 0) {
pos = _lseeki64(fd, size, SEEK_SET);
if (pos >= 0) {
ret = SetEndOfFile(handle);
if (!ret) errno = EBADF;
}
/* restore the file pointer */
_lseeki64(fd, cur, SEEK_SET);
}
return ret ? 0 : -1;
}
int getuid(void) {
/* Windows user is always a superuser :) */
return 0;
}
int geteuid(void) {
return 0;
}
int getgid(void) {
return 0;
}
int getegid(void) {
return 0;
}
int utf8_stat(const char * name, struct utf8_stat * buf) {
struct _stati64 tmp;
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
memset(&tmp, 0, sizeof(tmp));
if (_wstati64(path, &tmp)) return -1;
buf->st_dev = tmp.st_dev;
buf->st_ino = tmp.st_ino;
buf->st_mode = tmp.st_mode;
buf->st_nlink = tmp.st_nlink;
buf->st_uid = tmp.st_uid;
buf->st_gid = tmp.st_gid;
buf->st_rdev = tmp.st_rdev;
buf->st_size = tmp.st_size;
buf->st_atime = tmp.st_atime;
buf->st_mtime = tmp.st_mtime;
buf->st_ctime = tmp.st_ctime;
return 0;
}
int utf8_fstat(int fd, struct utf8_stat * buf) {
struct _stati64 tmp;
memset(&tmp, 0, sizeof(tmp));
if (_fstati64(fd, &tmp)) return -1;
buf->st_dev = tmp.st_dev;
buf->st_ino = tmp.st_ino;
buf->st_mode = tmp.st_mode;
buf->st_nlink = tmp.st_nlink;
buf->st_uid = tmp.st_uid;
buf->st_gid = tmp.st_gid;
buf->st_rdev = tmp.st_rdev;
buf->st_size = tmp.st_size;
buf->st_atime = tmp.st_atime;
buf->st_mtime = tmp.st_mtime;
buf->st_ctime = tmp.st_ctime;
return 0;
}
int utf8_open(const char * name, int flags, int perms) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wopen(path, flags, perms);
}
int utf8_chmod(const char * name, int mode) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wchmod(path, mode);
}
int utf8_remove(const char * name) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wremove(path);
}
int utf8_rmdir(const char * name) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wrmdir(path);
}
int utf8_mkdir(const char * name, int mode) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wmkdir(path);
}
int utf8_rename(const char * name1, const char * name2) {
wchar_t path1[FILE_PATH_SIZE];
wchar_t path2[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, name1, -1, path1, sizeof(path1) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
if (!MultiByteToWideChar(CP_UTF8, 0, name2, -1, path2, sizeof(path2) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return -1;
}
return _wrename(path1, path2);
}
DIR * utf8_opendir(const char * path) {
DIR * d = (DIR *)loc_alloc(sizeof(DIR));
if (!d) { errno = ENOMEM; return 0; }
strcpy(d->path, path);
strcat(d->path, "/*.*");
d->hdl = -1;
return d;
}
struct dirent * utf8_readdir(DIR * d) {
static struct dirent de;
if (d->hdl < 0) {
wchar_t path[FILE_PATH_SIZE];
if (!MultiByteToWideChar(CP_UTF8, 0, d->path, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return 0;
}
d->hdl = _wfindfirsti64(path, &d->blk);
if (d->hdl < 0) {
if (errno == ENOENT) errno = 0;
return 0;
}
}
else {
int r = _wfindnexti64(d->hdl, &d->blk);
if (r < 0) {
if (errno == ENOENT) errno = 0;
return 0;
}
}
if (!WideCharToMultiByte(CP_UTF8, 0, d->blk.name, -1, de.d_name, sizeof(de.d_name), NULL, NULL)) {
set_win32_errno(GetLastError());
return 0;
}
de.d_size = d->blk.size;
de.d_atime = d->blk.time_access;
de.d_ctime = d->blk.time_create;
de.d_wtime = d->blk.time_write;
return &de;
}
int utf8_closedir(DIR * d) {
int r = 0;
if (!d) {
errno = EBADF;
return -1;
}
if (d->hdl >= 0) r = _findclose(d->hdl);
loc_free(d);
return r;
}
#endif /* defined(WIN32) && !defined(__CYGWIN__) */
#if defined(WIN32) && !defined(__CYGWIN__) || defined(_WRS_KERNEL) || defined(__SYMBIAN32__)
ssize_t pread(int fd, const void * buf, size_t size, off_t offset) {
off_t offs0;
ssize_t rd;
if ((offs0 = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) return -1;
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return -1;
rd = read(fd, (void *)buf, size);
if (lseek(fd, offs0, SEEK_SET) == (off_t)-1) return -1;
return rd;
}
ssize_t pwrite(int fd, const void * buf, size_t size, off_t offset) {
off_t offs0;
ssize_t wr;
if ((offs0 = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) return -1;
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return -1;
wr = write(fd, (void *)buf, size);
if (lseek(fd, offs0, SEEK_SET) == (off_t)-1) return -1;
return wr;
}
#endif /* defined(WIN32) && !defined(__CYGWIN__) || defined(_WRS_KERNEL) || defined(__SYMBIAN32__) */
#if defined(WIN32)
#include <shlobj.h>
char * get_os_name(void) {
static char str[256];
OSVERSIONINFOEX info;
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx((OSVERSIONINFO *)&info);
switch (info.dwMajorVersion) {
case 4:
return "Windows NT";
case 5:
switch (info.dwMinorVersion) {
case 0: return "Windows 2000";
case 1: return "Windows XP";
case 2: return "Windows Server 2003";
}
break;
case 6:
return "Windows Vista";
}
snprintf(str, sizeof(str), "Windows %d.%d", (int)info.dwMajorVersion, (int)info.dwMinorVersion);
return str;
}
char * get_user_home(void) {
WCHAR w_buf[MAX_PATH];
static char a_buf[MAX_PATH];
if (a_buf[0] != 0) return a_buf;
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, w_buf))) {
errno = ERR_OTHER;
return NULL;
}
if (!WideCharToMultiByte(CP_UTF8, 0, w_buf, -1, a_buf, sizeof(a_buf), NULL, NULL)) {
set_win32_errno(GetLastError());
return 0;
}
return a_buf;
}
void ini_mdep(void) {
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
int err;
SetErrorMode(SEM_FAILCRITICALERRORS);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
fprintf(stderr, "Couldn't access winsock.dll.\n");
exit(1);
}
/* Confirm that the Windows Sockets DLL supports 1.1.*/
/* Note that if the DLL supports versions greater */
/* than 1.1 in addition to 1.1, it will still return */
/* 1.1 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
fprintf(stderr, "Unacceptable version of winsock.dll.\n");
WSACleanup();
exit(1);
}
pthread_attr_init(&pthread_create_attr);
#if defined(_DEBUG) && defined(_MSC_VER)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /* | _CRTDBG_LEAK_CHECK_DF */);
#endif
}
#elif defined(_WRS_KERNEL)
void usleep(useconds_t useconds) {
struct timespec tv;
tv.tv_sec = useconds / 1000000;
tv.tv_nsec = (useconds % 1000000) * 1000;
nanosleep(&tv, NULL);
}
int truncate(char * path, int64_t size) {
int f = open(path, O_RDWR, 0);
if (f < 0) return -1;
if (ftruncate(f, size) < 0) {
int err = errno;
close(f);
errno = err;
return -1;
}
return close(f);
}
int getuid(void) {
return 0;
}
int geteuid(void) {
return 0;
}
int getgid(void) {
return 0;
}
int getegid(void) {
return 0;
}
char * get_os_name(void) {
static char str[256];
#if _WRS_VXWORKS_MAJOR > 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 7
snprintf(str, sizeof(str), "VxWorks %s", vxWorksVersion);
#else
snprintf(str, sizeof(str), "VxWorks %s", kernelVersion());
#endif
return str;
}
char * get_user_home(void) {
return "/";
}
void ini_mdep(void) {
pthread_attr_init(&pthread_create_attr);
pthread_attr_setstacksize(&pthread_create_attr, 0x8000);
pthread_attr_setname(&pthread_create_attr, "tTcf");
}
#elif defined(__SYMBIAN32__)
int truncate(const char * path, int64_t size) {
int res = 0;
int f = open(path, O_RDWR | O_BINARY, 0);
if (f < 0) return -1;
res = ftruncate(f, size);
close(f);
return res;
}
char * get_os_name(void) {
static char str[] = "SYMBIAN";
return str;
}
char * get_user_home(void) {
static char buf[] = "C:";
return buf;
}
void ini_mdep(void) {
pthread_attr_init(&pthread_create_attr);
}
int loc_clock_gettime(int clock_id, struct timespec * now) {
/*
* OpenC has a bug for several releases using a timezone-sensitive time in clock_realtime().
* gettimeofday() is more reliable.
*/
struct timeval timenowval;
int ret;
assert(clock_id == CLOCK_REALTIME);
if (!now) {
errno = EINVAL;
return -1;
}
ret = gettimeofday(&timenowval, NULL);
if (ret < 0)
return ret;
now->tv_sec = timenowval.tv_sec;
now->tv_nsec = timenowval.tv_usec * 1000L;
return 0;
}
/**
* Some of the dynamic IP interface scanning routines are unreliable, so
* include a workaround to manually set the desired interface from outside.
*/
#include <framework/ip_ifc.h>
static ip_ifc_info* gSelectedIPInterface;
void set_ip_ifc(ip_ifc_info* info) {
gSelectedIPInterface = info;
}
ip_ifc_info* get_ip_ifc(void) {
return gSelectedIPInterface;
}
#else
#include <pwd.h>
#include <sys/utsname.h>
#if defined(__linux__)
# include <asm/unistd.h>
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
int clock_gettime(clockid_t clock_id, struct timespec * tp) {
struct timeval tv;
assert(clock_id == CLOCK_REALTIME);
if (!tp) {
errno = EINVAL;
return -1;
}
if (gettimeofday(&tv, NULL) < 0) {
return -1;
}
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000;
return 0;
}
#endif
char * get_os_name(void) {
static char str[256];
struct utsname info;
memset(&info, 0, sizeof(info));
uname(&info);
assert(strlen(info.sysname) + strlen(info.release) < sizeof(str));
snprintf(str, sizeof(str), "%s %s", info.sysname, info.release);
return str;
}
char * get_user_home(void) {
static char buf[PATH_MAX];
if (buf[0] == 0) {
struct passwd * pwd = getpwuid(getuid());
if (pwd == NULL) return NULL;
strcpy(buf, pwd->pw_dir);
}
return buf;
}
int tkill(pid_t pid, int signal) {
#if defined(__linux__)
return syscall(__NR_tkill, pid, signal);
#else
return kill(pid, signal);
#endif
}
void ini_mdep(void) {
signal(SIGPIPE, SIG_IGN);
pthread_attr_init(&pthread_create_attr);
pthread_attr_setstacksize(&pthread_create_attr, 0x8000);
}
#endif
/** canonicalize_file_name ****************************************************/
#if defined(WIN32)
char * canonicalize_file_name(const char * name) {
DWORD len;
int i = 0;
wchar_t buf[FILE_PATH_SIZE];
wchar_t * basename = NULL;
wchar_t path[FILE_PATH_SIZE];
char res[FILE_PATH_SIZE];
assert(name != NULL);
if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) {
set_win32_errno(GetLastError());
return NULL;
}
len = GetFullPathNameW(path, sizeof(buf) / sizeof(wchar_t), buf, &basename);
if (len == 0) {
errno = ENOENT;
return NULL;
}
if (len > FILE_PATH_SIZE - 1) {
errno = ENAMETOOLONG;
return NULL;
}
while (buf[i] != 0) {
if (buf[i] == '\\') buf[i] = '/';
i++;
}
len = WideCharToMultiByte(CP_UTF8, 0, buf, -1, res, sizeof(res), NULL, NULL);
if (len == 0) {
set_win32_errno(GetLastError());
return NULL;
}
if (len > FILE_PATH_SIZE - 1) {
errno = ENAMETOOLONG;
return NULL;
}
return strdup(res);
}
#elif defined(_WRS_KERNEL)
char * canonicalize_file_name(const char * path) {
char buf[PATH_MAX];
int i = 0, j = 0;
if (path[0] == '.' && (path[1] == '/' || path[1] == '\\' || path[1] == 0)) {
getcwd(buf, sizeof(buf));
j = strlen(buf);
if (j == 1 && buf[0] == '/') j = 0;
i = 1;
}
else if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\' || path[2] == 0)) {
getcwd(buf, sizeof(buf));
j = strlen(buf);
while (j > 0 && buf[j - 1] != '/') j--;
if (j > 0 && buf[j - 1] == '/') j--;
i = 2;
}
while (path[i] && j < PATH_MAX - 1) {
char ch = path[i];
if (ch == '\\') ch = '/';
if (ch == '/') {
if (path[i + 1] == '/' || path[i + 1] == '\\') {
i++;
continue;
}
if (path[i + 1] == '.') {
if (path[i + 2] == 0) {
break;
}
if (path[i + 2] == '/' || path[i + 2] == '\\') {
i += 2;
continue;
}
if ((j == 0 || buf[0] == '/') && path[i + 2] == '.') {
if (path[i + 3] == '/' || path[i + 3] == '\\' || path[i + 3] == 0) {
while (j > 0 && buf[j - 1] != '/') j--;
if (j > 0 && buf[j - 1] == '/') j--;
i += 3;
continue;
}
}
}
}
buf[j++] = ch;
i++;
}
if (j == 0 && path[0] != 0) buf[j++] = '/';
buf[j] = 0;
return strdup(buf);
}
#endif
/** getaddrinfo ***************************************************************/
#if defined(_WRS_KERNEL) && defined(USE_VXWORKS_GETADDRINFO)
/* TODO: VxWorks 6.6 getaddrinfo returns error when port is empty string, should return port 0 */
/* TODO: VxWorks 6.6 source (as shipped at 2007 fall release) does not include ipcom header files. */
extern void ipcom_freeaddrinfo();
extern int ipcom_getaddrinfo();
static struct ai_errlist {
const char * str;
int code;
} ai_errlist[] = {
{ "Success", 0 },
/*
{ "Invalid value for ai_flags", IP_EAI_BADFLAGS },
{ "Non-recoverable failure in name resolution", IP_EAI_FAIL },
{ "ai_family not supported", IP_EAI_FAMILY },
{ "Memory allocation failure", IP_EAI_MEMORY },
{ "hostname nor servname provided, or not known", IP_EAI_NONAME },
{ "servname not supported for ai_socktype", IP_EAI_SERVICE },
{ "ai_socktype not supported", IP_EAI_SOCKTYPE },
{ "System error returned in errno", IP_EAI_SYSTEM },
*/
/* backward compatibility with userland code prior to 2553bis-02 */
{ "Address family for hostname not supported", 1 },
{ "No address associated with hostname", 7 },
{ NULL, -1 },
};
void loc_freeaddrinfo(struct addrinfo * ai) {
ipcom_freeaddrinfo(ai);
}
int loc_getaddrinfo(const char * nodename, const char * servname,
const struct addrinfo * hints, struct addrinfo ** res) {
return ipcom_getaddrinfo(nodename, servname, hints, res);
}
const char * loc_gai_strerror(int ecode) {
struct ai_errlist * p;
static char buf[32];
for (p = ai_errlist; p->str; p++) {
if (p->code == ecode) return p->str;
}
snprintf(buf, sizeof(buf), "Error code %d", ecode);
return buf;
}
#elif defined(_WRS_KERNEL)
union sockaddr_union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
extern int ipcom_getsockaddrbyaddr();
void loc_freeaddrinfo(struct addrinfo * ai) {
while (ai != NULL) {
struct addrinfo * next = ai->ai_next;
if (ai->ai_canonname != NULL) loc_free(ai->ai_canonname);
if (ai->ai_addr != NULL) loc_free(ai->ai_addr);
loc_free(ai);
ai = next;
}
}
int loc_getaddrinfo(const char * nodename, const char * servname,
const struct addrinfo * hints, struct addrinfo ** res) {
int family = 0;
int flags = 0;
int socktype = 0;
int protocol = 0;
int err = 0;
int port = 0;
char * canonname = NULL;
const char * host = NULL;
struct addrinfo * ai = NULL;
union sockaddr_union * sa = NULL;
*res = NULL;
if (hints != NULL) {
flags = hints->ai_flags;
family = hints->ai_family;
socktype = hints->ai_socktype;
protocol = hints->ai_protocol;
}
if (family == AF_UNSPEC) {
struct addrinfo lhints;
int err_v6;
if (hints == NULL) memset(&lhints, 0, sizeof(lhints));
else memcpy(&lhints, hints, sizeof(lhints));
lhints.ai_family = AF_INET6;
err_v6 = loc_getaddrinfo(nodename, servname, &lhints, res);
lhints.ai_family = AF_INET;
while (*res != NULL) res = &(*res)->ai_next;
err = loc_getaddrinfo(nodename, servname, &lhints, res);
return err && err_v6 ? err : 0;
}
if (servname != NULL && servname[0] != 0) {
char * p = NULL;
port = strtol(servname, &p, 10);
if (port < 0 || port > 0xffff || *p != '\0' || p == servname) {
return 1;
}
}
if (nodename != NULL && nodename[0] != 0) {
host = nodename;
}
else if (flags & AI_PASSIVE) {
host = family == AF_INET ? "0.0.0.0" : "::";
}
else {
host = family == AF_INET ? "127.0.0.1" : "::1";
}
if (socktype == 0) {
socktype = SOCK_STREAM;
}
if (protocol == 0) {
protocol = socktype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP;
}
sa = loc_alloc_zero(sizeof(*sa));
err = ipcom_getsockaddrbyaddr(family, host, (struct sockaddr *)sa);
if (err) {
loc_free(sa);
return err;
}
ai = loc_alloc_zero(sizeof(*ai));
switch (family) {
case AF_INET:
assert(sa->sin.sin_family == AF_INET);
sa->sin.sin_port = htons(port);
ai->ai_addrlen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
assert(sa->sin6.sin6_family == AF_INET6);
sa->sin6.sin6_port = htons(port);
ai->ai_addrlen = sizeof(struct sockaddr_in6);
break;
default:
loc_free(sa);
loc_free(ai);
return 2;
}
ai->ai_flags = 0;
ai->ai_family = family;
ai->ai_socktype = socktype;
ai->ai_protocol = protocol;
ai->ai_canonname = canonname;
ai->ai_addr = (struct sockaddr *)sa;
ai->ai_next = NULL;
*res = ai;
return 0;
}
const char * loc_gai_strerror(int ecode) {
static char buf[32];
if (ecode == 0) return "Success";
snprintf(buf, sizeof(buf), "Error code %d", ecode);
return buf;
}
#elif defined(WIN32)
const char * loc_gai_strerror(int ecode) {
WCHAR * buf = NULL;
static char msg[512];
if (ecode == 0) return "Success";
if (!FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
ecode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&buf, 0, NULL) ||
!WideCharToMultiByte(CP_UTF8, 0, buf, -1, msg, sizeof(msg), NULL, NULL))
{
snprintf(msg, sizeof(msg), "GAI Error Code %d", ecode);
}
if (buf != NULL) LocalFree(buf);
return msg;
}
#elif defined(__SYMBIAN32__)
const char * loc_gai_strerror(int ecode) {
static char buf[32];
if (ecode == 0) return "Success";
snprintf(buf, sizeof(buf), "Error code %d", ecode);
return buf;
}
#endif
#if defined(WIN32) || defined(_WRS_KERNEL) || defined (__SYMBIAN32__)
int is_daemon(void) {
return 0;
}
void become_daemon(void) {
fprintf(stderr, "tcf-agent: Running in the background is not supported on %s\n", get_os_name());
exit(1);
}
#else
#include <syslog.h>
static int running_as_daemon = 0;
int is_daemon(void) {
return running_as_daemon;
}
void become_daemon(void) {
assert(!running_as_daemon);
openlog("tcf-agent", LOG_PID, LOG_DAEMON);
if (daemon(0, 0) < 0) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Cannot become a daemon: %m");
exit(1);
}
running_as_daemon = 1;
}
#endif
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(__VXWORKS__)
size_t strlcpy(char * dst, const char * src, size_t size) {
char ch;
const char * src0 = src;
const char * dst1 = dst + size - 1;
while ((ch = *src) != 0) {
if (dst < dst1) *dst++ = ch;
src++;
}
if (dst <= dst1) *dst = 0;
return src - src0;
}
size_t strlcat(char * dst, const char * src, size_t size) {
char ch;
const char * dst0 = dst;
const char * src0 = src;
const char * dst1 = dst + size - 1;
while (dst <= dst1 && *dst != 0) dst++;
while ((ch = *src) != 0) {
if (dst < dst1) *dst++ = ch;
src++;
}
if (dst <= dst1) *dst = 0;
return (dst - dst0) + (src - src0);
}
#endif