- removed AmUtils and AmThread from sipctrl directory.

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@670 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Raphael Coeffic 19 years ago
parent 7e4f0709f9
commit c034470ee0

@ -1,299 +0,0 @@
/*
* $Id: AmThread.cpp 390 2007-07-06 23:57:00Z sayer $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "AmThread.h"
#include "log.h"
#include <unistd.h>
#include "errno.h"
#include <string>
using std::string;
AmMutex::AmMutex()
{
pthread_mutex_init(&m,NULL);
}
AmMutex::~AmMutex()
{
pthread_mutex_destroy(&m);
}
void AmMutex::lock()
{
pthread_mutex_lock(&m);
}
void AmMutex::unlock()
{
pthread_mutex_unlock(&m);
}
AmThread::AmThread()
: _stopped(true)
{
}
// int thread_nr=0;
// AmMutex thread_nr_mut;
void * AmThread::_start(void * _t)
{
AmThread* _this = (AmThread*)_t;
_this->_pid = (pid_t) _this->_td;
DBG("Thread %lu is starting.\n", (unsigned long int) _this->_pid);
_this->run();
_this->_stopped.set(true);
//thread_nr_mut.lock();
//INFO("threads = %i\n",--thread_nr);
//thread_nr_mut.unlock();
DBG("Thread %lu is ending.\n", (unsigned long int) _this->_pid);
return NULL;
}
void AmThread::start(bool realtime)
{
// start thread realtime...seems to not improve any thing
//
// if (realtime) {
// pthread_attr_t attributes;
// pthread_attr_init(&attributes);
// struct sched_param rt_param;
// if (pthread_attr_setschedpolicy (&attributes, SCHED_FIFO)) {
// ERROR ("cannot set FIFO scheduling class for RT thread");
// }
// if (pthread_attr_setscope (&attributes, PTHREAD_SCOPE_SYSTEM)) {
// ERROR ("Cannot set scheduling scope for RT thread");
// }
// memset (&rt_param, 0, sizeof (rt_param));
// rt_param.sched_priority = 80;
// if (pthread_attr_setschedparam (&attributes, &rt_param)) {
// ERROR ("Cannot set scheduling priority for RT thread (%s)", strerror (errno));
// }
// int res;
// _pid = 0;
// res = pthread_create(&_td,&attributes,_start,this);
// if (res != 0) {
// ERROR("pthread create of RT thread failed with code %s\n", strerror(res));
// ERROR("Trying to start normal thread...\n");
// _pid = 0;
// res = pthread_create(&_td,NULL,_start,this);
// if (res != 0) {
// ERROR("pthread create failed with code %i\n", res);
// }
// }
// DBG("Thread %ld is just created.\n", (unsigned long int) _pid);
// return;
// }
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,1024*1024);// 1 MB
int res;
_pid = 0;
res = pthread_create(&_td,&attr,_start,this);
pthread_attr_destroy(&attr);
if (res != 0) {
ERROR("pthread create failed with code %i\n", res);
throw string("thread could not be started");
}
// thread_nr_mut.lock();
// INFO("threads = %i\n",++thread_nr);
// thread_nr_mut.unlock();
_stopped.set(false);
//DBG("Thread %lu is just created.\n", (unsigned long int) _pid);
}
void AmThread::stop()
{
_m_td.lock();
// gives the thread a chance to clean up
DBG("Thread %lu (%lu) calling on_stop, give it a chance to clean up.\n",
(unsigned long int) _pid, (unsigned long int) _td);
try { on_stop(); } catch(...) {}
int res;
if ((res = pthread_detach(_td)) != 0) {
if (res == EINVAL) {
WARN("pthread_detach failed with code EINVAL: thread already in detached state.\n");
} else if (res == ESRCH) {
WARN("pthread_detach failed with code ESRCH: thread could not be found.\n");
} else {
WARN("pthread_detach failed with code %i\n", res);
}
}
DBG("Thread %lu (%lu) finished detach.\n", (unsigned long int) _pid, (unsigned long int) _td);
//pthread_cancel(_td);
_m_td.unlock();
}
void AmThread::cancel() {
_m_td.lock();
int res;
if ((res = pthread_cancel(_td)) != 0) {
ERROR("pthread_cancel failed with code %i\n", res);
} else {
DBG("Thread %lu is canceled.\n", (unsigned long int) _pid);
_stopped.set(true);
}
_m_td.unlock();
}
void AmThread::join()
{
if(!is_stopped())
pthread_join(_td,NULL);
}
int AmThread::setRealtime() {
// set process realtime
// int policy;
// struct sched_param rt_param;
// memset (&rt_param, 0, sizeof (rt_param));
// rt_param.sched_priority = 80;
// int res = sched_setscheduler(0, SCHED_FIFO, &rt_param);
// if (res) {
// ERROR("sched_setscheduler failed. Try to run SEMS as root or suid.\n");
// }
// policy = sched_getscheduler(0);
// std::string str_policy = "unknown";
// switch(policy) {
// case SCHED_OTHER: str_policy = "SCHED_OTHER"; break;
// case SCHED_RR: str_policy = "SCHED_RR"; break;
// case SCHED_FIFO: str_policy = "SCHED_FIFO"; break;
// }
// DBG("Thread has now policy '%s' - priority 80 (from %d to %d).\n", str_policy.c_str(),
// sched_get_priority_min(policy), sched_get_priority_max(policy));
// return 0;
return 0;
}
AmThreadWatcher* AmThreadWatcher::_instance=0;
AmMutex AmThreadWatcher::_inst_mut;
AmThreadWatcher::AmThreadWatcher()
: _run_cond(false)
{
}
AmThreadWatcher* AmThreadWatcher::instance()
{
_inst_mut.lock();
if(!_instance){
_instance = new AmThreadWatcher();
_instance->start();
}
_inst_mut.unlock();
return _instance;
}
void AmThreadWatcher::add(AmThread* t)
{
DBG("trying to add thread %lu to thread watcher.\n", (unsigned long int) t->_pid);
q_mut.lock();
thread_queue.push(t);
_run_cond.set(true);
q_mut.unlock();
DBG("added thread %lu to thread watcher.\n", (unsigned long int) t->_pid);
}
void AmThreadWatcher::on_stop()
{
}
void AmThreadWatcher::run()
{
for(;;){
_run_cond.wait_for();
// Let some time for to threads
// to stop by themselves
sleep(10);
q_mut.lock();
DBG("Thread watcher starting its work\n");
try {
queue<AmThread*> n_thread_queue;
while(!thread_queue.empty()){
AmThread* cur_thread = thread_queue.front();
thread_queue.pop();
q_mut.unlock();
DBG("thread %lu is to be processed in thread watcher.\n", (unsigned long int) cur_thread->_pid);
if(cur_thread->is_stopped()){
DBG("thread %lu has been destroyed.\n", (unsigned long int) cur_thread->_pid);
delete cur_thread;
}
else {
DBG("thread %lu still running.\n", (unsigned long int) cur_thread->_pid);
n_thread_queue.push(cur_thread);
}
q_mut.lock();
}
swap(thread_queue,n_thread_queue);
}catch(...){
/* this one is IMHO very important, as lock is called in try block! */
ERROR("unexpected exception, state may be invalid!\n");
}
bool more = !thread_queue.empty();
q_mut.unlock();
DBG("Thread watcher finished\n");
if(!more)
_run_cond.set(false);
}
}

@ -1,228 +0,0 @@
/*
* $Id: AmThread.h 457 2007-09-24 17:37:04Z sayer $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file AmThread.h */
#ifndef _AmThread_h_
#define _AmThread_h_
#include <pthread.h>
#include <queue>
using std::queue;
/**
* \brief C++ Wrapper class for pthread mutex
*/
class AmMutex
{
pthread_mutex_t m;
public:
AmMutex();
~AmMutex();
void lock();
void unlock();
};
/**
* \brief Simple lock class
*/
class AmLock
{
AmMutex& m;
public:
AmLock(AmMutex& _m) : m(_m) {
m.lock();
}
~AmLock(){
m.unlock();
}
};
/**
* \brief Shared variable.
*
* Include a variable and its mutex.
* @warning Don't use safe functions (set,get)
* within a {lock(); ... unlock();} block. Use
* unsafe function instead.
*/
template<class T>
class AmSharedVar
{
T t;
AmMutex m;
public:
AmSharedVar(const T& _t) : t(_t) {}
AmSharedVar() {}
T get() {
lock();
T res = unsafe_get();
unlock();
return res;
}
void set(const T& new_val) {
lock();
unsafe_set(new_val);
unlock();
}
void lock() { m.lock(); }
void unlock() { m.unlock(); }
const T& unsafe_get() { return t; }
void unsafe_set(const T& new_val) { t = new_val; }
};
/**
* \brief C++ Wrapper class for pthread condition
*/
template<class T>
class AmCondition
{
T t;
pthread_mutex_t m;
pthread_cond_t cond;
public:
AmCondition(const T& _t)
: t(_t)
{
pthread_mutex_init(&m,NULL);
pthread_cond_init(&cond,NULL);
}
~AmCondition()
{
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&m);
}
/** Change the condition's value. */
void set(const T& newval)
{
pthread_mutex_lock(&m);
t = newval;
if(t)
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&m);
}
T get()
{
T val;
pthread_mutex_lock(&m);
val = t;
pthread_mutex_unlock(&m);
return val;
}
/** Waits for the condition to be true. */
void wait_for()
{
pthread_mutex_lock(&m);
while(!t){
pthread_cond_wait(&cond,&m);
}
pthread_mutex_unlock(&m);
}
};
/**
* \brief C++ Wrapper class for pthread
*/
class AmThread
{
pthread_t _td;
AmMutex _m_td;
AmSharedVar<bool> _stopped;
static void* _start(void*);
protected:
virtual void run()=0;
virtual void on_stop()=0;
public:
pid_t _pid;
AmThread();
virtual ~AmThread() {}
virtual void onIdle() {}
/** Start it ! */
void start(bool realtime = false);
/** Stop it ! */
void stop();
/** @return true if this thread doesn't run. */
bool is_stopped() { return _stopped.get(); }
/** Wait for this thread to finish */
void join();
/** kill the thread (if pthread_setcancelstate(PTHREAD_CANCEL_ENABLED) has been set) **/
void cancel();
int setRealtime();
};
/**
* \brief Container/garbage collector for threads.
*
* AmThreadWatcher waits for threads to stop
* and delete them.
* It gets started automatically when needed.
* Once you added a thread to the container,
* there is no mean to get it out.
*/
class AmThreadWatcher: public AmThread
{
static AmThreadWatcher* _instance;
static AmMutex _inst_mut;
queue<AmThread*> thread_queue;
AmMutex q_mut;
/** the daemon only runs if this is true */
AmCondition<bool> _run_cond;
AmThreadWatcher();
void run();
void on_stop();
public:
static AmThreadWatcher* instance();
void add(AmThread*);
};
#endif
// Local Variables:
// mode:C++
// End:

@ -1,893 +0,0 @@
/*
* $Id: AmUtils.cpp 611 2008-01-21 13:33:22Z rco $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file AmUtils.cpp */
#include "AmUtils.h"
#include "AmThread.h"
//#include "AmConfig.h"
#include "log.h"
//#include "AmServer.h"
//#include "AmSipMsg.h"
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <regex.h>
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 104
#endif
// timeout in us (ms/1000)
#define SER_WRITE_TIMEOUT 250000 // 250 ms
// write retry interval in us
#define SER_WRITE_INTERVAL 50000 // 50 ms
// timeout in us (ms/1000)
#define SER_SIPREQ_TIMEOUT 5*60*1000*1000 // 5 minutes
#define SER_DBREQ_TIMEOUT 250000 // 250 ms
// read retry interval in us
#define SER_READ_INTERVAL 50000 // 50 ms
static char _int2str_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9' };
string int2str(int val)
{
char buffer[64] = {0};
int i=62;
div_t d;
d.quot = val;
do{
d = div(d.quot,10);
buffer[i] = _int2str_lookup[d.rem];
}while(--i && d.quot);
return string((const char*)(buffer+i+1));
}
static char _int2hex_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9','A','B','C','D','E','F' };
string int2hex(unsigned int val)
{
unsigned int digit=0;
char buffer[2*sizeof(int)+1] = {0};
int i,j=0;
for(i=0; i<int(2*sizeof(int)); i++){
digit = val >> 4*(2*sizeof(int)-1);
val = val << 4;
buffer[j++] = _int2hex_lookup[(unsigned char)digit];
}
return string((char*)buffer);
}
string long2hex(unsigned long val)
{
unsigned int digit=0;
char buffer[2*sizeof(long)+1] = {0};
int i,j=0;
for(i=0; i<int(2*sizeof(long)); i++){
digit = val >> 4*(2*sizeof(long)-1);
val = val << 4;
buffer[j++] = _int2hex_lookup[(unsigned char)digit];
}
return string((char*)buffer);
}
/**
* Convert a reversed hex string to uint.
* @param str [in] string to convert.
* @param result [out] result integer.
* @return true if failed.
*/
bool reverse_hex2int(const string& str, unsigned int& result)
{
result=0;
char mychar;
for (string::const_reverse_iterator pc = str.rbegin();
pc != str.rend(); ++pc) {
result <<= 4;
mychar=*pc;
if ( mychar >='0' && mychar <='9')
result += mychar -'0';
else if (mychar >='a' && mychar <='f')
result += mychar -'a'+10;
else if (mychar >='A' && mychar <='F')
result += mychar -'A'+10;
else
return true;
}
return false;
}
bool str2i(const string& str, unsigned int& result)
{
char* s = (char*)str.c_str();
return str2i(s,result);
}
bool str2i(char*& str, unsigned int& result, char sep)
{
unsigned int ret=0;
int i=0;
char* init = str;
for(; (*str != '\0') && (*str == ' '); str++);
for(; *str != '\0';str++){
if ( (*str <= '9' ) && (*str >= '0') ){
ret=ret*10+*str-'0';
i++;
if (i>10) goto error_digits;
} else if( *str == sep )
break;
else
goto error_char;
}
result = ret;
return false;
error_digits:
DBG("str2i: too many letters in [%s]\n", init);
return true;
error_char:
DBG("str2i: unexpected char %c in %s\n", *str, init);
return true;
}
int parse_return_code(const char* lbuf, unsigned int& res_code, string& res_msg )
{
char res_code_str[4] = {'\0'};
const char* cur=lbuf;
// parse xxx code
for( int i=0; i<3; i++ ){
if( (*cur >= '0') && (*cur <= '9') )
res_code_str[i] = *cur;
else
goto error;
cur++;
}
if( (*cur != ' ') && (*cur != '\t') && (*cur !='-') ){
ERROR("expected 0x%x or 0x%x or 0x%x, found 0x%x\n",' ','\t','-',*cur);
goto error;
}
if(sscanf(res_code_str,"%u",&res_code) != 1){
ERROR("wrong code (%s)\n",res_code_str);
goto error;
}
// wrap spaces and tabs
while( (*cur == ' ') || (*cur == '\t') || (*cur =='-'))
cur++;
res_msg = cur;
return 0;
error:
ERROR("while parsing response\n");
return -1;
}
int fifo_get_line(FILE* fifo_stream, char* str, size_t len)
{
char c;
size_t l;
char* s=str;
if(!len)
return 0;
l=len;
while( l && (c=fgetc(fifo_stream)) && !ferror(fifo_stream) && c!=EOF && c!='\n' ){
if(c!='\r'){
*(s++) = c;
l--;
}
}
if(l>0){
// We need one more character
// for trailing '\0'.
*s='\0';
return int(s-str);
}
else
// buffer overran.
return -1;
}
int fifo_get_lines(FILE* fifo_stream, char* str, size_t len)
{
int l=0,max=len;
char* s=str;
if(!len)
return 0;
while( max>0 && (l=fifo_get_line(fifo_stream,s,max)) && l!=-1 ) {
if(!strcmp(".",s))
break;
s+=l;
*(s++)='\n';
max-=l+1;
}
s[0]='\0';
return (l!=-1 ? s-str : -1);
}
int fifo_get_param(FILE* fp, string& p, char* line_buf, unsigned int size)
{
if( fifo_get_line(fp,line_buf,size) !=-1 ){
if(!strcmp(".",line_buf))
line_buf[0]='\0';
p = line_buf;
}
else {
ERROR("could not read from FIFO: %s\n",strerror(errno));
return -1;
}
return 0;
}
int msg_get_line(char*& msg_c, char* str, size_t len)
{
size_t l;
char* s=str;
if(!len)
return 0;
for(l=len; l && (*msg_c) && (*msg_c !='\n'); msg_c++ ){
if(*msg_c!='\r'){
*(s++) = *msg_c;
l--;
}
}
if(*msg_c)
msg_c++;
if(l>0){
// We need one more character
// for trailing '\0'.
*s='\0';
return int(s-str);
}
else {
ERROR("buffer too small (size=%u)\n",(unsigned int)len);
// buffer overran.
return -1;
}
}
int msg_get_lines(char*& msg_c, char* str, size_t len)
{
int l=0,max=len;
char* s=str;
if(!len)
return 0;
while( max>0 && (l=msg_get_line(msg_c,s,max)) && l!=-1 ) {
if(!strcmp(".",s))
break;
s+=l;
*(s++)='\n';
max-=l+1;
}
s[0]='\0';
return (l!=-1 ? s-str : -1);
}
int msg_get_param(char*& msg_c, string& p, char* line_buf, unsigned int size)
{
if( msg_get_line(msg_c,line_buf,size) != -1 ){
if(!strcmp(".",line_buf))
line_buf[0]='\0';
p = line_buf;
}
else {
ERROR("msg_get_line failed\n");
return -1;
}
return 0;
}
bool file_exists(const string& name)
{
FILE* test_fp = fopen(name.c_str(),"r");
if(test_fp){
fclose(test_fp);
return true;
}
return false;
}
string filename_from_fullpath(const string& path)
{
string::size_type pos = path.rfind('/');
if(pos != string::npos)
return path.substr(pos+1);
return "";
}
AmMutex inet_ntoa_mut;
string get_addr_str(struct in_addr in)
{
inet_ntoa_mut.lock();
string addr = inet_ntoa(in);
inet_ntoa_mut.unlock();
return addr;
}
AmMutex inet_gethostbyname;
string get_ip_from_name(const string& name)
{
inet_gethostbyname.lock();
struct hostent *he = gethostbyname(name.c_str());
if(!he){
inet_gethostbyname.unlock();
return "";
}
struct in_addr a;
bcopy(he->h_addr, (char *) &a, sizeof(a));
inet_gethostbyname.unlock();
return get_addr_str(a);
}
string uri_from_name_addr(const string& name_addr)
{
string uri = name_addr;
string::size_type pos = uri.find('<');
if(pos != string::npos)
uri.erase(0,pos+1);
pos = uri.find('>');
if(pos != string::npos)
uri.erase(pos,uri.length()-pos);
return uri;
}
#ifdef SUPPORT_IPV6
#include <netdb.h>
int inet_aton_v6(const char* name, struct sockaddr_storage* ss)
{
int error;
//struct sockaddr *sa;
struct addrinfo hints;
struct addrinfo *res;
memset(&hints, 0, sizeof(hints));
/* set-up hints structure */
hints.ai_family = PF_UNSPEC;
error = getaddrinfo(name, NULL, &hints, &res);
if (error)
ERROR("%s\n",gai_strerror(error));
else if (res) {
assert( (res->ai_family == PF_INET) ||
(res->ai_family == PF_INET6) );
memset(ss,0,sizeof(struct sockaddr_storage));
memcpy(ss,res->ai_addr,res->ai_addrlen);
freeaddrinfo(res);
return 1;
}
return 0;
}
void set_port_v6(struct sockaddr_storage* ss, short port)
{
switch(ss->ss_family){
case PF_INET:
((struct sockaddr_in*)ss)->sin_port = htons(port);
break;
case PF_INET6:
((struct sockaddr_in6*)ss)->sin6_port = htons(port);
break;
default:
ERROR("unknown address family\n");
assert(0);
break;
}
}
short get_port_v6(struct sockaddr_storage* ss)
{
switch(ss->ss_family){
case PF_INET:
return ntohs(((struct sockaddr_in*)ss)->sin_port);
case PF_INET6:
return ntohs(((struct sockaddr_in6*)ss)->sin6_port);
default:
ERROR("unknown address family\n");
assert(0);
break;
}
}
#endif
int create_unix_socket(const string& path)
{
if(path.empty()){
ERROR("parameter path is empty\n");
return -1;
}
int sd = socket(PF_UNIX,SOCK_DGRAM,0);
if(sd == -1){
ERROR("could not create unix socket: %s\n",strerror(errno));
return -1;
}
if(path.size() > UNIX_PATH_MAX-1){
ERROR("could not create unix socket: unix socket path is too long\n");
close(sd);
return -1;
}
struct sockaddr_un sock_addr;
sock_addr.sun_family = AF_UNIX;
strcpy(sock_addr.sun_path,path.c_str());
if(bind(sd,(struct sockaddr *)&sock_addr,
sizeof(struct sockaddr_un)) == -1) {
ERROR("could not bind unix socket (path=%s): %s\n",path.c_str(),strerror(errno));
close(sd);
return -1;
}
return sd;
}
string file_extension(const string& path)
{
string::size_type pos = path.rfind('.');
if(pos == string::npos)
return "";
return path.substr(pos+1,string::npos);
}
string add2path( const string& path, int n_suffix, ...)
{
va_list ap;
string outpath = path;
va_start(ap,n_suffix);
for(int i=0; i<n_suffix; i++){
const char* s = va_arg(ap,const char*);
if(!outpath.empty() && (outpath[outpath.length()-1] != '/'))
outpath += '/';
outpath += s;
}
va_end(ap);
return outpath;
}
int write_to_fifo(const string& fifo, const char * buf, unsigned int len)
{
int fd_fifo;
int retry = SER_WRITE_TIMEOUT / SER_WRITE_INTERVAL;
for(;retry>0; retry--){
if((fd_fifo = open(fifo.c_str(),
O_WRONLY | O_NONBLOCK)) == -1) {
ERROR("while opening %s: %s\n",
fifo.c_str(),strerror(errno));
if(retry)
sleep_us(50000);
}
else {
break;
}
}
if(!retry)
return -1;
DBG("write_to_fifo: <%s>\n",buf);
int l = write(fd_fifo,buf,len);
close(fd_fifo);
if(l==-1)
ERROR("while writing: %s\n",strerror(errno));
else
DBG("Write to fifo: completed\n");
return l;
}
int write_to_socket(int sd, const char* to_addr, const char * buf, unsigned int len)
{
int retry = SER_WRITE_TIMEOUT / SER_WRITE_INTERVAL;
int ret=-1;
struct sockaddr_un ser_addr;
memset (&ser_addr, 0, sizeof (ser_addr));
ser_addr.sun_family = AF_UNIX;
strncpy(ser_addr.sun_path,to_addr,UNIX_PATH_MAX);
DBG("sending: <%.*s>\n",len,buf);
for(;retry>0;retry--){
if( (sendto(sd,buf,len,MSG_DONTWAIT,
(struct sockaddr*)&ser_addr,
sizeof(struct sockaddr_un)) == -1) ) {
if(errno == EAGAIN){
if(retry)
sleep_us(SER_WRITE_INTERVAL);
continue;
}
ERROR("while sending request to %s: %s\n",
ser_addr.sun_path,strerror(errno));
goto error;
}
break;
}
if(!retry){
ERROR("timeout while sending request to %s\n",ser_addr.sun_path);
goto error;
}
DBG("write to unix socket: completed\n");
ret = 0;
error:
// close(sd);
// return (ret == -1 ? ret : len);
return ret;
}
string extract_tag(const string& addr)
{
string::size_type p = addr.find(";tag=");
if(p == string::npos)
return "";
p += 5/*sizeof(";tag=")*/;
string::size_type p_end = p;
while(p_end < addr.length()){
if( addr[p_end] == '>'
|| addr[p_end] == ';' )
break;
p_end++;
}
return addr.substr(p,p_end-p);
}
bool key_in_list(const string& s_list, const string& key,
char list_delim)
{
size_t pos = 0;
size_t pos2 = 0;
size_t pos_n = 0;
while (pos < s_list.length()) {
pos_n = pos2 = s_list.find(list_delim, pos);
if (pos2==string::npos)
pos2 = s_list.length()-1;
while ((pos2>0)&&
((s_list[pos2] == ' ')||(s_list[pos2] == list_delim)
||(s_list[pos2] == '\n')))
pos2--;
if (s_list.substr(pos, pos2-pos+1)==key)
return true;
if (pos_n == string::npos)
return false;
while ((pos_n<s_list.length()) &&
((s_list[pos_n] == ' ')||(s_list[pos_n] == list_delim)||
(s_list[pos_n] == '\n')))
pos_n++;
if (pos_n == s_list.length())
return false;
pos = pos_n;
}
return false;
}
string strip_header_params(const string& hdr_string)
{
size_t val_begin = 0; // skip trailing ' '
for (;(val_begin<hdr_string.length()) &&
hdr_string[val_begin]==' ';val_begin++);
// strip parameters
size_t val_end = hdr_string.find(';', val_begin);
if (val_end == string::npos)
val_end=hdr_string.length();
return hdr_string.substr(val_begin, val_end-val_begin);
}
string get_header_param(const string& hdr_string,
const string& param_name)
{
size_t pos = 0;
while (pos<hdr_string.length()) {
pos = hdr_string.find(';',pos);
if (pos == string::npos)
return "";
if ((hdr_string.length()>pos+param_name.length()+1)
&& hdr_string.substr(++pos, param_name.length())==param_name
&& hdr_string[pos+param_name.length()] == '=') {
size_t pos2 = pos+param_name.length()+1;
while(pos2<hdr_string.length() && hdr_string[pos2] != ';'
&& hdr_string[pos2] != '\n')
pos2++;
return hdr_string.substr(pos + param_name.length()+1,
pos2 - pos + - param_name.length() -1);
}
pos +=param_name.length();
}
return "";
}
/**
* get value from parameter header with the name @param name
* while skipping escaped values
*/
string get_header_keyvalue(const string& param_hdr, const string& name) {
// ugly, but we need escaping
#define ST_FINDKEY 0
#define ST_FK_ESC 1
#define ST_CMPKEY 2
#define ST_SRCHEND 3
#define ST_SE_VAL 4
#define ST_SE_ESC 5
size_t p=0, s_begin=0, corr=0,
v_begin=0, v_end=0;
unsigned int st = ST_FINDKEY;
while (p<param_hdr.length()) {
char curr = param_hdr[p];
switch(st) {
default:
case ST_FINDKEY: {
if (curr=='"') {
st = ST_FK_ESC;
} else if (curr==name[0]) {
st = ST_CMPKEY;
s_begin = p;
corr = 1;
}
p++;
}; break;
case ST_FK_ESC: {
if (curr=='"')
st = ST_FINDKEY;
p++;
}; break;
case ST_CMPKEY: {
if (corr==name.length()) {
if (curr=='=') {
st = ST_SRCHEND;
v_begin=++p;
} else {
p=s_begin+1;
st = ST_FINDKEY;
corr=0;
}
} else {
if (curr==name[corr]) {
p++;
corr++;
} else {
st = ST_FINDKEY;
corr=0;
p=s_begin+1;
}
}
}; break;
case ST_SRCHEND: {
if (curr=='"') {
v_begin++;
st = ST_SE_ESC;
} else
st = ST_SE_VAL;
p++;
v_end = p;
}; break;
case ST_SE_VAL: {
if (curr==';')
p = param_hdr.length();
else {
v_end = p;
p++;
}
}; break;
case ST_SE_ESC: {
if (curr=='"')
p = param_hdr.length();
else {
v_end = p;
p++;
}
}; break;
}
}
if (v_begin && v_end)
return param_hdr.substr(v_begin, v_end-v_begin+1);
else
return "";
}
#if 0
/** get the value of key @param name from \ref PARAM_HDR header in hdrs */
string get_session_param(const string& hdrs, const string& name) {
string iptel_app_param = getHeader(hdrs, PARAM_HDR);
if (!iptel_app_param.length()) {
// DBG("call parameters header PARAM_HDR not found "
// "(need to configure ser's tw_append?).\n");
return "";
}
return get_header_keyvalue(iptel_app_param, name);
}
#endif
// support for thread-safe pseudo-random numbers
static unsigned int _s_rand=0;
static AmMutex _s_rand_mut;
void init_random()
{
int seed=0;
FILE* fp_rand = fopen("/dev/urandom","r");
if(fp_rand){
fread(&seed,sizeof(int),1,fp_rand);
fclose(fp_rand);
}
seed += getpid();
seed += time(0);
_s_rand = seed;
}
unsigned int get_random()
{
_s_rand_mut.lock();
unsigned int r = rand_r(&_s_rand);
_s_rand_mut.unlock();
return r;
}
#if 0
// Explode string by a separator to a vector
vector <string> explode(string s, string e) {
vector <string> ret;
int iPos = s.find(e, 0);
int iLen = e.length();
while (iPos > -1) {
if (iPos != 0)
ret.push_back(s.substr(0, iPos));
s.erase(0, iPos+iLen);
iPos = s.find(e, 0);
}
if (s != "")
ret.push_back(s);
return ret;
}
#endif
// Warning: static var is not mutexed
// Call this func only in init code.
//
void add_env_path(const char* name, const string& path)
{
string var(path);
char* old_path=0;
regex_t path_reg;
assert(name);
if((old_path = getenv(name)) != 0) {
if(strlen(old_path)){
if(regcomp(&path_reg,("[:|^]" + path + "[:|$]").c_str(),REG_NOSUB)){
ERROR("could not compile regex\n");
return;
}
if(!regexec(&path_reg,old_path,0,0,0)) { // match
return; // do nothing
}
var += ":" + string(old_path);
}
}
DBG("setting %s to: '%s'\n",name,var.c_str());
setenv("PYTHONPATH",var.c_str(),1);
}

@ -1,282 +0,0 @@
/*
* $Id: AmUtils.h 457 2007-09-24 17:37:04Z sayer $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _AmUtils_h_
#define _AmUtils_h_
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <string>
using std::string;
#include <vector>
#define FIFO_PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define PARAM_HDR "P-App-Param"
#define APPNAME_HDR "P-App-Name"
/** @file AmUtils.h */
/**
* Convert an int to a string.
*/
string int2str(int val);
/**
* Convert an unsigned int to a string using hexdecimal representation.
*/
string int2hex(unsigned int val);
/**
* Convert an unsigned long to a string using hexdecimal representation.
*/
string long2hex(unsigned long val);
/**
* Convert a reversed hex string to uint.
* @param str [in] string to convert.
* @param result [out] result integer.
* @return true if failed.
*/
bool reverse_hex2int(const string& str, unsigned int& result);
/**
* Convert a string to an uint.
* @param str [in] string to convert.
* @param result [out] result integer.
* @return true if failed.
*/
bool str2i(const string& str, unsigned int& result);
/**
* Internal version of preceeding 'str2i' method.
* @param str [in,out] gets incremented until sep char or error occurs
* @param result [out] result of the function
* @param sep [in] character seprating the number to convert and the next token
*/
bool str2i(char*& str, unsigned int& result, char sep = ' ');
/**
* Parse code/reason line.
* Syntax: "code reason"
*
* @param lbuf line buffer to parse.
* @param res_code_str char[4]; Syntax: xxxx whereby
* each x is a between 0 and 9.
* @param res_code where to store the resulting integer 'code'.
* @param res_msg where to store the 'reason'.
*/
int parse_return_code(const char* lbuf,
unsigned int& res_code, string& res_msg );
/**
* Get a line from a file.
*
* @param fifo_stream file to read from.
* @param str [out] line buffer.
* @param len size of the line buffer.
*
* @return -1 if buffer overruns,
* else the line's length.
*/
int fifo_get_line(FILE* fifo_stream, char* str, size_t len);
/**
* Gets one or more lines from a file.
* It stops to read as soon as a '.' line
* gets read or encounters EOF.
*
* Syntax:
* "[
* {one or more lines}
* ]
* ."
*
* @param fifo_stream file to read from.
* @param str [out] line buffer.
* @param len size of the line buffer.
*
* @return -1 if buffer overruns,
* else total length.
*/
int fifo_get_lines(FILE* fifo_stream, char* str, size_t len);
/**
* Size of line buffer used within fifo_get_param.
*/
//#define MAX_LINE_SIZE 256
/**
* Gets a line parameter from file pointer.
* If line only contain '.', the parameter is empty.
* Throws error string if failed.
*/
int fifo_get_param(FILE* fp, string& p, char* line_buf, unsigned int size);
/**
* Gets a line from the message buffer.
* @param msg_c [in,out] pointer to current message buffer.
* @param str line buffer.
* @param len line buffer size.
* @return size read or -1 if something went wrong.
*/
int msg_get_line(char*& msg_c, char* str, size_t len);
/**
* Gets [1..n] line(s) from the message buffer.
* @param msg_c [in,out] pointer to current message buffer.
* @param str line buffer.
* @param len line buffer size.
* @return size read or -1 if something went wrong.
*/
int msg_get_lines(char*& msg_c, char* str, size_t len);
/**
* Size of line buffer used within msg_get_param.
*/
//#define MSG_LINE_SIZE 1024
/**
* Gets a line parameter from message buffer.
* If line only contain '.', the parameter is empty.
* Throws error string if failed.
* @param msg_c [in,out] pointer to current message buffer.
* @param p [out] parameter to be filled.
*/
int msg_get_param(char*& msg_c, string& p, char* line_buf, unsigned int size);
/**
* Tells if a file exists.
* @param name file name.
* @return true if file could be openned.
*/
bool file_exists(const string& name);
/**
* @return A file name extracted from the given full path file name.
*/
string filename_from_fullpath(const string& path);
/**
* @return A file extension extracted from the given full path file name.
*/
string file_extension(const string& path);
/**
* @return new path resulting from the concatanation of path,
* suffix and eventually a slash between them
*/
string add2path(const string& path, int n_suffix, ...);
/**
* Reads a line from file and stores it in a string.
* @param f file to read from.
* @param p [out] where to store the line.
* @param lb line buffer.
* @param lbs line buffer's size.
*/
#define READ_FIFO_PARAMETER(f,p,lb,lbs)\
{\
if( fifo_get_line(f,lb,lbs) !=-1 ){\
if(!strcmp(".",lb))\
lb[0]='\0';\
DBG("%s= <%s>\n",#p,lb);\
p = lb;\
}\
else {\
throw string("could not read from FIFO: ") + string(strerror(errno));\
} \
}
struct in_addr;
string get_addr_str(struct in_addr in);
string uri_from_name_addr(const string& name_addr);
string get_ip_from_name(const string& name);
#ifdef SUPPORT_IPV6
int inet_aton_v6(const char* name, struct sockaddr_storage* ss);
void set_port_v6(struct sockaddr_storage* ss, short port);
short get_port_v6(struct sockaddr_storage* ss);
#endif
/**
* Creates and binds a unix socket to given path.
* @param path path the new socket should be bound to.
*/
int create_unix_socket(const string& path);
/** \brief microseconds sleep using select */
#define sleep_us(nusecs) \
{ \
struct timeval tval; \
tval.tv_sec=nusecs/1000000; \
tval.tv_usec=nusecs%1000000; \
select(0, NULL, NULL, NULL, &tval ); \
}
int write_to_fifo(const string& fifo, const char * buf, unsigned int len);
int write_to_socket(int sd, const char* to_addr, const char * buf, unsigned int len);
string extract_tag(const string& addr);
/** returns true if key is in s_list, a list of items delimited by list_delim
*skips whitespaces, too */
bool key_in_list(const string& s_list, const string& key, char list_delim = ',');
/** return string with trailing spaces and everything after ; including ; itself removed */
string strip_header_params(const string& hdr_string);
/** get a header parameter value */
string get_header_param(const string& hdr_string, const string& param_name);
/** get the value of key @param name from the list param_hdr*/
string get_header_keyvalue(const string& param_hdr, const string& name);
/** get the value of key @param name from P-Iptel-Param header in hdrs */
string get_session_param(const string& hdrs, const string& name);
/** support for thread-safe pseudo-random numbers - init function */
void init_random();
/** support for thread-safe pseudo-random numbers - make a random number function */
unsigned int get_random();
/** Explode string by a separator to a vector */
std::vector <string> explode(string s, string e);
/** add a directory to an environement variable */
void add_env_path(const char* name, const string& path);
#endif
// Local Variables:
// mode:C++
// End:

@ -20,14 +20,17 @@ SRCS = main.cpp \
resolver.cpp \
wheeltimer.cpp \
sip_trans.cpp \
AmThread.cpp \
AmUtils.cpp \
SipCtrlInterface.cpp
SipCtrlInterface.cpp \
../../AmThread.cpp \
../../AmUtils.cpp \
../../AmSipMsg.cpp
CORE_PATH ?= ../..
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
CXXFLAGS += -g
CXXFLAGS += -g -I $(CORE_PATH)
LDFLAGS += -lpthread -g
CPPFLAGS += -D_DEBUG -D_STANDALONE

@ -1,7 +1,7 @@
#include "SipCtrlInterface.h"
#include "AmUtils.h"
#include "../../AmSipMsg.h"
#include "AmSipMsg.h"
#include "trans_layer.h"
#include "sip_parser.h"

@ -35,7 +35,7 @@
#include "SipCtrlInterface.h"
#include "../../AmSipMsg.h"
#include "AmSipMsg.h"
#include "AmUtils.h"
#define SERVER

@ -16,7 +16,7 @@
#include "SipCtrlInterface.h"
#include "AmUtils.h"
#include "../../AmSipMsg.h"
#include "AmSipMsg.h"
#include <sys/socket.h>
#include <netinet/in.h>

Loading…
Cancel
Save