mod_rayo FS-6081 --resolve added mixer presence with entity capabilities

This commit is contained in:
Chris Rienzo 2014-01-06 21:06:31 -05:00
parent 9efe980438
commit 587ba2ed52
3 changed files with 155 additions and 11 deletions

View File

@ -522,6 +522,29 @@ char *iks_server_dialback_key(const char *secret, const char *receiving_server,
return NULL;
}
/**
* Print base 64 encoded SHA-1 hash
* @param sha hash to print
* @param buf to store baes 64 encoded hash
*/
void iks_sha_print_base64(iksha *sha, char *buf)
{
int i;
char hex_digit[3] = { 0 };
char hex_buf[SHA_1_HASH_BUF_SIZE];
unsigned char bin_buf[SHA_1_HASH_BUF_SIZE / 2];
iks_sha_print(sha, hex_buf);
/* convert hex string to octets */
for (i = 0; i < SHA_1_HASH_BUF_SIZE; i += 2) {
hex_digit[0] = hex_buf[i];
hex_digit[1] = hex_buf[i + 1];
bin_buf[i / 2] = strtol(hex_digit, NULL, 16);
}
switch_b64_encode(bin_buf, SHA_1_HASH_BUF_SIZE / 2, (unsigned char *)buf, SHA_1_HASH_BUF_SIZE);
}
/* For Emacs:
* Local Variables:
* mode:c

View File

@ -32,6 +32,8 @@
#include <iksemel.h>
#include <switch.h>
#define SHA_1_HASH_BUF_SIZE 40
#define IKS_JABBER_SERVER_PORT 5269
#define IKS_NS_XMPP_DISCO "http://jabber.org/protocol/disco#info"
@ -40,6 +42,7 @@
#define IKS_NS_XMPP_STREAMS "http://etherx.jabber.org/streams"
#define IKS_NS_XMPP_DIALBACK "jabber:server:dialback"
#define IKS_NS_XMPP_TLS "urn:ietf:params:xml:ns:xmpp-tls"
#define IKS_NS_XMPP_ENTITY_CAPABILITIES "http://jabber.org/protocol/caps"
struct xmpp_error {
const char *name;
@ -53,7 +56,6 @@ struct xmpp_error {
#include "xmpp_errors.def"
/* See RFC-3920 XMPP core for error definitions */
extern iks *iks_new_presence(const char *name, const char *namespace, const char *from, const char *to);
extern iks *iks_new_error(iks *iq, const struct xmpp_error *err);
extern iks *iks_new_error_detailed(iks *iq, const struct xmpp_error *err, const char *detail_text);
@ -70,6 +72,7 @@ extern const char *iks_net_error_to_string(int err);
extern iks *iks_insert_attrib_printf(iks *xml, const char *name, const char *fmt, ...);
extern char *iks_server_dialback_key(const char *secret, const char *receiving_server, const char *originating_server, const char *stream_id);
extern void iks_sha_print_base64(iksha *sha, char *buf);
/** A function to validate attribute value */
typedef int (*iks_attrib_validation_function)(const char *);

View File

@ -170,9 +170,9 @@ struct rayo_mixer_member {
* A subscriber to mixer events
*/
struct rayo_mixer_subscriber {
/** JID of subscriber */
/** JID of client */
const char *jid;
/** Number of controlled parties in mixer */
/** Number of client's calls in mixer */
int ref_count;
};
@ -250,6 +250,54 @@ typedef switch_bool_t (* rayo_actor_match_fn)(struct rayo_actor *);
static switch_bool_t is_call_actor(struct rayo_actor *actor);
/**
* Entity features returned by service discovery
*/
struct entity_identity {
/** identity category */
const char *category;
/** identity type */
const char *type;
};
static struct entity_identity rayo_server_identity = { "server", "im" };
static const char *rayo_server_features[] = { IKS_NS_XMPP_ENTITY_CAPABILITIES, IKS_NS_XMPP_DISCO, RAYO_NS, RAYO_CPA_NS, RAYO_FAX_NS, 0 };
static struct entity_identity rayo_mixer_identity = { "client", "rayo_mixer" };
static const char *rayo_mixer_features[] = { 0 };
static struct entity_identity rayo_call_identity = { "client", "rayo_call" };
static const char *rayo_call_features[] = { 0 };
/**
* Calculate SHA-1 hash of entity capabilities
* @param identity of entity
* @param features of identity (NULL terminated)
* @return base64 hash (free when done)
*/
static char *calculate_entity_sha1_ver(struct entity_identity *identity, const char **features)
{
int i;
const char *feature;
char ver[SHA_1_HASH_BUF_SIZE + 1] = { 0 };
iksha *sha;
sha = iks_sha_new();
iks_sha_hash(sha, (const unsigned char *)identity->category, strlen(identity->category), 0);
iks_sha_hash(sha, (const unsigned char *)"/", 1, 0);
iks_sha_hash(sha, (const unsigned char *)identity->type, strlen(identity->type), 0);
iks_sha_hash(sha, (const unsigned char *)"//", 2, 0);
i = 0;
while ((feature = features[i++])) {
iks_sha_hash(sha, (const unsigned char *)"<", 1, 0);
iks_sha_hash(sha, (const unsigned char *)feature, strlen(feature), 0);
}
iks_sha_hash(sha, (const unsigned char *)"<", 1, 1);
iks_sha_print_base64(sha, ver);
iks_sha_delete(sha);
return strdup(ver);
}
/**
* @param msg to check
@ -408,6 +456,32 @@ static void add_header(iks *node, const char *name, const char *value)
}
}
/**
* Send event to clients
* @param from event sender
* @param rayo_event the event to send
* @param online_only only send to online clients
*/
static void broadcast_event(struct rayo_actor *from, iks *rayo_event, int online_only)
{
switch_hash_index_t *hi = NULL;
switch_mutex_lock(globals.clients_mutex);
for (hi = switch_hash_first(NULL, globals.clients_roster); hi; hi = switch_hash_next(hi)) {
struct rayo_client *rclient;
const void *key;
void *val;
switch_hash_this(hi, &key, NULL, &val);
rclient = (struct rayo_client *)val;
switch_assert(rclient);
if (!online_only || rclient->availability == PS_ONLINE) {
iks_insert_attrib(rayo_event, "to", RAYO_JID(rclient));
RAYO_SEND_MESSAGE_DUP(from, RAYO_JID(rclient), rayo_event);
}
}
switch_mutex_unlock(globals.clients_mutex);
}
/**
* Add an outbound dialing gateway
* @param uri_prefix to match
@ -2445,15 +2519,20 @@ static iks *on_iq_get_xmpp_disco(struct rayo_actor *server, struct rayo_message
iks *response = NULL;
iks *x;
iks *feature;
iks *identity;
int i = 0;
const char *feature_string;
response = iks_new_iq_result(node);
x = iks_insert(response, "query");
iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_DISCO);
identity = iks_insert(x, "identity");
iks_insert_attrib(identity, "category", rayo_server_identity.category);
iks_insert_attrib(identity, "type", rayo_server_identity.type);
i = 0;
while((feature_string = rayo_server_features[i++])) {
feature = iks_insert(x, "feature");
iks_insert_attrib(feature, "var", RAYO_NS);
feature = iks_insert(x, "feature");
iks_insert_attrib(feature, "var", RAYO_CPA_NS);
feature = iks_insert(x, "feature");
iks_insert_attrib(feature, "var", RAYO_FAX_NS);
iks_insert_attrib(feature, "var", feature_string);
}
/* TODO The response MUST also include features for the application formats and transport methods supported by
* the responding entity, as described in the relevant specifications.
@ -2669,6 +2748,15 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_
static void on_mixer_destroy_event(struct rayo_mixer *mixer, switch_event_t *event)
{
if (mixer) {
iks *presence;
/* notify online clients of mixer destruction */
presence = iks_new("presence");
iks_insert_attrib(presence, "from", RAYO_JID(mixer));
iks_insert_attrib(presence, "type", "unavailable");
broadcast_event(RAYO_ACTOR(mixer), presence, 1);
iks_delete(presence);
/* remove from hash and destroy */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, destroying mixer: %s\n", RAYO_JID(mixer), rayo_mixer_get_name(mixer));
RAYO_UNLOCK(mixer); /* release original lock */
@ -2688,10 +2776,25 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
if (!mixer) {
char *ver;
iks *presence, *c;
/* new mixer */
const char *mixer_name = switch_event_get_header(event, "Conference-Name");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "creating mixer: %s\n", mixer_name);
mixer = rayo_mixer_create(mixer_name);
/* notify online clients of mixer presence */
ver = calculate_entity_sha1_ver(&rayo_mixer_identity, rayo_mixer_features);
presence = iks_new_presence("c", IKS_NS_XMPP_ENTITY_CAPABILITIES, RAYO_JID(mixer), "");
c = iks_find(presence, "c");
iks_insert_attrib(c, "hash", "sha-1");
iks_insert_attrib(c, "node", RAYO_MIXER_NS);
iks_insert_attrib(c, "ver", ver);
free(ver);
broadcast_event(RAYO_ACTOR(mixer), presence, 1);
}
if (call) {
@ -2719,6 +2822,9 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
if (call->pending_join_request) {
iks *request = call->pending_join_request;
iks *result = iks_new_iq_result(request);
iks *ref = iks_insert(result, "ref");
iks_insert_attrib(ref, "xmlns", RAYO_NS);
iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(mixer));
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
@ -3135,12 +3241,24 @@ static iks *rayo_create_offer(struct rayo_call *call, switch_core_session_t *ses
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel);
iks *presence = iks_new("presence");
iks *c = iks_insert(presence, "c");
iks *offer = iks_insert(presence, "offer");
const char *val;
char *ver;
/* <presence> */
iks_insert_attrib(presence, "from", RAYO_JID(call));
iks_insert_attrib(offer, "xmlns", RAYO_NS);
/* <c> */
ver = calculate_entity_sha1_ver(&rayo_call_identity, rayo_call_features);
iks_insert_attrib(c, "xmlns", IKS_NS_XMPP_ENTITY_CAPABILITIES);
iks_insert_attrib(c, "hash", "sha-1");
iks_insert_attrib(c, "node", RAYO_CALL_NS);
iks_insert_attrib(c, "ver", ver);
free(ver);
/* <offer> */
iks_insert_attrib(offer, "xmlns", RAYO_NS);
if (globals.offer_uri && (val = switch_channel_get_variable(channel, "sip_from_uri"))) {
/* is a SIP call - pass the URI */
if (!strchr(val, ':')) {
@ -3287,8 +3405,8 @@ SWITCH_STANDARD_APP(rayo_app)
RAYO_SEND_MESSAGE_DUP(call, RAYO_JID(rclient), offer);
}
}
iks_delete(offer);
switch_mutex_unlock(globals.clients_mutex);
iks_delete(offer);
/* nobody to offer to */
if (!ok) {