mod_rayo FS-6081 --resolve added mixer presence with entity capabilities
This commit is contained in:
parent
9efe980438
commit
587ba2ed52
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue