introduced a new DNS cache

- added aotmic_types for lock-free operations
- simple DNS cache
- support for SRV records

(work in progress...)
sayer/1.4-spce2.6
Raphael Coeffic 16 years ago
parent e7771d3f38
commit 5120770a4e

@ -50,6 +50,8 @@ deps: $(DEPS)
COREPATH=.
include ../Makefile.defs
LDFLAGS += -lresolv
CPPFLAGS += -I$(COREPATH)
# implicit rules
%.o : %.cpp %.d ../Makefile.defs

@ -5,8 +5,6 @@ HDRS=$(SRCS:.cpp=.h)
OBJS=$(SRCS:.cpp=.o)
DEPS=$(SRCS:.cpp=.d)
CPPFLAGS += -I..
.PHONY: all
all: ../../Makefile.defs
-@$(MAKE) deps && \
@ -20,17 +18,19 @@ clean:
.PHONY: deps
deps: $(DEPS)
COREPATH=..
include ../../Makefile.defs
COREPATH = ..
include $(COREPATH)/../Makefile.defs
CPPFLAGS += -I$(COREPATH)
# implicit rules
%.o : %.cpp %.d ../../Makefile.defs
%.o : %.cpp %.d $(COREPATH)/../Makefile.defs
$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)
%.d : %.cpp %.h ../../Makefile.defs
%.d : %.cpp %.h $(COREPATH)/../Makefile.defs
$(CXX) -MM $< $(CPPFLAGS) $(CXXFLAGS) > $@
$(LIBNAME): $(OBJS) ../../Makefile.defs
$(LIBNAME): $(OBJS) $(COREPATH)/../Makefile.defs
-@echo ""
-@echo "making $(LIBNAME)"
$(AR) rvs $(LIBNAME) $(OBJS)

@ -0,0 +1,137 @@
#ifndef _atomic_types_h_
#define _atomic_types_h_
#if defined(__GNUC__)
# if defined(__GNUC_PATCHLEVEL__)
# define __GNUC_VERSION__ (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
# else
# define __GNUC_VERSION__ (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100)
# endif
#else
#error Unsupported compiler
#endif
#if __GNUC_VERSION__ < 40101
#error GCC version >= 4.1.1 is required for proper atomic operations
#endif
#include <assert.h>
#include "log.h"
// 32 bit unsigned integer
class atomic_int
{
volatile unsigned int i;
public:
atomic_int() : i(0) {}
void set(unsigned int val) {
i = val;
}
unsigned int get() {
return i;
}
// ++i;
unsigned int inc() {
return __sync_add_and_fetch(&i,1);
}
// --i;
unsigned int dec() {
return __sync_sub_and_fetch(&i,1);
}
// return --ll != 0;
bool dec_and_test() {
return dec() == 0;
};
};
// 64 bit unsigned integer
class atomic_int64
{
volatile unsigned long long ll;
public:
void set(unsigned long long val) {
#ifndef __LP64__ || !__LP64__
unsigned long long tmp_ll;
do {
tmp_ll = ll;
}
while(!__sync_bool_compare_and_swap(&ll, tmp_ll, val));
#else
ll = val;
#endif
}
unsigned long long get() {
#ifndef __LP64__ || !__LP64__
unsigned long long tmp_ll;
do {
tmp_ll = ll;
}
while(!__sync_bool_compare_and_swap(&ll, tmp_ll, tmp_ll));
return tmp_ll;
#else
return ll;
#endif
}
// returns ++ll;
unsigned long long inc() {
return __sync_add_and_fetch(&ll,1);
}
// returns --ll;
unsigned long long dec() {
return __sync_sub_and_fetch(&ll,1);
}
// return --ll == 0;
bool dec_and_test() {
return dec() == 0;
};
};
class atomic_ref_cnt;
void inc_ref(atomic_ref_cnt* rc);
void dec_ref(atomic_ref_cnt* rc);
class atomic_ref_cnt
: protected atomic_int
{
protected:
atomic_ref_cnt()
: atomic_int() {}
virtual ~atomic_ref_cnt() {}
friend void inc_ref(atomic_ref_cnt* rc);
friend void dec_ref(atomic_ref_cnt* rc);
};
inline void inc_ref(atomic_ref_cnt* rc)
{
assert(rc);
rc->inc();
//DBG("after inc_ref(%p): ref_cnt = %u",rc,rc->get());
}
inline void dec_ref(atomic_ref_cnt* rc)
{
assert(rc);
//DBG("before dec_ref(%p): ref_cnt = %u",rc,rc->get());
if(rc->dec_and_test())
delete rc;
}
#endif

@ -29,12 +29,13 @@
#ifndef _hash_table_h
#define _hash_table_h
#include "cstring.h"
#include "../AmThread.h"
#include "../log.h"
#include "AmThread.h"
#include "log.h"
#include <list>
#include <map>
using std::list;
using std::map;
struct sip_trans;
struct sip_msg;
@ -70,13 +71,12 @@ public:
* if it was still present.
*/
void remove(Value* t) {
typename value_list::iterator it = find(t);
typename value_list::iterator it = find(t);
if(it != elmts.end()){
elmts.erase(it);
delete t;
DBG("~sip_trans()\n");
}
if(it != elmts.end()){
elmts.erase(it);
delete t;
}
}
/**
@ -123,13 +123,88 @@ protected:
value_list elmts;
};
template<class Bucket, unsigned long size>
template<class Key, class Value>
class ht_map_bucket: public AmMutex
{
public:
typedef map<Key,Value*> value_map;
ht_map_bucket(unsigned long id) : id(id) {}
~ht_map_bucket() {}
/**
* Caution: The bucket MUST be locked before you can
* do anything with it.
*/
/**
* Searches for the value ptr in this bucket.
* This is used to check if the value
* still exists.
*
* @return true if the value still exists.
*/
bool exist(const Key& k) {
return find(k) != elmts.end();
}
/**
* Remove the value from this bucket,
* if it was still present.
*/
void remove(const Key& k) {
typename value_map::iterator it = find(k);
if(it != elmts.end()){
Value* v = it->second;
elmts.erase(it);
delete v;
}
}
/**
* Returns the bucket id, which should be an index
* into the corresponding hash table.
*/
unsigned long get_id() const {
return id;
}
// debug method
void dump() const {
if(elmts.empty())
return;
DBG("*** Bucket ID: %i ***\n",(int)get_id());
for(typename value_map::const_iterator it = elmts.begin(); it != elmts.end(); ++it) {
(*it)->dump();
}
}
protected:
typename value_map::iterator find(const Key& k)
{
return elmts.find(k);
}
unsigned long id;
value_map elmts;
};
template<class Bucket>
class hash_table
{
Bucket* _table[size];
unsigned long size;
Bucket** _table;
public:
hash_table() {
hash_table(unsigned long size)
: size(size)
{
_table = new Bucket* [size];
for(unsigned long i=0; i<size; i++)
_table[i] = new Bucket(i);
}
@ -137,14 +212,21 @@ public:
~hash_table() {
for(unsigned long i=0; i<size; i++)
delete _table[i];
delete [] _table;
}
Bucket* operator [](unsigned long hash) const {
return get_bucket(hash);
}
Bucket* get_bucket(unsigned long hash) const {
return _table[hash % size];
}
Bucket* operator [](unsigned long hash) const {
return get_bucket(hash);
void dump() const {
for(unsigned long l=0; l<size; l++){
_table[l]->dump();
}
}
};

@ -26,16 +26,245 @@
*/
#include "resolver.h"
#include "hash.h"
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <assert.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <arpa/nameser_compat.h> // Darwin
#include <list>
using std::pair;
using std::list;
#include "log.h"
#include <sys/socket.h>
#include <netinet/in.h>
struct ip_entry
: public dns_base_entry
{
address_type type;
in_addr addr;
void to_sa(sockaddr_storage* sa);
};
struct srv_entry
: public dns_base_entry
{
unsigned short p;
unsigned short w;
unsigned short port;
string target;
};
class dns_ip_entry
: public dns_entry
{
public:
dns_ip_entry()
: dns_entry()
{}
int next_ip(dns_handle* h, sockaddr_storage* sa);
};
int dns_ip_entry::next_ip(dns_handle* h, sockaddr_storage* sa)
{
if(h->ip_e != this){
if(h->ip_e) dec_ref(h->ip_e);
h->ip_e = this;
h->ip_n = 0;
}
int& index = h->ip_n;
if(index >= (int)ip_vec.size()) return -1;
//copy address
((ip_entry*)ip_vec[index++])->to_sa(sa);
// reached the end?
if(index >= (int)ip_vec.size()) {
index = -1;
}
return 0;
}
class dns_srv_entry
: public dns_entry
{
public:
dns_srv_entry()
: dns_entry()
{}
int next_ip(dns_handle* h, sockaddr_storage* sa);
};
int dns_srv_entry::next_ip(dns_handle* h, sockaddr_storage* sa)
{
int& index = h->srv_n;
if(index >= (int)ip_vec.size()) return -1;
if(h->srv_e != this){
if(h->srv_e) dec_ref(h->srv_e);
h->srv_e = this;
h->srv_n = 0;
}
else if(h->ip_n != -1){
((sockaddr_in*)sa)->sin_port = h->port;
return h->ip_e->next_ip(h,sa);
}
// reset IP record
if(h->ip_e){
dec_ref(h->ip_e);
h->ip_e = NULL;
h->ip_n = 0;
}
list<pair<unsigned int,int> > srv_lst;
int i = index;
// fetch current priority
unsigned short p = ((srv_entry*)ip_vec[i])->p;
unsigned int w_sum = ((srv_entry*)ip_vec[i])->w;
srv_lst.push_back(std::make_pair(w_sum,i));
// and fetch records with same priority
while( (++i != (int)ip_vec.size()) &&
(p==((srv_entry*)ip_vec[i])->p) ){
w_sum += ((srv_entry*)ip_vec[i])->w;
srv_lst.push_back(std::make_pair(w_sum,i));
}
srv_entry* e=NULL;
if((i - index > 1) && w_sum){
// multiple records: apply weigthed load balancing
// TODO:
// - generate random number
// - pick the first record with cum. sum >= random number
unsigned int r = rand() % (w_sum+1);
list<pair<unsigned int,int> >::iterator srv_lst_it = srv_lst.begin();
while(srv_lst_it != srv_lst.end()){
if(srv_lst_it->first >= r){
//TODO: add this entry to some "already tried" list
e = (srv_entry*)ip_vec[srv_lst_it->second];
}
}
// should never trigger
assert(e);
}
else {
// single record or all weights == 0
e = (srv_entry*)ip_vec[index];
if(++index >= (int)ip_vec.size()){
h->srv_n = -1;
}
}
//TODO: find a solution for IPv6
h->port = htons(e->port);
((sockaddr_in*)sa)->sin_port = h->port;
return resolver::instance()->resolve_name(e->target.c_str(),h,sa,IPv4);
}
dns_entry::dns_entry()
: dns_base_entry()
{
}
dns_entry::~dns_entry()
{
DBG("~dns_entry()");
for(vector<dns_base_entry*>::iterator it = ip_vec.begin();
it != ip_vec.end(); ++it) {
delete *it;
}
}
dns_bucket::dns_bucket(unsigned long id)
: dns_bucket_base(id)
{
}
bool dns_bucket::insert(const string& name, dns_entry* e)
{
if(!e) return false;
lock();
if(!(elmts.insert(std::make_pair(name,e)).second)){
// if insertion failed
unlock();
return false;
}
inc_ref(e);
unlock();
return true;
}
bool dns_bucket::remove(const string& name)
{
lock();
value_map::iterator it = elmts.find(name);
if(it != elmts.end()){
dns_entry* e = it->second;
elmts.erase(it);
dec_ref(e);
unlock();
return true;
}
unlock();
return false;
}
dns_entry* dns_bucket::find(const string& name)
{
lock();
value_map::iterator it = elmts.find(name);
if(it == elmts.end()){
unlock();
return NULL;
}
dns_entry* e = it->second;
timeval now;
gettimeofday(&now,NULL);
if(now.tv_sec >= e->expire){
elmts.erase(it);
dec_ref(e);
unlock();
return NULL;
}
inc_ref(e);
unlock();
return e;
}
_resolver::_resolver()
: cache(DNS_CACHE_SIZE)
{
}
@ -45,41 +274,334 @@ _resolver::~_resolver()
}
int _resolver::resolve_name(const char* name, sockaddr_storage* sa,
const address_type types, const proto_type protos)
static void dns_error(int error, const char* domain)
{
struct addrinfo hints,*res=0;
memset(&hints,0,sizeof(hints));
switch(error){
case HOST_NOT_FOUND:
DBG("Unknown domain: %s\n", domain);
break;
case NO_DATA:
DBG("No records for %s\n", domain);
break;
case TRY_AGAIN:
DBG("No response for query (try again)\n");
break;
default:
ERROR("Unexpected error\n");
break;
}
}
void ip_entry::to_sa(sockaddr_storage* sa)
{
sockaddr_in* sa_in = (sockaddr_in*)sa;
sa_in->sin_family = AF_INET;
memcpy(&(sa_in->sin_addr),&addr,sizeof(in_addr));
}
static int collect_rr(ns_msg* handle, ns_sect section, ns_type type,
dns_entry* dns_e, long now,
dns_base_entry* (rr_to_entry)(ns_msg*,ns_rr*))
{
/*
* Look at all the resource records in this section.
*/
assert(handle);
assert(dns_e);
ns_rr rr;
for(int rrnum = 0; rrnum < ns_msg_count(*handle, section); rrnum++) {
/*
* Expand the resource record number rrnum into rr.
*/
if (ns_parserr(handle, section, rrnum, &rr)) {
ERROR("ns_parserr: %s\n", strerror(errno));
continue;
}
int err=0;
if(types & IPv4){
/*
* If the record type is correct, save the data into
* the proper entry.
*/
if(ns_rr_type(rr) == type) {
dns_base_entry* new_entry = (*rr_to_entry)(handle,&rr);
if(!new_entry){ continue; }
new_entry->expire = now + ns_rr_ttl(rr);
dns_e->ip_vec.push_back(new_entry);
if(dns_e->expire < new_entry->expire)
dns_e->expire = new_entry->expire;
}
}
return 0;
}
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
static dns_base_entry* rr_to_a_entry(ns_msg*, ns_rr* rr)
{
DBG("A:\tTTL=%i\t%s\t%i.%i.%i.%i\n",
ns_rr_ttl(*rr),
ns_rr_name(*rr),
ns_rr_rdata(*rr)[0],
ns_rr_rdata(*rr)[1],
ns_rr_rdata(*rr)[2],
ns_rr_rdata(*rr)[3]);
ip_entry* new_ip = new ip_entry();
new_ip->type = IPv4;
memcpy(&(new_ip->addr), ns_rr_rdata(*rr), sizeof(in_addr));
return new_ip;
}
static int collect_a_rr(ns_msg* handle, ns_sect section, dns_entry* dns_e, long now)
{
return collect_rr(handle,section,ns_t_a,dns_e,now,rr_to_a_entry);
}
static dns_base_entry* rr_to_srv_entry(ns_msg* handle, ns_rr* rr)
{
char name_buf[MAXDNAME];
const u_char * rdata = ns_rr_rdata(*rr);
err = getaddrinfo(name,NULL,&hints,&res);
if(err){
switch(err){
case EAI_AGAIN:
case EAI_NONAME:
ERROR("Could not resolve '%s'\n",name);
break;
default:
ERROR("getaddrinfo('%s'): %s\n",
name,gai_strerror(err));
break;
}
err = -1;
/* Expand the target's name */
if (ns_name_uncompress(
ns_msg_base(*handle),/* Start of the packet */
ns_msg_end(*handle), /* End of the packet */
rdata+6, /* Position in the packet*/
name_buf, /* Result */
MAXDNAME) /* Size of result buffer */
< 0) { /* Negative: error */
ERROR("ns_name_uncompress failed\n");
return NULL;
}
printf("SRV:\tTTL=%i\t%s\tP=<%i> W=<%i> P=<%i> T=<%s>\n",
ns_rr_ttl(*rr),
ns_rr_name(*rr),
ns_get16(rdata),
ns_get16(rdata+2),
ns_get16(rdata+4),
name_buf);
srv_entry* srv_r = new srv_entry();
srv_r->p = ns_get16(rdata);
srv_r->w = ns_get16(rdata+2);
srv_r->port = ns_get16(rdata+4);
srv_r->target = (const char*)name_buf;
return srv_r;
}
static bool srv_less(const dns_base_entry* le, const dns_base_entry* re)
{
const srv_entry* l_srv = (const srv_entry*)le;
const srv_entry* r_srv = (const srv_entry*)re;
if(l_srv->p != r_srv->p)
return l_srv->p < r_srv->p;
else
return l_srv->w < r_srv->w;
};
static int collect_srv_rr(ns_msg* handle, ns_sect section, dns_entry* dns_e, long now)
{
int ret = collect_rr(handle,section,ns_t_srv,dns_e,now,rr_to_srv_entry);
if(!ret){
stable_sort(dns_e->ip_vec.begin(),dns_e->ip_vec.end(),srv_less);
}
return ret;
}
int _resolver::query_dns(const char* name, dns_entry** e, long now)
{
typedef union {
HEADER hdr; /* defined in resolv.h */
u_char buf[NS_PACKETSZ]; /* defined in arpa/nameser.h */
} dns_response; /* response buffers */
if(!name) return -1;
dns_response dns_res;
ns_type t = (name[0] == '_') ? ns_t_srv : ns_t_a;
//TODO: add AAAA record support
int dns_res_len = res_search(name,ns_c_in,t,
(u_char *)&dns_res.buf,sizeof(dns_response));
if(dns_res_len < 0){
dns_error(h_errno,name);
return -1;
}
/*
* Initialize a handle to this response. The handle will
* be used later to extract information from the response.
*/
ns_msg handle;
if (ns_initparse(dns_res.buf, dns_res_len, &handle) < 0) {
ERROR("ns_initparse: %s\n", strerror(errno));
return -1;
}
if(!ns_msg_count(handle,ns_s_an)) {
// nothing in the answer section
return -1;
}
int ret;
switch(t){
case ns_t_srv:
*e = new dns_srv_entry();
ret = collect_srv_rr(&handle,ns_s_an,*e,now);
break;
case ns_t_a:
*e = new dns_ip_entry();
ret = collect_a_rr(&handle,ns_s_an,*e,now);
break;
default:
ret = -1;
break;
}
if((ret < 0) || (*e)->ip_vec.empty()){
delete *e;
*e = NULL;
return -1;
}
inc_ref(*e);
return 0;
}
int _resolver::resolve_name(const char* name,
dns_handle* h,
sockaddr_storage* sa,
const address_type types)
{
int ret;
// already have a valid handle?
if(h->valid()){
if(h->eoip()) return -1;
return h->next_ip(sa);
}
// first try to detect if 'name' is already an IP address
ret = str2ip(name,sa,types);
if(ret == 1) {
h->ip_n = -1; // flag end of IP list
h->srv_n = -1;
return 0; // 'name' is an IP address
}
// name is NOT an IP address -> try a cache look up
dns_bucket* b = cache.get_bucket(hashlittle(name,strlen(name),0));
dns_entry* e = b->find(name);
// first attempt to get a valid IP
// (from the cache)
if(e){
return e->next_ip(h,sa);
}
timeval tv_now;
gettimeofday(&tv_now,NULL);
// no valid IP, query the DNS
if(query_dns(name,&e,tv_now.tv_sec) < 0) {
// DNS query failed
WARN("DNS query failed");
return -1;
}
// if ttl != 0
if(e->expire != tv_now.tv_sec){
// cache the new record
b->insert(name,e);
}
if(e) {
// now we should have a valid IP
return e->next_ip(h,sa);
}
// should not happen...
return -1;
}
int _resolver::str2ip(const char* name,
sockaddr_storage* sa,
const address_type types)
{
if(types & IPv4){
int ret = inet_pton(AF_INET,name,&((sockaddr_in*)sa)->sin_addr);
if(ret==1) {
DBG("inet_pton() succeeded");
((sockaddr_in*)sa)->sin_family = AF_INET;
return 1;
}
else {
memcpy(sa,res->ai_addr,res->ai_addrlen);
freeaddrinfo(res);
else if(ret < 0) {
ERROR("while trying to detect an IPv4 address '%s': %s",name,strerror(errno));
return ret;
}
}
return err;
if(types & IPv6){
int ret = inet_pton(AF_INET6,name,&((sockaddr_in6*)sa)->sin6_addr);
if(ret==1) {
DBG("inet_pton() succeeded");
((sockaddr_in6*)sa)->sin6_family = AF_INET6;
return 1;
}
else if(ret < 0) {
ERROR("while trying to detect an IPv6 address '%s': %s",name,strerror(errno));
return ret;
}
}
return 0;
}
dns_handle::dns_handle()
: srv_e(0), srv_n(0), ip_e(0), ip_n(0)
{}
dns_handle::~dns_handle()
{
DBG("~dns_handle()");
if(ip_e)
dec_ref(ip_e);
if(srv_e)
dec_ref(srv_e);
}
bool dns_handle::valid()
{
return (ip_e);
}
bool dns_handle::eoip()
{
if(srv_n)
return (srv_n == -1) && (ip_n == -1);
else
return (ip_n == -1);
}
int dns_handle::next_ip(sockaddr_storage* sa)
{
if(!valid() || eoip()) return -1;
if(srv_e)
return srv_e->next_ip(this,sa);
else
return ip_e->next_ip(this,sa);
}
/** EMACS **

@ -28,11 +28,21 @@
#define _resolver_h_
#include "singleton.h"
#include "hash_table.h"
#include "atomic_types.h"
struct sockaddr_storage;
#include <string>
#include <vector>
using std::string;
using std::vector;
#include <netinet/in.h>
#define DNS_CACHE_SIZE 128
enum address_type {
IPnone=0,
IPv4=1,
IPv6=2
};
@ -43,16 +53,95 @@ enum proto_type {
UDP=2
};
class _resolver
struct dns_handle;
struct dns_base_entry
{
long int expire;
dns_base_entry()
:expire(0)
{}
virtual ~dns_base_entry() {}
};
class dns_entry
: public atomic_ref_cnt,
public dns_base_entry
{
public:
int resolve_name(const char* name, sockaddr_storage* sa,
const address_type types, const proto_type protos);
vector<dns_base_entry*> ip_vec;
dns_entry();
virtual ~dns_entry();
virtual int next_ip(dns_handle* h, sockaddr_storage* sa)=0;
};
typedef ht_map_bucket<string,dns_entry> dns_bucket_base;
class dns_bucket
: protected dns_bucket_base
{
public:
dns_bucket(unsigned long id);
bool insert(const string& name, dns_entry* e);
bool remove(const string& name);
dns_entry* find(const string& name);
};
typedef hash_table<dns_bucket> dns_cache;
class dns_srv_entry;
class dns_ip_entry;
struct dns_handle
{
dns_handle();
~dns_handle();
bool valid();
bool eoip();
int next_ip(sockaddr_storage* sa);
private:
friend class _resolver;
friend class dns_entry;
friend class dns_srv_entry;
friend class dns_ip_entry;
dns_srv_entry* srv_e;
int srv_n;
unsigned short port;
dns_ip_entry* ip_e;
int ip_n;
};
class _resolver
{
public:
int resolve_name(const char* name,
dns_handle* h,
sockaddr_storage* sa,
const address_type types);
protected:
_resolver();
~_resolver();
int query_dns(const char* name,
dns_entry** e,
long now);
int str2ip(const char* name,
sockaddr_storage* sa,
const address_type types);
private:
dns_cache cache;
};
typedef singleton<_resolver> resolver;

@ -30,6 +30,7 @@
#include "cstring.h"
#include "parse_uri.h"
#include "resolver.h"
#include <list>
using std::list;
@ -41,6 +42,7 @@ struct sip_request;
struct sip_reply;
struct sip_header;
struct sip_via_parm;
struct dns_handle;
//
// SIP message types:
@ -125,7 +127,8 @@ struct sip_msg
sockaddr_storage local_ip;
sockaddr_storage remote_ip;
dns_handle h_dns;
sip_msg();
sip_msg(const char* msg_buf, int msg_len);
~sip_msg();

@ -35,7 +35,14 @@
#include <assert.h>
int _timer_type_lookup[] = { -1, 0,1,2, 0,1,2, 0,1,2, 0,2 };
int _timer_type_lookup[] = {
-1, // STIMER_INVALID
0,1,2, // STIMER_A, STIMER_B, STIMER_D
0,1,2, // STIMER_E, STIMER_F, STIMER_K
0,1,2, // STIMER_G, STIMER_H, STIMER_I
0, // STIMER_J
2 // STIMER_L; shares the same slot as STIMER_D
};
inline timer** fetch_timer(unsigned int timer_type, timer** base)
{

@ -86,7 +86,7 @@ enum sip_timer_type {
// This timer is not defined by
// RFC 3261. But it is needed
// to handle 200 ACKs automatically
// in UAC transactions.
// in INVITE client transactions.
STIMER_L // Terminated_200 -> Terminated
};
@ -128,10 +128,12 @@ class sip_trans
sent/received reply */
int reply_status;
/** Transaction state */
int state;
/** used by UAS only; keeps RSeq of last sent reliable 1xx */
unsigned int last_rseq;
/**
* Retransmission buffer
* - UAC transaction: ACK
@ -142,9 +144,6 @@ class sip_trans
/** Length of the retransmission buffer */
int retr_len;
/** used by UAS only; keeps RSeq of last sent reliable 1xx */
unsigned int last_rseq;
/** Destination for retransmissions */
sockaddr_storage retr_addr;

@ -533,7 +533,6 @@ int _trans_layer::set_next_hop(sip_msg* msg)
list<sip_header*>& route_hdrs = msg->route;
cstring& r_uri = msg->u.request->ruri_str;
sockaddr_storage* remote_ip = &msg->remote_ip;
cstring next_hop;
unsigned short next_port = 0;
@ -682,13 +681,15 @@ int _trans_layer::set_next_hop(sip_msg* msg)
DBG("next_hop:next_port is <%.*s:%u>\n", next_hop.len, next_hop.s, next_port);
err = resolver::instance()->resolve_name(c2stlstr(next_hop).c_str(),remote_ip,IPv4,UDP);
err = resolver::instance()->resolve_name(c2stlstr(next_hop).c_str(),
&(msg->h_dns),
&(msg->remote_ip),IPv4);
if(err < 0){
ERROR("Unresolvable Request URI\n");
return -1;
}
((sockaddr_in*)remote_ip)->sin_port = htons(next_port);
((sockaddr_in*)&(msg->remote_ip))->sin_port = htons(next_port);
return 0;
}
@ -804,6 +805,7 @@ int _trans_layer::send_request(sip_msg* msg, trans_ticket* tt)
}
memcpy(&p_msg->remote_ip,&msg->remote_ip,sizeof(sockaddr_storage));
memcpy(&p_msg->h_dns,&msg->h_dns,sizeof(dns_handle));
DBG("Sending to %s:%i <%.*s...>\n",
get_addr_str(((sockaddr_in*)&p_msg->remote_ip)->sin_addr).c_str(),
@ -1283,6 +1285,7 @@ int _trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg*
t->state = TS_COMPLETED;
t->clear_timer(STIMER_E);
t->clear_timer(STIMER_F);
t->reset_timer(STIMER_K, K_TIMER, bucket->get_id());
if(t->msg->u.request->method != sip_request::CANCEL)

@ -44,7 +44,7 @@
// Global transaction table
//
//trans_bucket _trans_table[H_TABLE_ENTRIES];
hash_table<trans_bucket,H_TABLE_ENTRIES> _trans_table;
hash_table<trans_bucket> _trans_table(H_TABLE_ENTRIES);
trans_bucket::trans_bucket(unsigned long id)
: ht_bucket<sip_trans>::ht_bucket(id)
@ -494,13 +494,13 @@ void compute_branch(char* branch/*[8]*/, const cstring& callid, const cstring& c
trans_bucket* get_trans_bucket(const cstring& callid, const cstring& cseq_num)
{
return /*&*/_trans_table[hash(callid,cseq_num)];
return _trans_table[hash(callid,cseq_num)];
}
trans_bucket* get_trans_bucket(unsigned int h)
{
assert(h < H_TABLE_ENTRIES);
return /*&*/_trans_table[h];
return _trans_table[h];
}
void dumps_transactions()

@ -2,6 +2,7 @@
#define _trans_table_h_
#include "hash_table.h"
#include "cstring.h"
#define H_TABLE_POWER 10
#define H_TABLE_ENTRIES (1<<H_TABLE_POWER)

@ -40,18 +40,6 @@ timer::~timer()
DBG("timer::~timer(this=%p)\n",this);
}
//wheeltimer* wheeltimer::_instance=NULL;
// wheeltimer* wheeltimer::instance()
// {
// if(!_instance)
// _instance = new wheeltimer();
// return _instance;
// }
_wheeltimer::_wheeltimer()
: wall_clock(0)
{
@ -71,7 +59,7 @@ void _wheeltimer::insert_timer(timer* t)
void _wheeltimer::remove_timer(timer* t)
{
//add new timer to user request list
//add timer to remove to user request list
utimer_rem_m.lock();
utimer_rem.push_back(t);
utimer_rem_m.unlock();

Loading…
Cancel
Save