aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_agi.c
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-01-19 00:28:49 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-01-19 00:28:49 +0000
commitfb0c85edeb22827b7f7a242fb5266c1944b40c9e (patch)
tree1fa70043dacf63a29de615f9f6c82ad0f824f011 /res/res_agi.c
parent4c5831b3e5f9c280dafe6ec76c4f067d8ebcc713 (diff)
Create iterative method for querying SRV results, and use that for finding AGI servers.
(closes issue #14775) Reported by: _brent_ Patches: 20091215__issue14775.diff.txt uploaded by tilghman (license 14) hagi-5.patch uploaded by brent (license 388) Tested by: _brent_ Reviewboard: https://reviewboard.asterisk.org/r/378/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@241188 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_agi.c')
-rw-r--r--res/res_agi.c106
1 files changed, 88 insertions, 18 deletions
diff --git a/res/res_agi.c b/res/res_agi.c
index da4ebe8af..b055a23e6 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -60,6 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/features.h"
#include "asterisk/term.h"
#include "asterisk/xmldoc.h"
+#include "asterisk/srv.h"
#define AST_API_MODULE
#include "asterisk/agi.h"
@@ -897,6 +898,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define MAX_CMD_LEN 80
#define AGI_NANDFS_RETRY 3
#define AGI_BUF_LEN 2048
+#define SRV_PREFIX "_agi._tcp."
static char *app = "AGI";
@@ -1339,32 +1341,28 @@ quit:
/* launch_netscript: The fastagi handler.
FastAGI defaults to port 4573 */
-static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
+static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
{
int s, flags, res, port = AGI_PORT;
struct pollfd pfds[1];
- char *host, *c, *script = "";
+ char *host, *c, *script;
struct sockaddr_in addr_in;
struct hostent *hp;
struct ast_hostent ahp;
- /* agiusl is "agi://host.domain[:port][/script/name]" */
+ /* agiurl is "agi://host.domain[:port][/script/name]" */
host = ast_strdupa(agiurl + 6); /* Remove agi:// */
/* Strip off any script name */
- if ((c = strchr(host, '/'))) {
- *c = '\0';
- c++;
- script = c;
+ if ((script = strchr(host, '/'))) {
+ *script++ = '\0';
+ } else {
+ script = "";
}
+
if ((c = strchr(host, ':'))) {
- *c = '\0';
- c++;
+ *c++ = '\0';
port = atoi(c);
}
- if (efd) {
- ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
- return -1;
- }
if (!(hp = ast_gethostbyname(host, &ahp))) {
ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
return -1;
@@ -1423,20 +1421,92 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, in
ast_debug(4, "Wow, connected!\n");
fds[0] = s;
fds[1] = s;
- *opid = -1;
return AGI_RESULT_SUCCESS_FAST;
}
+/*!
+ * \internal
+ * \brief The HA fastagi handler.
+ * \param agiurl The request URL as passed to Agi() in the dial plan
+ * \param argv The parameters after the URL passed to Agi() in the dial plan
+ * \param fds Input/output file descriptors
+ *
+ * Uses SRV lookups to try to connect to a list of FastAGI servers. The hostname in
+ * the URI is prefixed with _agi._tcp. prior to the DNS resolution. For
+ * example, if you specify the URI \a hagi://agi.example.com/foo.agi the DNS
+ * query would be for \a _agi._tcp.agi.example.com and you'll need to make sure
+ * this resolves.
+ *
+ * This function parses the URI, resolves the SRV service name, forms new URIs
+ * with the results of the DNS lookup, and then calls launch_netscript on the
+ * new URIs until one succeeds.
+ *
+ * \return the result of the AGI operation.
+ */
+static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
+{
+ char *host, *script;
+ enum agi_result result = AGI_RESULT_FAILURE;
+ struct srv_context *context = NULL;
+ int srv_ret;
+ char service[256];
+ char resolved_uri[1024];
+ const char *srvhost;
+ unsigned short srvport;
+
+ /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
+ if (!(host = ast_strdupa(agiurl + 7))) { /* Remove hagi:// */
+ ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
+ return AGI_RESULT_FAILURE;
+ }
+
+ /* Strip off any script name */
+ if ((script = strchr(host, '/'))) {
+ *script++ = '\0';
+ } else {
+ script = "";
+ }
+
+ if (strchr(host, ':')) {
+ ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
+ return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
+ }
+
+ snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
+
+ while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
+ snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
+ result = launch_netscript(resolved_uri, argv, fds);
+ if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
+ ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
+ } else {
+ break;
+ }
+ }
+ if (srv_ret < 0) {
+ ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
+ } else {
+ ast_srv_cleanup(&context);
+ }
+
+ return result;
+}
+
static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
{
char tmp[256];
int pid, toast[2], fromast[2], audio[2], res;
struct stat st;
- if (!strncasecmp(script, "agi://", 6))
- return launch_netscript(script, argv, fds, efd, opid);
- if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
+ if (!strncasecmp(script, "agi://", 6)) {
+ return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
+ }
+ if (!strncasecmp(script, "hagi://", 7)) {
+ return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
+ }
+ if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
return launch_asyncagi(chan, argv, efd);
+ }
if (script[0] != '/') {
snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
@@ -3590,7 +3660,7 @@ static int agi_exec_full(struct ast_channel *chan, const char *data, int enhance
{
enum agi_result res;
char *buf;
- int fds[2], efd = -1, pid;
+ int fds[2], efd = -1, pid = -1;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(arg)[MAX_ARGS];
);