mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
Version 0.1.8 from FTP
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
88
callerid.c
88
callerid.c
@@ -24,6 +24,8 @@
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/fskmodem.h>
|
||||
#include "sas.h"
|
||||
#include "cas.h"
|
||||
|
||||
|
||||
struct callerid_state {
|
||||
@@ -96,6 +98,33 @@ void callerid_get(struct callerid_state *cid, char **name, char **number, int *f
|
||||
*number = cid->number;
|
||||
}
|
||||
|
||||
int ast_callerid_gen_cas(unsigned char *outbuf, int len)
|
||||
{
|
||||
int pos = 0;
|
||||
int cnt;
|
||||
int saslen=2400;
|
||||
if (len < saslen)
|
||||
return -1;
|
||||
while(saslen) {
|
||||
cnt = saslen;
|
||||
if (cnt > sizeof(sas))
|
||||
cnt = sizeof(sas);
|
||||
memcpy(outbuf + pos, sas, cnt);
|
||||
pos += cnt;
|
||||
len -= cnt;
|
||||
saslen -= cnt;
|
||||
}
|
||||
while(len) {
|
||||
cnt = len;
|
||||
if (cnt > sizeof(cas))
|
||||
cnt = sizeof(cas);
|
||||
memcpy(outbuf + pos, cas, cnt);
|
||||
pos += cnt;
|
||||
len -= cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
|
||||
{
|
||||
int mylen = len;
|
||||
@@ -363,7 +392,7 @@ static inline float callerid_getcarrier(float *cr, float *ci, int bit)
|
||||
PUT_CLID_BAUD(1); /* Stop bit */ \
|
||||
} while(0);
|
||||
|
||||
int callerid_generate(unsigned char *buf, char *number, char *name, int flags)
|
||||
int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting)
|
||||
{
|
||||
int bytes=0;
|
||||
int x, sum;
|
||||
@@ -373,11 +402,14 @@ int callerid_generate(unsigned char *buf, char *number, char *name, int flags)
|
||||
float scont = 0.0;
|
||||
char msg[256];
|
||||
callerid_genmsg(msg, sizeof(msg), number, name, flags);
|
||||
for (x=0;x<4000;x++)
|
||||
PUT_BYTE(0x7f);
|
||||
/* Transmit 30 0x55's (looks like a square wave */
|
||||
for (x=0;x<30;x++)
|
||||
PUT_CLID(0x55);
|
||||
if (!callwaiting) {
|
||||
/* Wait a half a second */
|
||||
for (x=0;x<4000;x++)
|
||||
PUT_BYTE(0x7f);
|
||||
/* Transmit 30 0x55's (looks like a square wave) for channel seizure */
|
||||
for (x=0;x<30;x++)
|
||||
PUT_CLID(0x55);
|
||||
}
|
||||
/* Send 150ms of callerid marks */
|
||||
for (x=0;x<150;x++)
|
||||
PUT_CLID_MARKMS;
|
||||
@@ -412,6 +444,8 @@ void ast_shrink_phone_number(char *n)
|
||||
int ast_isphonenumber(char *n)
|
||||
{
|
||||
int x;
|
||||
if (!n)
|
||||
return 0;
|
||||
for (x=0;n[x];x++)
|
||||
if (!strchr("0123456789", n[x]))
|
||||
return 0;
|
||||
@@ -422,6 +456,7 @@ int ast_callerid_parse(char *instr, char **name, char **location)
|
||||
{
|
||||
char *ns, *ne;
|
||||
char *ls, *le;
|
||||
char tmp[256];
|
||||
/* Try for "name" <location> format or
|
||||
name <location> format */
|
||||
if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
|
||||
@@ -446,29 +481,46 @@ int ast_callerid_parse(char *instr, char **name, char **location)
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Assume it's just a location */
|
||||
*name = NULL;
|
||||
*location = instr;
|
||||
strncpy(tmp, instr, sizeof(tmp));
|
||||
ast_shrink_phone_number(tmp);
|
||||
if (!ast_isphonenumber(tmp)) {
|
||||
/* Assume it's just a location */
|
||||
*name = NULL;
|
||||
*location = instr;
|
||||
} else {
|
||||
/* Assume it's just a name */
|
||||
*name = instr;
|
||||
*location = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ast_callerid_generate(unsigned char *buf, char *callerid)
|
||||
static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting)
|
||||
{
|
||||
char tmp[256];
|
||||
char *n, *l;
|
||||
if (!callerid)
|
||||
return callerid_generate(buf, NULL, NULL, 0);
|
||||
return callerid_generate(buf, NULL, NULL, 0, callwaiting);
|
||||
strncpy(tmp, callerid, sizeof(tmp));
|
||||
if (ast_callerid_parse(tmp, &n, &l)) {
|
||||
ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
|
||||
return callerid_generate(buf, NULL, NULL, 0);
|
||||
return callerid_generate(buf, NULL, NULL, 0, callwaiting);
|
||||
}
|
||||
ast_shrink_phone_number(l);
|
||||
if (!n && (!ast_isphonenumber(l)))
|
||||
return callerid_generate(buf, NULL, NULL, 0);
|
||||
if (!ast_isphonenumber(l))
|
||||
return callerid_generate(buf, NULL, n, 0);
|
||||
return callerid_generate(buf, l, n, 0);
|
||||
if (l)
|
||||
ast_shrink_phone_number(l);
|
||||
if (!ast_isphonenumber(l))
|
||||
return callerid_generate(buf, NULL, n, 0, callwaiting);
|
||||
return callerid_generate(buf, l, n, 0, callwaiting);
|
||||
}
|
||||
|
||||
int ast_callerid_generate(unsigned char *buf, char *callerid)
|
||||
{
|
||||
return __ast_callerid_generate(buf, callerid, 0);
|
||||
}
|
||||
|
||||
int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid)
|
||||
{
|
||||
return __ast_callerid_generate(buf, callerid, 1);
|
||||
}
|
||||
|
457
channel.c
457
channel.c
@@ -28,6 +28,7 @@
|
||||
#include <asterisk/translate.h>
|
||||
|
||||
|
||||
/* XXX Lock appropriately in more functions XXX */
|
||||
|
||||
#ifdef DEBUG_MUTEX
|
||||
/* Convenient mutex debugging functions */
|
||||
@@ -36,16 +37,16 @@
|
||||
|
||||
static int __PTHREAD_MUTEX_LOCK(char *f, pthread_mutex_t *a) {
|
||||
ast_log(LOG_DEBUG, "Locking %p (%s)\n", a, f);
|
||||
return pthread_mutex_lock(a);
|
||||
return ast_pthread_mutex_lock(a);
|
||||
}
|
||||
|
||||
static int __PTHREAD_MUTEX_UNLOCK(char *f, pthread_mutex_t *a) {
|
||||
ast_log(LOG_DEBUG, "Unlocking %p (%s)\n", a, f);
|
||||
return pthread_mutex_unlock(a);
|
||||
return ast_pthread_mutex_unlock(a);
|
||||
}
|
||||
#else
|
||||
#define PTHREAD_MUTEX_LOCK(a) pthread_mutex_lock(a)
|
||||
#define PTHREAD_MUTEX_UNLOCK(a) pthread_mutex_unlock(a)
|
||||
#define PTHREAD_MUTEX_LOCK(a) ast_pthread_mutex_lock(a)
|
||||
#define PTHREAD_MUTEX_UNLOCK(a) ast_pthread_mutex_unlock(a)
|
||||
#endif
|
||||
|
||||
struct chanlist {
|
||||
@@ -103,10 +104,35 @@ int ast_channel_register(char *type, char *description, int capabilities,
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *ast_state2str(int state)
|
||||
{
|
||||
switch(state) {
|
||||
case AST_STATE_DOWN:
|
||||
return "Down";
|
||||
case AST_STATE_RESERVED:
|
||||
return "Rsrvd";
|
||||
case AST_STATE_OFFHOOK:
|
||||
return "OffHook";
|
||||
case AST_STATE_DIALING:
|
||||
return "Dialing";
|
||||
case AST_STATE_RING:
|
||||
return "Ring";
|
||||
case AST_STATE_RINGING:
|
||||
return "Ringing";
|
||||
case AST_STATE_UP:
|
||||
return "Up";
|
||||
case AST_STATE_BUSY:
|
||||
return "Busy";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct ast_channel *ast_channel_alloc(void)
|
||||
{
|
||||
struct ast_channel *tmp;
|
||||
struct ast_channel_pvt *pvt;
|
||||
int x;
|
||||
PTHREAD_MUTEX_LOCK(&chlock);
|
||||
tmp = malloc(sizeof(struct ast_channel));
|
||||
memset(tmp, 0, sizeof(struct ast_channel));
|
||||
@@ -116,7 +142,8 @@ struct ast_channel *ast_channel_alloc(void)
|
||||
memset(pvt, 0, sizeof(struct ast_channel_pvt));
|
||||
tmp->sched = sched_context_create();
|
||||
if (tmp->sched) {
|
||||
tmp->fd = -1;
|
||||
for (x=0;x<AST_MAX_FDS;x++)
|
||||
tmp->fds[x] = -1;
|
||||
strncpy(tmp->name, "**Unknown**", sizeof(tmp->name));
|
||||
tmp->pvt = pvt;
|
||||
tmp->state = AST_STATE_DOWN;
|
||||
@@ -206,16 +233,10 @@ void ast_channel_free(struct ast_channel *chan)
|
||||
int ast_softhangup(struct ast_channel *chan)
|
||||
{
|
||||
int res = 0;
|
||||
if (chan->stream)
|
||||
ast_stopstream(chan);
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
|
||||
if (chan->pvt->hangup)
|
||||
res = chan->pvt->hangup(chan);
|
||||
if (chan->pvt->pvt)
|
||||
ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
|
||||
if (chan->pbx)
|
||||
ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
|
||||
/* Inform channel driver that we need to be hung up, if it cares */
|
||||
chan->softhangup = 1;
|
||||
/* Interrupt any select call or such */
|
||||
if (chan->blocking)
|
||||
pthread_kill(chan->blocker, SIGURG);
|
||||
@@ -225,6 +246,16 @@ int ast_softhangup(struct ast_channel *chan)
|
||||
int ast_hangup(struct ast_channel *chan)
|
||||
{
|
||||
int res = 0;
|
||||
/* Don't actually hang up a channel that will masquerade as someone else, or
|
||||
if someone is going to masquerade as us */
|
||||
if (chan->masq)
|
||||
return 0;
|
||||
/* If this channel is one which will be masqueraded into something,
|
||||
mark it as a zombie already, so we know to free it later */
|
||||
if (chan->masqr) {
|
||||
chan->zombie=1;
|
||||
return 0;
|
||||
}
|
||||
if (chan->stream)
|
||||
ast_stopstream(chan);
|
||||
if (chan->sched)
|
||||
@@ -235,10 +266,15 @@ int ast_hangup(struct ast_channel *chan)
|
||||
pthread_self(), chan->name, chan->blocker, chan->blockproc);
|
||||
CRASH;
|
||||
}
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
|
||||
if (chan->pvt->hangup)
|
||||
res = chan->pvt->hangup(chan);
|
||||
if (!chan->zombie) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
|
||||
if (chan->pvt->hangup)
|
||||
res = chan->pvt->hangup(chan);
|
||||
} else
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Hanging up zombie '%s'\n", chan->name);
|
||||
|
||||
ast_channel_free(chan);
|
||||
return res;
|
||||
}
|
||||
@@ -271,10 +307,18 @@ void ast_channel_unregister(char *type)
|
||||
|
||||
int ast_answer(struct ast_channel *chan)
|
||||
{
|
||||
/* Answer the line, if possible */
|
||||
if (chan->state == AST_STATE_RING) {
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (chan->zombie || chan->softhangup)
|
||||
return -1;
|
||||
switch(chan->state) {
|
||||
case AST_STATE_RING:
|
||||
case AST_STATE_RINGING:
|
||||
if (chan->pvt->answer)
|
||||
return chan->pvt->answer(chan);
|
||||
chan->state = AST_STATE_UP;
|
||||
break;
|
||||
case AST_STATE_UP:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -293,84 +337,125 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&efds);
|
||||
for (x=0;x<n;x++) {
|
||||
FD_SET(fds[x], &rfds);
|
||||
FD_SET(fds[x], &efds);
|
||||
if (fds[x] > max)
|
||||
max = fds[x];
|
||||
if (fds[x] > -1) {
|
||||
FD_SET(fds[x], &rfds);
|
||||
FD_SET(fds[x], &efds);
|
||||
if (fds[x] > max)
|
||||
max = fds[x];
|
||||
}
|
||||
}
|
||||
if (*ms >= 0)
|
||||
res = select(max + 1, &rfds, NULL, &efds, &tv);
|
||||
else
|
||||
res = select(max + 1, &rfds, NULL, &efds, NULL);
|
||||
|
||||
if (res < 0) {
|
||||
/* Simulate a timeout if we were interrupted */
|
||||
if (errno != EINTR)
|
||||
*ms = -1;
|
||||
else
|
||||
*ms = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (x=0;x<n;x++) {
|
||||
if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
|
||||
if ((fds[x] > -1) && (FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
|
||||
if (exception)
|
||||
*exception = FD_ISSET(fds[x], &efds);
|
||||
winner = fds[x];
|
||||
}
|
||||
}
|
||||
*ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
if (res < 0)
|
||||
*ms = -10;
|
||||
return winner;
|
||||
}
|
||||
|
||||
static int ast_do_masquerade(struct ast_channel *original);
|
||||
|
||||
struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
|
||||
{
|
||||
/* Wait for x amount of time on a file descriptor to have input. */
|
||||
struct timeval tv;
|
||||
fd_set rfds, efds;
|
||||
int res;
|
||||
int x, max=-1;
|
||||
int x, y, max=-1;
|
||||
struct ast_channel *winner = NULL;
|
||||
|
||||
/* Perform any pending masquerades */
|
||||
for (x=0;x<n;x++) {
|
||||
if (c[x]->masq) {
|
||||
if (ast_do_masquerade(c[x])) {
|
||||
ast_log(LOG_WARNING, "Masquerade failed\n");
|
||||
*ms = -1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tv.tv_sec = *ms / 1000;
|
||||
tv.tv_usec = (*ms % 1000) * 1000;
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&efds);
|
||||
for (x=0;x<n;x++) {
|
||||
FD_SET(c[x]->fd, &rfds);
|
||||
FD_SET(c[x]->fd, &efds);
|
||||
for (y=0;y<AST_MAX_FDS;y++) {
|
||||
if (c[x]->fds[y] > 0) {
|
||||
FD_SET(c[x]->fds[y], &rfds);
|
||||
FD_SET(c[x]->fds[y], &efds);
|
||||
if (c[x]->fds[y] > max)
|
||||
max = c[x]->fds[y];
|
||||
}
|
||||
}
|
||||
CHECK_BLOCKING(c[x]);
|
||||
if (c[x]->fd > max)
|
||||
max = c[x]->fd;
|
||||
}
|
||||
if (*ms >= 0)
|
||||
res = select(max + 1, &rfds, NULL, &efds, &tv);
|
||||
else
|
||||
res = select(max + 1, &rfds, NULL, &efds, NULL);
|
||||
|
||||
if (res < 0) {
|
||||
for (x=0;x<n;x++)
|
||||
c[x]->blocking = 0;
|
||||
/* Simulate a timeout if we were interrupted */
|
||||
if (errno != EINTR)
|
||||
*ms = -1;
|
||||
else
|
||||
*ms = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (x=0;x<n;x++) {
|
||||
c[x]->blocking = 0;
|
||||
if ((FD_ISSET(c[x]->fd, &rfds) || FD_ISSET(c[x]->fd, &efds)) && !winner) {
|
||||
/* Set exception flag if appropriate */
|
||||
if (FD_ISSET(c[x]->fd, &efds))
|
||||
c[x]->exception = 1;
|
||||
winner = c[x];
|
||||
for (y=0;y<AST_MAX_FDS;y++) {
|
||||
if (c[x]->fds[y] > -1) {
|
||||
if ((FD_ISSET(c[x]->fds[y], &rfds) || FD_ISSET(c[x]->fds[y], &efds)) && !winner) {
|
||||
/* Set exception flag if appropriate */
|
||||
if (FD_ISSET(c[x]->fds[y], &efds))
|
||||
c[x]->exception = 1;
|
||||
c[x]->fdno = y;
|
||||
winner = c[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
if (res < 0)
|
||||
*ms = -10;
|
||||
return winner;
|
||||
}
|
||||
|
||||
int ast_waitfor(struct ast_channel *c, int ms)
|
||||
{
|
||||
if (ast_waitfor_n(&c, 1, &ms)) {
|
||||
if (ms < 0)
|
||||
return -ms;
|
||||
return ms;
|
||||
}
|
||||
/* Error if ms < 0 */
|
||||
if (ms < 0)
|
||||
struct ast_channel *chan;
|
||||
chan = ast_waitfor_n(&c, 1, &ms);
|
||||
if (ms < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
return ms;
|
||||
}
|
||||
|
||||
char ast_waitfordigit(struct ast_channel *c, int ms)
|
||||
{
|
||||
struct ast_frame *f;
|
||||
char result = 0;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (c->zombie || c->softhangup)
|
||||
return -1;
|
||||
/* Wait for a digit, no more than ms milliseconds total. */
|
||||
while(ms && !result) {
|
||||
ms = ast_waitfor(c, ms);
|
||||
@@ -397,6 +482,24 @@ struct ast_frame *ast_read(struct ast_channel *chan)
|
||||
{
|
||||
AST_FRAME_NULL,
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&chan->lock);
|
||||
if (chan->masq) {
|
||||
if (ast_do_masquerade(chan)) {
|
||||
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
|
||||
f = NULL;
|
||||
} else
|
||||
f = &null_frame;
|
||||
pthread_mutex_unlock(&chan->lock);
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (chan->zombie || chan->softhangup) {
|
||||
pthread_mutex_unlock(&chan->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chan->blocker = pthread_self();
|
||||
if (chan->exception) {
|
||||
if (chan->pvt->exception)
|
||||
@@ -417,12 +520,35 @@ struct ast_frame *ast_read(struct ast_channel *chan)
|
||||
f = &null_frame;
|
||||
}
|
||||
}
|
||||
/* Make sure we always return NULL in the future */
|
||||
if (!f)
|
||||
chan->softhangup = 1;
|
||||
pthread_mutex_unlock(&chan->lock);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int ast_indicate(struct ast_channel *chan, int condition)
|
||||
{
|
||||
int res = -1;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (chan->zombie || chan->softhangup)
|
||||
return -1;
|
||||
if (chan->pvt->indicate) {
|
||||
res = chan->pvt->indicate(chan, condition);
|
||||
if (res)
|
||||
ast_log(LOG_WARNING, "Driver for channel '%s' failed to indicate condition %d\n", chan->name, condition);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Driver for channel '%s' does not support indication\n", chan->name);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_sendtext(struct ast_channel *chan, char *text)
|
||||
{
|
||||
int res = 0;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (chan->zombie || chan->softhangup)
|
||||
return -1;
|
||||
CHECK_BLOCKING(chan);
|
||||
if (chan->pvt->send_text)
|
||||
res = chan->pvt->send_text(chan, text);
|
||||
@@ -434,6 +560,18 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
||||
{
|
||||
int res = -1;
|
||||
struct ast_frame *f;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (chan->zombie || chan->softhangup)
|
||||
return -1;
|
||||
/* Handle any pending masquerades */
|
||||
if (chan->masq) {
|
||||
if (ast_do_masquerade(chan)) {
|
||||
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (chan->masqr)
|
||||
return 0;
|
||||
CHECK_BLOCKING(chan);
|
||||
switch(fr->frametype) {
|
||||
case AST_FRAME_CONTROL:
|
||||
@@ -453,6 +591,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
||||
f = fr;
|
||||
if (f)
|
||||
res = chan->pvt->write(chan, f);
|
||||
else
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
chan->blocking = 0;
|
||||
@@ -483,7 +623,8 @@ int ast_set_write_format(struct ast_channel *chan, int fmts)
|
||||
ast_translator_free_path(chan->pvt->writetrans);
|
||||
/* Build a translation path from the user write format to the raw writing format */
|
||||
chan->pvt->writetrans = ast_translator_build_path(chan->pvt->rawwriteformat, chan->writeformat);
|
||||
ast_log(LOG_DEBUG, "Set channel %s to format %d\n", chan->name, chan->writeformat);
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Set channel %s to format %d\n", chan->name, chan->writeformat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -555,8 +696,12 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
|
||||
If the remote end does not answer within the timeout, then do NOT hang up, but
|
||||
return anyway. */
|
||||
int res = -1;
|
||||
if (chan->pvt->call)
|
||||
res = chan->pvt->call(chan, addr, timeout);
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
pthread_mutex_lock(&chan->lock);
|
||||
if (!chan->zombie && !chan->softhangup)
|
||||
if (chan->pvt->call)
|
||||
res = chan->pvt->call(chan, addr, timeout);
|
||||
pthread_mutex_unlock(&chan->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -565,6 +710,9 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
|
||||
int pos=0;
|
||||
int to = ftimeout;
|
||||
char d;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (c->zombie || c->softhangup)
|
||||
return -1;
|
||||
if (!len)
|
||||
return -1;
|
||||
do {
|
||||
@@ -638,7 +786,134 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
|
||||
{
|
||||
ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
|
||||
clone->name, original->name);
|
||||
if (original->masq) {
|
||||
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
|
||||
original->masq->name, original->name);
|
||||
return -1;
|
||||
}
|
||||
if (clone->masqr) {
|
||||
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
|
||||
clone->name, clone->masqr->name);
|
||||
return -1;
|
||||
}
|
||||
original->masq = clone;
|
||||
clone->masqr = original;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ast_do_masquerade(struct ast_channel *original)
|
||||
{
|
||||
int x;
|
||||
int res=0;
|
||||
char *tmp;
|
||||
struct ast_channel_pvt *p;
|
||||
struct ast_channel *clone = original->masq;
|
||||
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
|
||||
clone->name, clone->state, original->name, original->state);
|
||||
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
|
||||
the clone channel into the original channel. Start by killing off the original
|
||||
channel's backend. I'm not sure we're going to keep this function, because
|
||||
while the features are nice, the cost is very high in terms of pure nastiness. XXX */
|
||||
|
||||
/* We need the clone's lock, too */
|
||||
pthread_mutex_lock(&clone->lock);
|
||||
|
||||
/* Unlink the masquerade */
|
||||
original->masq = NULL;
|
||||
clone->masqr = NULL;
|
||||
|
||||
/* Copy the name from the clone channel */
|
||||
strncpy(original->name, clone->name, sizeof(original->name));
|
||||
|
||||
/* Mangle the name of the clone channel */
|
||||
strncat(clone->name, "<MASQ>", sizeof(clone->name));
|
||||
|
||||
/* Swap the guts */
|
||||
p = original->pvt;
|
||||
original->pvt = clone->pvt;
|
||||
clone->pvt = p;
|
||||
|
||||
/* Start by disconnecting the original's physical side */
|
||||
if (clone->pvt->hangup)
|
||||
res = clone->pvt->hangup(clone);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n");
|
||||
pthread_mutex_unlock(&clone->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Mangle the name of the clone channel */
|
||||
snprintf(clone->name, sizeof(clone->name), "%s<ZOMBIE>", original->name);
|
||||
|
||||
/* Keep the same language. */
|
||||
/* Update the type. */
|
||||
original->type = clone->type;
|
||||
/* Copy the FD's */
|
||||
for (x=0;x<AST_MAX_FDS;x++)
|
||||
original->fds[x] = clone->fds[x];
|
||||
/* Bridge remains the same */
|
||||
/* CDR fields remain the same */
|
||||
/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
|
||||
/* Application and data remain the same */
|
||||
/* Clone exception becomes real one, as with fdno */
|
||||
original->exception = clone->exception;
|
||||
original->fdno = clone->fdno;
|
||||
/* Schedule context remains the same */
|
||||
/* Stream stuff stays the same */
|
||||
/* Keep the original state. The fixup code will need to work with it most likely */
|
||||
|
||||
/* dnid and callerid change to become the new, HOWEVER, we also link the original's
|
||||
fields back into the defunct 'clone' so that they will be freed when
|
||||
ast_frfree is eventually called */
|
||||
tmp = original->dnid;
|
||||
original->dnid = clone->dnid;
|
||||
clone->dnid = tmp;
|
||||
|
||||
tmp = original->callerid;
|
||||
original->callerid = clone->callerid;
|
||||
clone->callerid = tmp;
|
||||
|
||||
/* Context, extension, priority, app data, jump table, remain the same */
|
||||
/* pvt switches. pbx stays the same, as does next */
|
||||
|
||||
/* Now, at this point, the "clone" channel is totally F'd up. We mark it as
|
||||
a zombie so nothing tries to touch it. If it's already been marked as a
|
||||
zombie, then free it now (since it already is considered invalid). */
|
||||
if (clone->zombie) {
|
||||
pthread_mutex_unlock(&clone->lock);
|
||||
ast_channel_free(clone);
|
||||
} else {
|
||||
clone->zombie=1;
|
||||
pthread_mutex_unlock(&clone->lock);
|
||||
}
|
||||
/* Set the write format */
|
||||
ast_set_write_format(original, original->writeformat);
|
||||
|
||||
/* Set the read format */
|
||||
ast_set_read_format(original, original->readformat);
|
||||
|
||||
/* Okay. Last thing is to let the channel driver know about all this mess, so he
|
||||
can fix up everything as best as possible */
|
||||
if (original->pvt->fixup) {
|
||||
res = original->pvt->fixup(clone, original);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n",
|
||||
original->type, original->name);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)! Bad things may happen.\n",
|
||||
original->type, original->name);
|
||||
|
||||
/* Signal any blocker */
|
||||
if (original->blocking)
|
||||
pthread_kill(original->blocker, SIGURG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
|
||||
{
|
||||
@@ -648,11 +923,33 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
int to = -1;
|
||||
struct ast_frame *f;
|
||||
struct ast_channel *who;
|
||||
int res;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
if (c0->zombie || c0->softhangup || c1->zombie || c1->softhangup)
|
||||
return -1;
|
||||
if (c0->bridge) {
|
||||
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
|
||||
c0->name, c0->bridge->name);
|
||||
return -1;
|
||||
}
|
||||
if (c1->bridge) {
|
||||
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
|
||||
c1->name, c1->bridge->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Keep track of bridge */
|
||||
c0->bridge = c1;
|
||||
c1->bridge = c0;
|
||||
|
||||
if (c0->pvt->bridge &&
|
||||
(c0->pvt->bridge == c1->pvt->bridge)) {
|
||||
/* Looks like they share a bridge code */
|
||||
if (!c0->pvt->bridge(c0, c1, flags, fo, rc))
|
||||
if (!c0->pvt->bridge(c0, c1, flags, fo, rc)) {
|
||||
c0->bridge = NULL;
|
||||
c1->bridge = NULL;
|
||||
return 0;
|
||||
}
|
||||
ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
|
||||
/* If they return non-zero then continue on normally */
|
||||
}
|
||||
@@ -664,36 +961,47 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
for (/* ever */;;) {
|
||||
who = ast_waitfor_n(cs, 2, &to);
|
||||
if (!who) {
|
||||
ast_log(LOG_WARNING, "Nobody there??\n");
|
||||
ast_log(LOG_WARNING, "Nobody there??\n");
|
||||
continue;
|
||||
}
|
||||
f = ast_read(who);
|
||||
if (!f) {
|
||||
*fo = NULL;
|
||||
*rc = who;
|
||||
return 0;
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
|
||||
*fo = f;
|
||||
*rc = who;
|
||||
return 0;
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_VOICE) ||
|
||||
(f->frametype == AST_FRAME_TEXT) ||
|
||||
(f->frametype == AST_FRAME_VIDEO) ||
|
||||
(f->frametype == AST_FRAME_IMAGE) ||
|
||||
(f->frametype == AST_FRAME_DTMF)) {
|
||||
if ((f->frametype == AST_FRAME_DTMF) && (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
|
||||
if ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
|
||||
*rc = c0;
|
||||
*fo = f;
|
||||
/* Take out of conference mode */
|
||||
return 0;
|
||||
if ((f->frametype == AST_FRAME_DTMF) &&
|
||||
(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
|
||||
if ((who == c0)) {
|
||||
if ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
|
||||
*rc = c0;
|
||||
*fo = f;
|
||||
/* Take out of conference mode */
|
||||
res = 0;
|
||||
break;
|
||||
} else
|
||||
goto tackygoto;
|
||||
} else
|
||||
if ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
|
||||
*rc = c1;
|
||||
*fo = f;
|
||||
return 0;
|
||||
if ((who == c1)) {
|
||||
if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
|
||||
*rc = c1;
|
||||
*fo = f;
|
||||
res = 0;
|
||||
break;
|
||||
} else
|
||||
goto tackygoto;
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
@@ -702,6 +1010,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
|
||||
last = who;
|
||||
#endif
|
||||
tackygoto:
|
||||
if (who == c0)
|
||||
ast_write(c1, f);
|
||||
else
|
||||
@@ -715,5 +1024,27 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
cs[0] = cs[1];
|
||||
cs[1] = cs[2];
|
||||
}
|
||||
c0->bridge = NULL;
|
||||
c1->bridge = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block)
|
||||
{
|
||||
int res;
|
||||
if (chan->pvt->setoption) {
|
||||
res = chan->pvt->setoption(chan, option, data, datalen);
|
||||
if (res < 0)
|
||||
return res;
|
||||
} else {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
if (block) {
|
||||
/* XXX Implement blocking -- just wait for our option frame reply, discarding
|
||||
intermediate packets. XXX */
|
||||
ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -25,6 +25,60 @@ extern "C" {
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
#define TRIES 500
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct mutex_info {
|
||||
pthread_mutex_t *mutex;
|
||||
char *file;
|
||||
int lineno;
|
||||
char *func;
|
||||
struct mutex_info *next;
|
||||
};
|
||||
|
||||
static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, pthread_mutex_t *t) {
|
||||
int res;
|
||||
int tries = TRIES;
|
||||
do {
|
||||
res = pthread_mutex_trylock(t);
|
||||
/* If we can't run, yield */
|
||||
if (res) {
|
||||
sched_yield();
|
||||
usleep(1);
|
||||
}
|
||||
} while(res && tries--);
|
||||
if (res) {
|
||||
fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
|
||||
filename, lineno, func, strerror(res));
|
||||
res = pthread_mutex_lock(t);
|
||||
fprintf(stderr, "%s line %d (%s): Got it eventually...\n",
|
||||
filename, lineno, func);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define ast_pthread_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
|
||||
|
||||
static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, pthread_mutex_t *t) {
|
||||
int res;
|
||||
res = pthread_mutex_unlock(t);
|
||||
if (res)
|
||||
fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n",
|
||||
filename, lineno, func, strerror(res));
|
||||
return res;
|
||||
}
|
||||
#define ast_pthread_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
|
||||
#else
|
||||
#define ast_pthread_mutex_lock pthread_mutex_lock
|
||||
#define ast_pthread_mutex_unlock pthread_mutex_unlock
|
||||
#endif
|
||||
|
||||
#define AST_CHANNEL_NAME 80
|
||||
#define AST_CHANNEL_MAX_STACK 32
|
||||
|
||||
@@ -33,14 +87,24 @@ extern "C" {
|
||||
/* Max length an extension can be (unique) is this number */
|
||||
#define AST_MAX_EXTENSION 80
|
||||
|
||||
#define AST_MAX_FDS 4
|
||||
|
||||
struct ast_channel {
|
||||
char name[AST_CHANNEL_NAME]; /* ASCII Description of channel name */
|
||||
char language[MAX_LANGUAGE]; /* Language requested */
|
||||
char *type; /* Type of channel */
|
||||
int fd; /* File descriptor for channel -- all must have
|
||||
a file descriptor! */
|
||||
int fds[AST_MAX_FDS]; /* File descriptor for channel -- Drivers will poll
|
||||
on these file descriptors, so at least one must be
|
||||
non -1. */
|
||||
|
||||
struct ast_channel *bridge; /* Who are we bridged to, if we're bridged */
|
||||
struct ast_channel *masq; /* Channel that will masquerade as us */
|
||||
struct ast_channel *masqr; /* Who we are masquerading as */
|
||||
int cdrflags; /* Call Detail Record Flags */
|
||||
|
||||
int blocking; /* Whether or not we're blocking */
|
||||
int softhangup; /* Whether or not we have been hung up */
|
||||
int zombie; /* Non-zero if this is a zombie channel */
|
||||
pthread_t blocker; /* If anyone is blocking, this is them */
|
||||
pthread_mutex_t lock; /* Lock, can be used to lock a channel for some operations */
|
||||
char *blockproc; /* Procedure causing blocking */
|
||||
@@ -49,6 +113,7 @@ struct ast_channel {
|
||||
char *data; /* Data passed to current application */
|
||||
|
||||
int exception; /* Has an exception been detected */
|
||||
int fdno; /* Which fd had an event detected on */
|
||||
struct sched_context *sched; /* Schedule context */
|
||||
|
||||
int streamid; /* For streaming playback, the schedule ID */
|
||||
@@ -79,6 +144,11 @@ struct ast_channel {
|
||||
};
|
||||
|
||||
|
||||
#define AST_CDR_TRANSFER (1 << 0)
|
||||
#define AST_CDR_FORWARD (1 << 1)
|
||||
#define AST_CDR_CALLWAIT (1 << 2)
|
||||
#define AST_CDR_CONFERENCE (1 << 3)
|
||||
|
||||
/* Bits 0-15 of state are reserved for the state (up/down) of the line */
|
||||
|
||||
#define AST_STATE_DOWN 0 /* Channel is down and available */
|
||||
@@ -123,6 +193,9 @@ int ast_answer(struct ast_channel *chan);
|
||||
the number of seconds the connect took otherwise. */
|
||||
int ast_call(struct ast_channel *chan, char *addr, int timeout);
|
||||
|
||||
/* Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel */
|
||||
int ast_indicate(struct ast_channel *chan, int condition);
|
||||
|
||||
/* Misc stuff */
|
||||
|
||||
/* Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
|
||||
@@ -180,6 +253,28 @@ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
|
||||
*rf (remember, it could be NULL) and which channel (0 or 1) in rc */
|
||||
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
|
||||
|
||||
/* This is a very strange and freaky function used primarily for transfer. Suppose that
|
||||
"original" and "clone" are two channels in random situations. This function takes
|
||||
the guts out of "clone" and puts them into the "original" channel, then alerts the
|
||||
channel driver of the change, asking it to fixup any private information (like the
|
||||
p->owner pointer) that is affected by the change. The physical layer of the original
|
||||
channel is hung up. */
|
||||
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
|
||||
|
||||
/* Give a name to a state */
|
||||
char *ast_state2str(int state);
|
||||
|
||||
/* Options: Some low-level drivers may implement "options" allowing fine tuning of the
|
||||
low level channel. See frame.h for options. Note that many channel drivers may support
|
||||
none or a subset of those features, and you should not count on this if you want your
|
||||
asterisk application to be portable. They're mainly useful for tweaking performance */
|
||||
|
||||
/* Set an option on a channel (see frame.h), optionally blocking awaiting the reply */
|
||||
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
|
||||
|
||||
/* Query the value of an option, optionally blocking until a reply is received */
|
||||
struct ast_frame *ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
|
||||
|
||||
#ifdef DO_CRASH
|
||||
#define CRASH do { *((int *)0) = 0; } while(0)
|
||||
#else
|
||||
|
@@ -23,7 +23,7 @@ extern "C" {
|
||||
|
||||
struct ast_channel_pvt {
|
||||
/* Private data used by channel backend */
|
||||
void *pvt;
|
||||
void *pvt;
|
||||
/* Write translation path */
|
||||
struct ast_trans_pvt *writetrans;
|
||||
/* Read translation path */
|
||||
@@ -51,6 +51,14 @@ struct ast_channel_pvt {
|
||||
struct ast_frame * (*exception)(struct ast_channel *chan);
|
||||
/* Bridge two channels of the same type together */
|
||||
int (*bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
|
||||
/* Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */
|
||||
int (*indicate)(struct ast_channel *c, int condition);
|
||||
/* Fix up a channel: If a channel is consumed, this is called. Basically update any ->owner links */
|
||||
int (*fixup)(struct ast_channel *oldchan, struct ast_channel *newchan);
|
||||
/* Set a given option */
|
||||
int (*setoption)(struct ast_channel *chan, int option, void *data, int datalen);
|
||||
/* Query a given option */
|
||||
int (*queryoption)(struct ast_channel *chan, int option, void *data, int *datalen);
|
||||
};
|
||||
|
||||
/* Create a channel structure */
|
||||
|
Reference in New Issue
Block a user