return actor;
}
+/**
+ * Handle stream resource binding
+ * @param stream the new stream
+ */
+static int on_xmpp_stream_bind(struct xmpp_stream *stream)
+{
+ if (!xmpp_stream_is_s2s(stream)) {
+ /* client belongs to stream */
+ struct rayo_client *client = rayo_client_create(xmpp_stream_get_jid(stream), xmpp_stream_get_jid(stream), PS_OFFLINE, rayo_client_send, NULL);
+ if (client) {
+ xmpp_stream_set_private(stream, client);
+ } else {
+ /* this went really bad... */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create client entity!\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+
/**
* Handle new stream creation
* @param stream the new stream
*/
-static void on_xmpp_stream_ready(struct xmpp_stream *stream)
+static int on_xmpp_stream_ready(struct xmpp_stream *stream)
{
if (xmpp_stream_is_s2s(stream)) {
if (xmpp_stream_is_incoming(stream)) {
} else {
/* this went really bad... */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create peer server entity!\n");
+ return 0;
}
} else {
/* send directed presence to domain */
iks_insert_cdata(x, "chat", 4);
RAYO_SEND_MESSAGE(globals.server, xmpp_stream_get_jid(stream), presence);
}
- } else {
- /* client belongs to stream */
- struct rayo_client *client = rayo_client_create(xmpp_stream_get_jid(stream), xmpp_stream_get_jid(stream), PS_OFFLINE, rayo_client_send, NULL);
- if (client) {
- xmpp_stream_set_private(stream, client);
- } else {
- /* this went really bad... */
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create client entity!\n");
- }
}
+ return 1;
}
/**
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing shared secret for %s domain. Server dialback will not work\n", name);
}
- globals.xmpp_context = xmpp_stream_context_create(name, shared_secret, on_xmpp_stream_ready, on_xmpp_stream_recv, on_xmpp_stream_destroy);
+ globals.xmpp_context = xmpp_stream_context_create(name, shared_secret, on_xmpp_stream_bind, on_xmpp_stream_ready, on_xmpp_stream_recv, on_xmpp_stream_destroy);
globals.server = rayo_server_create(name);
/* set up TLS */
/*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2013, Grasshopper
+ * Copyright (C) 2013-2015, Grasshopper
*
* Version: MPL 1.1
*
switch_hash_t *users;
/** shared secret for server dialback */
const char *dialback_secret;
+ /** callback when a new resource is bound */
+ xmpp_stream_bind_callback bind_callback;
/** callback when a new stream is ready */
xmpp_stream_ready_callback ready_callback;
/** callback when a stream is destroyed */
switch(stream->state) {
case XSS_RESOURCE_BOUND: {
- reply = iks_new_iq_result(node);
- stream->state = XSS_READY;
-
- /* add to available streams */
- switch_mutex_lock(context->streams_mutex);
- switch_core_hash_insert(context->routes, stream->jid, stream);
- switch_mutex_unlock(context->streams_mutex);
+ if (context->ready_callback && !context->ready_callback(stream)) {
+ reply = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR);
+ stream->state = XSS_ERROR;
+ } else {
+ reply = iks_new_iq_result(node);
+ stream->state = XSS_READY;
- if (context->ready_callback) {
- context->ready_callback(stream);
+ /* add to available streams */
+ switch_mutex_lock(context->streams_mutex);
+ switch_core_hash_insert(context->routes, stream->jid, stream);
+ switch_mutex_unlock(context->streams_mutex);
}
+
break;
}
case XSS_AUTHENTICATED:
switch(stream->state) {
case XSS_AUTHENTICATED: {
+ struct xmpp_stream_context *context = stream->context;
iks *bind = iks_find(node, "bind");
iks *x;
/* get optional client resource ID */
switch_uuid_str(resource_id_buf, sizeof(resource_id_buf));
resource_id = switch_core_strdup(stream->pool, resource_id_buf);
}
+
stream->jid = switch_core_sprintf(stream->pool, "%s/%s", stream->jid, resource_id);
- stream->state = XSS_RESOURCE_BOUND;
+ if (context->bind_callback && !context->bind_callback(stream)) {
+ stream->jid = NULL;
+ reply = iks_new_error(node, STANZA_ERROR_CONFLICT);
+ } else {
+ stream->state = XSS_RESOURCE_BOUND;
- /* create reply */
- reply = iks_new_iq_result(node);
- x = iks_insert(reply, "bind");
- iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_BIND);
- iks_insert_cdata(iks_insert(x, "jid"), stream->jid, strlen(stream->jid));
+ reply = iks_new_iq_result(node);
+ x = iks_insert(reply, "bind");
+ iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_BIND);
+ iks_insert_cdata(iks_insert(x, "jid"), stream->jid, strlen(stream->jid));
+ }
break;
}
default:
/* TODO check domain pair and allow access if pending request exists */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_DEBUG, "%s, %s:%i, valid dialback result\n", stream->jid, stream->address, stream->port);
- /* this stream is routable */
- stream->state = XSS_READY;
-
- /* add to available streams */
- switch_mutex_lock(context->streams_mutex);
- switch_core_hash_insert(context->routes, stream->jid, stream);
- switch_mutex_unlock(context->streams_mutex);
+ if (context->ready_callback && !context->ready_callback(stream)) {
+ stream->state = XSS_ERROR;
+ } else {
+ /* this stream is routable */
+ stream->state = XSS_READY;
- if (context->ready_callback) {
- context->ready_callback(stream);
+ /* add to available streams */
+ switch_mutex_lock(context->streams_mutex);
+ switch_core_hash_insert(context->routes, stream->jid, stream);
+ switch_mutex_unlock(context->streams_mutex);
}
}
return;
}
+ /* this stream is not routable */
+ stream->state = XSS_READY;
+ stream->jid = switch_core_strdup(stream->pool, from);
+
+ if (context->ready_callback && !context->ready_callback(stream)) {
+ iks *error = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR);
+ iks_send(stream->parser, error);
+ iks_delete(error);
+ stream->state = XSS_ERROR;
+ return;
+ }
+
/* TODO validate key */
reply = iks_new("db:result");
iks_insert_attrib(reply, "from", to);
iks_insert_attrib(reply, "type", "valid");
iks_send(stream->parser, reply);
iks_delete(reply);
-
- /* this stream is not routable */
- stream->state = XSS_READY;
- stream->jid = switch_core_strdup(stream->pool, from);
-
- if (context->ready_callback) {
- context->ready_callback(stream);
- }
}
/**
case XSS_SECURE:
break;
case XSS_AUTHENTICATED: {
+ if (context->ready_callback && !context->ready_callback(stream)) {
+ stream->state = XSS_ERROR;
+ break;
+ }
+
/* all set */
xmpp_send_server_header_features(stream);
stream->state = XSS_READY;
switch_mutex_lock(context->streams_mutex);
switch_core_hash_insert(context->routes, stream->jid, stream);
switch_mutex_unlock(context->streams_mutex);
-
- if (context->ready_callback) {
- context->ready_callback(stream);
- }
break;
}
case XSS_SHUTDOWN:
* Create a new XMPP stream context
* @param domain for new streams
* @param domain_secret domain shared secret for server dialback
+ * @param bind_cb callback function when a resource is bound to a new stream
* @param ready callback function when new stream is ready
* @param recv callback function when a new stanza is received
* @param destroy callback function when a stream is destroyed
* @return the context
*/
-struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy)
+struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_bind_callback bind_cb, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy)
{
switch_memory_pool_t *pool;
struct xmpp_stream_context *context;
switch_core_hash_init(&context->routes);
switch_core_hash_init(&context->streams);
context->dialback_secret = switch_core_strdup(context->pool, domain_secret);
+ context->bind_callback = bind_cb;
context->ready_callback = ready;
context->destroy_callback = destroy;
context->recv_callback = recv;