Skip to content
Snippets Groups Projects
Commit d5ccd47a authored by Mark Spencer's avatar Mark Spencer
Browse files

Version 0.3.0 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@564 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent 88d965b9
Branches
Tags
No related merge requests found
......@@ -52,11 +52,13 @@ static char *app = "AgentLogin";
static char *synopsis = "Call agent login";
static char *descrip =
" AgentLogin():\n"
" AgentLogin([AgentNo][|options]):\n"
"Asks the agent to login to the system. Always returns -1. While\n"
"logged in, the agent can receive calls and will hear a 'beep'\n"
"when a new call comes in. The agent can dump the call by pressing\n"
"the star key.\n";
"the star key.\n"
"The option string may contain zero or more of the following characters:\n"
" 's' -- silent login - do not announce the login ok segment\n";
static char moh[80] = "default";
......@@ -77,6 +79,9 @@ static struct agent_pvt {
char agent[AST_MAX_AGENT]; /* Agent ID */
char password[AST_MAX_AGENT]; /* Password for Agent login */
char name[AST_MAX_AGENT];
pthread_mutex_t app_lock; /* Synchronization between owning applications */
volatile pthread_t owning_app; /* Owning application thread id */
volatile int app_sleep_cond; /* Sleep condition for the login app */
struct ast_channel *owner; /* Agent */
struct ast_channel *chan; /* Channel we use */
struct agent_pvt *next; /* Agent */
......@@ -119,6 +124,10 @@ static int add_agent(struct ast_variable *var)
if (p) {
memset(p, 0, sizeof(struct agent_pvt));
strncpy(p->agent, tmp, sizeof(p->agent) -1);
ast_pthread_mutex_init( &p->lock );
ast_pthread_mutex_init( &p->app_lock );
p->owning_app = -1;
p->app_sleep_cond = 1;
p->next = agents;
agents = p;
......@@ -179,6 +188,7 @@ static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
ast_pthread_mutex_lock(&p->lock);
if (p->owner != oldchan) {
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
ast_pthread_mutex_unlock(&p->lock);
return -1;
}
p->owner = newchan;
......@@ -228,6 +238,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
}
/* Call is immediately up */
ast_setstate(ast, AST_STATE_UP);
CLEANUP(ast,p);
ast_pthread_mutex_unlock(&p->lock);
return res;
}
......@@ -238,21 +249,43 @@ static int agent_hangup(struct ast_channel *ast)
ast_pthread_mutex_lock(&p->lock);
p->owner = NULL;
ast->pvt->pvt = NULL;
p->app_sleep_cond = 1;
ast_pthread_mutex_unlock(&p->lock);
/* Release ownership of the agent to other threads (presumably running the login app). */
ast_pthread_mutex_unlock(&p->app_lock);
if (p->chan) {
/* If they're dead, go ahead and hang up on the agent now */
ast_pthread_mutex_lock(&p->chan->lock);
if (p->dead)
ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
ast_moh_start(p->chan, p->moh);
} else if (p->dead)
ast_pthread_mutex_unlock(&p->chan->lock);
} else if (p->dead)
/* Go ahead and lose it */
free(p);
return 0;
}
static int agent_cont_sleep( void *data )
{
struct agent_pvt *p;
int res;
p = (struct agent_pvt *)data;
ast_pthread_mutex_lock(&p->lock);
res = p->app_sleep_cond;
ast_pthread_mutex_unlock(&p->lock);
if( !res )
ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
return res;
}
static struct ast_channel *agent_new(struct agent_pvt *p, int state)
{
struct ast_channel *tmp;
struct ast_frame null_frame = { AST_FRAME_NULL };
if (!p->chan) {
ast_log(LOG_WARNING, "No channel? :(\n");
return NULL;
......@@ -286,12 +319,26 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
tmp->priority = 1;
/* Wake up any waiting blockers (by definition the login app) */
/* Wake up and wait for other applications (by definition the login app)
* to release this channel). Takes ownership of the agent channel
* to this thread only.
* For signalling the other thread, ast_queue_frame is used until we
* can safely use signals for this purpose. The pselect() needs to be
* implemented in the kernel for this.
*/
p->app_sleep_cond = 0;
if( pthread_mutex_trylock(&p->app_lock) )
{
ast_queue_frame(p->chan, &null_frame, 1);
ast_pthread_mutex_unlock(&p->lock); /* For other thread to read the condition. */
ast_pthread_mutex_lock(&p->app_lock);
ast_pthread_mutex_lock(&p->lock);
}
p->owning_app = pthread_self();
/* After the above step, there should not be any blockers. */
if (p->chan->blocking) {
pthread_kill(p->chan->blocker, SIGURG);
/* Wait until the blocker releases it */
while(p->chan->blocking)
usleep(1000);
ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
CRASH;
}
ast_moh_stop(p->chan);
} else
......@@ -435,11 +482,35 @@ static int login_exec(struct ast_channel *chan, void *data)
char pass[AST_MAX_AGENT];
char xpass[AST_MAX_AGENT] = "";
char *errmsg;
char info[512];
char *opt_user = NULL;
char *options = NULL;
int play_announcement;
struct timespec required;
struct timespec remaining;
int delay;
LOCAL_USER_ADD(u);
/* Parse the arguments XXX Check for failure XXX */
strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
opt_user = info;
if( opt_user ) {
options = strchr(opt_user, '|');
if (options) {
*options = '\0';
options++;
}
}
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (!res)
res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
if (!res) {
if( opt_user )
strncpy( user, opt_user, AST_MAX_AGENT );
else
res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
}
while (!res && (tries < 3)) {
/* Check for password */
ast_pthread_mutex_lock(&agentlock);
......@@ -451,7 +522,7 @@ static int login_exec(struct ast_channel *chan, void *data)
}
ast_pthread_mutex_unlock(&agentlock);
if (!res) {
if (strlen(xpass) || !p)
if (strlen(xpass))
res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
else
strcpy(pass, "");
......@@ -470,7 +541,12 @@ static int login_exec(struct ast_channel *chan, void *data)
if (!strcmp(p->agent, user) &&
!strcmp(p->password, pass)) {
if (!p->chan) {
res = ast_streamfile(chan, "agent-loginok", chan->language);
play_announcement = 1;
if( options )
if( strchr( options, 's' ) )
play_announcement = 0;
if( play_announcement )
res = ast_streamfile(chan, "agent-loginok", chan->language);
if (!res)
ast_waitstream(chan, "");
if (!res) {
......@@ -500,13 +576,33 @@ static int login_exec(struct ast_channel *chan, void *data)
p->chan = chan;
ast_pthread_mutex_unlock(&p->lock);
ast_pthread_mutex_unlock(&agentlock);
while ((res >= 0) && (p->chan == chan)) {
/* True sleep here, since we're being monitored
elsewhere instead */
while (res >= 0) {
/* If we are not the owner, delay here for a while
* so other interested threads can kick in. */
delay = 0;
ast_pthread_mutex_lock(&p->lock);
if (p->chan != chan)
res = -1;
if (p->owner)
sleep(1);
else
res = ast_safe_sleep(chan, 1000);
delay = 1;
ast_pthread_mutex_unlock(&p->lock);
if (delay) {
sched_yield();
required.tv_sec = 0;
required.tv_nsec = 20 * 1000 * 1000;
nanosleep( &required, &remaining );
}
if (res)
break;
/* Synchronize channel ownership between call to agent and itself. */
pthread_mutex_lock( &p->app_lock );
ast_pthread_mutex_lock(&p->lock);
p->owning_app = pthread_self();
ast_pthread_mutex_unlock(&p->lock);
res = ast_safe_sleep_conditional( chan, 1000,
agent_cont_sleep, p );
pthread_mutex_unlock( &p->app_lock );
}
if (res && p->owner)
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
......@@ -522,6 +618,10 @@ static int login_exec(struct ast_channel *chan, void *data)
if (p->dead && !p->owner)
free(p);
}
else {
ast_pthread_mutex_unlock(&p->lock);
p = NULL;
}
res = -1;
} else {
ast_pthread_mutex_unlock(&p->lock);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment