aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-04-09 14:37:50 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-04-09 14:37:50 +0000
commit6c57cdc6ac82a6a6700ebdb788d690471d8fc49d (patch)
treea4229d9951584abfc017622e1a74d2d358d9edf5 /channels
parentc39bfddbfd1fcb7bb65c61e9592d024cc16d87d0 (diff)
func_srv and explicit specification of a remote IP for SIP.
From Review Board: There are two interrelated changes here. First, there is the introduction of func_srv. This adds two new read-only dialplan functions, SRVQUERY and SRVRESULT. They work very similarly to the ENUMQUERY and ENUMRESULT functions, except that this allows one to query SRV records instead. In order to facilitate this work, I added a couple of new API calls to srv.h. ast_srv_get_record_count tells the number of records returned by an SRV lookup. This number is calculated at the time of the SRV lookup. ast_srv_get_nth_record allows one to get a numbered SRV record. Second, there is the modification to chan_sip that allows one to specify a hostname or IP address (along with a port) to send an outgoing INVITE to when dialing a SIP peer. This goes hand-in-hand with func_srv. You can query SRV records and then use the host and port from the results to dial via a specific host instead of what is configured in sip.conf. Review: https://reviewboard.asterisk.org/r/608 SWP-1200 git-svn-id: http://svn.digium.com/svn/asterisk/trunk@256485 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c74
1 files changed, 56 insertions, 18 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f2308fabe..bd6cb1889 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1260,7 +1260,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
static void build_via(struct sip_pvt *p);
static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
-static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog);
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog, struct sockaddr_in *remote_address);
static char *generate_random_string(char *buf, size_t size);
static void build_callid_pvt(struct sip_pvt *pvt);
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
@@ -3998,7 +3998,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
/*! \brief create address structure from device name
* Or, if peer not found, find it in the global DNS
* returns TRUE (-1) on failure, FALSE on success */
-static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog)
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog, struct sockaddr_in *remote_address)
{
struct hostent *hp;
struct ast_hostent ahp;
@@ -4026,7 +4026,9 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd
set_socket_transport(&dialog->socket, 0);
}
res = create_addr_from_peer(dialog, peer);
- if (!ast_strlen_zero(port)) {
+ if (remote_address && remote_address->sin_addr.s_addr) {
+ dialog->sa = dialog->recv = *remote_address;
+ } else if (!ast_strlen_zero(port)) {
if ((portno = atoi(port))) {
dialog->sa.sin_port = dialog->recv.sin_port = htons(portno);
}
@@ -9859,7 +9861,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
}
/* Setup the destination of our subscription */
- if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0)) {
+ if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0, NULL)) {
dialog_unlink_all(mwi->call, TRUE, TRUE);
mwi->call = dialog_unref(mwi->call, "unref dialog after unlink_all");
return 0;
@@ -10267,7 +10269,7 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
return 0;
}
- if (create_addr(p, channame, NULL, 0)) {
+ if (create_addr(p, channame, NULL, 0, NULL)) {
/* Maybe they're not registered, etc. */
dialog_unlink_all(p, TRUE, TRUE);
dialog_unref(p, "unref dialog inside for loop" );
@@ -10570,7 +10572,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
r->us.sin_port = htons(r->portno);
/* Find address to hostname */
- if (create_addr(p, r->hostname, &r->us, 0)) {
+ if (create_addr(p, r->hostname, &r->us, 0, NULL)) {
/* we have what we hope is a temporary network error,
* probably DNS. We need to reschedule a registration try */
dialog_unlink_all(p, TRUE, TRUE);
@@ -15947,7 +15949,7 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
return CLI_FAILURE;
}
- if (create_addr(p, a->argv[i], NULL, 1)) {
+ if (create_addr(p, a->argv[i], NULL, 1, NULL)) {
/* Maybe they're not registered, etc. */
dialog_unlink_all(p, TRUE, TRUE);
dialog_unref(p, "unref dialog inside for loop" );
@@ -22330,12 +22332,19 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
char tmp[256];
char *dest = data;
char *dnid;
- char *secret = NULL;
- char *md5secret = NULL;
- char *authname = NULL;
+ char *secret = NULL;
+ char *md5secret = NULL;
+ char *authname = NULL;
char *trans = NULL;
+ char *remote_address;
enum sip_transport transport = 0;
+ struct sockaddr_in remote_address_sin = { .sin_family = AF_INET };
format_t oldformat = format;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(peerorhost);
+ AST_APP_ARG(exten);
+ AST_APP_ARG(remote_address);
+ );
/* mask request with some set of allowed formats.
* XXX this needs to be fixed.
@@ -22372,7 +22381,6 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
/* Save the destination, the SIP dial string */
ast_copy_string(tmp, dest, sizeof(tmp));
-
/* Find DNID and take it away */
dnid = strchr(tmp, '!');
if (dnid != NULL) {
@@ -22380,11 +22388,14 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
ast_string_field_set(p, todnid, dnid);
}
+ /* Divvy up the items separated by slashes */
+ AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
+
/* Find at sign - @ */
- host = strchr(tmp, '@');
+ host = strchr(args.peerorhost, '@');
if (host) {
*host++ = '\0';
- ext = tmp;
+ ext = args.peerorhost;
secret = strchr(ext, ':');
}
if (secret) {
@@ -22415,10 +22426,37 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
}
if (!host) {
- ext = strchr(tmp, '/');
- if (ext)
- *ext++ = '\0';
- host = tmp;
+ ext = args.exten;
+ host = args.peerorhost;
+ remote_address = args.remote_address;
+ } else {
+ remote_address = args.remote_address;
+ if (!ast_strlen_zero(args.exten)) {
+ ast_log(LOG_NOTICE, "Conflicting extension values given. Using '%s' and not '%s'\n", ext, args.exten);
+ }
+ }
+
+ if (!ast_strlen_zero(remote_address)) {
+ struct hostent *hp;
+ struct ast_hostent ahp;
+ char *port;
+ unsigned short port_num = transport & SIP_TRANSPORT_TLS ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
+
+ port = strchr(remote_address, ':');
+ if (port) {
+ *port++ = '\0';
+ if (sscanf(port, "%hu", &port_num) != 1) {
+ ast_log(LOG_WARNING, "Invalid port number provided in remote address. Using %hu\n", port_num);
+ }
+ }
+
+ hp = ast_gethostbyname(remote_address, &ahp);
+ if (!hp) {
+ ast_log(LOG_WARNING, "Unable to find IP address for host %s. We will not use this remote IP address\n", remote_address);
+ } else {
+ memcpy(&remote_address_sin.sin_addr, hp->h_addr, sizeof(remote_address_sin.sin_addr));
+ remote_address_sin.sin_port = htons(port_num);
+ }
}
set_socket_transport(&p->socket, transport);
@@ -22428,7 +22466,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
ext = extension (user part of URI)
dnid = destination of the call (applies to the To: header)
*/
- if (create_addr(p, host, NULL, 1)) {
+ if (create_addr(p, host, NULL, 1, &remote_address_sin)) {
*cause = AST_CAUSE_UNREGISTERED;
ast_debug(3, "Cant create SIP call - target device not registered\n");
dialog_unlink_all(p, TRUE, TRUE);