Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange Version 2
*
* Copyright (C) 2003 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/frame.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/logger.h>
#include <asterisk/module.h>
#include <asterisk/pbx.h>
#include <asterisk/sched.h>
#include <asterisk/io.h>
#include <asterisk/config.h>
#include <asterisk/options.h>
#include <asterisk/cli.h>
#include <asterisk/translate.h>
#include <asterisk/md5.h>
#include <asterisk/cdr.h>
#include <asterisk/crypto.h>
#include <asterisk/acl.h>
#include <asterisk/manager.h>
#include <asterisk/callerid.h>
#include <asterisk/musiconhold.h>
Mark Spencer
committed
#include <asterisk/features.h>
Mark Spencer
committed
#include <asterisk/causes.h>
#include <asterisk/localtime.h>
Mark Spencer
committed
#include <asterisk/aes.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#ifdef IAX_TRUNKING
#include <sys/ioctl.h>
#else
#include <zaptel.h>
#endif /* __linux__ */
#ifndef IPTOS_MINCOST
#define IPTOS_MINCOST 0x02
#endif
/*
* Uncomment to try experimental IAX bridge optimization,
* designed to reduce latency when IAX calls cannot
* be trasnferred
*/
#define BRIDGE_OPTIMIZATION
#define PTR_TO_CALLNO(a) ((unsigned short)(unsigned long)(a))
#define CALLNO_TO_PTR(a) ((void *)(unsigned long)(a))
#define DEFAULT_RETRY_TIME 1000
#define MEMORY_SIZE 100
#define DEFAULT_DROP 3
/* Flag to use with trunk calls, keeping these calls high up. It halves our effective use
but keeps the division between trunked and non-trunked better. */
#define TRUNK_CALL_START 0x4000
#define MIN_REUSE_TIME 60 /* Don't reuse a call number within 60 seconds */
/* Sample over last 100 units to determine historic jitter */
#define GAMMA (0.01)
static struct ast_codec_pref prefs;
static char *desc = "Inter Asterisk eXchange (Ver 2)";
static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)";
static char context[80] = "default";
static char language[MAX_LANGUAGE] = "";
static char regcontext[AST_MAX_EXTENSION] = "";
static int max_retries = 4;
static int ping_time = 20;
static int lagrq_time = 10;
static int maxtrunkcall = TRUNK_CALL_START;
static int maxnontrunkcall = 1;
static int maxjitterbuffer=1000;
static int jittershrinkrate=2;
Mark Spencer
committed
static int iaxcompat = 0;
static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes by default */
static int iaxdefaulttimeout = 5; /* Default to wait no more than 5 seconds for a reply to come back */
static int tos = 0;
static int expirey = IAX_DEFAULT_REG_EXPIRE;
static int timingfd = -1; /* Timing file descriptor */
static struct ast_netsock_list netsock;
static int defaultsockfd = -1;
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
int (*iax2_regfunk)(char *username, int onoff) = NULL;
/* Ethernet, etc */
#define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
/* T1, maybe ISDN */
#define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
~AST_FORMAT_SLINEAR & \
~AST_FORMAT_ULAW & \
~AST_FORMAT_ALAW)
/* A modem */
#define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
~AST_FORMAT_G726 & \
~AST_FORMAT_ADPCM)
#define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
~AST_FORMAT_G723_1)
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
#define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */
#define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */
static struct io_context *io;
static struct sched_context *sched;
static int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;
static int iax2_dropcount = DEFAULT_DROP;
static int iaxdebug = 0;
static char accountcode[20];
static int amaflags = 0;
Mark Spencer
committed
static int delayreject = 0;
Mark Spencer
committed
static int iax2_encryption = 0;
static struct ast_flags globalflags = {0};
static pthread_t netthreadid = AST_PTHREADT_NULL;
#define IAX_STATE_AUTHENTICATED (1 << 1)
#define IAX_STATE_TBD (1 << 2)
struct iax2_context {
char context[AST_MAX_EXTENSION];
struct iax2_context *next;
};
#define IAX_HASCALLERID (1 << 0) /* CallerID has been specified */
#define IAX_DELME (1 << 1) /* Needs to be deleted */
#define IAX_TEMPONLY (1 << 2) /* Temporary (realtime) */
#define IAX_TRUNK (1 << 3) /* Treat as a trunk */
#define IAX_NOTRANSFER (1 << 4) /* Don't native bridge */
#define IAX_USEJITTERBUF (1 << 5) /* Use jitter buffer */
#define IAX_DYNAMIC (1 << 6) /* dynamic peer */
#define IAX_SENDANI (1 << 7) /* Send ANI along with CallerID */
#define IAX_MESSAGEDETAIL (1 << 8) /* Show exact numbers */
#define IAX_ALREADYGONE (1 << 9) /* Already disconnected */
#define IAX_PROVISION (1 << 10) /* This is a provisioning request */
#define IAX_QUELCH (1 << 11) /* Whether or not we quelch audio */
Mark Spencer
committed
#define IAX_ENCRYPTED (1 << 12) /* Whether we should assume encrypted tx/rx */
#define IAX_KEYPOPULATED (1 << 13) /* Whether we have a key populated */
#define IAX_CODEC_USER_FIRST (1 << 14) /* are we willing to let the other guy choose the codec? */
#define IAX_CODEC_NOPREFS (1 << 15) /* Force old behaviour by turning off prefs */
#define IAX_CODEC_NOCAP (1 << 16) /* only consider requested format and ignore capabilities*/
#define IAX_RTCACHEFRIENDS (1 << 17) /* let realtime stay till your reload */
#define IAX_RTNOUPDATE (1 << 18) /* Don't send a realtime update */
#define IAX_RTAUTOCLEAR (1 << 19) /* erase me on expire */
static int global_rtautoclear = 120;
static struct iax2_peer *realtime_peer(const char *peername);
static int reload_config(void);
struct iax2_user {
char name[80];
char secret[80];
Mark Spencer
committed
int encmethods;
char accountcode[20];
char inkeys[80]; /* Key(s) this user can use to authenticate to us */
char language[MAX_LANGUAGE];
int capability;
char cid_num[AST_MAX_EXTENSION];
char cid_name[AST_MAX_EXTENSION];
struct ast_codec_pref prefs;
struct ast_ha *ha;
struct iax2_context *contexts;
struct iax2_user *next;
};
struct iax2_peer {
char name[80];
char username[80];
char secret[80];
char outkey[80]; /* What key we use to talk to this peer */
char context[AST_MAX_EXTENSION]; /* For transfers only */
char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */
char peercontext[AST_MAX_EXTENSION]; /* Context to pass to peer */
char mailbox[AST_MAX_EXTENSION]; /* Mailbox */
struct ast_codec_pref prefs;
struct sockaddr_in addr;
int formats;
int sockfd; /* Socket to use for transmission */
struct sockaddr_in defaddr; /* Default address if there is one */
int authmethods; /* Authentication methods (IAX_AUTH_*) */
Mark Spencer
committed
int encmethods; /* Encryption methods (IAX_ENCRYPT_*) */
char inkeys[80]; /* Key(s) this peer can use to authenticate to us */
/* Suggested caller id if registering */
char cid_num[AST_MAX_EXTENSION]; /* Default context (for transfer really) */
char cid_name[AST_MAX_EXTENSION]; /* Default context (for transfer really) */
int expire; /* Schedule entry for expirey */
int expirey; /* How soon to expire */
int capability; /* Capability */
char zonetag[80]; /* Time Zone */
/* Qualification */
int callno; /* Call number of POKE request */
int pokeexpire; /* When to expire poke */
int lastms; /* How long last response took (in ms), or -1 for no response */
int maxms; /* Max ms we will accept for the host to be up, 0 to not monitor */
struct ast_ha *ha;
struct iax2_peer *next;
};
#define IAX2_TRUNK_PREFACE (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
static struct iax2_trunk_peer {
ast_mutex_t lock;
int sockfd;
struct sockaddr_in addr;
struct timeval txtrunktime; /* Transmit trunktime */
struct timeval rxtrunktime; /* Receive trunktime */
struct timeval lasttxtime; /* Last transmitted trunktime */
struct timeval trunkact; /* Last trunk activity */
unsigned int lastsent; /* Last sent time */
/* Trunk data and length */
unsigned char *trunkdata;
unsigned int trunkdatalen;
unsigned int trunkdataalloc;
struct iax2_trunk_peer *next;
int trunkerror;
int calls;
} *tpeers = NULL;
AST_MUTEX_DEFINE_STATIC(tpeerlock);
struct iax_firmware {
struct iax_firmware *next;
int fd;
int mmaplen;
int dead;
struct ast_iax2_firmware_header *fwh;
unsigned char *buf;
};
#define REG_STATE_UNREGISTERED 0
#define REG_STATE_REGSENT 1
#define REG_STATE_AUTHSENT 2
#define REG_STATE_REGISTERED 3
#define REG_STATE_REJECTED 4
#define REG_STATE_TIMEOUT 5
#define REG_STATE_NOAUTH 6
#define TRANSFER_NONE 0
#define TRANSFER_BEGIN 1
#define TRANSFER_READY 2
#define TRANSFER_RELEASED 3
#define TRANSFER_PASSTHROUGH 4
struct iax2_registry {
struct sockaddr_in addr; /* Who we connect to for registration purposes */
char username[80];
char secret[80]; /* Password or key name in []'s */
char random[80];
int expire; /* Sched ID of expiration */
int refresh; /* How often to refresh */
int messages; /* Message count */
int callno; /* Associated call number if applicable */
struct sockaddr_in us; /* Who the server thinks we are */
struct iax2_registry *next;
};
static struct iax2_registry *registrations;
/* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
#define MIN_JITTER_BUFFER 10
#define DEFAULT_TRUNKDATA 640 * 10 /* 40ms, uncompressed linear * 10 channels */
#define MAX_TRUNKDATA 640 * 200 /* 40ms, uncompressed linear * 200 channels */
#define MAX_TIMESTAMP_SKEW 640
/* If consecutive voice frame timestamps jump by more than this many milliseconds, then jitter buffer will resync */
#define TS_GAP_FOR_JB_RESYNC 5000
/* If we have more than this much excess real jitter buffer, shrink it. */
static int max_jitter_buffer = MAX_JITTER_BUFFER;
/* If we have less than this much excess real jitter buffer, enlarge it. */
static int min_jitter_buffer = MIN_JITTER_BUFFER;
/* Socket to send/receive on for this call */
int sockfd;
/* Last received voice format */
int voiceformat;
/* Last received voice format */
int videoformat;
/* Last sent voice format */
int svoiceformat;
/* Last sent video format */
int svideoformat;
/* What we are capable of sending */
int capability;
/* Last received timestamp */
unsigned int last;
/* Last sent timestamp - never send the same timestamp twice in a single call */
unsigned int lastsent;
/* Next outgoing timestamp if everything is good */
unsigned int nextpred;
/* True if the last voice we transmitted was not silence/CNG */
int notsilenttx;
/* Ping time */
unsigned int pingtime;
/* Max time for initial response */
int maxtime;
/* Peer Address */
struct sockaddr_in addr;
struct ast_codec_pref prefs;
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/* Our call number */
unsigned short callno;
/* Peer callno */
unsigned short peercallno;
/* Peer selected format */
int peerformat;
/* Peer capability */
int peercapability;
/* timeval that we base our transmission on */
struct timeval offset;
/* timeval that we base our delivery on */
struct timeval rxcore;
/* Historical delivery time */
int history[MEMORY_SIZE];
/* Current base jitterbuffer */
int jitterbuffer;
/* Current jitter measure */
int jitter;
/* Historic jitter value */
int historicjitter;
/* LAG */
int lag;
/* Error, as discovered by the manager */
int error;
/* Owner if we have one */
struct ast_channel *owner;
/* What's our state? */
int state;
/* Expirey (optional) */
int expirey;
/* Next outgoing sequence number */
/* Next sequence number they have not yet acknowledged */
/* Last incoming sequence number we have acknowledged */
/* Peer name */
char peer[80];
/* Default Context */
char context[80];
/* Caller ID if available */
char cid_num[80];
char cid_name[80];
/* Hidden Caller ID (i.e. ANI) if appropriate */
char ani[80];
/* DNID */
char dnid[80];
/* Requested Extension */
char exten[AST_MAX_EXTENSION];
/* Expected Username */
char username[80];
/* Expected Secret */
char secret[80];
/* permitted authentication methods */
int authmethods;
Mark Spencer
committed
/* permitted encryption methods */
int encmethods;
/* MD5 challenge */
char challenge[10];
/* Public keys permitted keys for incoming authentication */
char inkeys[80];
/* Private key for outgoing authentication */
char outkey[80];
Mark Spencer
committed
/* Encryption AES-128 Key */
aes_encrypt_ctx ecx;
/* Decryption AES-128 Key */
aes_decrypt_ctx dcx;
/* 32 bytes of semi-random data */
char semirand[32];
char language[MAX_LANGUAGE];
/* Hostname/peername for naming purposes */
char host[80];
/* Associated registry */
struct iax2_registry *reg;
/* Associated peer for poking */
struct iax2_peer *peerpoke;
Mark Spencer
committed
/* Transferring status */
int transferring;
/* Transfer identifier */
int transferid;
/* Who we are IAX transfering to */
struct sockaddr_in transfer;
/* What's the new call number for the transfer */
unsigned short transfercallno;
Mark Spencer
committed
/* Transfer decrypt AES-128 Key */
aes_encrypt_ctx tdcx;
/* Status of knowledge of peer ADSI capability */
int peeradsicpe;
/* Who we are bridged to */
unsigned short bridgecallno;
unsigned int bridgesfmt;
struct ast_trans_pvt *bridgetrans;
int pingid; /* Transmit PING request */
int lagid; /* Retransmit lag request */
int autoid; /* Auto hangup for Dialplan requestor */
Mark Spencer
committed
int authid; /* Authentication rejection ID */
int authfail; /* Reason to report failure */
int initid; /* Initial peer auto-congest ID (based on qualified peers) */
int calling_ton;
int calling_tns;
int calling_pres;
char dproot[AST_MAX_EXTENSION];
char accountcode[20];
int amaflags;
struct iax2_dpcache *dpentries;
};
static struct ast_iax2_queue {
struct iax_frame *head;
struct iax_frame *tail;
ast_mutex_t lock;
} iaxq;
static struct ast_user_list {
struct iax2_user *users;
ast_mutex_t lock;
} userl;
static struct ast_peer_list {
struct iax2_peer *peers;
ast_mutex_t lock;
static struct ast_firmware_list {
struct iax_firmware *wares;
ast_mutex_t lock;
} waresl;
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
/* Extension exists */
#define CACHE_FLAG_EXISTS (1 << 0)
/* Extension is non-existant */
#define CACHE_FLAG_NONEXISTANT (1 << 1)
/* Extension can exist */
#define CACHE_FLAG_CANEXIST (1 << 2)
/* Waiting to hear back response */
#define CACHE_FLAG_PENDING (1 << 3)
/* Timed out */
#define CACHE_FLAG_TIMEOUT (1 << 4)
/* Request transmitted */
#define CACHE_FLAG_TRANSMITTED (1 << 5)
/* Timeout */
#define CACHE_FLAG_UNKNOWN (1 << 6)
/* Matchmore */
#define CACHE_FLAG_MATCHMORE (1 << 7)
static struct iax2_dpcache {
char peercontext[AST_MAX_EXTENSION];
char exten[AST_MAX_EXTENSION];
struct timeval orig;
struct timeval expirey;
int flags;
unsigned short callno;
int waiters[256];
struct iax2_dpcache *next;
struct iax2_dpcache *peer; /* For linking in peers */
} *dpcache;
Mark Spencer
committed
AST_MUTEX_DEFINE_STATIC(dpcache_lock);
static void destroy_peer(struct iax2_peer *peer);
static void iax_debug_output(const char *data)
static void iax_error_output(const char *data)
/* XXX We probably should use a mutex when working with this XXX */
static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
static ast_mutex_t iaxsl[IAX_MAX_CALLS];
static struct timeval lastused[IAX_MAX_CALLS];
static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
static int send_command_locked(unsigned short callno, char, int, unsigned int, char *, int, int);
static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, char *, int);
static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
static void destroy_user(struct iax2_user *user);
static int expire_registry(void *data);
static int iax2_write(struct ast_channel *c, struct ast_frame *f);
static int iax2_do_register(struct iax2_registry *reg);
static void prune_peers(void);
static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
static int iax2_provision(struct sockaddr_in *end, char *dest, const char *template, int force);
static int send_ping(void *data)
{
int callno = (long)data;
/* Ping only if it's real, not if it's bridged */
if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
if (!iaxs[callno]->bridgecallno)
#endif
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
return 1;
} else
return 0;
}
Mark Spencer
committed
static int get_encrypt_methods(const char *s)
{
int e;
if (!strcasecmp(s, "aes128"))
e = IAX_ENCRYPT_AES128;
else if (ast_true(s))
e = IAX_ENCRYPT_AES128;
else
e = 0;
return e;
}
static int send_lagrq(void *data)
{
int callno = (long)data;
/* Ping only if it's real not if it's bridged */
if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
if (!iaxs[callno]->bridgecallno)
#endif
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
return 1;
} else
return 0;
}
static unsigned char compress_subclass(int subclass)
{
int x;
int power=-1;
/* If it's 128 or smaller, just return it */
return subclass;
/* Otherwise find its power */
if (subclass & (1 << x)) {
if (power > -1) {
ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);
return 0;
} else
power = x;
}
}
}
static int uncompress_subclass(unsigned char csub)
{
/* If the SC_LOG flag is set, return 2^csub otherwise csub */
/* special case for 'compressed' -1 */
if (csub == 0xff)
return -1;
else
return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
static struct iax2_peer *find_peer(const char *name, int realtime)
{
struct iax2_peer *peer;
ast_mutex_lock(&peerl.lock);
for(peer = peerl.peers; peer; peer = peer->next) {
if (!strcasecmp(peer->name, name)) {
break;
}
}
ast_mutex_unlock(&peerl.lock);
peer = realtime_peer(name);
return peer;
}
static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
{
struct iax2_peer *peer;
int res = 0;
if (lockpeer)
ast_mutex_lock(&peerl.lock);
peer = peerl.peers;
while(peer) {
if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
(peer->addr.sin_port == sin.sin_port)) {
strncpy(host, peer->name, len-1);
res = 1;
break;
}
peer = peer->next;
}
if (lockpeer)
ast_mutex_unlock(&peerl.lock);
static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, const char *host)
{
struct chan_iax2_pvt *tmp;
tmp = malloc(sizeof(struct chan_iax2_pvt));
if (tmp) {
memset(tmp, 0, sizeof(struct chan_iax2_pvt));
tmp->prefs = prefs;
tmp->callno = 0;
tmp->peercallno = 0;
tmp->transfercallno = 0;
tmp->bridgecallno = 0;
tmp->pingid = -1;
tmp->lagid = -1;
tmp->autoid = -1;
Mark Spencer
committed
tmp->authid = -1;
tmp->initid = -1;
/* strncpy(tmp->context, context, sizeof(tmp->context)-1); */
strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
strncpy(tmp->host, host, sizeof(tmp->host)-1);
}
return tmp;
}
static int get_samples(struct ast_frame *f)
{
int samples=0;
switch(f->subclass) {
case AST_FORMAT_SPEEX:
samples = 160; /* XXX Not necessarily true XXX */
break;
case AST_FORMAT_G723_1:
samples = 240 /* XXX Not necessarily true XXX */;
break;
case AST_FORMAT_GSM:
samples = 160 * (f->datalen / 33);
break;
case AST_FORMAT_G729A:
samples = 160 * (f->datalen / 20);
break;
case AST_FORMAT_SLINEAR:
samples = f->datalen / 2;
break;
case AST_FORMAT_LPC10:
samples = 22 * 8;
samples += (((char *)(f->data))[7] & 0x1) * 8;
break;
case AST_FORMAT_ULAW:
samples = f->datalen;
break;
case AST_FORMAT_ALAW:
samples = f->datalen;
break;
case AST_FORMAT_ADPCM:
case AST_FORMAT_G726:
samples = f->datalen *2;
break;
default:
ast_log(LOG_WARNING, "Don't know how to calculate samples on %d packets\n", f->subclass);
}
return samples;
}
static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
struct iax_frame *new = iax_frame_new(DIRECTION_INGRESS, fr->af.datalen);
memcpy(new, fr, sizeof(struct iax_frame));
iax_frame_wrap(new, &fr->af);
new->data = NULL;
new->datalen = 0;
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
new->direction = DIRECTION_INGRESS;
new->retrans = -1;
}
return new;
}
#define NEW_PREVENT 0
#define NEW_ALLOW 1
#define NEW_FORCE 2
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur)
{
if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
(cur->addr.sin_port == sin->sin_port)) {
/* This is the main host */
if ((cur->peercallno == callno) ||
((dcallno == cur->callno) && !cur->peercallno)) {
/* That's us. Be sure we keep track of the peer call number */
return 1;
}
}
if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
/* We're transferring */
if (dcallno == cur->callno)
return 1;
}
return 0;
}
static void update_max_trunk(void)
{
int max = TRUNK_CALL_START;
int x;
/* XXX Prolly don't need locks here XXX */
for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
if (iaxs[x])
max = x + 1;
}
maxtrunkcall = max;
if (option_debug)
ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
}
static void update_max_nontrunk(void)
{
int max = 1;
int x;
/* XXX Prolly don't need locks here XXX */
for (x=1;x<TRUNK_CALL_START - 1; x++) {
if (iaxs[x])
max = x + 1;
}
maxnontrunkcall = max;
if (option_debug)
ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);
}
static int make_trunk(unsigned short callno, int locked)
{
int x;
int res= 0;
struct timeval now;
if (iaxs[callno]->oseqno) {
ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");
return -1;
}
if (callno & TRUNK_CALL_START) {
ast_log(LOG_WARNING, "Call %d is already a trunk\n", callno);
return -1;
}
gettimeofday(&now, NULL);
for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
ast_mutex_lock(&iaxsl[x]);
if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
iaxs[x] = iaxs[callno];
iaxs[x]->callno = x;
iaxs[callno] = NULL;
/* Update the two timers that should have been started */
if (iaxs[x]->pingid > -1)
ast_sched_del(sched, iaxs[x]->pingid);
if (iaxs[x]->lagid > -1)
ast_sched_del(sched, iaxs[x]->lagid);
iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
ast_mutex_unlock(&iaxsl[callno]);
ast_mutex_unlock(&iaxsl[x]);
ast_mutex_unlock(&iaxsl[x]);
ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
return -1;
}
ast_log(LOG_DEBUG, "Made call %d into trunk call %d\n", callno, x);
/* We move this call from a non-trunked to a trunked call */
update_max_trunk();
update_max_nontrunk();
return res;
}
static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd)
char iabuf[INET_ADDRSTRLEN];
char host[80];
if (new <= NEW_ALLOW) {
/* Look for an existing connection first */
for (x=1;(res < 1) && (x<maxnontrunkcall);x++) {
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x]) {
/* Look for an exact match */
if (match(sin, callno, dcallno, iaxs[x])) {
res = x;
}
}
ast_mutex_unlock(&iaxsl[x]);
}
for (x=TRUNK_CALL_START;(res < 1) && (x<maxtrunkcall);x++) {
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x]) {
/* Look for an exact match */
if (match(sin, callno, dcallno, iaxs[x])) {
res = x;
}
}
ast_mutex_unlock(&iaxsl[x]);
if ((res < 1) && (new >= NEW_ALLOW)) {
if (!iax2_getpeername(*sin, host, sizeof(host), lockpeer))
snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
gettimeofday(&now, NULL);
for (x=1;x<TRUNK_CALL_START;x++) {
/* Find first unused call number that hasn't been used in a while */
ast_mutex_lock(&iaxsl[x]);
if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) break;
ast_mutex_unlock(&iaxsl[x]);
}
/* We've still got lock held if we found a spot */
if (x >= TRUNK_CALL_START) {
ast_log(LOG_WARNING, "No more space\n");
return -1;
iaxs[x] = new_iax(sin, lockpeer, host);
if (iaxs[x]) {
if (option_debug)
ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);
iaxs[x]->sockfd = sockfd;
iaxs[x]->addr.sin_port = sin->sin_port;
iaxs[x]->addr.sin_family = sin->sin_family;
iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
iaxs[x]->peercallno = callno;
iaxs[x]->callno = x;
iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
iaxs[x]->expirey = expirey;
iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_USEJITTERBUF);
strncpy(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)-1);
} else {
ast_log(LOG_WARNING, "Out of resources\n");
res = x;
}
return res;
}
static void iax2_frame_free(struct iax_frame *fr)
{
if (fr->retrans > -1)
ast_sched_del(sched, fr->retrans);
iax_frame_free(fr);
}
static int iax2_queue_frame(int callno, struct ast_frame *f)
{
/* Assumes lock for callno is already held... */
for (;;) {
if (iaxs[callno] && iaxs[callno]->owner) {
if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {
/* Avoid deadlock by pausing and trying again */
ast_mutex_unlock(&iaxsl[callno]);
ast_mutex_lock(&iaxsl[callno]);
Mark Spencer
committed
ast_queue_frame(iaxs[callno]->owner, f);
ast_mutex_unlock(&iaxs[callno]->owner->lock);
break;
}
} else
break;
}
return 0;
}
static void destroy_firmware(struct iax_firmware *cur)
{
/* Close firmware */
if (cur->fwh) {
munmap(cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
}
close(cur->fd);
free(cur);
}
static int try_firmware(char *s)
{
struct stat stbuf;
struct iax_firmware *cur;