[asterisk-commits] phsultan: branch phsultan/jingle-support r222808 - in /team/phsultan/jingle-s...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Oct 8 12:17:08 CDT 2009
Author: phsultan
Date: Thu Oct 8 12:17:02 2009
New Revision: 222808
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=222808
Log:
Update to the Jingle signalling and STUN stack.
- compatibility with XEP-0166 (basic Jingle exchanges)
* handle incoming calls only
* fix namespaces
- compatibility with XEP-0176 (Jingle ICE-UDP Transport method)
- compatibility with RFC5389 (STUN) that obsoletes RFC3489
- code simplications
- code formatting fixes
Modified:
team/phsultan/jingle-support/channels/chan_gtalk.c
team/phsultan/jingle-support/channels/chan_h323.c
team/phsultan/jingle-support/channels/chan_jingle.c
team/phsultan/jingle-support/channels/chan_mgcp.c
team/phsultan/jingle-support/channels/chan_sip.c
team/phsultan/jingle-support/channels/chan_skinny.c
team/phsultan/jingle-support/channels/chan_unistim.c
team/phsultan/jingle-support/include/asterisk/jingle.h
team/phsultan/jingle-support/include/asterisk/rtp_engine.h
team/phsultan/jingle-support/include/asterisk/stun.h
team/phsultan/jingle-support/main/rtp_engine.c
team/phsultan/jingle-support/main/stun.c
team/phsultan/jingle-support/res/res_rtp_asterisk.c
Modified: team/phsultan/jingle-support/channels/chan_gtalk.c
URL: http://svnview.digium.com/svn/asterisk/team/phsultan/jingle-support/channels/chan_gtalk.c?view=diff&rev=222808&r1=222807&r2=222808
==============================================================================
--- team/phsultan/jingle-support/channels/chan_gtalk.c (original)
+++ team/phsultan/jingle-support/channels/chan_gtalk.c Thu Oct 8 12:17:02 2009
@@ -1269,15 +1269,15 @@
tmp = p->theircandidates;
p->laststun = time(NULL);
while (tmp) {
- char username[256];
+ struct stun_credentials credentials;
/* Find the IP address of the host */
hp = ast_gethostbyname(tmp->ip, &ahp);
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(tmp->port);
- snprintf(username, sizeof(username), "%s%s", tmp->username,
- p->ourcandidates->username);
+ ast_copy_string(credentials.local_ufrag, p->ourcandidates->username, sizeof(credentials.local_ufrag));
+ ast_copy_string(credentials.remote_ufrag, tmp->username, sizeof(credentials.remote_ufrag));
/* Find out the result of the STUN */
ast_rtp_instance_get_remote_address(p->rtp, &aux);
@@ -1287,9 +1287,9 @@
remote client */
if (aux.sin_addr.s_addr &&
aux.sin_addr.s_addr != sin.sin_addr.s_addr)
- ast_rtp_instance_stun_request(p->rtp, &aux, username);
+ ast_rtp_instance_stun_request(p->rtp, &aux, &credentials);
else
- ast_rtp_instance_stun_request(p->rtp, &sin, username);
+ ast_rtp_instance_stun_request(p->rtp, &sin, &credentials);
if (aux.sin_addr.s_addr) {
ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
@@ -1390,7 +1390,7 @@
if (!p->rtp)
return &ast_null_frame;
- f = ast_rtp_instance_read(p->rtp, 0);
+ f = ast_rtp_instance_read(p->rtp, 0, NULL);
gtalk_update_stun(p->parent, p);
if (p->owner) {
/* We already hold the channel lock */
Modified: team/phsultan/jingle-support/channels/chan_h323.c
URL: http://svnview.digium.com/svn/asterisk/team/phsultan/jingle-support/channels/chan_h323.c?view=diff&rev=222808&r1=222807&r2=222808
==============================================================================
--- team/phsultan/jingle-support/channels/chan_h323.c (original)
+++ team/phsultan/jingle-support/channels/chan_h323.c Thu Oct 8 12:17:02 2009
@@ -753,7 +753,7 @@
pvt->options.nat = 0;
}
- f = ast_rtp_instance_read(pvt->rtp, 0);
+ f = ast_rtp_instance_read(pvt->rtp, 0, NULL);
/* Don't send RFC2833 if we're not supposed to */
if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO))) {
return &ast_null_frame;
@@ -810,7 +810,7 @@
break;
case 1:
if (pvt->rtp)
- fr = ast_rtp_instance_read(pvt->rtp, 1);
+ fr = ast_rtp_instance_read(pvt->rtp, 1, NULL);
else
fr = &ast_null_frame;
break;
Modified: team/phsultan/jingle-support/channels/chan_jingle.c
URL: http://svnview.digium.com/svn/asterisk/team/phsultan/jingle-support/channels/chan_jingle.c?view=diff&rev=222808&r1=222807&r2=222808
==============================================================================
--- team/phsultan/jingle-support/channels/chan_jingle.c (original)
+++ team/phsultan/jingle-support/channels/chan_jingle.c Thu Oct 8 12:17:02 2009
@@ -68,6 +68,7 @@
#include "asterisk/abstract_jb.h"
#include "asterisk/jabber.h"
#include "asterisk/jingle.h"
+#include "asterisk/stun.h"
#define JINGLE_CONFIG "jingle.conf"
@@ -97,13 +98,12 @@
ast_mutex_t lock; /*!< Channel private lock */
time_t laststun;
struct jingle *parent; /*!< Parent client */
- char sid[100];
+ char sid[JINGLE_MAX_ATTRLEN];
char them[AJI_MAX_JIDLEN];
char ring[10]; /*!< Message ID of ring */
iksrule *ringrule; /*!< Rule for matching RING request */
int initiator; /*!< If we're the initiator */
int alreadygone;
- int capability;
struct ast_codec_pref prefs;
struct jingle_candidate *theircandidates;
struct jingle_candidate *ourcandidates;
@@ -111,16 +111,23 @@
char cid_name[80]; /*!< Caller ID name */
char exten[80]; /*!< Called extension */
struct ast_channel *owner; /*!< Master Channel */
- char audio_content_name[100]; /*!< name attribute of content tag */
- struct ast_rtp_instance *rtp; /*!< RTP audio session */
- char video_content_name[100]; /*!< name attribute of content tag */
- struct ast_rtp_instance *vrtp; /*!< RTP video session */
- int jointcapability; /*!< Supported capability at both ends (codecs ) */
- int peercapability;
+ char local_password[JINGLE_MAX_ATTRLEN];
+ char remote_password[JINGLE_MAX_ATTRLEN];
+ char local_ufrag[JINGLE_MAX_ATTRLEN];
+ char remote_ufrag[JINGLE_MAX_ATTRLEN];
+ char audio_content_name[JINGLE_MAX_ATTRLEN]; /*!< name attribute of content tag */
+ struct ast_rtp_instance *rtp; /*!< RTP audio session */
+ char video_content_name[JINGLE_MAX_ATTRLEN]; /*!< name attribute of content tag */
+ struct ast_rtp_instance *vrtp; /*!< RTP video session */
+ int capability; /*!< Channel codec capability */
+ int peercapability; /*!< Peer advertized codec capability */
+ int peernoncodeccapability; /*!< Peer advertized non codec capability (ex. DTMF) */
+ int jointcapability; /*!< Common codec capability */
struct jingle_pvt *next; /* Next entity */
};
struct jingle_candidate {
+ char id[JINGLE_MAX_ATTRLEN];
unsigned int component; /*!< ex. : 1 for RTP, 2 for RTCP */
unsigned int foundation; /*!< Function of IP, protocol, type */
unsigned int generation;
@@ -129,9 +136,7 @@
unsigned int port;
unsigned int priority;
enum jingle_protocol protocol;
- char password[100];
enum jingle_connect_type type;
- char ufrag[100];
unsigned int preference;
struct jingle_candidate *next;
};
@@ -163,7 +168,7 @@
static const char desc[] = "Jingle Channel";
static const char channel_type[] = "Jingle";
-static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
+static int global_capability = 0;
AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_pvt's) */
@@ -175,7 +180,7 @@
static int jingle_call(struct ast_channel *ast, char *dest, int timeout);
static int jingle_hangup(struct ast_channel *ast);
static int jingle_answer(struct ast_channel *ast);
-static int jingle_newcall(struct jingle *client, ikspak *pak);
+static int jingle_incomingcall(struct jingle *client, ikspak *pak);
static struct ast_frame *jingle_read(struct ast_channel *ast);
static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
@@ -292,71 +297,143 @@
iks_insert_attrib(payload_g723, "name", "G723");
iks_insert_node(dcodecs, payload_g723);
}
+ if (!strcasecmp("speex", format)) {
+ iks *payload_speex;
+ payload_speex = iks_new("payload-type");
+ iks_insert_attrib(payload_speex, "id", "110");
+ iks_insert_attrib(payload_speex, "name", "SPEEX");
+ iks_insert_attrib(payload_speex, "clockrate", "16000");
+ iks_insert_node(dcodecs, payload_speex);
+ }
}
static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p)
{
struct jingle_pvt *tmp = client->p;
+ struct jingle_candidate *aux = NULL;
struct aji_client *c = client->connection;
- iks *iq, *jingle, *dcodecs, *payload_red, *payload_audio, *payload_cn;
+ iks *iq, *jingle, *content, *dcodecs, *transport;
+ iks *candidates[2];
int x;
int pref_codec = 0;
int alreadysent = 0;
+ int num = 0;
+ char component[16], foundation[16], generation[16], network[16], port[7], priority[16];
if (p->initiator)
return 1;
+ /* allocate memory structures */
iq = iks_new("iq");
jingle = iks_new(JINGLE_NODE);
+ content = iks_new("content");
dcodecs = iks_new("description");
- if (iq && jingle && dcodecs) {
- iks_insert_attrib(dcodecs, "xmlns", JINGLE_AUDIO_RTP_NS);
-
- for (x = 0; x < 32; x++) {
- if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
- break;
- if (!(client->capability & pref_codec))
- continue;
- if (alreadysent & pref_codec)
- continue;
- add_codec_to_answer(p, pref_codec, dcodecs);
- alreadysent |= pref_codec;
- }
- payload_red = iks_new("payload-type");
- iks_insert_attrib(payload_red, "id", "117");
- iks_insert_attrib(payload_red, "name", "red");
- payload_audio = iks_new("payload-type");
- iks_insert_attrib(payload_audio, "id", "106");
- iks_insert_attrib(payload_audio, "name", "audio/telephone-event");
- payload_cn = iks_new("payload-type");
- iks_insert_attrib(payload_cn, "id", "13");
- iks_insert_attrib(payload_cn, "name", "CN");
-
-
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user);
- iks_insert_attrib(iq, "id", client->connection->mid);
- ast_aji_increment_mid(client->connection->mid);
-
- iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
- iks_insert_attrib(jingle, "action", JINGLE_ACCEPT);
- iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
- iks_insert_attrib(jingle, JINGLE_SID, tmp->sid);
- iks_insert_node(iq, jingle);
- iks_insert_node(jingle, dcodecs);
- iks_insert_node(dcodecs, payload_red);
- iks_insert_node(dcodecs, payload_audio);
- iks_insert_node(dcodecs, payload_cn);
-
- ast_aji_send(c, iq);
-
- iks_delete(payload_red);
- iks_delete(payload_audio);
- iks_delete(payload_cn);
- iks_delete(dcodecs);
- iks_delete(jingle);
- iks_delete(iq);
- }
+ transport = iks_new("transport");
+ candidates[0] = iks_new("candidate");
+ candidates[1] = iks_new("candidate");
+ if (!iq || !jingle || !content || !transport || !candidates[0] || !candidates[1]) {
+ ast_log(LOG_ERROR, "Memory allocation error\n");
+ goto safeout;
+ }
+
+ iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
+ iks_insert_attrib(transport, "ufrag", p->local_ufrag);
+ iks_insert_attrib(transport, "pwd", p->local_password);
+
+ for (aux = p->ourcandidates; aux; aux = aux->next) {
+ snprintf(component, sizeof(component), "%u", aux->component);
+ snprintf(foundation, sizeof(foundation), "%u", aux->foundation);
+ snprintf(generation, sizeof(generation), "%u", aux->generation);
+ snprintf(network, sizeof(network), "%u", aux->network);
+ snprintf(port, sizeof(port), "%u", aux->port);
+ snprintf(priority, sizeof(priority), "%u", aux->priority);
+
+ iks_insert_attrib(candidates[num], "id", aux->id);
+ iks_insert_attrib(candidates[num], "component", component);
+ iks_insert_attrib(candidates[num], "foundation", foundation);
+ iks_insert_attrib(candidates[num], "generation", generation);
+ iks_insert_attrib(candidates[num], "ip", aux->ip);
+ iks_insert_attrib(candidates[num], "network", network);
+ iks_insert_attrib(candidates[num], "port", port);
+ iks_insert_attrib(candidates[num], "priority", priority);
+ switch (aux->protocol) {
+ case AJI_PROTOCOL_UDP:
+ iks_insert_attrib(candidates[num], "protocol", "udp");
+ break;
+ case AJI_PROTOCOL_SSLTCP:
+ iks_insert_attrib(candidates[num], "protocol", "ssltcp");
+ break;
+ }
+ switch (aux->type) {
+ case AJI_CONNECT_HOST:
+ iks_insert_attrib(candidates[num], "type", "host");
+ break;
+ case AJI_CONNECT_PRFLX:
+ iks_insert_attrib(candidates[num], "type", "prflx");
+ break;
+ case AJI_CONNECT_RELAY:
+ iks_insert_attrib(candidates[num], "type", "relay");
+ break;
+ case AJI_CONNECT_SRFLX:
+ iks_insert_attrib(candidates[num], "type", "srflx");
+ break;
+ }
+ num ++;
+ }
+ p->laststun = 0;
+
+ iks_insert_attrib(dcodecs, "xmlns", JINGLE_RTP_NS);
+ iks_insert_attrib(dcodecs, "media", "audio");
+
+ for (x = 0; x < 32; x++) {
+ if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
+ break;
+ if (!(p->jointcapability & pref_codec))
+ continue;
+ if (alreadysent & pref_codec)
+ continue;
+ add_codec_to_answer(p, pref_codec, dcodecs);
+ alreadysent |= pref_codec;
+ }
+
+ iks_insert_attrib(iq, "type", "set");
+ iks_insert_attrib(iq, "from", client->connection->jid->full);
+ iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user);
+ iks_insert_attrib(iq, "id", client->connection->mid);
+ ast_aji_increment_mid(client->connection->mid);
+
+ iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+ iks_insert_attrib(jingle, "action", JINGLE_ACCEPT);
+ iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
+ if (!p->initiator) {
+ iks_insert_attrib(jingle, "responder", client->connection->jid->full);
+ }
+ iks_insert_attrib(jingle, JINGLE_SID, tmp->sid);
+
+ iks_insert_attrib(content, "creator", "initiator");
+ iks_insert_attrib(content, "name", "A");
+ iks_insert_attrib(content, "senders", "both");
+
+ /* insert nodes */
+ iks_insert_node(iq, jingle);
+ iks_insert_node(jingle, content);
+ iks_insert_node(content, dcodecs);
+ iks_insert_node(content, transport);
+ iks_insert_node(transport, candidates[0]);
+ iks_insert_node(transport, candidates[1]);
+
+ /* send IQ */
+ ast_aji_send(c, iq);
+
+safeout:
+ iks_delete(iq);
+ iks_delete(jingle);
+ iks_delete(content);
+ iks_delete(dcodecs);
+ iks_delete(transport);
+ iks_delete(candidates[0]);
+ iks_delete(candidates[1]);
+
return 1;
}
@@ -574,162 +651,36 @@
return 1;
}
-static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, char *sid, char *from)
-{
- struct jingle_candidate *tmp;
- struct aji_client *c = client->connection;
- struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
- struct sockaddr_in sin = { 0, };
- struct sockaddr_in dest;
- struct in_addr us;
- struct in_addr externaddr;
- iks *iq, *jingle, *content, *transport, *candidate;
- char component[16], foundation[16], generation[16], network[16], pass[16], port[7], priority[16], user[16];
-
-
- iq = iks_new("iq");
- jingle = iks_new(JINGLE_NODE);
- content = iks_new("content");
- transport = iks_new("transport");
- candidate = iks_new("candidate");
- if (!iq || !jingle || !content || !transport || !candidate) {
- ast_log(LOG_ERROR, "Memory allocation error\n");
- goto safeout;
- }
- ours1 = ast_calloc(1, sizeof(*ours1));
- ours2 = ast_calloc(1, sizeof(*ours2));
- if (!ours1 || !ours2)
- goto safeout;
-
- iks_insert_node(iq, jingle);
- iks_insert_node(jingle, content);
- iks_insert_node(content, transport);
- iks_insert_node(transport, candidate);
-
- for (; p; p = p->next) {
- if (!strcasecmp(p->sid, sid))
- break;
- }
-
- if (!p) {
- ast_log(LOG_NOTICE, "No matching jingle session - SID %s!\n", sid);
- goto safeout;
- }
-
- ast_rtp_instance_get_local_address(p->rtp, &sin);
- ast_find_ourip(&us, bindaddr);
-
- /* Setup our first jingle candidate */
- ours1->component = 1;
- ours1->foundation = (unsigned int)bindaddr.sin_addr.s_addr | AJI_CONNECT_HOST | AJI_PROTOCOL_UDP;
- ours1->generation = 0;
- ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
- ours1->network = 0;
- ours1->port = ntohs(sin.sin_port);
- ours1->priority = 1678246398;
- ours1->protocol = AJI_PROTOCOL_UDP;
- snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours1->password, pass, sizeof(ours1->password));
- ours1->type = AJI_CONNECT_HOST;
- snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours1->ufrag, user, sizeof(ours1->ufrag));
- p->ourcandidates = ours1;
-
- if (!ast_strlen_zero(externip)) {
- /* XXX We should really stun for this one not just go with externip XXX */
- if (inet_aton(externip, &externaddr))
- ast_log(LOG_WARNING, "Invalid extern IP : %s\n", externip);
-
- ours2->component = 1;
- ours2->foundation = (unsigned int)externaddr.s_addr | AJI_CONNECT_PRFLX | AJI_PROTOCOL_UDP;
- ours2->generation = 0;
- ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
- ours2->network = 0;
- ours2->port = ntohs(sin.sin_port);
- ours2->priority = 1678246397;
- ours2->protocol = AJI_PROTOCOL_UDP;
- snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours2->password, pass, sizeof(ours2->password));
- ours2->type = AJI_CONNECT_PRFLX;
-
- snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours2->ufrag, user, sizeof(ours2->ufrag));
- ours1->next = ours2;
- ours2 = NULL;
- }
- ours1 = NULL;
- dest.sin_addr = __ourip;
- dest.sin_port = sin.sin_port;
-
-
- for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
- snprintf(component, sizeof(component), "%u", tmp->component);
- snprintf(foundation, sizeof(foundation), "%u", tmp->foundation);
- snprintf(generation, sizeof(generation), "%u", tmp->generation);
- snprintf(network, sizeof(network), "%u", tmp->network);
- snprintf(port, sizeof(port), "%u", tmp->port);
- snprintf(priority, sizeof(priority), "%u", tmp->priority);
-
- iks_insert_attrib(iq, "from", c->jid->full);
- iks_insert_attrib(iq, "to", from);
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "id", c->mid);
- ast_aji_increment_mid(c->mid);
- iks_insert_attrib(jingle, "action", JINGLE_NEGOTIATE);
- iks_insert_attrib(jingle, JINGLE_SID, sid);
- iks_insert_attrib(jingle, "initiator", (p->initiator) ? c->jid->full : from);
- iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
- iks_insert_attrib(content, "creator", p->initiator ? "initiator" : "responder");
- iks_insert_attrib(content, "name", "asterisk-audio-content");
- iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
- iks_insert_attrib(candidate, "component", component);
- iks_insert_attrib(candidate, "foundation", foundation);
- iks_insert_attrib(candidate, "generation", generation);
- iks_insert_attrib(candidate, "ip", tmp->ip);
- iks_insert_attrib(candidate, "network", network);
- iks_insert_attrib(candidate, "port", port);
- iks_insert_attrib(candidate, "priority", priority);
- switch (tmp->protocol) {
- case AJI_PROTOCOL_UDP:
- iks_insert_attrib(candidate, "protocol", "udp");
- break;
- case AJI_PROTOCOL_SSLTCP:
- iks_insert_attrib(candidate, "protocol", "ssltcp");
- break;
- }
- iks_insert_attrib(candidate, "pwd", tmp->password);
- switch (tmp->type) {
- case AJI_CONNECT_HOST:
- iks_insert_attrib(candidate, "type", "host");
- break;
- case AJI_CONNECT_PRFLX:
- iks_insert_attrib(candidate, "type", "prflx");
- break;
- case AJI_CONNECT_RELAY:
- iks_insert_attrib(candidate, "type", "relay");
- break;
- case AJI_CONNECT_SRFLX:
- iks_insert_attrib(candidate, "type", "srflx");
- break;
- }
- iks_insert_attrib(candidate, "ufrag", tmp->ufrag);
-
- ast_aji_send(c, iq);
- }
- p->laststun = 0;
-
-safeout:
- if (ours1)
- ast_free(ours1);
- if (ours2)
- ast_free(ours2);
- iks_delete(iq);
- iks_delete(jingle);
- iks_delete(content);
- iks_delete(transport);
- iks_delete(candidate);
-
- return 1;
+static int jingle_append_candidate(struct jingle_pvt *p, struct jingle_candidate *candidate, struct sockaddr_in sin, int offset)
+{
+ int res = -1;
+
+ if (!p || !candidate) {
+ ast_log(LOG_WARNING, "Could not append candidate\n");
+ return res;
+ }
+
+ snprintf(candidate->id, sizeof(candidate->id), "%08lx", ast_random());
+ candidate->component = 1 + offset;
+ candidate->foundation = 0;
+ candidate->generation = 0;
+ ast_copy_string(candidate->ip, ast_inet_ntoa(sin.sin_addr), sizeof(candidate->ip));
+ candidate->network = 0;
+ candidate->port = ntohs(sin.sin_port) + offset;
+ candidate->priority = 1678246398 - offset;
+ candidate->protocol = AJI_PROTOCOL_UDP;
+ candidate->type = AJI_CONNECT_HOST;
+ candidate->next = NULL;
+
+ if (p->ourcandidates) {
+ p->ourcandidates->next = candidate;
+ } else {
+ p->ourcandidates = candidate;
+ }
+
+ res = 1;
+
+ return res;;
}
static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid)
@@ -764,7 +715,16 @@
return NULL;
}
+ /* set codec preferences to what has been configured in jingle.conf
+ * and create an RTP (and RTCP) instance from the asterisk engine */
memcpy(&tmp->prefs, &client->prefs, sizeof(tmp->prefs));
+ tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL);
+ if (!tmp->rtp) {
+ ast_log(LOG_WARNING, "Out of RTP sessions?\n");
+ ast_free(tmp);
+ return NULL;
+ }
+ ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
if (sid) {
ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
@@ -774,13 +734,8 @@
ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
tmp->initiator = 1;
}
- tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL);
+
tmp->parent = client;
- if (!tmp->rtp) {
- ast_log(LOG_WARNING, "Out of RTP sessions?\n");
- ast_free(tmp);
- return NULL;
- }
ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
ast_mutex_init(&tmp->lock);
ast_mutex_lock(&jinglelock);
@@ -791,79 +746,119 @@
}
/*! \brief Start new jingle channel */
-static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const char *linkedid)
+static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *p, int state, const char *title, const char *linkedid)
{
struct ast_channel *tmp;
int fmt;
- int what;
const char *str;
-
- if (title)
+ char pass[JINGLE_MAX_ATTRLEN];
+ char user[JINGLE_MAX_ATTRLEN];
+ struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
+ struct sockaddr_in sin;
+
+ if (title) {
str = title;
- else
- str = i->them;
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", "", "", linkedid, 0, "Jingle/%s-%04lx", str, ast_random() & 0xffff);
+ } else {
+ str = p->them;
+ }
+ tmp = ast_channel_alloc(1, state, p->cid_num, p->cid_name, "", "", "", linkedid, 0, "Jingle/%s-%04lx", str, ast_random() & 0xffff);
if (!tmp) {
ast_log(LOG_WARNING, "Unable to allocate Jingle channel structure!\n");
return NULL;
}
tmp->tech = &jingle_tech;
+
+ /* setup ICE ufrag and pwd attributes */
+ snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
+ ast_copy_string(p->local_password, pass, sizeof(p->local_password));
+ snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
+ ast_copy_string(p->local_ufrag, user, sizeof(p->local_ufrag));
+
+ /* Create our ICE candidates */
+ ours1 = ast_calloc(1, sizeof(*ours1));
+ if (!ours1) {
+ return NULL;
+ }
+ ours2 = ast_calloc(1, sizeof(*ours2));
+ if (!ours2) {
+ return NULL;
+ }
+ ast_rtp_instance_get_local_address(p->rtp, &sin);
+ jingle_append_candidate(p, ours1, sin, 0);
+ jingle_append_candidate(p, ours2, sin, 1);
+
/* Select our native format based on codec preference until we receive
something from another device to the contrary. */
- if (i->jointcapability)
- what = i->jointcapability;
- else if (i->capability)
- what = i->capability;
- else
- what = global_capability;
+ if (client->capability) {
+ p->capability = client->capability;
+ } else {
+ p->capability = global_capability;
+ }
+
+ /* Nothing has been received from the remote Jingle peer yet */
+ p->peercapability = 0;
+ p->peernoncodeccapability = 0;
+ p->jointcapability = 0;
/* Set Frame packetization */
- if (i->rtp)
- ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
-
- tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
+ if (p->rtp) {
+ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
+ }
+
+ tmp->nativeformats = ast_codec_choose(&p->prefs, p->capability, 1);
fmt = ast_best_codec(tmp->nativeformats);
-
- if (i->rtp) {
- ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
- ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
- }
- if (i->vrtp) {
- ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
- ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
- }
- if (state == AST_STATE_RING)
+ ast_log(LOG_NOTICE, "Codec initialized to : %s\n", ast_codec2str(fmt));
+
+ if (p->rtp) {
+ /* set file descriptors (RTP/RTCP) for audio channels */
+ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(p->rtp, 0));
+ ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(p->rtp, 1));
+ }
+ if (p->vrtp) {
+ /* set file descriptors (RTP/RTCP) for video channels */
+ ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(p->vrtp, 0));
+ ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(p->vrtp, 1));
+ }
+
+ if (state == AST_STATE_RING) {
tmp->rings = 1;
+ }
+
tmp->adsicpe = AST_ADSI_UNAVAILABLE;
tmp->writeformat = fmt;
tmp->rawwriteformat = fmt;
tmp->readformat = fmt;
tmp->rawreadformat = fmt;
- tmp->tech_pvt = i;
-
+ tmp->tech_pvt = p;
tmp->callgroup = client->callgroup;
tmp->pickupgroup = client->pickupgroup;
tmp->cid.cid_pres = client->callingpres;
- if (!ast_strlen_zero(client->accountcode))
+ if (!ast_strlen_zero(client->accountcode)) {
ast_string_field_set(tmp, accountcode, client->accountcode);
- if (client->amaflags)
+ }
+ if (client->amaflags) {
tmp->amaflags = client->amaflags;
- if (!ast_strlen_zero(client->language))
+ }
+ if (!ast_strlen_zero(client->language)) {
ast_string_field_set(tmp, language, client->language);
- if (!ast_strlen_zero(client->musicclass))
+ }
+ if (!ast_strlen_zero(client->musicclass)) {
ast_string_field_set(tmp, musicclass, client->musicclass);
- i->owner = tmp;
+ }
+ p->owner = tmp;
ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
+ ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
/* Don't use ast_set_callerid() here because it will
* generate an unnecessary NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
- if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
- tmp->cid.cid_dnid = ast_strdup(i->exten);
+ tmp->cid.cid_ani = ast_strdup(p->cid_num);
+ if (!ast_strlen_zero(p->exten) && strcmp(p->exten, "s")) {
+ tmp->cid.cid_dnid = ast_strdup(p->exten);
+ }
tmp->priority = 1;
- if (i->rtp)
+ if (p->rtp) {
ast_jb_configure(tmp, &global_jbconf);
+ }
if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
@@ -874,33 +869,39 @@
return tmp;
}
-static int jingle_action(struct jingle *client, struct jingle_pvt *p, const char *action)
-{
- iks *iq, *jingle = NULL;
+static int jingle_terminate(struct jingle *client, struct jingle_pvt *p, const char *causestring)
+{
+ iks *iq, *jingle, *reason, *cause;
int res = -1;
iq = iks_new("iq");
jingle = iks_new("jingle");
+ reason = iks_new("reason");
+ cause = iks_new(causestring ? causestring : "gone");
- if (iq) {
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "from", client->connection->jid->full);
- iks_insert_attrib(iq, "to", p->them);
- iks_insert_attrib(iq, "id", client->connection->mid);
- ast_aji_increment_mid(client->connection->mid);
- if (jingle) {
- iks_insert_attrib(jingle, "action", action);
- iks_insert_attrib(jingle, JINGLE_SID, p->sid);
- iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
- iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
-
- iks_insert_node(iq, jingle);
-
- ast_aji_send(client->connection, iq);
- res = 0;
- }
- }
-
+ if (!iq || !jingle || !reason || !cause) {
+ ast_log(LOG_ERROR, "Memory allocation error\n");
+ goto safeout;
+ }
+
+ iks_insert_attrib(iq, "type", "set");
+ iks_insert_attrib(iq, "from", client->connection->jid->full);
+ iks_insert_attrib(iq, "to", p->them);
+ iks_insert_attrib(iq, "id", client->connection->mid);
+ ast_aji_increment_mid(client->connection->mid);
+ iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+ iks_insert_attrib(jingle, "action", "session-terminate");
+ iks_insert_attrib(jingle, JINGLE_SID, p->sid);
+
+ iks_insert_node(reason, cause);
+ iks_insert_node(jingle, reason);
+ iks_insert_node(iq, jingle);
+
+ res = ast_aji_send(client->connection, iq);
+
+safeout:
+ iks_delete(cause);
+ iks_delete(reason);
iks_delete(jingle);
iks_delete(iq);
@@ -921,7 +922,9 @@
{
struct jingle_pvt *cur, *prev = NULL;
cur = client->p;
+
while (cur) {
+ /* take our jingle_pvt struct out of the list */
if (cur == p) {
if (prev)
prev->next = p->next;
@@ -932,31 +935,43 @@
prev = cur;
cur = cur->next;
}
- if (p->ringrule)
+
+ if (p->ringrule) {
iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
- if (p->owner)
+ }
+
+ if (p->owner) {
ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
- if (p->rtp)
+ }
+
+ if (p->rtp) {
ast_rtp_instance_destroy(p->rtp);
- if (p->vrtp)
+ }
+
+ if (p->vrtp) {
ast_rtp_instance_destroy(p->vrtp);
+ }
+
+ jingle_free_candidates(p->ourcandidates);
jingle_free_candidates(p->theircandidates);
ast_free(p);
}
-static int jingle_newcall(struct jingle *client, ikspak *pak)
+static int jingle_incomingcall(struct jingle *client, ikspak *pak)
{
struct jingle_pvt *p, *tmp = client->p;
struct ast_channel *chan;
int res;
iks *codec, *content, *description;
char *from = NULL;
+ struct ast_rtp_codecs *rtpcodecs = NULL;
/* Make sure our new call doesn't exist yet */
from = iks_find_attrib(pak->x,"to");
- if(!from)
+ if(!from) {
from = client->connection->jid->full;
+ }
while (tmp) {
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
@@ -973,6 +988,7 @@
client->connection = ast_aji_get_client(from);
if (!client->connection) {
ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
+ jingle_response(client, pak, "service-unavailable", NULL);
return -1;
}
}
@@ -980,32 +996,55 @@
p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID));
if (!p) {
ast_log(LOG_WARNING, "Unable to allocate jingle structure!\n");
+ jingle_response(client, pak, "resource-constraint", NULL);
return -1;
}
+
chan = jingle_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
if (!chan) {
jingle_free_pvt(client, p);
+ jingle_response(client, pak, "resource-constraint", NULL);
return -1;
}
+
ast_mutex_lock(&p->lock);
ast_copy_string(p->them, pak->from->full, sizeof(p->them));
if (iks_find_attrib(pak->query, JINGLE_SID)) {
- ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID),
- sizeof(p->sid));
+ ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID), sizeof(p->sid));
}
/* content points to the first <content/> tag */
content = iks_child(iks_child(pak->x));
+ if (!content) {
+ ast_log(LOG_WARNING, "No content tag found, aborting\n");
+ ast_hangup(chan);
+ jingle_free_pvt(client, p);
+ jingle_response(client, pak, "bad-request", NULL);
+ return -1;
+ }
+
+ rtpcodecs = ast_rtp_instance_get_codecs(p->rtp);
+ if (!rtpcodecs) {
+ ast_log(LOG_WARNING, "RTP instance has no codecs\n");
+ ast_hangup(chan);
+ jingle_free_pvt(client, p);
+ jingle_response(client, pak, "resource-constraint", NULL);
+ return -1;
+ }
+
while (content) {
- description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_AUDIO_RTP_NS);
+ /* We record the audio and video contents advertized by the
+ * remote Jingle client here. We'll compare that with our
+ * local capabilities later */
+ description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS);
if (description) {
- /* audio content found */
+ /* process audio content */
codec = iks_child(iks_child(content));
ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name));
while (codec) {
- ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
- ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+ ast_rtp_codecs_payloads_set_m_type(rtpcodecs, p->rtp, atoi(iks_find_attrib(codec, "id")));
+ ast_rtp_codecs_payloads_set_rtpmap_type(rtpcodecs, p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
codec = iks_next(codec);
}
}
@@ -1013,20 +1052,34 @@
description = NULL;
codec = NULL;
- description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_VIDEO_RTP_NS);
+ description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS);
if (description) {
- /* video content found */
+ /* process video content */
codec = iks_child(iks_child(content));
ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name));
while (codec) {
- ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
- ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+ ast_rtp_codecs_payloads_set_m_type(rtpcodecs, p->rtp, atoi(iks_find_attrib(codec, "id")));
+ ast_rtp_codecs_payloads_set_rtpmap_type(rtpcodecs, p->rtp, atoi(iks_find_attrib(codec, "id")), "video", iks_find_attrib(codec, "name"), 0);
codec = iks_next(codec);
}
}
content = iks_next(content);
+ }
+
+ /* now we can acknowledge the session-initiate message, and possibly
+ * terminate the session immediatly in case of an error */
+ jingle_response(client, pak, NULL, NULL);
+
+ ast_rtp_codecs_payload_formats(rtpcodecs, &p->peercapability, &p->peernoncodeccapability);
+ p->jointcapability = p->capability & p->peercapability;
+ if (!p->jointcapability) {
+ ast_debug(1, "No matching codec found.\n");
+ jingle_terminate(client, p, "failed-application");
+ p->alreadygone = 1;
+ ast_hangup(chan);
+ return -1;
}
ast_mutex_unlock(&p->lock);
@@ -1036,18 +1089,18 @@
switch (res) {
case AST_PBX_FAILED:
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
- jingle_response(client, pak, "service-unavailable", NULL);
+ jingle_terminate(client, p, "failed-application");
+ p->alreadygone = 1;
+ ast_hangup(chan);
break;
case AST_PBX_CALL_LIMIT:
ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
- jingle_response(client, pak, "service-unavailable", NULL);
+ jingle_terminate(client, p, "failed-application");
+ p->alreadygone = 1;
+ ast_hangup(chan);
break;
case AST_PBX_SUCCESS:
- jingle_response(client, pak, NULL, NULL);
- jingle_create_candidates(client, p,
- iks_find_attrib(pak->query, JINGLE_SID),
- iks_find_attrib(pak->x, "from"));
- /* nothing to do */
+ /* nothing to do here */
break;
}
@@ -1067,14 +1120,17 @@
tmp = p->theircandidates;
p->laststun = time(NULL);
while (tmp) {
- char username[256];
+ struct stun_credentials credentials;
hp = ast_gethostbyname(tmp->ip, &ahp);
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(tmp->port);
- snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag);
-
- ast_rtp_instance_stun_request(p->rtp, &sin, username);
+ ast_copy_string(credentials.local_ufrag, p->local_ufrag, sizeof(credentials.local_ufrag));
+ ast_copy_string(credentials.remote_ufrag, p->remote_ufrag, sizeof(credentials.remote_ufrag));
+ ast_copy_string(credentials.local_password, p->local_password, sizeof(credentials.local_password));
+ ast_copy_string(credentials.remote_password, p->remote_password, sizeof(credentials.remote_password));
+
+ ast_rtp_instance_stun_request(p->rtp, &sin, &credentials);
tmp = tmp->next;
}
return 1;
@@ -1108,17 +1164,20 @@
continue;
}
if(!strcasecmp(iks_name(traversenodes), "transport")) {
+ ast_copy_string(p->remote_ufrag, iks_find_attrib(traversenodes, "ufrag"), sizeof(p->remote_ufrag));
+ ast_copy_string(p->remote_password, iks_find_attrib(traversenodes, "pwd"), sizeof(p->remote_password));
traversenodes = iks_child(traversenodes);
continue;
}
if(!strcasecmp(iks_name(traversenodes), "candidate")) {
+ ast_log(LOG_NOTICE, "Processing candidate\n");
newcandidate = ast_calloc(1, sizeof(*newcandidate));
if (!newcandidate)
return 0;
+ ast_copy_string(newcandidate->id, iks_find_attrib(traversenodes, "id"), sizeof(newcandidate->id));
ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "ip"), sizeof(newcandidate->ip));
newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
- ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "pwd"), sizeof(newcandidate->password));
if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
newcandidate->protocol = AJI_PROTOCOL_UDP;
else if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
@@ -1135,7 +1194,6 @@
newcandidate->network = atoi(iks_find_attrib(traversenodes, "network"));
newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
- newcandidate->next = NULL;
newcandidate->next = p->theircandidates;
p->theircandidates = newcandidate;
@@ -1145,6 +1203,7 @@
}
traversenodes = iks_next(traversenodes);
}
+ ast_log(LOG_NOTICE, "Candidates parsed\n");
receipt = iks_new("iq");
iks_insert_attrib(receipt, "type", "result");
@@ -1161,10 +1220,29 @@
static struct ast_frame *jingle_rtp_read(struct ast_channel *ast, struct jingle_pvt *p)
{
struct ast_frame *f;
+ struct stun_credentials credentials;
if (!p->rtp)
return &ast_null_frame;
- f = ast_rtp_instance_read(p->rtp, 0);
+
+ ast_copy_string(credentials.local_ufrag, p->local_ufrag, sizeof(credentials.local_ufrag));
+ ast_copy_string(credentials.remote_ufrag, p->remote_ufrag, sizeof(credentials.remote_ufrag));
+ ast_copy_string(credentials.local_password, p->local_password, sizeof(credentials.local_password));
+ ast_copy_string(credentials.remote_password, p->remote_password, sizeof(credentials.remote_password));
+
+ switch (ast->fdno) {
+ case 0:
+ /* RTP auudio */
+ f = ast_rtp_instance_read(p->rtp, 0, &credentials);
+ break;
+ case 1:
+ /* RTCP audio control channel */
+ f = ast_rtp_instance_read(p->rtp, 1, &credentials);
+ break;
+ default:
+ f = &ast_null_frame;
+ }
+
jingle_update_stun(p->parent, p);
if (p->owner) {
/* We already hold the channel lock */
@@ -1357,6 +1435,7 @@
return -1;
}
+
static int jingle_transmit_invite(struct jingle_pvt *p)
{
struct jingle *aux = NULL;
@@ -1390,7 +1469,8 @@
[... 1106 lines stripped ...]
More information about the asterisk-commits
mailing list