mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-05-03 20:46:28 +00:00
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@486 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
499 lines
11 KiB
C
499 lines
11 KiB
C
|
|
/*
|
|
The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
|
|
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
|
|
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.1 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
|
|
*/
|
|
|
|
|
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
|
#include "ortp-config-win32.h"
|
|
#else
|
|
#include "ortp-config.h"
|
|
#endif
|
|
#include "ortp/port.h"
|
|
#include "ortp/ortp.h"
|
|
#include "utils.h"
|
|
|
|
#if defined(_WIN32) && !defined(_WIN32_WCE)
|
|
#include <process.h>
|
|
#endif
|
|
|
|
static void *ortp_libc_malloc(size_t sz){
|
|
return malloc(sz);
|
|
}
|
|
|
|
static void *ortp_libc_realloc(void *ptr, size_t sz){
|
|
return realloc(ptr,sz);
|
|
}
|
|
|
|
static void ortp_libc_free(void*ptr){
|
|
free(ptr);
|
|
}
|
|
|
|
static bool_t allocator_used=FALSE;
|
|
|
|
static OrtpMemoryFunctions ortp_allocator={
|
|
ortp_libc_malloc,
|
|
ortp_libc_realloc,
|
|
ortp_libc_free
|
|
};
|
|
|
|
void ortp_set_memory_functions(OrtpMemoryFunctions *functions){
|
|
if (allocator_used){
|
|
ortp_fatal("ortp_set_memory_functions() must be called before "
|
|
"first use of ortp_malloc or ortp_realloc");
|
|
return;
|
|
}
|
|
ortp_allocator=*functions;
|
|
}
|
|
|
|
void* ortp_malloc(size_t sz){
|
|
allocator_used=TRUE;
|
|
return ortp_allocator.malloc_fun(sz);
|
|
}
|
|
|
|
void* ortp_realloc(void *ptr, size_t sz){
|
|
allocator_used=TRUE;
|
|
return ortp_allocator.realloc_fun(ptr,sz);
|
|
}
|
|
|
|
void ortp_free(void* ptr){
|
|
ortp_allocator.free_fun(ptr);
|
|
}
|
|
|
|
void * ortp_malloc0(size_t size){
|
|
void *ptr=ortp_malloc(size);
|
|
memset(ptr,0,size);
|
|
return ptr;
|
|
}
|
|
|
|
char * ortp_strdup(const char *tmp){
|
|
size_t sz;
|
|
char *ret;
|
|
if (tmp==NULL)
|
|
return NULL;
|
|
sz=strlen(tmp)+1;
|
|
ret=(char*)ortp_malloc(sz);
|
|
strcpy(ret,tmp);
|
|
ret[sz-1]='\0';
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* this method is an utility method that calls fnctl() on UNIX or
|
|
* ioctlsocket on Win32.
|
|
* int retrun the result of the system method
|
|
*/
|
|
int set_non_blocking_socket (ortp_socket_t sock)
|
|
{
|
|
|
|
|
|
#if !defined(_WIN32) && !defined(_WIN32_WCE)
|
|
return fcntl (sock, F_SETFL, O_NONBLOCK);
|
|
#else
|
|
unsigned long nonBlock = 1;
|
|
return ioctlsocket(sock, FIONBIO , &nonBlock);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* this method is an utility method that calls close() on UNIX or
|
|
* closesocket on Win32.
|
|
* int retrun the result of the system method
|
|
*/
|
|
int close_socket(ortp_socket_t sock){
|
|
#if !defined(_WIN32) && !defined(_WIN32_WCE)
|
|
return close (sock);
|
|
#else
|
|
return closesocket(sock);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#if !defined(_WIN32) && !defined(_WIN32_WCE)
|
|
/* Use UNIX inet_aton method */
|
|
#else
|
|
int inet_aton (const char * cp, struct in_addr * addr)
|
|
{
|
|
unsigned long retval;
|
|
|
|
retval = inet_addr (cp);
|
|
|
|
if (retval == INADDR_NONE)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
addr->S_un.S_addr = retval;
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
char *ortp_strndup(const char *str,int n){
|
|
int min=MIN((int)strlen(str),n)+1;
|
|
char *ret=(char*)ortp_malloc(min);
|
|
strncpy(ret,str,n);
|
|
ret[min-1]='\0';
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(_WIN32) && !defined(_WIN32_WCE)
|
|
int __ortp_thread_join(ortp_thread_t thread, void **ptr){
|
|
int err=pthread_join(thread,ptr);
|
|
if (err!=0) {
|
|
ortp_error("pthread_join error: %s",strerror(err));
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int __ortp_thread_create(pthread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg){
|
|
pthread_attr_t my_attr;
|
|
pthread_attr_init(&my_attr);
|
|
if (attr)
|
|
my_attr = *attr;
|
|
#ifdef ORTP_DEFAULT_THREAD_STACK_SIZE
|
|
if (ORTP_DEFAULT_THREAD_STACK_SIZE!=0)
|
|
pthread_attr_setstacksize(&my_attr, ORTP_DEFAULT_THREAD_STACK_SIZE);
|
|
#endif
|
|
return pthread_create(thread, &my_attr, routine, arg);
|
|
}
|
|
|
|
#endif
|
|
#if defined(_WIN32) || defined(_WIN32_WCE)
|
|
|
|
int WIN_mutex_init(ortp_mutex_t *mutex, void *attr)
|
|
{
|
|
*mutex=CreateMutex(NULL, FALSE, NULL);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_mutex_lock(ortp_mutex_t * hMutex)
|
|
{
|
|
WaitForSingleObject(*hMutex, INFINITE); /* == WAIT_TIMEOUT; */
|
|
return 0;
|
|
}
|
|
|
|
int WIN_mutex_unlock(ortp_mutex_t * hMutex)
|
|
{
|
|
ReleaseMutex(*hMutex);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_mutex_destroy(ortp_mutex_t * hMutex)
|
|
{
|
|
CloseHandle(*hMutex);
|
|
return 0;
|
|
}
|
|
|
|
typedef struct thread_param{
|
|
void * (*func)(void *);
|
|
void * arg;
|
|
}thread_param_t;
|
|
|
|
static unsigned WINAPI thread_starter(void *data){
|
|
thread_param_t *params=(thread_param_t*)data;
|
|
void *ret=params->func(params->arg);
|
|
ortp_free(data);
|
|
return (DWORD)ret;
|
|
}
|
|
|
|
#if defined _WIN32_WCE
|
|
# define _beginthreadex CreateThread
|
|
# define _endthreadex ExitThread
|
|
#endif
|
|
|
|
int WIN_thread_create(ortp_thread_t *th, void *attr, void * (*func)(void *), void *data)
|
|
{
|
|
thread_param_t *params=ortp_new(thread_param_t,1);
|
|
params->func=func;
|
|
params->arg=data;
|
|
*th=(HANDLE)_beginthreadex( NULL, 0, thread_starter, params, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_thread_join(ortp_thread_t thread_h, void **unused)
|
|
{
|
|
if (thread_h!=NULL)
|
|
{
|
|
WaitForSingleObject(thread_h, INFINITE);
|
|
CloseHandle(thread_h);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int WIN_cond_init(ortp_cond_t *cond, void *attr)
|
|
{
|
|
*cond=CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_cond_wait(ortp_cond_t* hCond, ortp_mutex_t * hMutex)
|
|
{
|
|
//gulp: this is not very atomic ! bug here ?
|
|
WIN_mutex_unlock(hMutex);
|
|
WaitForSingleObject(*hCond, INFINITE);
|
|
WIN_mutex_lock(hMutex);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_cond_signal(ortp_cond_t * hCond)
|
|
{
|
|
SetEvent(*hCond);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_cond_broadcast(ortp_cond_t * hCond)
|
|
{
|
|
WIN_cond_signal(hCond);
|
|
return 0;
|
|
}
|
|
|
|
int WIN_cond_destroy(ortp_cond_t * hCond)
|
|
{
|
|
CloseHandle(*hCond);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if defined(_WIN32_WCE)
|
|
#include <time.h>
|
|
|
|
int
|
|
gettimeofday (struct timeval *tv, void *tz)
|
|
{
|
|
DWORD timemillis = GetTickCount();
|
|
tv->tv_sec = timemillis/1000;
|
|
tv->tv_usec = (timemillis - (tv->tv_sec*1000)) * 1000;
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
int gettimeofday (struct timeval *tv, void* tz)
|
|
{
|
|
union
|
|
{
|
|
__int64 ns100; /*time since 1 Jan 1601 in 100ns units */
|
|
FILETIME fileTime;
|
|
} now;
|
|
|
|
GetSystemTimeAsFileTime (&now.fileTime);
|
|
tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
|
|
tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
|
|
return (0);
|
|
}
|
|
|
|
#endif
|
|
|
|
const char *getWinSocketError(int error)
|
|
{
|
|
static char buf[80];
|
|
|
|
switch (error)
|
|
{
|
|
case WSANOTINITIALISED: return "Windows sockets not initialized : call WSAStartup";
|
|
case WSAEADDRINUSE: return "Local Address already in use";
|
|
case WSAEADDRNOTAVAIL: return "The specified address is not a valid address for this machine";
|
|
case WSAEINVAL: return "The socket is already bound to an address.";
|
|
case WSAENOBUFS: return "Not enough buffers available, too many connections.";
|
|
case WSAENOTSOCK: return "The descriptor is not a socket.";
|
|
case WSAECONNRESET: return "Connection reset by peer";
|
|
|
|
default :
|
|
sprintf(buf, "Error code : %d", error);
|
|
return buf;
|
|
break;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
#ifdef _WORKAROUND_MINGW32_BUGS
|
|
char * WSAAPI gai_strerror(int errnum){
|
|
return (char*)getWinSocketError(errnum);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <sys/un.h>
|
|
#include <sys/stat.h>
|
|
|
|
static char *make_pipe_name(const char *name){
|
|
return ortp_strdup_printf("/tmp/%s",name);
|
|
}
|
|
|
|
/* portable named pipes */
|
|
ortp_socket_t ortp_server_pipe_create(const char *name){
|
|
struct sockaddr_un sa;
|
|
char *pipename=make_pipe_name(name);
|
|
ortp_socket_t sock;
|
|
sock=socket(AF_UNIX,SOCK_STREAM,0);
|
|
sa.sun_family=AF_UNIX;
|
|
strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1);
|
|
unlink(pipename);/*in case we didn't finished properly previous time */
|
|
ortp_free(pipename);
|
|
fchmod(sock,S_IRUSR|S_IWUSR);
|
|
if (bind(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
|
|
ortp_error("Failed to bind command unix socket: %s",strerror(errno));
|
|
return -1;
|
|
}
|
|
listen(sock,1);
|
|
return sock;
|
|
}
|
|
|
|
ortp_socket_t ortp_server_pipe_accept_client(ortp_socket_t server){
|
|
struct sockaddr_un su;
|
|
socklen_t ssize=sizeof(su);
|
|
ortp_socket_t client_sock=accept(server,(struct sockaddr*)&su,&ssize);
|
|
return client_sock;
|
|
}
|
|
|
|
int ortp_server_pipe_close_client(ortp_socket_t client){
|
|
return close(client);
|
|
}
|
|
|
|
int ortp_server_pipe_close(ortp_socket_t spipe){
|
|
return close(spipe);
|
|
}
|
|
|
|
ortp_socket_t ortp_client_pipe_connect(const char *name){
|
|
struct sockaddr_un sa;
|
|
char *pipename=make_pipe_name(name);
|
|
ortp_socket_t sock=socket(AF_UNIX,SOCK_STREAM,0);
|
|
sa.sun_family=AF_UNIX;
|
|
strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1);
|
|
ortp_free(pipename);
|
|
if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
return sock;
|
|
}
|
|
|
|
int ortp_pipe_read(ortp_socket_t p, uint8_t *buf, int len){
|
|
return read(p,buf,len);
|
|
}
|
|
|
|
int ortp_pipe_write(ortp_socket_t p, const uint8_t *buf, int len){
|
|
return write(p,buf,len);
|
|
}
|
|
|
|
int ortp_client_pipe_close(ortp_socket_t sock){
|
|
return close(sock);
|
|
}
|
|
|
|
#else
|
|
|
|
static char *make_pipe_name(const char *name){
|
|
return ortp_strdup_printf("\\\\.\\pipe\\%s",name);
|
|
}
|
|
|
|
static HANDLE event=NULL;
|
|
|
|
/* portable named pipes */
|
|
ortp_pipe_t ortp_server_pipe_create(const char *name){
|
|
ortp_pipe_t h;
|
|
char *pipename=make_pipe_name(name);
|
|
h=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_MESSAGE|PIPE_WAIT,1,
|
|
32768,32768,0,NULL);
|
|
ortp_free(pipename);
|
|
if (h==INVALID_HANDLE_VALUE){
|
|
ortp_error("Fail to create named pipe %s",pipename);
|
|
}
|
|
if (event==NULL) event=CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
return h;
|
|
}
|
|
|
|
|
|
/*this function is a bit complex because we need to wakeup someday
|
|
even if nobody connects to the pipe.
|
|
ortp_server_pipe_close() makes this function to exit.
|
|
*/
|
|
ortp_pipe_t ortp_server_pipe_accept_client(ortp_pipe_t server){
|
|
OVERLAPPED ol;
|
|
DWORD undef;
|
|
HANDLE handles[2];
|
|
memset(&ol,0,sizeof(ol));
|
|
ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
ConnectNamedPipe(server,&ol);
|
|
handles[0]=ol.hEvent;
|
|
handles[1]=event;
|
|
WaitForMultipleObjects(2,handles,FALSE,INFINITE);
|
|
if (GetOverlappedResult(server,&ol,&undef,FALSE)){
|
|
CloseHandle(ol.hEvent);
|
|
return server;
|
|
}
|
|
CloseHandle(ol.hEvent);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
int ortp_server_pipe_close_client(ortp_pipe_t server){
|
|
return DisconnectNamedPipe(server)==TRUE ? 0 : -1;
|
|
}
|
|
|
|
int ortp_server_pipe_close(ortp_pipe_t spipe){
|
|
SetEvent(event);
|
|
//CancelIoEx(spipe,NULL); /*vista only*/
|
|
return CloseHandle(spipe);
|
|
}
|
|
|
|
ortp_pipe_t ortp_client_pipe_connect(const char *name){
|
|
char *pipename=make_pipe_name(name);
|
|
ortp_pipe_t hpipe = CreateFile(
|
|
pipename, // pipe name
|
|
GENERIC_READ | // read and write access
|
|
GENERIC_WRITE,
|
|
0, // no sharing
|
|
NULL, // default security attributes
|
|
OPEN_EXISTING, // opens existing pipe
|
|
0, // default attributes
|
|
NULL); // no template file
|
|
ortp_free(pipename);
|
|
return hpipe;
|
|
}
|
|
|
|
int ortp_pipe_read(ortp_pipe_t p, uint8_t *buf, int len){
|
|
DWORD ret=0;
|
|
if (ReadFile(p,buf,len,&ret,NULL))
|
|
return ret;
|
|
/*ortp_error("Could not read from pipe: %s",strerror(GetLastError()));*/
|
|
return -1;
|
|
}
|
|
|
|
int ortp_pipe_write(ortp_pipe_t p, const uint8_t *buf, int len){
|
|
DWORD ret=0;
|
|
if (WriteFile(p,buf,len,&ret,NULL))
|
|
return ret;
|
|
/*ortp_error("Could not write to pipe: %s",strerror(GetLastError()));*/
|
|
return -1;
|
|
}
|
|
|
|
|
|
int ortp_client_pipe_close(ortp_pipe_t sock){
|
|
return CloseHandle(sock);
|
|
}
|
|
|
|
#endif
|