[asterisk-commits] russell: branch russell/sla_rewrite r52136 - in
/team/russell/sla_rewrite: ap...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Wed Jan 24 17:15:25 MST 2007
Author: russell
Date: Wed Jan 24 18:15:24 2007
New Revision: 52136
URL: http://svn.digium.com/view/asterisk?view=rev&rev=52136
Log:
Commit progress on the SLA code. I'm pretty close to getting the correct
behavior when a call comes in on a trunk ...
Modified:
team/russell/sla_rewrite/apps/app_meetme.c
team/russell/sla_rewrite/include/asterisk/dial.h
team/russell/sla_rewrite/main/dial.c
Modified: team/russell/sla_rewrite/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/russell/sla_rewrite/apps/app_meetme.c?view=diff&rev=52136&r1=52135&r2=52136
==============================================================================
--- team/russell/sla_rewrite/apps/app_meetme.c (original)
+++ team/russell/sla_rewrite/apps/app_meetme.c Wed Jan 24 18:15:24 2007
@@ -60,6 +60,7 @@
#include "asterisk/ulaw.h"
#include "asterisk/astobj.h"
#include "asterisk/devicestate.h"
+#include "asterisk/dial.h"
#include "enter.h"
#include "leave.h"
@@ -182,7 +183,7 @@
AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
-END_OPTIONS);
+END_OPTIONS );
static const char *app = "MeetMe";
static const char *app2 = "MeetMeCount";
@@ -333,19 +334,13 @@
AST_LIST_ENTRY(ast_conf_user) list;
};
-struct sla_trunk {
- AST_RWLIST_ENTRY(sla_trunk) entry;
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name);
- AST_STRING_FIELD(device);
- AST_STRING_FIELD(autocontext);
- );
+enum sla_trunk_state {
+ SLA_TRUNK_STATE_IDLE,
+ SLA_TRUNK_STATE_RINGING,
+ SLA_TRUNK_STATE_UP,
};
-struct sla_trunk_ref {
- struct sla_trunk *trunk;
- AST_LIST_ENTRY(sla_trunk_ref) entry;
-};
+struct sla_trunk_ref;
struct sla_station {
AST_RWLIST_ENTRY(sla_station) entry;
@@ -355,6 +350,30 @@
AST_STRING_FIELD(autocontext);
);
AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
+};
+
+struct sla_station_ref {
+ AST_LIST_ENTRY(sla_station_ref) entry;
+ struct sla_station *station;
+};
+
+struct sla_trunk {
+ AST_RWLIST_ENTRY(sla_trunk) entry;
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ AST_STRING_FIELD(device);
+ AST_STRING_FIELD(autocontext);
+ );
+ AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
+ unsigned int num_stations;
+ enum sla_trunk_state state;
+ pthread_t station_thread;
+};
+
+struct sla_trunk_ref {
+ AST_LIST_ENTRY(sla_trunk_ref) entry;
+ struct sla_trunk *trunk;
+ enum sla_trunk_state state;
};
static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
@@ -867,11 +886,18 @@
"-------------------------------------------------------------\n\n");
AST_RWLIST_RDLOCK(&sla_trunks);
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
+ struct sla_station_ref *station_ref;
ast_cli(fd, "--- Trunk Name: %s\n"
"--- ==> Device: %s\n"
- "--- ==> AutoContext: %s\n\n",
+ "--- ==> AutoContext: %s\n"
+ "--- ==> Stations ...\n",
trunk->name, trunk->device,
S_OR(trunk->autocontext, "(none)"));
+ AST_RWLIST_RDLOCK(&sla_stations);
+ AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
+ ast_cli(fd, "--- =====> Station name: %s\n", station_ref->station->name);
+ AST_RWLIST_UNLOCK(&sla_stations);
+ ast_cli(fd, "\n");
}
AST_RWLIST_UNLOCK(&sla_trunks);
ast_cli(fd, "-------------------------------------------------------------\n");
@@ -2726,9 +2752,162 @@
ast_config_destroy(cfg);
}
+static const char *trunkstate2str(enum sla_trunk_state state)
+{
+#define S(e) case e: return # e;
+ switch (state) {
+ S(SLA_TRUNK_STATE_IDLE)
+ S(SLA_TRUNK_STATE_RINGING)
+ S(SLA_TRUNK_STATE_UP)
+ }
+ return "Uknown State";
+#undef S
+}
+
+/*! \brief Find an SLA trunk by name
+ * \note This must be called with the sla_trunks container locked
+ */
+static struct sla_trunk *find_trunk(const char *name)
+{
+ struct sla_trunk *trunk = NULL;
+
+ AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
+ if (!strcasecmp(trunk->name, name))
+ break;
+ }
+
+ return trunk;
+}
+
static int slastation_exec(struct ast_channel *chan, void *data)
{
return 0;
+}
+
+static void *dial_stations(void *data)
+{
+ struct sla_trunk *trunk = data;
+ struct sla_station_ref *station_ref;
+ struct ast_dial **dials;
+ struct sla_trunk_ref **trunk_refs;
+ struct ast_channel *chan;
+ struct ast_flags conf_flags;
+ struct ast_conference *conf;
+ int res = 0, len, num_dials = 0, i, winner;
+ char conf_name[MAX_CONFNUM];
+
+ len = (trunk->num_stations + 1) * sizeof(*dials);
+ ast_log(LOG_DEBUG, "len is %d\n", len);
+ dials = alloca(len);
+ memset(dials, 0, len);
+ trunk_refs = alloca(len);
+ memset(trunk_refs, 0, len);
+
+ AST_RWLIST_RDLOCK(&sla_stations);
+ AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
+ struct ast_dial *dial;
+ char *tech, *tech_data;
+ struct sla_trunk_ref *trunk_ref;
+
+ if (!(dial = ast_dial_create())) {
+ res = -1;
+ break;
+ }
+
+ tech_data = ast_strdupa(station_ref->station->device);
+ tech = strsep(&tech_data, "/");
+ ast_dial_append(dial, tech, tech_data);
+
+ AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
+ if (trunk == trunk_ref->trunk)
+ break;
+ }
+ if (!trunk_ref) {
+ res = -1;
+ ast_log(LOG_ERROR, "Trunk referenced this station, "
+ "but the station didn't reference the trunk!\n");
+ break;
+ }
+ trunk_refs[num_dials] = trunk_ref;
+ dials[num_dials++] = dial;
+ }
+ AST_RWLIST_UNLOCK(&sla_stations);
+
+ if (res) {
+ for (i = 0; dials[i]; i++)
+ ast_dial_destroy(dials[i]);
+ return NULL;
+ }
+
+ for (i = 0; dials[i]; i++) {
+ enum ast_dial_result dial_res;
+ dial_res = ast_dial_run(dials[i], NULL, 1);
+ if (dial_res != AST_DIAL_RESULT_TRYING) {
+ ast_log(LOG_ERROR, "Failed to begin dial to station!\n");
+ res = -1;
+ break;
+ }
+ }
+
+ if (res) {
+ for (i = 0; dials[i]; i++) {
+ ast_dial_join(dials[i]);
+ ast_dial_destroy(dials[i]);
+ }
+ return NULL;
+ }
+
+ for (i = 0, winner = -1; ; i = (i + 1) % num_dials) {
+ if (!dials[i])
+ continue;
+
+ switch (ast_dial_status(dials[i])) {
+ case AST_DIAL_RESULT_HANGUP:
+ trunk_refs[i]->state = SLA_TRUNK_STATE_IDLE;
+ case AST_DIAL_RESULT_INVALID:
+ case AST_DIAL_RESULT_FAILED:
+ case AST_DIAL_RESULT_TIMEOUT:
+ case AST_DIAL_RESULT_UNANSWERED:
+ ast_dial_join(dials[i]);
+ ast_dial_destroy(dials[i]);
+ dials[i] = NULL;
+ break;
+ case AST_DIAL_RESULT_TRYING:
+ break;
+ case AST_DIAL_RESULT_RINGING:
+ case AST_DIAL_RESULT_PROGRESS:
+ case AST_DIAL_RESULT_PROCEEDING:
+ trunk_refs[i]->state = SLA_TRUNK_STATE_RINGING;
+ break;
+ case AST_DIAL_RESULT_ANSWERED:
+ winner = i;
+ break;
+ }
+ if (winner > -1)
+ break;
+ }
+
+ for (i = 0; i < num_dials; i++) {
+ if (!dials[i] || i == winner)
+ continue;
+ ast_dial_join(dials[i]);
+ ast_dial_destroy(dials[i]);
+ dials[i] = NULL;
+ }
+
+ chan = ast_dial_answered(dials[winner]);
+ ast_set_flag(&conf_flags,
+ CONFFLAG_QUIET |
+ CONFFLAG_MARKEDEXIT);
+ snprintf(conf_name, sizeof(conf_name), "SLA-%s", trunk->name);
+ conf = build_conf(conf_name, "", "", 0, 0, 1);
+ if (conf)
+ res = conf_run(chan, conf, conf_flags.flags, NULL);
+ trunk_refs[winner]->state = SLA_TRUNK_STATE_IDLE;
+ ast_dial_join(dials[winner]);
+ ast_dial_destroy(dials[winner]);
+
+ return NULL;
}
static int slatrunk_exec(struct ast_channel *chan, void *data)
@@ -2737,33 +2916,94 @@
char conf_name[MAX_CONFNUM];
struct ast_conference *conf;
int res;
- struct ast_flags conf_flags = { 0 };
+ struct ast_flags conf_flags;
+ struct sla_trunk *trunk;
+
+ AST_RWLIST_RDLOCK(&sla_trunks);
+ trunk = find_trunk(trunk_name);
+ if (!trunk) {
+ ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
+ AST_RWLIST_UNLOCK(&sla_trunks);
+ pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
+ return 0;
+ }
+ if (trunk->state != SLA_TRUNK_STATE_IDLE) {
+ ast_log(LOG_ERROR, "Call came in on %s, but the trunk is in state %s?!\n",
+ trunk_name, trunkstate2str(trunk->state));
+ AST_RWLIST_UNLOCK(&sla_trunks);
+ pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
+ return 0;
+ }
+ AST_RWLIST_UNLOCK(&sla_trunks);
snprintf(conf_name, sizeof(conf_name), "SLA-%s", trunk_name);
-
- conf = build_conf(conf_name, NULL, NULL,
- 1 /* make it! */, 1 /* dynamic */, 1 /* refcount++ */);
+ conf = build_conf(conf_name, "", "", 1, 1, 1);
if (!conf) {
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
return 0;
}
- /* Set flags for the conf */
-
+ if (ast_pthread_create_background(&trunk->station_thread, NULL, dial_stations, trunk)) {
+ pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
+ return 0;
+ }
+
+ ast_set_flag(&conf_flags,
+ CONFFLAG_QUIET | /* We don't want sounds played to the SLA */
+ CONFFLAG_MARKEDEXIT | /* Close the conference when the trunk leaves */
+ CONFFLAG_MARKEDUSER); /* Set the trunk as the "marked" user, so others will
+ * exit when the trunk leaves. */
+
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ trunk->state = SLA_TRUNK_STATE_RINGING;
res = conf_run(chan, conf, conf_flags.flags, NULL);
+ trunk->state = SLA_TRUNK_STATE_IDLE;
return 0;
}
static int sla_state(const char *data)
{
- return AST_DEVICE_INUSE;
+ char *buf, *station_name, *trunk_name;
+ struct sla_station *station;
+ struct sla_trunk_ref *trunk_ref;
+ int res = AST_DEVICE_INVALID;
+
+ trunk_name = buf = ast_strdupa(data);
+ station_name = strsep(&trunk_name, "_");
+
+ AST_RWLIST_RDLOCK(&sla_stations);
+ AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+ if (strcasecmp(station_name, station->name))
+ continue;
+ AST_RWLIST_RDLOCK(&sla_trunks);
+ AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+ if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
+ break;
+ }
+ if (trunk_ref)
+ res = trunk_ref->state;
+ AST_RWLIST_UNLOCK(&sla_trunks);
+ }
+ AST_RWLIST_UNLOCK(&sla_stations);
+
+ if (res == AST_DEVICE_INVALID) {
+ ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
+ trunk_name, station_name);
+ }
+
+ return res;
}
static void destroy_trunk(struct sla_trunk *trunk)
{
+ struct sla_station_ref *station_ref;
+
if (!ast_strlen_zero(trunk->autocontext))
ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
+
+ while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
+ free(station_ref);
ast_string_field_free_all(trunk);
free(trunk);
@@ -2811,6 +3051,19 @@
AST_RWLIST_UNLOCK(&sla_stations);
}
+static int check_device(const char *device)
+{
+ char *tech, *tech_data;
+
+ tech_data = ast_strdupa(device);
+ tech = strsep(&tech_data, "/");
+
+ if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
+ return -1;
+
+ return 0;
+}
+
static int build_trunk(struct ast_config *cfg, const char *cat)
{
struct sla_trunk *trunk;
@@ -2819,6 +3072,12 @@
if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
+ return -1;
+ }
+
+ if (check_device(dev)) {
+ ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
+ cat, dev);
return -1;
}
@@ -2891,6 +3150,7 @@
if (!strcasecmp(var->name, "trunk")) {
struct sla_trunk *trunk;
struct sla_trunk_ref *trunk_ref;
+ struct sla_station_ref *station_ref;
AST_RWLIST_RDLOCK(&sla_trunks);
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
if (!strcasecmp(trunk->name, var->value))
@@ -2904,6 +3164,16 @@
if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
continue;
trunk_ref->trunk = trunk;
+ trunk_ref->state = AST_DEVICE_NOT_INUSE;
+ if (!(station_ref = ast_calloc(1, sizeof(*station_ref)))) {
+ free(trunk_ref);
+ continue;
+ }
+ station_ref->station = station;
+ AST_RWLIST_WRLOCK(&sla_trunks);
+ trunk->num_stations++;
+ AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
+ AST_RWLIST_UNLOCK(&sla_trunks);
AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
} else if (!strcasecmp(var->name, "autocontext")) {
ast_string_field_set(station, autocontext, var->value);
Modified: team/russell/sla_rewrite/include/asterisk/dial.h
URL: http://svn.digium.com/view/asterisk/team/russell/sla_rewrite/include/asterisk/dial.h?view=diff&rev=52136&r1=52135&r2=52136
==============================================================================
--- team/russell/sla_rewrite/include/asterisk/dial.h (original)
+++ team/russell/sla_rewrite/include/asterisk/dial.h Wed Jan 24 18:15:24 2007
@@ -42,7 +42,7 @@
/*! \brief List of return codes for dial run API calls */
enum ast_dial_result {
- AST_DIAL_RESULT_INVALID = 0, /*!< Invalid options were passed to run function */
+ AST_DIAL_RESULT_INVALID, /*!< Invalid options were passed to run function */
AST_DIAL_RESULT_FAILED, /*!< Attempts to dial failed before reaching critical state */
AST_DIAL_RESULT_TRYING, /*!< Currently trying to dial */
AST_DIAL_RESULT_RINGING, /*!< Dial is presently ringing */
Modified: team/russell/sla_rewrite/main/dial.c
URL: http://svn.digium.com/view/asterisk/team/russell/sla_rewrite/main/dial.c?view=diff&rev=52136&r1=52135&r2=52136
==============================================================================
--- team/russell/sla_rewrite/main/dial.c (original)
+++ team/russell/sla_rewrite/main/dial.c Wed Jan 24 18:15:24 2007
@@ -228,33 +228,37 @@
ast_copy_string(numsubst, channel->device, sizeof(numsubst));
/* Request that the channel be created */
- if (!(channel->owner = ast_request(channel->tech, chan->nativeformats, numsubst, &channel->cause)))
+ if (!(channel->owner = ast_request(channel->tech,
+ chan ? chan->nativeformats : 0xFFFFFFFF, numsubst, &channel->cause))) {
continue;
+ }
channel->owner->appl = "AppDial2";
channel->owner->data = "(Outgoing Line)";
channel->owner->whentohangup = 0;
/* Inherit everything from he who spawned this Dial */
- ast_channel_inherit_variables(chan, channel->owner);
-
- /* Copy over callerid information */
- S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
- S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
- S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
- S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
-
- ast_string_field_set(channel->owner, language, chan->language);
- ast_string_field_set(channel->owner, accountcode, chan->accountcode);
- channel->owner->cdrflags = chan->cdrflags;
- if (ast_strlen_zero(channel->owner->musicclass))
- ast_string_field_set(channel->owner, musicclass, chan->musicclass);
-
- channel->owner->cid.cid_pres = chan->cid.cid_pres;
- channel->owner->cid.cid_ton = chan->cid.cid_ton;
- channel->owner->cid.cid_tns = chan->cid.cid_tns;
- channel->owner->adsicpe = chan->adsicpe;
- channel->owner->transfercapability = chan->transfercapability;
+ if (chan) {
+ ast_channel_inherit_variables(chan, channel->owner);
+
+ /* Copy over callerid information */
+ S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
+ S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
+ S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
+ S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+
+ ast_string_field_set(channel->owner, language, chan->language);
+ ast_string_field_set(channel->owner, accountcode, chan->accountcode);
+ channel->owner->cdrflags = chan->cdrflags;
+ if (ast_strlen_zero(channel->owner->musicclass))
+ ast_string_field_set(channel->owner, musicclass, chan->musicclass);
+
+ channel->owner->cid.cid_pres = chan->cid.cid_pres;
+ channel->owner->cid.cid_ton = chan->cid.cid_ton;
+ channel->owner->cid.cid_tns = chan->cid.cid_tns;
+ channel->owner->adsicpe = chan->adsicpe;
+ channel->owner->transfercapability = chan->transfercapability;
+ }
/* Actually call the device */
if ((res = ast_call(channel->owner, numsubst, 0))) {
@@ -530,7 +534,7 @@
enum ast_dial_result res = AST_DIAL_RESULT_TRYING;
/* Ensure required arguments are passed */
- if (!dial || !chan)
+ if (!dial || (!chan && !async))
return AST_DIAL_RESULT_INVALID;
/* If there are no channels to dial we can't very well try to dial them */
More information about the asterisk-commits
mailing list