chan_motif.c File Reference

Motif Jingle Channel Driver. More...

#include "asterisk.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include <iksemel.h>
#include <pthread.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config_options.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/stringfields.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/xmpp.h"
#include "asterisk/endpoints.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/format_cache.h"

Include dependency graph for chan_motif.c:

Go to the source code of this file.

Data Structures

struct  jingle_action_handler
 Defined handlers for different Jingle actions. More...
struct  jingle_config
struct  jingle_endpoint
 Endpoint which contains configuration information and active sessions. More...
struct  jingle_endpoint_state
 Endpoint state information. More...
struct  jingle_reason_mapping
 Reason text <-> cause code mapping. More...
struct  jingle_session
 Session which contains information about an active session. More...

Defines

#define DEFAULT_MAX_ICE_CANDIDATES   "10"
 Default maximum number of ICE candidates we will offer.
#define DEFAULT_MAX_PAYLOADS   "30"
 Default maximum number of payloads we will offer.
#define ENDPOINT_BUCKETS   37
 Number of buckets for endpoints.
#define GOOGLE_PHONE_NS   "http://www.google.com/session/phone"
 Namespace for Google Phone description.
#define GOOGLE_SESSION_NS   "http://www.google.com/session"
 Namespace for Google Session.
#define GOOGLE_TRANSPORT_NS   "http://www.google.com/transport/p2p"
 Namespace for Google Talk ICE-UDP.
#define GOOGLE_TRANSPORT_RAW_NS   "http://www.google.com/transport/raw-udp"
 Namespace for Google Talk Raw UDP.
#define GOOGLE_VIDEO_NS   "http://www.google.com/session/video"
 Namespace for Google Video description.
#define JINGLE_ICE_UDP_NS   "urn:xmpp:jingle:transports:ice-udp:1"
 Namespace for Jingle ICE-UDP.
#define JINGLE_NS   "urn:xmpp:jingle:1"
 Namespace for Jingle itself.
#define JINGLE_RTP_INFO_NS   "urn:xmpp:jingle:apps:rtp:info:1"
 Namespace for Jingle RTP info.
#define JINGLE_RTP_NS   "urn:xmpp:jingle:apps:rtp:1"
 Namespace for Jingle RTP sessions.
#define SESSION_BUCKETS   37
 Number of buckets for sessions, on a per-endpoint basis.
#define XMPP_STANZAS_NS   "urn:ietf:params:xml:ns:xmpp-stanzas"
 Namespace for XMPP stanzas.

Enumerations

enum  jingle_transport { JINGLE_TRANSPORT_ICE_UDP = 3, JINGLE_TRANSPORT_GOOGLE_V2 = 2, JINGLE_TRANSPORT_GOOGLE_V1 = 1, JINGLE_TRANSPORT_NONE = 0 }
 The various transport methods supported, from highest priority to lowest priority when doing fallback. More...

Functions

static void __reg_module (void)
static void __unreg_module (void)
static AO2_GLOBAL_OBJ_STATIC (globals)
 CONFIG_INFO_STANDARD (cfg_info, globals, jingle_config_alloc,.files=ACO_FILES(&jingle_conf),)
static int custom_connection_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 Custom handler for connection.
static int custom_group_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 Custom handler for groups.
static int custom_transport_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 Custom handler for transport.
static int jingle_action_hook (void *data, ikspak *pak)
 Callback for when a Jingle action is received from an endpoint.
static void jingle_action_session_accept (struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
 Handler function for the 'session-accept' action.
static void jingle_action_session_info (struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
 Handler function for the 'session-info' action.
static void jingle_action_session_initiate (struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
 Action handlers.
static void jingle_action_session_terminate (struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
 Handler function for the 'session-terminate' action.
static void jingle_action_transport_info (struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
 Handler function for the 'transport-info' action.
static int jingle_add_content (struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport, const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads)
 Helper function which adds content to a description.
static int jingle_add_google_candidates_to_transport (struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int video, enum jingle_transport transport_type, unsigned int maximum)
 Internal helper function which adds Google candidates to a transport node.
static int jingle_add_ice_udp_candidates_to_transport (struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
 Internal helper function which adds ICE-UDP candidates to a transport node.
static int jingle_add_payloads_to_description (struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_media_type type)
 Internal helper function which adds payloads to a description.
static struct jingle_sessionjingle_alloc (struct jingle_endpoint *endpoint, const char *from, const char *sid)
 Internal helper function used to allocate Jingle session on an endpoint.
static int jingle_answer (struct ast_channel *ast)
 Function called by core when we should answer a Jingle session.
static int jingle_call (struct ast_channel *ast, const char *dest, int timeout)
 Function called by core to actually start calling a remote party.
static void * jingle_config_alloc (void)
 Allocator called when module configuration should appear.
static void jingle_config_destructor (void *obj)
 Destructor called when module configuration goes away.
static int jingle_digit_begin (struct ast_channel *chan, char digit)
 Function called by core to start a DTMF digit.
static int jingle_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
 Function called by core to stop a DTMF digit.
static void jingle_enable_video (struct jingle_session *session)
 Internal helper function which enables video support on a sesson if possible.
static void * jingle_endpoint_alloc (const char *cat)
 Allocator function for Jingle endpoints.
static int jingle_endpoint_cmp (void *obj, void *arg, int flags)
 Comparator function for Jingle endpoints.
static void jingle_endpoint_destructor (void *obj)
 Destructor for Jingle endpoints.
static void * jingle_endpoint_find (struct ao2_container *tmp_container, const char *category)
 Find function for Jingle endpoints.
static int jingle_endpoint_hash (const void *obj, const int flags)
 Hashing function for Jingle endpoints.
static struct
jingle_endpoint_state
jingle_endpoint_state_create (void)
 Allocator function for Jingle endpoint state.
static void jingle_endpoint_state_destructor (void *obj)
 Destructor for Jingle endpoint state.
static struct
jingle_endpoint_state
jingle_endpoint_state_find_or_create (const char *category)
 State find/create function.
static int jingle_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
 Function called by core to change the underlying owner channel.
static void jingle_get_codec (struct ast_channel *chan, struct ast_format_cap *result)
 Function called by RTP engine to get peer capabilities.
static enum ast_rtp_glue_result jingle_get_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance **instance)
 Function called by RTP engine to get local RTP peer.
static int jingle_hangup (struct ast_channel *ast)
 Function called by core to hang up a Jingle session.
static int jingle_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
 Function called by core to ask the channel to indicate some sort of condition.
static int jingle_interpret_content (struct jingle_session *session, ikspak *pak)
 Helper function which locates content stanzas and interprets them.
static int jingle_interpret_description (struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
 Helper function which handles content descriptions.
static int jingle_interpret_google_transport (struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
 Helper function which handles Google transport information.
static int jingle_interpret_ice_udp_transport (struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
 Helper function which handles ICE-UDP transport information.
static struct ast_channeljingle_new (struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
 Function called to create a new Jingle Asterisk channel.
static int jingle_outgoing_hook (void *data, ikspak *pak)
 Callback for when a response is received for an outgoing session-initiate message.
static void jingle_queue_hangup_with_cause (struct jingle_session *session, int cause)
 Helper function which queues a hangup frame with cause code.
static struct ast_framejingle_read (struct ast_channel *ast)
 Function called by core to read any waiting frames.
static struct ast_channeljingle_request (const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 Function called by core to create a new outgoing Jingle session.
static void jingle_send_error_response (struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
 Internal helper function which sends an error response.
static void jingle_send_response (struct ast_xmpp_client *connection, ikspak *pak)
 Internal helper function which sends a response.
static void jingle_send_session_accept (struct jingle_session *session)
 Internal function which sends a session-accept message.
static void jingle_send_session_action (struct jingle_session *session, const char *action)
 Internal function which sends a complete session message.
static void jingle_send_session_info (struct jingle_session *session, const char *info)
 Internal function which sends a session-info message.
static void jingle_send_session_initiate (struct jingle_session *session)
 Internal function which sends a session-inititate message.
static void jingle_send_session_terminate (struct jingle_session *session, const char *reasontext)
 Internal function which sends a session-terminate message.
static void jingle_send_transport_info (struct jingle_session *session, const char *from)
 Internal function which sends a transport-info message.
static int jingle_sendtext (struct ast_channel *chan, const char *text)
 Function called by core to send text to the remote party of the Jingle session.
static int jingle_session_cmp (void *obj, void *arg, int flags)
 Comparator function for Jingle sessions.
static void jingle_session_destructor (void *obj)
 Destructor for Jingle sessions.
static int jingle_session_hash (const void *obj, const int flags)
 Hashing function for Jingle sessions.
static struct ast_channeljingle_session_lock_full (struct jingle_session *pvt)
static void jingle_set_owner (struct jingle_session *session, struct ast_channel *chan)
 Set the channel owner on the jingle_session object and related objects.
static int jingle_set_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
 Function called by RTP engine to change where the remote party should send media.
static int jingle_write (struct ast_channel *ast, struct ast_frame *frame)
 Function called by core to write frames.
static int load_module (void)
 Load the module.
static int reload (void)
 Reload module.
static int unload_module (void)
 Unload the jingle channel from Asterisk.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Motif Jingle Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static struct ast_module_infoast_module_info = &__mod_info
static const char channel_type [] = "Motif"
static const char desc [] = "Motif Jingle Channel"
static struct aco_type endpoint_option
struct aco_typeendpoint_options [] = ACO_TYPES(&endpoint_option)
static struct jingle_action_handler jingle_action_handlers []
 Defined handlers for different Jingle actions.
struct aco_file jingle_conf
static struct jingle_reason_mapping jingle_reason_mappings []
 Reason text <-> cause code mapping.
static struct ast_rtp_glue jingle_rtp_glue
 Local glue for interacting with the RTP engine core.
static struct ast_channel_tech jingle_tech
 PBX interface structure for channel registration.
static struct ast_sched_contextsched


Detailed Description

Motif Jingle Channel Driver.

Author:
Joshua Colp <jcolp@digium.com>
Iksemel http://iksemel.jabberstudio.org/

Definition in file chan_motif.c.


Define Documentation

#define DEFAULT_MAX_ICE_CANDIDATES   "10"

Default maximum number of ICE candidates we will offer.

Definition at line 222 of file chan_motif.c.

Referenced by load_module().

#define DEFAULT_MAX_PAYLOADS   "30"

Default maximum number of payloads we will offer.

Definition at line 225 of file chan_motif.c.

Referenced by load_module().

#define ENDPOINT_BUCKETS   37

Number of buckets for endpoints.

Definition at line 228 of file chan_motif.c.

Referenced by ast_endpoint_init(), and jingle_config_alloc().

#define GOOGLE_PHONE_NS   "http://www.google.com/session/phone"

Namespace for Google Phone description.

Definition at line 255 of file chan_motif.c.

Referenced by jingle_add_content(), jingle_add_payloads_to_description(), and jingle_interpret_content().

#define GOOGLE_SESSION_NS   "http://www.google.com/session"

#define GOOGLE_TRANSPORT_NS   "http://www.google.com/transport/p2p"

Namespace for Google Talk ICE-UDP.

Definition at line 246 of file chan_motif.c.

Referenced by jingle_add_content(), jingle_add_google_candidates_to_transport(), and jingle_interpret_content().

#define GOOGLE_TRANSPORT_RAW_NS   "http://www.google.com/transport/raw-udp"

Namespace for Google Talk Raw UDP.

Definition at line 249 of file chan_motif.c.

#define GOOGLE_VIDEO_NS   "http://www.google.com/session/video"

Namespace for Google Video description.

Definition at line 258 of file chan_motif.c.

Referenced by jingle_interpret_content().

#define JINGLE_ICE_UDP_NS   "urn:xmpp:jingle:transports:ice-udp:1"

Namespace for Jingle ICE-UDP.

Definition at line 243 of file chan_motif.c.

Referenced by jingle_add_content(), jingle_add_ice_udp_candidates_to_transport(), and jingle_interpret_content().

#define JINGLE_NS   "urn:xmpp:jingle:1"

#define JINGLE_RTP_INFO_NS   "urn:xmpp:jingle:apps:rtp:info:1"

Namespace for Jingle RTP info.

Definition at line 240 of file chan_motif.c.

Referenced by jingle_action_session_info().

#define JINGLE_RTP_NS   "urn:xmpp:jingle:apps:rtp:1"

Namespace for Jingle RTP sessions.

Definition at line 237 of file chan_motif.c.

Referenced by jingle_add_content(), and jingle_interpret_content().

#define SESSION_BUCKETS   37

Number of buckets for sessions, on a per-endpoint basis.

Definition at line 231 of file chan_motif.c.

Referenced by jingle_endpoint_state_create().

#define XMPP_STANZAS_NS   "urn:ietf:params:xml:ns:xmpp-stanzas"

Namespace for XMPP stanzas.

Definition at line 261 of file chan_motif.c.

Referenced by jingle_outgoing_hook().


Enumeration Type Documentation

The various transport methods supported, from highest priority to lowest priority when doing fallback.

Enumerator:
JINGLE_TRANSPORT_ICE_UDP  XEP-0176
JINGLE_TRANSPORT_GOOGLE_V2  https://developers.google.com/talk/call_signaling
JINGLE_TRANSPORT_GOOGLE_V1  Undocumented initial Google specification
JINGLE_TRANSPORT_NONE  No transport specified

Definition at line 264 of file chan_motif.c.

00264                       {
00265    JINGLE_TRANSPORT_ICE_UDP = 3,   /*!< XEP-0176 */
00266    JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
00267    JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
00268    JINGLE_TRANSPORT_NONE = 0,      /*!< No transport specified */
00269 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2827 of file chan_motif.c.

static void __unreg_module ( void   )  [static]

Definition at line 2827 of file chan_motif.c.

static AO2_GLOBAL_OBJ_STATIC ( globals   )  [static]

CONFIG_INFO_STANDARD ( cfg_info  ,
globals  ,
jingle_config_alloc  ,
files = ACO_FILES(&jingle_conf) 
)

static int custom_connection_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Custom handler for connection.

Definition at line 2672 of file chan_motif.c.

References ast_log, ast_xmpp_client_find(), jingle_endpoint::connection, ast_xmpp_client::filter, GOOGLE_SESSION_NS, jingle_action_hook(), JINGLE_NS, LOG_ERROR, jingle_endpoint::name, jingle_endpoint::rule, and ast_variable::value.

Referenced by load_module().

02673 {
02674    struct jingle_endpoint *endpoint = obj;
02675 
02676    /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
02677     * this will not actually get called, so even if the config turns out to be bogus this is harmless.
02678     */
02679    if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
02680       ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
02681       return -1;
02682    }
02683 
02684    if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
02685                      IKS_RULE_TYPE, IKS_PAK_IQ,
02686                      IKS_RULE_NS, JINGLE_NS,
02687                      IKS_RULE_NS, GOOGLE_SESSION_NS,
02688                      IKS_RULE_DONE))) {
02689       ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
02690       return -1;
02691    }
02692 
02693    return 0;
02694 }

static int custom_group_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Custom handler for groups.

Definition at line 2656 of file chan_motif.c.

References ast_get_group(), jingle_endpoint::callgroup, ast_variable::name, jingle_endpoint::pickupgroup, and ast_variable::value.

Referenced by load_module().

02657 {
02658    struct jingle_endpoint *endpoint = obj;
02659 
02660    if (!strcasecmp(var->name, "callgroup")) {
02661       endpoint->callgroup = ast_get_group(var->value);
02662    } else if (!strcasecmp(var->name, "pickupgroup")) {
02663       endpoint->pickupgroup = ast_get_group(var->value);
02664    } else {
02665       return -1;
02666    }
02667 
02668    return 0;
02669 }

static int custom_transport_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Custom handler for transport.

Definition at line 2697 of file chan_motif.c.

References ast_log, JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, JINGLE_TRANSPORT_ICE_UDP, LOG_WARNING, jingle_endpoint::name, jingle_endpoint::transport, and ast_variable::value.

Referenced by load_module().

02698 {
02699    struct jingle_endpoint *endpoint = obj;
02700 
02701    if (!strcasecmp(var->value, "ice-udp")) {
02702       endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02703    } else if (!strcasecmp(var->value, "google")) {
02704       endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02705    } else if (!strcasecmp(var->value, "google-v1")) {
02706       endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
02707    } else {
02708       ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
02709       endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02710    }
02711 
02712    return 0;
02713 }

static int jingle_action_hook ( void *  data,
ikspak *  pak 
) [static]

Callback for when a Jingle action is received from an endpoint.

Definition at line 2593 of file chan_motif.c.

References ao2_find, ao2_ref, ARRAY_LEN, ast_callid_threadassoc_add(), ast_callid_threadassoc_remove(), ast_log, ast_strlen_zero, jingle_session::callid, jingle_action_handler::handler, jingle_action_handlers, LOG_NOTICE, NULL, OBJ_KEY, session, jingle_endpoint_state::sessions, and jingle_endpoint::state.

Referenced by custom_connection_handler().

02594 {
02595    char *action;
02596    const char *sid = NULL;
02597    struct jingle_session *session = NULL;
02598    struct jingle_endpoint *endpoint = data;
02599    int i, handled = 0;
02600 
02601    /* We accept both Jingle and Google-V1 */
02602    if (!(action = iks_find_attrib(pak->query, "action")) &&
02603        !(action = iks_find_attrib(pak->query, "type"))) {
02604       /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
02605        * to a message that has no response hook. */
02606       return IKS_FILTER_EAT;
02607    }
02608 
02609    /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
02610     * does not permit us to make this completely safe. */
02611    ao2_ref(endpoint, +1);
02612 
02613    /* If a Jingle session identifier is present use it */
02614    if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02615       /* If a Google-V1 session identifier is present use it */
02616       sid = iks_find_attrib(pak->query, "id");
02617    }
02618 
02619    /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
02620     * this is required or not */
02621    if (!ast_strlen_zero(sid)) {
02622       session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
02623    }
02624 
02625    /* If a session is present associate the callid with this thread */
02626    if (session) {
02627       ast_callid_threadassoc_add(session->callid);
02628    }
02629 
02630    /* Iterate through supported action handlers looking for one that is able to handle this */
02631    for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
02632       if (!strcasecmp(jingle_action_handlers[i].action, action)) {
02633          jingle_action_handlers[i].handler(endpoint, session, pak);
02634          handled = 1;
02635          break;
02636       }
02637    }
02638 
02639    /* If no action handler is present for the action they sent us make it evident */
02640    if (!handled) {
02641       ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
02642    }
02643 
02644    /* If a session was successfully found for this message deref it now since the handler is done */
02645    if (session) {
02646       ast_callid_threadassoc_remove();
02647       ao2_ref(session, -1);
02648    }
02649 
02650    ao2_ref(endpoint, -1);
02651 
02652    return IKS_FILTER_EAT;
02653 }

static void jingle_action_session_accept ( struct jingle_endpoint endpoint,
struct jingle_session session,
ikspak *  pak 
) [static]

Handler function for the 'session-accept' action.

Definition at line 2472 of file chan_motif.c.

References ao2_unlock, ast_channel_unlock, ast_channel_unref, AST_CONTROL_ANSWER, ast_queue_control(), jingle_endpoint::connection, jingle_interpret_content(), jingle_send_error_response(), jingle_send_response(), and jingle_session_lock_full().

02473 {
02474    struct ast_channel *chan;
02475 
02476    if (!session) {
02477       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02478                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02479       return;
02480    }
02481 
02482 
02483    jingle_interpret_content(session, pak);
02484 
02485    if ((chan = jingle_session_lock_full(session))) {
02486       ast_queue_control(chan, AST_CONTROL_ANSWER);
02487       ast_channel_unlock(chan);
02488       ast_channel_unref(chan);
02489    }
02490    ao2_unlock(session);
02491 
02492    jingle_send_response(endpoint->connection, pak);
02493 }

static void jingle_action_session_info ( struct jingle_endpoint endpoint,
struct jingle_session session,
ikspak *  pak 
) [static]

Handler function for the 'session-info' action.

Definition at line 2496 of file chan_motif.c.

References ao2_unlock, ast_channel_unlock, ast_channel_unref, AST_CONTROL_RINGING, ast_queue_control(), ast_queue_hold(), ast_queue_unhold(), ast_setstate(), AST_STATE_RINGING, AST_STATE_UP, jingle_endpoint::connection, JINGLE_RTP_INFO_NS, jingle_send_error_response(), jingle_send_response(), jingle_session_lock_full(), and NULL.

02497 {
02498    struct ast_channel *chan;
02499 
02500    if (!session) {
02501       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02502                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02503       return;
02504    }
02505 
02506    if (!(chan = jingle_session_lock_full(session))) {
02507       ao2_unlock(session);
02508       jingle_send_response(endpoint->connection, pak);
02509       return;
02510    }
02511 
02512    if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
02513       ast_queue_control(chan, AST_CONTROL_RINGING);
02514       if (ast_channel_state(chan) != AST_STATE_UP) {
02515          ast_setstate(chan, AST_STATE_RINGING);
02516       }
02517    } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
02518       ast_queue_hold(chan, NULL);
02519    } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
02520       ast_queue_unhold(chan);
02521    }
02522 
02523    ast_channel_unlock(chan);
02524    ast_channel_unref(chan);
02525    ao2_unlock(session);
02526 
02527    jingle_send_response(endpoint->connection, pak);
02528 }

static void jingle_action_session_initiate ( struct jingle_endpoint endpoint,
struct jingle_session session,
ikspak *  pak 
) [static]

Action handlers.

Handler function for the 'session-initiate' action.

Definition at line 2388 of file chan_motif.c.

References ao2_link, ao2_ref, ast_channel_lock, ast_channel_unlock, ast_hangup(), ast_log, AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, jingle_endpoint::connection, jingle_session::gone, jingle_alloc(), jingle_interpret_content(), jingle_new(), jingle_send_error_response(), jingle_send_response(), jingle_send_transport_info(), JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_NONE, LOG_WARNING, NULL, jingle_endpoint_state::sessions, jingle_endpoint::state, and jingle_session::transport.

02389 {
02390    char *sid;
02391    enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
02392    struct ast_channel *chan;
02393    int res;
02394 
02395    if (session) {
02396       /* This is a duplicate session setup, so respond accordingly */
02397       jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
02398       return;
02399    }
02400 
02401    /* Retrieve the session identifier from the message, note that this may alter the transport */
02402    if ((sid = iks_find_attrib(pak->query, "id"))) {
02403       /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
02404       transport = JINGLE_TRANSPORT_GOOGLE_V1;
02405    } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02406       jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
02407       return;
02408    }
02409 
02410    /* Create a new local session */
02411    if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
02412       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02413       return;
02414    }
02415 
02416    /* If we determined that the transport should change as a result of how we got the SID change it */
02417    if (transport != JINGLE_TRANSPORT_NONE) {
02418       session->transport = transport;
02419    }
02420 
02421    /* Create a new Asterisk channel using the above local session */
02422    if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
02423       ao2_ref(session, -1);
02424       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02425       return;
02426    }
02427 
02428    ao2_link(endpoint->state->sessions, session);
02429 
02430    ast_channel_lock(chan);
02431    ast_setstate(chan, AST_STATE_RING);
02432    ast_channel_unlock(chan);
02433    res = ast_pbx_start(chan);
02434 
02435    switch (res) {
02436    case AST_PBX_FAILED:
02437       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
02438       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02439       session->gone = 1;
02440       ast_hangup(chan);
02441       break;
02442    case AST_PBX_CALL_LIMIT:
02443       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
02444       jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02445       ast_hangup(chan);
02446       break;
02447    case AST_PBX_SUCCESS:
02448       jingle_send_response(endpoint->connection, pak);
02449 
02450       /* Only send a transport-info message if we successfully interpreted the available content */
02451       if (!jingle_interpret_content(session, pak)) {
02452          jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
02453       }
02454       break;
02455    }
02456 }

static void jingle_action_session_terminate ( struct jingle_endpoint endpoint,
struct jingle_session session,
ikspak *  pak 
) [static]

Handler function for the 'session-terminate' action.

Definition at line 2531 of file chan_motif.c.

References ao2_unlock, ARRAY_LEN, ast_alloca, ast_control_pvt_cause_code::ast_cause, AST_CAUSE_NORMAL, ast_channel_hangupcause_hash_set(), AST_CHANNEL_NAME, ast_channel_name(), ast_channel_unlock, ast_channel_unref, AST_CONTROL_PVT_CAUSE_CODE, ast_copy_string(), ast_debug, ast_queue_control_data(), ast_queue_hangup_with_cause(), jingle_reason_mapping::cause, ast_control_pvt_cause_code::chan_name, ast_control_pvt_cause_code::code, jingle_endpoint::connection, jingle_session::gone, jingle_reason_mappings, jingle_send_error_response(), jingle_send_response(), jingle_session_lock_full(), and text.

02532 {
02533    struct ast_channel *chan;
02534    iks *reason, *text;
02535    int cause = AST_CAUSE_NORMAL;
02536    struct ast_control_pvt_cause_code *cause_code;
02537    int data_size = sizeof(*cause_code);
02538 
02539    if (!session) {
02540       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02541                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02542       return;
02543    }
02544 
02545    if (!(chan = jingle_session_lock_full(session))) {
02546       ao2_unlock(session);
02547       jingle_send_response(endpoint->connection, pak);
02548       return;
02549    }
02550 
02551    /* Pull the reason text from the session-terminate message and translate it into a cause code */
02552    if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
02553       int i;
02554 
02555       /* Size of the string making up the cause code is "Motif " + text */
02556       data_size += 6 + strlen(iks_name(text));
02557       cause_code = ast_alloca(data_size);
02558       memset(cause_code, 0, data_size);
02559 
02560       /* Get the appropriate cause code mapping for this reason */
02561       for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
02562          if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
02563             cause = jingle_reason_mappings[i].cause;
02564             break;
02565          }
02566       }
02567 
02568       /* Store the technology specific information */
02569       snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
02570    } else {
02571       /* No technology specific information is available */
02572       cause_code = ast_alloca(data_size);
02573       memset(cause_code, 0, data_size);
02574    }
02575 
02576    ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
02577    cause_code->ast_cause = cause;
02578    ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
02579    ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
02580 
02581    ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
02582    ast_queue_hangup_with_cause(chan, cause);
02583    session->gone = 1;
02584 
02585    ast_channel_unlock(chan);
02586    ast_channel_unref(chan);
02587    ao2_unlock(session);
02588 
02589    jingle_send_response(endpoint->connection, pak);
02590 }

static void jingle_action_transport_info ( struct jingle_endpoint endpoint,
struct jingle_session session,
ikspak *  pak 
) [static]

Handler function for the 'transport-info' action.

Definition at line 2459 of file chan_motif.c.

References jingle_endpoint::connection, jingle_interpret_content(), jingle_send_error_response(), and jingle_send_response().

02460 {
02461    if (!session) {
02462       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02463                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02464       return;
02465    }
02466 
02467    jingle_interpret_content(session, pak);
02468    jingle_send_response(endpoint->connection, pak);
02469 }

static int jingle_add_content ( struct jingle_session session,
iks *  jingle,
iks *  content,
iks *  description,
iks *  transport,
const char *  name,
enum ast_media_type  type,
struct ast_rtp_instance rtp,
iks **  payloads 
) [static]

Helper function which adds content to a description.

Definition at line 1391 of file chan_motif.c.

References AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, GOOGLE_PHONE_NS, GOOGLE_TRANSPORT_NS, jingle_add_payloads_to_description(), JINGLE_ICE_UDP_NS, JINGLE_RTP_NS, JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, JINGLE_TRANSPORT_ICE_UDP, jingle_session::outgoing, and jingle_session::transport.

Referenced by jingle_send_session_action().

01393 {
01394    int res = 0;
01395 
01396    if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
01397       iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
01398       iks_insert_attrib(content, "name", name);
01399       iks_insert_node(jingle, content);
01400 
01401       iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
01402       if (type == AST_MEDIA_TYPE_AUDIO) {
01403          iks_insert_attrib(description, "media", "audio");
01404       } else if (type == AST_MEDIA_TYPE_VIDEO) {
01405          iks_insert_attrib(description, "media", "video");
01406       } else {
01407          return -1;
01408       }
01409       iks_insert_node(content, description);
01410    } else {
01411       iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
01412       iks_insert_node(jingle, description);
01413    }
01414 
01415    if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
01416       if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01417          iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
01418          iks_insert_node(content, transport);
01419       } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01420          iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
01421          iks_insert_node(content, transport);
01422       }
01423    }
01424 
01425    return res;
01426 }

static int jingle_add_google_candidates_to_transport ( struct ast_rtp_instance rtp,
iks *  transport,
iks **  candidates,
unsigned int  video,
enum jingle_transport  transport_type,
unsigned int  maximum 
) [static]

Internal helper function which adds Google candidates to a transport node.

Definition at line 979 of file chan_motif.c.

References ast_rtp_engine_ice_candidate::address, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_log, AST_RTP_ICE_CANDIDATE_TYPE_HOST, AST_RTP_ICE_CANDIDATE_TYPE_SRFLX, ast_rtp_instance_get_ice(), ast_sockaddr_stringify_host(), ast_sockaddr_stringify_port(), ast_rtp_engine_ice::get_local_candidates, ast_rtp_engine_ice::get_password, ast_rtp_engine_ice::get_ufrag, GOOGLE_TRANSPORT_NS, ast_rtp_engine_ice_candidate::id, JINGLE_TRANSPORT_GOOGLE_V1, LOG_ERROR, and ast_rtp_engine_ice_candidate::type.

Referenced by jingle_send_transport_info().

00980 {
00981    struct ast_rtp_engine_ice *ice;
00982    struct ao2_container *local_candidates;
00983    struct ao2_iterator it;
00984    struct ast_rtp_engine_ice_candidate *candidate;
00985    int i = 0, res = 0;
00986 
00987    if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00988       ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
00989       return -1;
00990    }
00991 
00992    if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
00993       iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
00994    }
00995 
00996    it = ao2_iterator_init(local_candidates, 0);
00997 
00998    while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00999       iks *local_candidate;
01000       /* In Google land a username is 16 bytes, explicitly */
01001       char ufrag[17] = "";
01002 
01003       if (!(local_candidate = iks_new("candidate"))) {
01004          res = -1;
01005          ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
01006          break;
01007       }
01008 
01009       if (candidate->id == 1) {
01010          iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
01011       } else if (candidate->id == 2) {
01012          iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
01013       } else {
01014          iks_delete(local_candidate);
01015          continue;
01016       }
01017 
01018       iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
01019       iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
01020 
01021       if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
01022          iks_insert_attrib(local_candidate, "preference", "0.95");
01023          iks_insert_attrib(local_candidate, "type", "local");
01024       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
01025          iks_insert_attrib(local_candidate, "preference", "0.9");
01026          iks_insert_attrib(local_candidate, "type", "stun");
01027       }
01028 
01029       iks_insert_attrib(local_candidate, "protocol", "udp");
01030       iks_insert_attrib(local_candidate, "network", "0");
01031       snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
01032       iks_insert_attrib(local_candidate, "username", ufrag);
01033       iks_insert_attrib(local_candidate, "generation", "0");
01034 
01035       if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
01036          iks_insert_attrib(local_candidate, "password", "");
01037          iks_insert_attrib(local_candidate, "foundation", "0");
01038          iks_insert_attrib(local_candidate, "component", "1");
01039       } else {
01040          iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
01041       }
01042 
01043       /* You may notice a lack of relay support up above - this is because we don't support it for use with
01044        * the Google talk transport due to their arcane support. */
01045 
01046       iks_insert_node(transport, local_candidate);
01047       candidates[i++] = local_candidate;
01048    }
01049 
01050    ao2_iterator_destroy(&it);
01051    ao2_ref(local_candidates, -1);
01052 
01053    return res;
01054 }

static int jingle_add_ice_udp_candidates_to_transport ( struct ast_rtp_instance rtp,
iks *  transport,
iks **  candidates,
unsigned int  maximum 
) [static]

Internal helper function which adds ICE-UDP candidates to a transport node.

Definition at line 917 of file chan_motif.c.

References ast_rtp_engine_ice_candidate::address, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_log, ast_random(), AST_RTP_ICE_CANDIDATE_TYPE_HOST, AST_RTP_ICE_CANDIDATE_TYPE_RELAYED, AST_RTP_ICE_CANDIDATE_TYPE_SRFLX, ast_rtp_instance_get_ice(), ast_sockaddr_stringify_host(), ast_sockaddr_stringify_port(), ast_str_hash(), ast_rtp_engine_ice_candidate::foundation, ast_rtp_engine_ice::get_local_candidates, ast_rtp_engine_ice::get_password, ast_rtp_engine_ice::get_ufrag, ast_rtp_engine_ice_candidate::id, JINGLE_ICE_UDP_NS, LOG_ERROR, ast_rtp_engine_ice_candidate::priority, tmp(), and ast_rtp_engine_ice_candidate::type.

Referenced by jingle_send_transport_info().

00918 {
00919    struct ast_rtp_engine_ice *ice;
00920    struct ao2_container *local_candidates;
00921    struct ao2_iterator it;
00922    struct ast_rtp_engine_ice_candidate *candidate;
00923    int i = 0, res = 0;
00924 
00925    if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00926       ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
00927       return -1;
00928    }
00929 
00930    iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
00931    iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
00932    iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
00933 
00934    it = ao2_iterator_init(local_candidates, 0);
00935 
00936    while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00937       iks *local_candidate;
00938       char tmp[30];
00939 
00940       if (!(local_candidate = iks_new("candidate"))) {
00941          res = -1;
00942          ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
00943          break;
00944       }
00945 
00946       snprintf(tmp, sizeof(tmp), "%u", candidate->id);
00947       iks_insert_attrib(local_candidate, "component", tmp);
00948       snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
00949       iks_insert_attrib(local_candidate, "foundation", tmp);
00950       iks_insert_attrib(local_candidate, "generation", "0");
00951       iks_insert_attrib(local_candidate, "network", "0");
00952       snprintf(tmp, sizeof(tmp), "%04lx", (unsigned long)(ast_random() & 0xffff));
00953       iks_insert_attrib(local_candidate, "id", tmp);
00954       iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
00955       iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
00956       snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
00957       iks_insert_attrib(local_candidate, "priority", tmp);
00958       iks_insert_attrib(local_candidate, "protocol", "udp");
00959 
00960       if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
00961          iks_insert_attrib(local_candidate, "type", "host");
00962       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
00963          iks_insert_attrib(local_candidate, "type", "srflx");
00964       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
00965          iks_insert_attrib(local_candidate, "type", "relay");
00966       }
00967 
00968       iks_insert_node(transport, local_candidate);
00969       candidates[i++] = local_candidate;
00970    }
00971 
00972    ao2_iterator_destroy(&it);
00973    ao2_ref(local_candidates, -1);
00974 
00975    return res;
00976 }

static int jingle_add_payloads_to_description ( struct jingle_session session,
struct ast_rtp_instance rtp,
iks *  description,
iks **  payloads,
enum ast_media_type  type 
) [static]

Internal helper function which adds payloads to a description.

Definition at line 1305 of file chan_motif.c.

References ao2_ref, ast_format_cap_count(), ast_format_cap_get_format(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_g722, ast_format_get_type(), AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, ast_rtp_codecs_payload_code(), ast_rtp_instance_get_codecs(), ast_rtp_lookup_mime_subtype2(), ast_rtp_lookup_sample_rate2(), format, GOOGLE_PHONE_NS, JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, jingle_session::jointcap, jingle_session::maxpayloads, tmp(), jingle_session::transport, and ast_channel::x.

Referenced by jingle_add_content().

01306 {
01307    int x = 0, i = 0, res = 0;
01308 
01309    for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) {
01310       struct ast_format *format = ast_format_cap_get_format(session->jointcap, x);
01311       int rtp_code;
01312       iks *payload;
01313       char tmp[32];
01314 
01315       if (ast_format_get_type(format) != type) {
01316          ao2_ref(format, -1);
01317          continue;
01318       }
01319 
01320       if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) ||
01321           (!(payload = iks_new("payload-type")))) {
01322          ao2_ref(format, -1);
01323          return -1;
01324       }
01325 
01326       if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01327          iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01328       }
01329 
01330       snprintf(tmp, sizeof(tmp), "%d", rtp_code);
01331       iks_insert_attrib(payload, "id", tmp);
01332       iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
01333       iks_insert_attrib(payload, "channels", "1");
01334 
01335       if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) &&
01336          ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
01337          iks_insert_attrib(payload, "clockrate", "16000");
01338       } else {
01339          snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0));
01340          iks_insert_attrib(payload, "clockrate", tmp);
01341       }
01342 
01343       if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
01344          iks *parameter;
01345 
01346          /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
01347          if ((parameter = iks_new("parameter"))) {
01348             iks_insert_attrib(parameter, "name", "width");
01349             iks_insert_attrib(parameter, "value", "640");
01350             iks_insert_node(payload, parameter);
01351          }
01352          if ((parameter = iks_new("parameter"))) {
01353             iks_insert_attrib(parameter, "name", "height");
01354             iks_insert_attrib(parameter, "value", "480");
01355             iks_insert_node(payload, parameter);
01356          }
01357          if ((parameter = iks_new("parameter"))) {
01358             iks_insert_attrib(parameter, "name", "framerate");
01359             iks_insert_attrib(parameter, "value", "30");
01360             iks_insert_node(payload, parameter);
01361          }
01362       }
01363 
01364       iks_insert_node(description, payload);
01365       payloads[i++] = payload;
01366 
01367       ao2_ref(format, -1);
01368    }
01369    /* If this is for audio and there is room for RFC2833 add it in */
01370    if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) {
01371       iks *payload;
01372 
01373       if ((payload = iks_new("payload-type"))) {
01374          if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01375             iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01376          }
01377 
01378          iks_insert_attrib(payload, "id", "101");
01379          iks_insert_attrib(payload, "name", "telephone-event");
01380          iks_insert_attrib(payload, "channels", "1");
01381          iks_insert_attrib(payload, "clockrate", "8000");
01382          iks_insert_node(description, payload);
01383          payloads[i++] = payload;
01384       }
01385    }
01386 
01387    return res;
01388 }

static struct jingle_session * jingle_alloc ( struct jingle_endpoint endpoint,
const char *  from,
const char *  sid 
) [static, read]

Internal helper function used to allocate Jingle session on an endpoint.

Definition at line 700 of file chan_motif.c.

References ao2_alloc, ao2_ref, ast_copy_string(), ast_create_callid(), ast_format_cap_alloc, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, AST_MEDIA_TYPE_UNKNOWN, ast_random(), ast_read_threadstorage_callid(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_DTMF, AST_RTP_PROPERTY_RTCP, ast_sockaddr_parse(), ast_string_field_build, ast_string_field_init, ast_string_field_set, ast_strlen_zero, jingle_session::callid, jingle_endpoint::cap, jingle_session::cap, jingle_session::connection, jingle_endpoint::connection, jingle_session_destructor(), jingle_session::jointcap, jingle_endpoint::maxicecandidates, jingle_session::maxicecandidates, jingle_endpoint::maxpayloads, jingle_session::maxpayloads, NULL, jingle_session::outgoing, jingle_session::peercap, jingle_session::remote, jingle_session::remote_original, jingle_session::rtp, session, jingle_session::state, jingle_endpoint::state, jingle_endpoint::transport, and jingle_session::transport.

Referenced by jingle_action_session_initiate(), and jingle_request().

00701 {
00702    struct jingle_session *session;
00703    ast_callid callid;
00704    struct ast_sockaddr tmp;
00705 
00706    if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
00707       return NULL;
00708    }
00709 
00710    callid = ast_read_threadstorage_callid();
00711    session->callid = (callid ? callid : ast_create_callid());
00712 
00713    if (ast_string_field_init(session, 512)) {
00714       ao2_ref(session, -1);
00715       return NULL;
00716    }
00717 
00718    if (!ast_strlen_zero(from)) {
00719       ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
00720       ast_copy_string(session->remote, from, sizeof(session->remote));
00721    }
00722 
00723    if (ast_strlen_zero(sid)) {
00724       ast_string_field_build(session, sid, "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
00725       session->outgoing = 1;
00726       ast_string_field_set(session, audio_name, "audio");
00727       ast_string_field_set(session, video_name, "video");
00728    } else {
00729       ast_string_field_set(session, sid, sid);
00730    }
00731 
00732    ao2_ref(endpoint->state, +1);
00733    session->state = endpoint->state;
00734    ao2_ref(endpoint->connection, +1);
00735    session->connection = endpoint->connection;
00736    session->transport = endpoint->transport;
00737 
00738    if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
00739        !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
00740        !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
00741        !session->callid) {
00742       ao2_ref(session, -1);
00743       return NULL;
00744    }
00745 
00746    ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN);
00747 
00748    /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
00749     * that we want IPv4 */
00750    ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00751 
00752    /* Sessions always carry audio, but video is optional so don't enable it here */
00753    if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00754       ao2_ref(session, -1);
00755       return NULL;
00756    }
00757    ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
00758    ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
00759 
00760    session->maxicecandidates = endpoint->maxicecandidates;
00761    session->maxpayloads = endpoint->maxpayloads;
00762 
00763    return session;
00764 }

static int jingle_answer ( struct ast_channel ast  )  [static]

Function called by core when we should answer a Jingle session.

Definition at line 1624 of file chan_motif.c.

References ast_channel_tech_pvt(), AST_STATE_UP, jingle_send_session_accept(), and session.

01625 {
01626    struct jingle_session *session = ast_channel_tech_pvt(ast);
01627 
01628    /* The channel has already been answered so we don't need to do anything */
01629    if (ast_channel_state(ast) == AST_STATE_UP) {
01630       return 0;
01631    }
01632 
01633    jingle_send_session_accept(session);
01634 
01635    return 0;
01636 }

static int jingle_call ( struct ast_channel ast,
const char *  dest,
int  timeout 
) [static]

Function called by core to actually start calling a remote party.

Definition at line 1849 of file chan_motif.c.

References ast_channel_tech_pvt(), ast_format_cap_append_from_cap(), AST_MEDIA_TYPE_UNKNOWN, ast_setstate(), AST_STATE_RING, jingle_session::cap, jingle_session::connection, ast_xmpp_client::filter, jingle_outgoing_hook(), jingle_send_session_initiate(), jingle_session::jointcap, ast_xmpp_client::mid, jingle_session::rule, and session.

01850 {
01851    struct jingle_session *session = ast_channel_tech_pvt(ast);
01852 
01853    ast_setstate(ast, AST_STATE_RING);
01854 
01855    /* Since we have no idea of the remote capabilities use ours for now */
01856    ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN);
01857 
01858    /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
01859    session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01860                    IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01861 
01862    jingle_send_session_initiate(session);
01863 
01864    return 0;
01865 }

static void* jingle_config_alloc ( void   )  [static]

Allocator called when module configuration should appear.

Definition at line 599 of file chan_motif.c.

References ao2_alloc, ao2_container_alloc, ao2_ref, ENDPOINT_BUCKETS, jingle_config::endpoints, jingle_config_destructor(), jingle_endpoint_cmp(), jingle_endpoint_hash(), and NULL.

00600 {
00601    struct jingle_config *cfg;
00602 
00603    if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
00604       return NULL;
00605    }
00606 
00607    if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
00608       ao2_ref(cfg, -1);
00609       return NULL;
00610    }
00611 
00612    return cfg;
00613 }

static void jingle_config_destructor ( void *  obj  )  [static]

Destructor called when module configuration goes away.

Definition at line 592 of file chan_motif.c.

References ao2_cleanup, and jingle_config::endpoints.

Referenced by jingle_config_alloc().

00593 {
00594    struct jingle_config *cfg = obj;
00595    ao2_cleanup(cfg->endpoints);
00596 }

static int jingle_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Function called by core to start a DTMF digit.

Definition at line 1825 of file chan_motif.c.

References ast_channel_tech_pvt(), ast_rtp_instance_dtmf_begin(), jingle_session::rtp, and session.

01826 {
01827    struct jingle_session *session = ast_channel_tech_pvt(chan);
01828 
01829    if (session->rtp) {
01830       ast_rtp_instance_dtmf_begin(session->rtp, digit);
01831    }
01832 
01833    return 0;
01834 }

static int jingle_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Function called by core to stop a DTMF digit.

Definition at line 1837 of file chan_motif.c.

References ast_channel_tech_pvt(), ast_rtp_instance_dtmf_end_with_duration(), jingle_session::rtp, and session.

01838 {
01839    struct jingle_session *session = ast_channel_tech_pvt(ast);
01840 
01841    if (session->rtp) {
01842       ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
01843    }
01844 
01845    return 0;
01846 }

static void jingle_enable_video ( struct jingle_session session  )  [static]

Internal helper function which enables video support on a sesson if possible.

Definition at line 667 of file chan_motif.c.

References ast_channel_set_fd(), ast_channel_uniqueid(), ast_format_cap_get_framing(), ast_format_cap_has_type(), AST_MEDIA_TYPE_VIDEO, ast_rtp_codecs_set_framing(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_ice(), ast_rtp_instance_new(), ast_rtp_instance_set_channel_id(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_RTCP, ast_sockaddr_parse(), jingle_session::cap, JINGLE_TRANSPORT_GOOGLE_V2, NULL, jingle_session::owner, ast_rtp_engine_ice::stop, jingle_session::transport, and jingle_session::vrtp.

Referenced by jingle_interpret_description(), and jingle_request().

00668 {
00669    struct ast_sockaddr tmp;
00670    struct ast_rtp_engine_ice *ice;
00671 
00672    /* If video is already present don't do anything */
00673    if (session->vrtp) {
00674       return;
00675    }
00676 
00677    /* If there are no configured video codecs do not turn video support on, it just won't work */
00678    if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) {
00679       return;
00680    }
00681 
00682    ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00683 
00684    if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00685       return;
00686    }
00687 
00688    ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
00689    ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
00690    ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
00691    ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
00692    ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp),
00693       ast_format_cap_get_framing(session->cap));
00694    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
00695       ice->stop(session->vrtp);
00696    }
00697 }

static void* jingle_endpoint_alloc ( const char *  cat  )  [static]

Allocator function for Jingle endpoints.

Definition at line 500 of file chan_motif.c.

References ao2_alloc, ao2_ref, ast_format_cap_alloc, AST_FORMAT_CAP_FLAG_DEFAULT, ast_string_field_init, ast_string_field_set, jingle_endpoint::cap, jingle_endpoint_destructor(), jingle_endpoint_state_find_or_create(), JINGLE_TRANSPORT_ICE_UDP, name, NULL, jingle_endpoint::state, and jingle_endpoint::transport.

00501 {
00502    struct jingle_endpoint *endpoint;
00503 
00504    if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
00505       return NULL;
00506    }
00507 
00508    if (ast_string_field_init(endpoint, 512)) {
00509       ao2_ref(endpoint, -1);
00510       return NULL;
00511    }
00512 
00513    if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
00514       ao2_ref(endpoint, -1);
00515       return NULL;
00516    }
00517 
00518    ast_string_field_set(endpoint, name, cat);
00519 
00520    endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
00521    endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
00522 
00523    return endpoint;
00524 }

static int jingle_endpoint_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Comparator function for Jingle endpoints.

Definition at line 536 of file chan_motif.c.

References CMP_MATCH, CMP_STOP, jingle_endpoint::name, name, and OBJ_KEY.

Referenced by jingle_config_alloc().

00537 {
00538    struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
00539    const char *name = arg;
00540 
00541    return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
00542 }

static void jingle_endpoint_destructor ( void *  obj  )  [static]

Destructor for Jingle endpoints.

Definition at line 444 of file chan_motif.c.

References ao2_cleanup, ao2_ref, ast_string_field_free_memory, ast_xmpp_client_unref(), jingle_endpoint::cap, jingle_endpoint::connection, ast_xmpp_client::filter, jingle_endpoint::rule, and jingle_endpoint::state.

Referenced by jingle_endpoint_alloc().

00445 {
00446    struct jingle_endpoint *endpoint = obj;
00447 
00448    if (endpoint->rule) {
00449       iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
00450    }
00451 
00452    if (endpoint->connection) {
00453       ast_xmpp_client_unref(endpoint->connection);
00454    }
00455 
00456    ao2_cleanup(endpoint->cap);
00457    ao2_ref(endpoint->state, -1);
00458 
00459    ast_string_field_free_memory(endpoint);
00460 }

static void* jingle_endpoint_find ( struct ao2_container tmp_container,
const char *  category 
) [static]

Find function for Jingle endpoints.

Definition at line 463 of file chan_motif.c.

References ao2_find, and OBJ_KEY.

Referenced by jingle_endpoint_state_find_or_create(), and jingle_request().

00464 {
00465    return ao2_find(tmp_container, category, OBJ_KEY);
00466 }

static int jingle_endpoint_hash ( const void *  obj,
const int  flags 
) [static]

Hashing function for Jingle endpoints.

Definition at line 527 of file chan_motif.c.

References ast_str_hash(), jingle_endpoint::name, name, and OBJ_KEY.

Referenced by jingle_config_alloc().

00528 {
00529    const struct jingle_endpoint *endpoint = obj;
00530    const char *name = obj;
00531 
00532    return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
00533 }

static struct jingle_endpoint_state* jingle_endpoint_state_create ( void   )  [static, read]

Allocator function for Jingle endpoint state.

Definition at line 469 of file chan_motif.c.

References ao2_alloc, ao2_container_alloc, ao2_ref, jingle_endpoint_state_destructor(), jingle_session_cmp(), jingle_session_hash(), NULL, SESSION_BUCKETS, and jingle_endpoint_state::sessions.

Referenced by jingle_endpoint_state_find_or_create().

00470 {
00471    struct jingle_endpoint_state *state;
00472 
00473    if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
00474       return NULL;
00475    }
00476 
00477    if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
00478       ao2_ref(state, -1);
00479       return NULL;
00480    }
00481 
00482    return state;
00483 }

static void jingle_endpoint_state_destructor ( void *  obj  )  [static]

Destructor for Jingle endpoint state.

Definition at line 436 of file chan_motif.c.

References ao2_ref, and jingle_endpoint_state::sessions.

Referenced by jingle_endpoint_state_create().

00437 {
00438    struct jingle_endpoint_state *state = obj;
00439 
00440    ao2_ref(state->sessions, -1);
00441 }

static struct jingle_endpoint_state* jingle_endpoint_state_find_or_create ( const char *  category  )  [static, read]

State find/create function.

Definition at line 486 of file chan_motif.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_ref, globals, jingle_endpoint_find(), jingle_endpoint_state_create(), NULL, and RAII_VAR.

Referenced by jingle_endpoint_alloc().

00487 {
00488    RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00489    RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
00490 
00491    if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
00492       return jingle_endpoint_state_create();
00493    }
00494 
00495    ao2_ref(endpoint->state, +1);
00496    return endpoint->state;
00497 }

static int jingle_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Function called by core to change the underlying owner channel.

Definition at line 1734 of file chan_motif.c.

References ao2_lock, ao2_unlock, ast_channel_tech_pvt(), jingle_set_owner(), and session.

01735 {
01736    struct jingle_session *session = ast_channel_tech_pvt(newchan);
01737 
01738    ao2_lock(session);
01739 
01740    jingle_set_owner(session, newchan);
01741 
01742    ao2_unlock(session);
01743 
01744    return 0;
01745 }

static void jingle_get_codec ( struct ast_channel chan,
struct ast_format_cap result 
) [static]

Function called by RTP engine to get peer capabilities.

Definition at line 636 of file chan_motif.c.

00637 {
00638 }

static enum ast_rtp_glue_result jingle_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance **  instance 
) [static]

Function called by RTP engine to get local RTP peer.

Definition at line 620 of file chan_motif.c.

References ao2_ref, ast_channel_tech_pvt(), AST_RTP_GLUE_RESULT_FORBID, AST_RTP_GLUE_RESULT_LOCAL, jingle_session::rtp, and session.

00621 {
00622    struct jingle_session *session = ast_channel_tech_pvt(chan);
00623    enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
00624 
00625    if (!session->rtp) {
00626       return AST_RTP_GLUE_RESULT_FORBID;
00627    }
00628 
00629    ao2_ref(session->rtp, +1);
00630    *instance = session->rtp;
00631 
00632    return res;
00633 }

static int jingle_hangup ( struct ast_channel ast  )  [static]

Function called by core to hang up a Jingle session.

Definition at line 1868 of file chan_motif.c.

References ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ARRAY_LEN, AST_CAUSE_CONGESTION, ast_channel_hangupcause(), ast_channel_tech_pvt(), ast_channel_tech_pvt_set(), AST_STATE_DOWN, jingle_session::gone, jingle_reason_mappings, jingle_send_session_terminate(), jingle_set_owner(), NULL, jingle_session::owner, jingle_reason_mapping::reason, session, jingle_endpoint_state::sessions, and jingle_session::state.

01869 {
01870    struct jingle_session *session = ast_channel_tech_pvt(ast);
01871 
01872    ao2_lock(session);
01873 
01874    if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
01875       int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
01876       const char *reason = "success";
01877       int i;
01878 
01879       /* Get the appropriate reason and send a session-terminate */
01880       for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
01881          if (jingle_reason_mappings[i].cause == cause) {
01882             reason = jingle_reason_mappings[i].reason;
01883             break;
01884          }
01885       }
01886 
01887       jingle_send_session_terminate(session, reason);
01888    }
01889 
01890    ast_channel_tech_pvt_set(ast, NULL);
01891    jingle_set_owner(session, NULL);
01892 
01893    ao2_unlink(session->state->sessions, session);
01894    ao2_ref(session->state, -1);
01895 
01896    ao2_unlock(session);
01897    ao2_ref(session, -1);
01898 
01899    return 0;
01900 }

static int jingle_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Function called by core to ask the channel to indicate some sort of condition.

Definition at line 1748 of file chan_motif.c.

References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_hangupcause_set(), ast_channel_tech_pvt(), AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_INCOMPLETE, AST_CONTROL_MASQUERADE_NOTIFY, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_RINGING, AST_CONTROL_SRCCHANGE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_UPDATE_RTP_PEER, AST_CONTROL_VIDUPDATE, ast_log, ast_moh_start(), ast_moh_stop(), ast_rtp_instance_change_source(), ast_rtp_instance_update_source(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), AST_STATE_RING, AST_STATE_UP, jingle_send_session_info(), LOG_NOTICE, NULL, jingle_session::rtp, and session.

01749 {
01750    struct jingle_session *session = ast_channel_tech_pvt(ast);
01751    int res = 0;
01752 
01753    switch (condition) {
01754    case AST_CONTROL_RINGING:
01755       if (ast_channel_state(ast) == AST_STATE_RING) {
01756          jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
01757       } else {
01758          res = -1;
01759       }
01760       break;
01761    case AST_CONTROL_BUSY:
01762       if (ast_channel_state(ast) != AST_STATE_UP) {
01763          ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
01764          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01765       } else {
01766          res = -1;
01767       }
01768       break;
01769    case AST_CONTROL_CONGESTION:
01770       if (ast_channel_state(ast) != AST_STATE_UP) {
01771          ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01772          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01773       } else {
01774          res = -1;
01775       }
01776       break;
01777    case AST_CONTROL_INCOMPLETE:
01778       if (ast_channel_state(ast) != AST_STATE_UP) {
01779          ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01780          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01781       }
01782       break;
01783    case AST_CONTROL_HOLD:
01784       ast_moh_start(ast, data, NULL);
01785       break;
01786    case AST_CONTROL_UNHOLD:
01787       ast_moh_stop(ast);
01788       break;
01789    case AST_CONTROL_SRCUPDATE:
01790       if (session->rtp) {
01791          ast_rtp_instance_update_source(session->rtp);
01792       }
01793       break;
01794    case AST_CONTROL_SRCCHANGE:
01795       if (session->rtp) {
01796          ast_rtp_instance_change_source(session->rtp);
01797       }
01798       break;
01799    case AST_CONTROL_VIDUPDATE:
01800    case AST_CONTROL_UPDATE_RTP_PEER:
01801    case AST_CONTROL_CONNECTED_LINE:
01802       break;
01803    case AST_CONTROL_PVT_CAUSE_CODE:
01804    case AST_CONTROL_MASQUERADE_NOTIFY:
01805    case -1:
01806       res = -1;
01807       break;
01808    default:
01809       ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01810       res = -1;
01811    }
01812 
01813    return res;
01814 }

static int jingle_interpret_content ( struct jingle_session session,
ikspak *  pak 
) [static]

Helper function which locates content stanzas and interprets them.

Note:
The session *must not* be locked before calling this

Definition at line 2277 of file chan_motif.c.

References ao2_ref, ao2_unlock, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, AST_CAUSE_FACILITY_NOT_IMPLEMENTED, AST_CAUSE_SWITCH_CONGESTION, ast_channel_nativeformats_set(), ast_channel_unlock, ast_channel_unref, ast_format_cap_alloc, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_format(), ast_log, AST_MEDIA_TYPE_UNKNOWN, ast_set_read_format(), ast_set_write_format(), ast_strlen_zero, jingle_session::audio_name, GOOGLE_PHONE_NS, GOOGLE_SESSION_NS, GOOGLE_TRANSPORT_NS, GOOGLE_VIDEO_NS, JINGLE_ICE_UDP_NS, jingle_interpret_description(), jingle_interpret_google_transport(), jingle_interpret_ice_udp_transport(), jingle_queue_hangup_with_cause(), JINGLE_RTP_NS, jingle_session_lock_full(), JINGLE_TRANSPORT_GOOGLE_V1, jingle_session::jointcap, LOG_ERROR, name, NULL, jingle_session::rtp, jingle_session::sid, jingle_session::transport, jingle_session::video_name, and jingle_session::vrtp.

Referenced by jingle_action_session_accept(), jingle_action_session_initiate(), and jingle_action_transport_info().

02278 {
02279    iks *content;
02280    unsigned int changed = 0;
02281    struct ast_channel *chan;
02282 
02283    /* Look at the content in the session initiation */
02284    for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
02285       char *name;
02286       struct ast_rtp_instance *rtp = NULL;
02287       iks *description, *transport;
02288 
02289       /* Ignore specific parts if they are known not to be useful */
02290       if (!strcmp(iks_name(content), "conference-info")) {
02291          continue;
02292       }
02293 
02294       name = iks_find_attrib(content, "name");
02295 
02296       if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
02297          /* If this content stanza has no name consider it invalid and move on */
02298          if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
02299             jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02300             ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
02301             return -1;
02302          }
02303 
02304          /* Try to pre-populate which RTP instance this content is relevant to */
02305          if (!strcmp(session->audio_name, name)) {
02306             rtp = session->rtp;
02307          } else if (!strcmp(session->video_name, name)) {
02308             rtp = session->vrtp;
02309          }
02310       } else {
02311          /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
02312          rtp = session->rtp;
02313       }
02314 
02315       /* If description information is available use it */
02316       if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
02317           (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
02318           (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02319           (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
02320           (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02321           (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
02322          /* If we failed to do something with the content description abort immediately */
02323          if (jingle_interpret_description(session, description, name, &rtp)) {
02324             return -1;
02325          }
02326 
02327          /* If we successfully interpret the description then the codecs need updating */
02328          changed = 1;
02329       }
02330 
02331       /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
02332       if (!rtp) {
02333          ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
02334          jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02335          return -1;
02336       }
02337 
02338       /* If ICE UDP transport information is available use it */
02339       if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
02340          if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
02341             return -1;
02342          }
02343       } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
02344             (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
02345             (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
02346             (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
02347          /* If Google transport support is available use it */
02348          if (jingle_interpret_google_transport(session, transport, rtp)) {
02349             return -1;
02350          }
02351       } else if (iks_find(content, "transport")) {
02352          /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
02353          jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
02354          ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
02355          return -1;
02356       }
02357    }
02358 
02359    if (!changed) {
02360       return 0;
02361    }
02362 
02363    if ((chan = jingle_session_lock_full(session))) {
02364       struct ast_format_cap *caps;
02365       struct ast_format *fmt;
02366 
02367       caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
02368       if (caps) {
02369          ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
02370          ast_channel_nativeformats_set(chan, caps);
02371          ao2_ref(caps, -1);
02372       }
02373 
02374       fmt = ast_format_cap_get_format(session->jointcap, 0);
02375       ast_set_read_format(chan, fmt);
02376       ast_set_write_format(chan, fmt);
02377       ao2_ref(fmt, -1);
02378 
02379       ast_channel_unlock(chan);
02380       ast_channel_unref(chan);
02381    }
02382    ao2_unlock(session);
02383 
02384    return 0;
02385 }

static int jingle_interpret_description ( struct jingle_session session,
iks *  description,
const char *  name,
struct ast_rtp_instance **  rtp 
) [static]

Helper function which handles content descriptions.

Definition at line 2032 of file chan_motif.c.

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, ast_format_cap_count(), ast_format_cap_get_compatible(), ast_format_cap_remove_by_type(), ast_log, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_copy(), ast_rtp_codecs_payloads_destroy(), ast_rtp_codecs_payloads_initialize(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_codecs_payloads_set_rtpmap_type_rate(), ast_rtp_instance_get_codecs(), ast_string_field_set, ast_strlen_zero, jingle_session::cap, jingle_enable_video(), jingle_queue_hangup_with_cause(), JINGLE_TRANSPORT_GOOGLE_V1, jingle_session::jointcap, LOG_ERROR, NULL, jingle_session::peercap, jingle_session::rtp, jingle_session::sid, jingle_session::transport, and jingle_session::vrtp.

Referenced by jingle_interpret_content().

02033 {
02034    char *media = iks_find_attrib(description, "media");
02035    struct ast_rtp_codecs codecs;
02036    iks *codec;
02037    int othercapability = 0;
02038 
02039    /* Google-V1 is always carrying audio, but just doesn't tell us so */
02040    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
02041       media = "audio";
02042    } else if (ast_strlen_zero(media)) {
02043       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02044       ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
02045       return -1;
02046    }
02047 
02048    /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
02049    if (!strcasecmp(media, "audio")) {
02050       if (!ast_strlen_zero(name)) {
02051          ast_string_field_set(session, audio_name, name);
02052       }
02053       *rtp = session->rtp;
02054       ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO);
02055       ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO);
02056    } else if (!strcasecmp(media, "video")) {
02057       if (!ast_strlen_zero(name)) {
02058          ast_string_field_set(session, video_name, name);
02059       }
02060 
02061       jingle_enable_video(session);
02062       *rtp = session->vrtp;
02063 
02064       /* If video is not present cancel this session */
02065       if (!session->vrtp) {
02066          jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02067          ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
02068          return -1;
02069       }
02070 
02071       ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO);
02072       ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO);
02073    } else {
02074       /* Unknown media type */
02075       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02076       ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
02077       return -1;
02078    }
02079 
02080    if (ast_rtp_codecs_payloads_initialize(&codecs)) {
02081       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02082       ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
02083       return -1;
02084    }
02085 
02086    /* Iterate the codecs updating the relevant RTP instance as we go */
02087    for (codec = iks_child(description); codec; codec = iks_next(codec)) {
02088       char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
02089       char *clockrate = iks_find_attrib(codec, "clockrate");
02090       int rtp_id, rtp_clockrate;
02091 
02092       if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
02093          if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
02094             ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
02095          } else {
02096             ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
02097          }
02098       }
02099    }
02100 
02101    ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
02102    ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
02103 
02104    if (!ast_format_cap_count(session->jointcap)) {
02105       /* We have no compatible codecs, so terminate the session appropriately */
02106       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02107       ast_rtp_codecs_payloads_destroy(&codecs);
02108       return -1;
02109    }
02110 
02111    ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
02112    ast_rtp_codecs_payloads_destroy(&codecs);
02113 
02114    return 0;
02115 }

static int jingle_interpret_google_transport ( struct jingle_session session,
iks *  transport,
struct ast_rtp_instance rtp 
) [static]

Helper function which handles Google transport information.

Definition at line 2199 of file chan_motif.c.

References AST_CAUSE_PROTOCOL_ERROR, AST_CAUSE_SWITCH_CONGESTION, ast_log, ast_rtp_instance_get_ice(), ast_rtp_instance_stun_request(), ast_sockaddr_parse(), ast_sockaddr_set_port, ast_strlen_zero, ast_rtp_engine_ice::get_ufrag, jingle_queue_hangup_with_cause(), JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, LOG_ERROR, name, PARSE_PORT_FORBID, jingle_session::sid, ast_rtp_engine_ice::stop, and jingle_session::transport.

Referenced by jingle_interpret_content().

02200 {
02201    struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
02202    iks *candidate;
02203 
02204    if (!ice) {
02205       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02206       ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
02207       return -1;
02208    }
02209 
02210    /* If this session has not transitioned to the Google transport do so now */
02211    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
02212        (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
02213       /* Stop built-in ICE support... we need to fall back to the old old old STUN */
02214       ice->stop(rtp);
02215 
02216       session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02217    }
02218 
02219    for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
02220       char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
02221       char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
02222       char *protocol = iks_find_attrib(candidate, "protocol");
02223       int real_port;
02224       struct ast_sockaddr target = { { 0, } };
02225       /* In Google land the combined value is 32 bytes */
02226       char combined[33] = "";
02227 
02228       /* If this is NOT actually a candidate just skip it */
02229       if (strcasecmp(iks_name(candidate), "candidate") &&
02230           strcasecmp(iks_name(candidate), "p:candidate") &&
02231           strcasecmp(iks_name(candidate), "ses:candidate")) {
02232          continue;
02233       }
02234 
02235       /* If this candidate is incomplete skip it */
02236       if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
02237           ast_strlen_zero(name)) {
02238          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02239          ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
02240          return -1;
02241       }
02242 
02243       /* We only support UDP so skip any other protocols */
02244       if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
02245          continue;
02246       }
02247 
02248       /* We only permit audio and video, not RTCP */
02249       if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
02250          continue;
02251       }
02252 
02253       /* Parse the target information so we can send a STUN request to the candidate */
02254       if (sscanf(port, "%30d", &real_port) != 1) {
02255          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02256          ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
02257          return -1;
02258       }
02259       ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
02260       ast_sockaddr_set_port(&target, real_port);
02261 
02262       /* Per the STUN support Google talk uses combine the two usernames */
02263       snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
02264 
02265       /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
02266       ast_rtp_instance_stun_request(rtp, &target, combined);
02267    }
02268 
02269    return 0;
02270 }

static int jingle_interpret_ice_udp_transport ( struct jingle_session session,
iks *  transport,
struct ast_rtp_instance rtp 
) [static]

Helper function which handles ICE-UDP transport information.

Definition at line 2118 of file chan_motif.c.

References ast_rtp_engine_ice::add_remote_candidate, ast_rtp_engine_ice_candidate::address, AST_CAUSE_PROTOCOL_ERROR, AST_CAUSE_SWITCH_CONGESTION, ast_log, AST_RTP_ICE_CANDIDATE_TYPE_HOST, AST_RTP_ICE_CANDIDATE_TYPE_RELAYED, AST_RTP_ICE_CANDIDATE_TYPE_SRFLX, ast_rtp_instance_get_ice(), ast_rtp_instance_get_remote_address, ast_rtp_instance_set_remote_address, ast_sockaddr_is_ipv4(), ast_sockaddr_isnull(), ast_sockaddr_parse(), ast_sockaddr_set_port, ast_strlen_zero, ast_rtp_engine_ice_candidate::foundation, ast_rtp_engine_ice_candidate::id, jingle_queue_hangup_with_cause(), LOG_ERROR, PARSE_PORT_FORBID, ast_rtp_engine_ice_candidate::priority, ast_rtp_engine_ice::set_authentication, jingle_session::sid, ast_rtp_engine_ice::start, ast_rtp_engine_ice_candidate::transport, ast_rtp_engine_ice_candidate::type, and type.

Referenced by jingle_interpret_content().

02119 {
02120    struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
02121    char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
02122    iks *candidate;
02123 
02124    if (!ice) {
02125       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02126       ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
02127       return -1;
02128    }
02129 
02130    if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
02131       ice->set_authentication(rtp, ufrag, pwd);
02132    }
02133 
02134    for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
02135       char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
02136       char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
02137       char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
02138       char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
02139       char *type = iks_find_attrib(candidate, "type");
02140       struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
02141       int real_port;
02142       struct ast_sockaddr remote_address = { { 0, } };
02143 
02144       /* If this candidate is incomplete skip it */
02145       if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
02146           ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
02147           ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
02148          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02149          ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
02150          return -1;
02151       }
02152 
02153       if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
02154           (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
02155           (sscanf(port, "%30d", &real_port) != 1)) {
02156          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02157          ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
02158          return -1;
02159       }
02160 
02161       local_candidate.foundation = foundation;
02162       local_candidate.transport = protocol;
02163 
02164       ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
02165 
02166       /* We only support IPv4 right now */
02167       if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
02168          continue;
02169       }
02170 
02171       ast_sockaddr_set_port(&local_candidate.address, real_port);
02172 
02173       if (!strcasecmp(type, "host")) {
02174          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
02175       } else if (!strcasecmp(type, "srflx")) {
02176          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
02177       } else if (!strcasecmp(type, "relay")) {
02178          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
02179       } else {
02180          continue;
02181       }
02182 
02183       /* Worst case use the first viable address */
02184       ast_rtp_instance_get_remote_address(rtp, &remote_address);
02185 
02186       if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
02187          ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
02188       }
02189 
02190       ice->add_remote_candidate(rtp, &local_candidate);
02191    }
02192 
02193    ice->start(rtp);
02194 
02195    return 0;
02196 }

static struct ast_channel* jingle_new ( struct jingle_endpoint endpoint,
struct jingle_session session,
int  state,
const char *  title,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor,
const char *  cid_name 
) [static, read]

Function called to create a new Jingle Asterisk channel.

Definition at line 767 of file chan_motif.c.

References jingle_endpoint::accountcode, ao2_lock, ao2_ref, ao2_unlock, AST_ADSI_UNAVAILABLE, ast_channel_adsicpe_set(), ast_channel_alloc_with_endpoint, ast_channel_callgroup_set(), ast_channel_callid_set(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_nativeformats_set(), ast_channel_pickupgroup_set(), ast_channel_priority_set(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, ast_exists_extension(), ast_format_cap_alloc, ast_format_cap_append_from_cap(), ast_format_cap_count(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_format(), ast_format_cap_get_framing(), AST_MEDIA_TYPE_UNKNOWN, ast_random(), ast_rtp_codecs_set_framing(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_ice(), AST_STATE_RING, ast_strlen_zero, jingle_endpoint::callgroup, jingle_session::callid, jingle_session::cap, jingle_endpoint::connection, jingle_endpoint::context, ast_xmpp_client::endpoint, jingle_set_owner(), JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, jingle_endpoint::language, jingle_endpoint::musicclass, jingle_endpoint::name, NULL, jingle_endpoint::pickupgroup, jingle_session::remote, jingle_session::rtp, S_OR, ast_rtp_engine_ice::stop, str, and jingle_session::transport.

Referenced by jingle_action_session_initiate(), and jingle_request().

00768 {
00769    struct ast_channel *chan;
00770    const char *str = S_OR(title, session->remote);
00771    struct ast_format_cap *caps;
00772    struct ast_format *tmpfmt;
00773 
00774    if (!ast_format_cap_count(session->cap)) {
00775       return NULL;
00776    }
00777 
00778    caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
00779    if (!caps) {
00780       return NULL;
00781    }
00782 
00783    if (!(chan = ast_channel_alloc_with_endpoint(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, endpoint->connection->endpoint, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
00784       ao2_ref(caps, -1);
00785       return NULL;
00786    }
00787 
00788    ast_channel_stage_snapshot(chan);
00789 
00790    ast_channel_tech_set(chan, &jingle_tech);
00791    ast_channel_tech_pvt_set(chan, session);
00792    jingle_set_owner(session, chan);
00793 
00794    ast_channel_callid_set(chan, session->callid);
00795 
00796    ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN);
00797    ast_channel_nativeformats_set(chan, caps);
00798    ao2_ref(caps, -1);
00799 
00800    if (session->rtp) {
00801       struct ast_rtp_engine_ice *ice;
00802 
00803       ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
00804       ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
00805       ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp),
00806          ast_format_cap_get_framing(session->cap));
00807 
00808       if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
00809            (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
00810           (ice = ast_rtp_instance_get_ice(session->rtp))) {
00811          /* We stop built in ICE support because we need to fall back to old old old STUN support */
00812          ice->stop(session->rtp);
00813       }
00814    }
00815 
00816    if (state == AST_STATE_RING) {
00817       ast_channel_rings_set(chan, 1);
00818    }
00819 
00820    ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
00821 
00822    tmpfmt = ast_format_cap_get_format(session->cap, 0);
00823    ast_channel_set_writeformat(chan, tmpfmt);
00824    ast_channel_set_rawwriteformat(chan, tmpfmt);
00825    ast_channel_set_readformat(chan, tmpfmt);
00826    ast_channel_set_rawreadformat(chan, tmpfmt);
00827    ao2_ref(tmpfmt, -1);
00828 
00829    ao2_lock(endpoint);
00830 
00831    ast_channel_callgroup_set(chan, endpoint->callgroup);
00832    ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
00833 
00834    if (!ast_strlen_zero(endpoint->accountcode)) {
00835       ast_channel_accountcode_set(chan, endpoint->accountcode);
00836    }
00837 
00838    if (!ast_strlen_zero(endpoint->language)) {
00839       ast_channel_language_set(chan, endpoint->language);
00840    }
00841 
00842    if (!ast_strlen_zero(endpoint->musicclass)) {
00843       ast_channel_musicclass_set(chan, endpoint->musicclass);
00844    }
00845 
00846    ast_channel_context_set(chan, endpoint->context);
00847    if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
00848       ast_channel_exten_set(chan, endpoint->name);
00849    } else {
00850       ast_channel_exten_set(chan, "s");
00851    }
00852    ast_channel_priority_set(chan, 1);
00853 
00854    ao2_unlock(endpoint);
00855 
00856    ast_channel_stage_snapshot_done(chan);
00857    ast_channel_unlock(chan);
00858 
00859    return chan;
00860 }

static int jingle_outgoing_hook ( void *  data,
ikspak *  pak 
) [static]

Callback for when a response is received for an outgoing session-initiate message.

Definition at line 1523 of file chan_motif.c.

References ao2_unlock, ast_callid_threadassoc_add(), ast_callid_threadassoc_remove(), AST_CAUSE_CONGESTION, AST_CAUSE_FACILITY_NOT_IMPLEMENTED, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_PROTOCOL_ERROR, AST_CAUSE_REQUESTED_CHAN_UNAVAIL, ast_channel_unlock, ast_channel_unref, AST_CONTROL_PROCEEDING, ast_copy_string(), ast_queue_control(), ast_rtp_instance_get_ice(), ast_strlen_zero, jingle_session::callid, jingle_session::connection, end, error(), ast_xmpp_client::filter, jingle_session::gone, jingle_queue_hangup_with_cause(), jingle_send_session_initiate(), jingle_send_transport_info(), jingle_session_lock_full(), JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, JINGLE_TRANSPORT_NONE, ast_xmpp_client::mid, NULL, jingle_session::remote, jingle_session::remote_original, jingle_session::rtp, jingle_session::rule, session, ast_rtp_engine_ice::stop, jingle_session::transport, and XMPP_STANZAS_NS.

Referenced by jingle_call().

01524 {
01525    struct jingle_session *session = data;
01526    iks *error = iks_find(pak->x, "error"), *redirect;
01527 
01528    /* In all cases this hook is done with */
01529    iks_filter_remove_rule(session->connection->filter, session->rule);
01530    session->rule = NULL;
01531 
01532    ast_callid_threadassoc_add(session->callid);
01533 
01534    /* If no error occurred they accepted our session-initiate message happily */
01535    if (!error) {
01536       struct ast_channel *chan;
01537 
01538       if ((chan = jingle_session_lock_full(session))) {
01539          ast_queue_control(chan, AST_CONTROL_PROCEEDING);
01540          ast_channel_unlock(chan);
01541          ast_channel_unref(chan);
01542       }
01543       ao2_unlock(session);
01544 
01545       jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
01546 
01547       goto end;
01548    }
01549 
01550    /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
01551    session->gone = 1;
01552 
01553    /* Map the error we received to an appropriate cause code and hang up the channel */
01554    if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
01555       iks *to = iks_child(redirect);
01556       char *target;
01557 
01558       if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
01559          /* Make the xmpp: go away if it is present */
01560          if (!strncmp(target, "xmpp:", 5)) {
01561             target += 5;
01562          }
01563 
01564          /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
01565          ast_copy_string(session->remote, target, sizeof(session->remote));
01566 
01567          /* Add a new hook so we can get the status of redirected session */
01568          session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01569                          IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01570 
01571          jingle_send_session_initiate(session);
01572 
01573          session->gone = 0;
01574       } else {
01575          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01576       }
01577    } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
01578       jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
01579    } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
01580       jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
01581    } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
01582       jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01583    } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
01584       jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
01585    } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
01586       /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
01587       session->transport--;
01588 
01589       /* If we still have a viable transport mechanism re-send the session-initiate */
01590       if (session->transport != JINGLE_TRANSPORT_NONE) {
01591          struct ast_rtp_engine_ice *ice;
01592 
01593          if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
01594               (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
01595              (ice = ast_rtp_instance_get_ice(session->rtp))) {
01596             /* We stop built in ICE support because we need to fall back to old old old STUN support */
01597             ice->stop(session->rtp);
01598          }
01599 
01600          /* Re-send the message to the *original* target and not a redirected one */
01601          ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
01602 
01603          session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01604                          IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01605 
01606          jingle_send_session_initiate(session);
01607 
01608          session->gone = 0;
01609       } else {
01610          /* Otherwise we have exhausted all transports */
01611          jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
01612       }
01613    } else {
01614       jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01615    }
01616 
01617 end:
01618    ast_callid_threadassoc_remove();
01619 
01620    return IKS_FILTER_EAT;
01621 }

static void jingle_queue_hangup_with_cause ( struct jingle_session session,
int  cause 
) [static]

Helper function which queues a hangup frame with cause code.

Definition at line 1196 of file chan_motif.c.

References ao2_unlock, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_queue_hangup_with_cause(), and jingle_session_lock_full().

Referenced by jingle_interpret_content(), jingle_interpret_description(), jingle_interpret_google_transport(), jingle_interpret_ice_udp_transport(), jingle_outgoing_hook(), jingle_send_session_action(), and jingle_send_transport_info().

01197 {
01198    struct ast_channel *chan;
01199 
01200    if ((chan = jingle_session_lock_full(session))) {
01201       ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
01202       ast_queue_hangup_with_cause(chan, cause);
01203       ast_channel_unlock(chan);
01204       ast_channel_unref(chan);
01205    }
01206    ao2_unlock(session);
01207 }

static struct ast_frame * jingle_read ( struct ast_channel ast  )  [static, read]

Function called by core to read any waiting frames.

Definition at line 1639 of file chan_motif.c.

References ao2_ref, ast_channel_fdno(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_nativeformats_set(), ast_channel_readformat(), ast_channel_tech_pvt(), ast_channel_writeformat(), ast_debug, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_iscompatible_format(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_VOICE, ast_frfree, ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), ast_frame_subclass::format, ast_frame::frametype, jingle_session::jointcap, jingle_session::rtp, session, ast_frame::subclass, and jingle_session::vrtp.

01640 {
01641    struct jingle_session *session = ast_channel_tech_pvt(ast);
01642    struct ast_frame *frame = &ast_null_frame;
01643 
01644    switch (ast_channel_fdno(ast)) {
01645    case 0:
01646       if (session->rtp) {
01647          frame = ast_rtp_instance_read(session->rtp, 0);
01648       }
01649       break;
01650    case 1:
01651       if (session->rtp) {
01652          frame = ast_rtp_instance_read(session->rtp, 1);
01653       }
01654       break;
01655    case 2:
01656       if (session->vrtp) {
01657          frame = ast_rtp_instance_read(session->vrtp, 0);
01658       }
01659       break;
01660    case 3:
01661       if (session->vrtp) {
01662          frame = ast_rtp_instance_read(session->vrtp, 1);
01663       }
01664       break;
01665    default:
01666       break;
01667    }
01668 
01669    if (frame && frame->frametype == AST_FRAME_VOICE &&
01670        ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
01671       if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
01672          ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
01673               ast_format_get_name(frame->subclass.format), ast_channel_name(ast));
01674          ast_frfree(frame);
01675          frame = &ast_null_frame;
01676       } else {
01677          struct ast_format_cap *caps;
01678 
01679          ast_debug(1, "Oooh, format changed to %s\n",
01680               ast_format_get_name(frame->subclass.format));
01681 
01682          caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
01683          if (caps) {
01684             ast_format_cap_append(caps, frame->subclass.format, 0);
01685             ast_channel_nativeformats_set(ast, caps);
01686             ao2_ref(caps, -1);
01687          }
01688          ast_set_read_format(ast, ast_channel_readformat(ast));
01689          ast_set_write_format(ast, ast_channel_writeformat(ast));
01690       }
01691    }
01692 
01693    return frame;
01694 }

static struct ast_channel * jingle_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor,
const char *  data,
int *  cause 
) [static, read]

Function called by core to create a new outgoing Jingle session.

Definition at line 1903 of file chan_motif.c.

References ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, AST_CAUSE_CHANNEL_UNACCEPTABLE, AST_CAUSE_SWITCH_CONGESTION, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_format_cap_has_type(), ast_log, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, AST_NONSTANDARD_APP_ARGS, ast_rtp_instance_get_ice(), AST_STATE_DOWN, ast_strdupa, ast_strlen_zero, ast_xmpp_resource::caps, ast_channel::dialed, globals, ast_xmpp_capabilities::google, ast_rtp_engine_ice::ice_lite, ast_xmpp_capabilities::jingle, jingle_alloc(), jingle_enable_video(), jingle_endpoint_find(), jingle_new(), JINGLE_TRANSPORT_GOOGLE_V2, JINGLE_TRANSPORT_ICE_UDP, JINGLE_TRANSPORT_NONE, LOG_ERROR, name, NULL, OBJ_KEY, RAII_VAR, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, jingle_session::rtp, session, jingle_session::transport, and jingle_session::vrtp.

01904 {
01905    RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01906    RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
01907    char *dialed, target[200] = "";
01908    struct ast_xmpp_buddy *buddy;
01909    struct jingle_session *session;
01910    struct ast_channel *chan;
01911    enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
01912    struct ast_rtp_engine_ice *ice;
01913    AST_DECLARE_APP_ARGS(args,
01914               AST_APP_ARG(name);
01915               AST_APP_ARG(target);
01916       );
01917 
01918    /* We require at a minimum one audio format to be requested */
01919    if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) {
01920       ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
01921       *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
01922       return NULL;
01923    }
01924 
01925    if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
01926       ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
01927       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01928       return NULL;
01929    }
01930 
01931    /* Parse the given dial string and validate the results */
01932    AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
01933 
01934    if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
01935       ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
01936       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01937       return NULL;
01938    }
01939 
01940    if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
01941       ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
01942       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01943       return NULL;
01944    }
01945 
01946    ao2_lock(endpoint->state);
01947 
01948    /* If we don't have a connection for the endpoint we can't exactly start a session on it */
01949    if (!endpoint->connection) {
01950       ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
01951       *cause = AST_CAUSE_SWITCH_CONGESTION;
01952       ao2_unlock(endpoint->state);
01953       return NULL;
01954    }
01955 
01956    /* Find the target in the roster so we can choose a resource */
01957    if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
01958       struct ao2_iterator res;
01959       struct ast_xmpp_resource *resource;
01960 
01961       /* Iterate through finding the first viable Jingle capable resource */
01962       res = ao2_iterator_init(buddy->resources, 0);
01963       while ((resource = ao2_iterator_next(&res))) {
01964          if (resource->caps.jingle) {
01965             snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01966             transport = JINGLE_TRANSPORT_ICE_UDP;
01967             break;
01968          } else if (resource->caps.google) {
01969             snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01970             transport = JINGLE_TRANSPORT_GOOGLE_V2;
01971             break;
01972          }
01973          ao2_ref(resource, -1);
01974       }
01975       ao2_iterator_destroy(&res);
01976 
01977       ao2_ref(buddy, -1);
01978    } else {
01979       /* If the target is NOT in the roster use the provided target as-is */
01980       ast_copy_string(target, args.target, sizeof(target));
01981    }
01982 
01983    ao2_unlock(endpoint->state);
01984 
01985    /* If no target was found we can't set up a session */
01986    if (ast_strlen_zero(target)) {
01987       ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no capable resource for target '%s' was found\n", args.name, args.target);
01988       *cause = AST_CAUSE_SWITCH_CONGESTION;
01989       return NULL;
01990    }
01991 
01992    if (!(session = jingle_alloc(endpoint, target, NULL))) {
01993       ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
01994       *cause = AST_CAUSE_SWITCH_CONGESTION;
01995       return NULL;
01996    }
01997 
01998    /* Update the transport if we learned what we should actually use */
01999    if (transport != JINGLE_TRANSPORT_NONE) {
02000       session->transport = transport;
02001       /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
02002    }
02003 
02004    if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
02005       ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
02006       *cause = AST_CAUSE_SWITCH_CONGESTION;
02007       ao2_ref(session, -1);
02008       return NULL;
02009    }
02010 
02011    /* If video was requested try to enable it on the session */
02012    if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) {
02013       jingle_enable_video(session);
02014    }
02015 
02016    /* As this is outgoing set ourselves as controlling */
02017    if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
02018       ice->ice_lite(session->rtp);
02019    }
02020 
02021    if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
02022       ice->ice_lite(session->vrtp);
02023    }
02024 
02025    /* We purposely don't decrement the session here as there is a reference on the channel */
02026    ao2_link(endpoint->state->sessions, session);
02027 
02028    return chan;
02029 }

static void jingle_send_error_response ( struct ast_xmpp_client connection,
ikspak *  pak,
const char *  type,
const char *  reasonstr,
const char *  reasonstr2 
) [static]

Internal helper function which sends an error response.

Definition at line 883 of file chan_motif.c.

References ast_log, ast_strlen_zero, ast_xmpp_client_send(), end, error(), ast_xmpp_client::jid, LOG_ERROR, and NULL.

Referenced by jingle_action_session_accept(), jingle_action_session_info(), jingle_action_session_initiate(), jingle_action_session_terminate(), and jingle_action_transport_info().

00884 {
00885    iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
00886 
00887    if (!(response = iks_new("iq")) ||
00888        !(error = iks_new("error")) ||
00889        !(reason = iks_new(reasonstr))) {
00890       ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
00891       goto end;
00892    }
00893 
00894    iks_insert_attrib(response, "type", "error");
00895    iks_insert_attrib(response, "from", connection->jid->full);
00896    iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00897    iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00898 
00899    iks_insert_attrib(error, "type", type);
00900    iks_insert_node(error, reason);
00901 
00902    if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
00903       iks_insert_node(error, reason2);
00904    }
00905 
00906    iks_insert_node(response, error);
00907 
00908    ast_xmpp_client_send(connection, response);
00909 end:
00910    iks_delete(reason2);
00911    iks_delete(reason);
00912    iks_delete(error);
00913    iks_delete(response);
00914 }

static void jingle_send_response ( struct ast_xmpp_client connection,
ikspak *  pak 
) [static]

Internal helper function which sends a response.

Definition at line 863 of file chan_motif.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_client::jid, and LOG_ERROR.

Referenced by jingle_action_session_accept(), jingle_action_session_info(), jingle_action_session_initiate(), jingle_action_session_terminate(), and jingle_action_transport_info().

00864 {
00865    iks *response;
00866 
00867    if (!(response = iks_new("iq"))) {
00868       ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
00869       return;
00870    }
00871 
00872    iks_insert_attrib(response, "type", "result");
00873    iks_insert_attrib(response, "from", connection->jid->full);
00874    iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00875    iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00876 
00877    ast_xmpp_client_send(connection, response);
00878 
00879    iks_delete(response);
00880 }

static void jingle_send_session_accept ( struct jingle_session session  )  [static]

Internal function which sends a session-accept message.

Definition at line 1517 of file chan_motif.c.

References jingle_send_session_action(), JINGLE_TRANSPORT_GOOGLE_V1, and jingle_session::transport.

Referenced by jingle_answer().

01518 {
01519    jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
01520 }

static void jingle_send_session_action ( struct jingle_session session,
const char *  action 
) [static]

Internal function which sends a complete session message.

Definition at line 1429 of file chan_motif.c.

References AST_CAUSE_SWITCH_CONGESTION, ast_log, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, ast_xmpp_client_send(), ast_xmpp_increment_mid(), jingle_session::audio_name, jingle_session::connection, GOOGLE_SESSION_NS, ast_xmpp_client::jid, jingle_add_content(), JINGLE_NS, jingle_queue_hangup_with_cause(), JINGLE_TRANSPORT_GOOGLE_V1, LOG_ERROR, jingle_session::maxpayloads, ast_xmpp_client::mid, NULL, jingle_session::outgoing, jingle_session::remote, jingle_session::rtp, jingle_session::sid, jingle_session::transport, jingle_session::video_name, and jingle_session::vrtp.

Referenced by jingle_send_session_accept(), and jingle_send_session_initiate().

01430 {
01431    iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
01432    iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
01433    iks *audio_transport = NULL, *video_transport = NULL;
01434    int i, res = 0;
01435 
01436    if (!(iq = iks_new("iq")) ||
01437        !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01438       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01439       iks_delete(iq);
01440       return;
01441    }
01442 
01443    memset(audio_payloads, 0, sizeof(audio_payloads));
01444    memset(video_payloads, 0, sizeof(video_payloads));
01445 
01446    iks_insert_attrib(iq, "from", session->connection->jid->full);
01447    iks_insert_attrib(iq, "to", session->remote);
01448    iks_insert_attrib(iq, "type", "set");
01449    iks_insert_attrib(iq, "id", session->connection->mid);
01450    ast_xmpp_increment_mid(session->connection->mid);
01451 
01452    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01453       iks_insert_attrib(jingle, "type", action);
01454       iks_insert_attrib(jingle, "id", session->sid);
01455       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01456    } else {
01457       iks_insert_attrib(jingle, "action", action);
01458       iks_insert_attrib(jingle, "sid", session->sid);
01459       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01460    }
01461 
01462    if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
01463       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
01464    }
01465 
01466    iks_insert_node(iq, jingle);
01467 
01468    if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
01469        (audio_transport = iks_new("transport"))) {
01470       res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
01471                 AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads);
01472    } else {
01473       ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
01474       res = -1;
01475    }
01476 
01477    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01478       if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
01479           (video_transport = iks_new("transport"))) {
01480          res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
01481                    AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads);
01482       } else {
01483          ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
01484          res = -1;
01485       }
01486    }
01487 
01488    if (!res) {
01489       ast_xmpp_client_send(session->connection, iq);
01490    } else {
01491       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01492    }
01493 
01494    iks_delete(video_transport);
01495    iks_delete(audio_transport);
01496 
01497    for (i = 0; i < session->maxpayloads; i++) {
01498       iks_delete(video_payloads[i]);
01499       iks_delete(audio_payloads[i]);
01500    }
01501 
01502    iks_delete(video_description);
01503    iks_delete(video);
01504    iks_delete(audio_description);
01505    iks_delete(audio);
01506    iks_delete(jingle);
01507    iks_delete(iq);
01508 }

static void jingle_send_session_info ( struct jingle_session session,
const char *  info 
) [static]

Internal function which sends a session-info message.

Definition at line 1097 of file chan_motif.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_increment_mid(), jingle_session::connection, end, JINGLE_NS, JINGLE_TRANSPORT_GOOGLE_V1, LOG_ERROR, ast_xmpp_client::mid, NULL, jingle_session::remote, jingle_session::sid, text, and jingle_session::transport.

Referenced by jingle_indicate().

01098 {
01099    iks *iq = NULL, *jingle = NULL, *text = NULL;
01100 
01101    /* Google-V1 has no way to send informational messages so don't even bother trying */
01102    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01103       return;
01104    }
01105 
01106    if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
01107       ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
01108       goto end;
01109    }
01110 
01111    iks_insert_attrib(iq, "to", session->remote);
01112    iks_insert_attrib(iq, "type", "set");
01113    iks_insert_attrib(iq, "id", session->connection->mid);
01114    ast_xmpp_increment_mid(session->connection->mid);
01115 
01116    iks_insert_attrib(jingle, "action", "session-info");
01117    iks_insert_attrib(jingle, "sid", session->sid);
01118    iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01119    iks_insert_node(iq, jingle);
01120    iks_insert_node(jingle, text);
01121 
01122    ast_xmpp_client_send(session->connection, iq);
01123 
01124 end:
01125    iks_delete(text);
01126    iks_delete(jingle);
01127    iks_delete(iq);
01128 }

static void jingle_send_session_initiate ( struct jingle_session session  )  [static]

Internal function which sends a session-inititate message.

Definition at line 1511 of file chan_motif.c.

References jingle_send_session_action(), JINGLE_TRANSPORT_GOOGLE_V1, and jingle_session::transport.

Referenced by jingle_call(), and jingle_outgoing_hook().

01512 {
01513    jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
01514 }

static void jingle_send_session_terminate ( struct jingle_session session,
const char *  reasontext 
) [static]

Internal function which sends a session-terminate message.

Definition at line 1057 of file chan_motif.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_increment_mid(), jingle_session::connection, end, GOOGLE_SESSION_NS, ast_xmpp_client::jid, JINGLE_NS, JINGLE_TRANSPORT_GOOGLE_V1, LOG_ERROR, ast_xmpp_client::mid, NULL, jingle_session::outgoing, jingle_session::remote, jingle_session::sid, text, and jingle_session::transport.

Referenced by jingle_hangup().

01058 {
01059    iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
01060 
01061    if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
01062        !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
01063       ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
01064       goto end;
01065    }
01066 
01067    iks_insert_attrib(iq, "to", session->remote);
01068    iks_insert_attrib(iq, "type", "set");
01069    iks_insert_attrib(iq, "id", session->connection->mid);
01070    ast_xmpp_increment_mid(session->connection->mid);
01071 
01072    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01073       iks_insert_attrib(jingle, "type", "terminate");
01074       iks_insert_attrib(jingle, "id", session->sid);
01075       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01076       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
01077    } else {
01078       iks_insert_attrib(jingle, "action", "session-terminate");
01079       iks_insert_attrib(jingle, "sid", session->sid);
01080       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01081    }
01082 
01083    iks_insert_node(iq, jingle);
01084    iks_insert_node(jingle, reason);
01085    iks_insert_node(reason, text);
01086 
01087    ast_xmpp_client_send(session->connection, iq);
01088 
01089 end:
01090    iks_delete(text);
01091    iks_delete(reason);
01092    iks_delete(jingle);
01093    iks_delete(iq);
01094 }

static void jingle_send_transport_info ( struct jingle_session session,
const char *  from 
) [static]

Internal function which sends a transport-info message.

Definition at line 1210 of file chan_motif.c.

References AST_CAUSE_SWITCH_CONGESTION, ast_log, ast_xmpp_client_send(), ast_xmpp_increment_mid(), jingle_session::audio_name, jingle_session::connection, GOOGLE_SESSION_NS, ast_xmpp_client::jid, jingle_add_google_candidates_to_transport(), jingle_add_ice_udp_candidates_to_transport(), JINGLE_NS, jingle_queue_hangup_with_cause(), JINGLE_TRANSPORT_GOOGLE_V1, JINGLE_TRANSPORT_GOOGLE_V2, JINGLE_TRANSPORT_ICE_UDP, LOG_ERROR, jingle_session::maxicecandidates, ast_xmpp_client::mid, NULL, jingle_session::outgoing, jingle_session::rtp, jingle_session::sid, jingle_session::transport, jingle_session::video_name, and jingle_session::vrtp.

Referenced by jingle_action_session_initiate(), and jingle_outgoing_hook().

01211 {
01212    iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
01213    iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
01214    int i, res = 0;
01215 
01216    if (!(iq = iks_new("iq")) ||
01217        !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01218       iks_delete(iq);
01219       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01220       ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
01221       return;
01222    }
01223 
01224    memset(audio_candidates, 0, sizeof(audio_candidates));
01225    memset(video_candidates, 0, sizeof(video_candidates));
01226 
01227    iks_insert_attrib(iq, "from", session->connection->jid->full);
01228    iks_insert_attrib(iq, "to", from);
01229    iks_insert_attrib(iq, "type", "set");
01230    iks_insert_attrib(iq, "id", session->connection->mid);
01231    ast_xmpp_increment_mid(session->connection->mid);
01232 
01233    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01234       iks_insert_attrib(jingle, "type", "candidates");
01235       iks_insert_attrib(jingle, "id", session->sid);
01236       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01237       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
01238    } else {
01239       iks_insert_attrib(jingle, "action", "transport-info");
01240       iks_insert_attrib(jingle, "sid", session->sid);
01241       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01242    }
01243    iks_insert_node(iq, jingle);
01244 
01245    if (session->rtp) {
01246       if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01247          /* V1 protocol has the candidates directly in the session */
01248          res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
01249       } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
01250          iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
01251          iks_insert_attrib(audio, "name", session->audio_name);
01252          iks_insert_node(jingle, audio);
01253          iks_insert_node(audio, audio_transport);
01254 
01255          if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01256             res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
01257          } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01258             res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
01259                               session->maxicecandidates);
01260          }
01261       } else {
01262          res = -1;
01263       }
01264    }
01265 
01266    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01267       if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
01268          iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
01269          iks_insert_attrib(video, "name", session->video_name);
01270          iks_insert_node(jingle, video);
01271          iks_insert_node(video, video_transport);
01272 
01273          if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01274             res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
01275          } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01276             res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
01277                               session->maxicecandidates);
01278          }
01279       } else {
01280          res = -1;
01281       }
01282    }
01283 
01284    if (!res) {
01285       ast_xmpp_client_send(session->connection, iq);
01286    } else {
01287       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01288    }
01289 
01290    /* Clean up after ourselves */
01291    for (i = 0; i < session->maxicecandidates; i++) {
01292       iks_delete(video_candidates[i]);
01293       iks_delete(audio_candidates[i]);
01294    }
01295 
01296    iks_delete(video_transport);
01297    iks_delete(video);
01298    iks_delete(audio_transport);
01299    iks_delete(audio);
01300    iks_delete(jingle);
01301    iks_delete(iq);
01302 }

static int jingle_sendtext ( struct ast_channel ast,
const char *  text 
) [static]

Function called by core to send text to the remote party of the Jingle session.

Definition at line 1817 of file chan_motif.c.

References ast_channel_tech_pvt(), ast_xmpp_client_send_message(), jingle_session::connection, jingle_session::remote, and session.

01818 {
01819    struct jingle_session *session = ast_channel_tech_pvt(chan);
01820 
01821    return ast_xmpp_client_send_message(session->connection, session->remote, text);
01822 }

static int jingle_session_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Comparator function for Jingle sessions.

Definition at line 427 of file chan_motif.c.

References CMP_MATCH, CMP_STOP, OBJ_KEY, and jingle_session::sid.

Referenced by jingle_endpoint_state_create().

00428 {
00429    struct jingle_session *session1 = obj, *session2 = arg;
00430    const char *sid = arg;
00431 
00432    return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
00433 }

static void jingle_session_destructor ( void *  obj  )  [static]

Destructor for Jingle sessions.

Definition at line 562 of file chan_motif.c.

References ao2_cleanup, ast_rtp_instance_destroy(), ast_rtp_instance_stop(), ast_string_field_free_memory, ast_xmpp_client_unref(), jingle_session::cap, jingle_session::connection, ast_xmpp_client::filter, jingle_session::jointcap, jingle_session::peercap, jingle_session::rtp, jingle_session::rule, session, and jingle_session::vrtp.

Referenced by jingle_alloc().

00563 {
00564    struct jingle_session *session = obj;
00565 
00566    if (session->rule) {
00567       iks_filter_remove_rule(session->connection->filter, session->rule);
00568    }
00569 
00570    if (session->connection) {
00571       ast_xmpp_client_unref(session->connection);
00572    }
00573 
00574    if (session->rtp) {
00575       ast_rtp_instance_stop(session->rtp);
00576       ast_rtp_instance_destroy(session->rtp);
00577    }
00578 
00579    if (session->vrtp) {
00580       ast_rtp_instance_stop(session->vrtp);
00581       ast_rtp_instance_destroy(session->vrtp);
00582    }
00583 
00584    ao2_cleanup(session->cap);
00585    ao2_cleanup(session->jointcap);
00586    ao2_cleanup(session->peercap);
00587 
00588    ast_string_field_free_memory(session);
00589 }

static int jingle_session_hash ( const void *  obj,
const int  flags 
) [static]

Hashing function for Jingle sessions.

Definition at line 418 of file chan_motif.c.

References ast_str_hash(), OBJ_KEY, session, and jingle_session::sid.

Referenced by jingle_endpoint_state_create().

00419 {
00420    const struct jingle_session *session = obj;
00421    const char *sid = obj;
00422 
00423    return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
00424 }

static struct ast_channel* jingle_session_lock_full ( struct jingle_session pvt  )  [static, read]

Definition at line 1147 of file chan_motif.c.

References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, NULL, and jingle_session::owner.

Referenced by jingle_action_session_accept(), jingle_action_session_info(), jingle_action_session_terminate(), jingle_interpret_content(), jingle_outgoing_hook(), and jingle_queue_hangup_with_cause().

01148 {
01149    struct ast_channel *chan;
01150 
01151    /* Locking is simple when it is done right.  If you see a deadlock resulting
01152     * in this function, it is not this function's fault, Your problem exists elsewhere.
01153     * This function is perfect... seriously. */
01154    for (;;) {
01155       /* First, get the channel and grab a reference to it */
01156       ao2_lock(pvt);
01157       chan = pvt->owner;
01158       if (chan) {
01159          /* The channel can not go away while we hold the pvt lock.
01160           * Give the channel a ref so it will not go away after we let
01161           * the pvt lock go. */
01162          ast_channel_ref(chan);
01163       } else {
01164          /* no channel, return pvt locked */
01165          return NULL;
01166       }
01167 
01168       /* We had to hold the pvt lock while getting a ref to the owner channel
01169        * but now we have to let this lock go in order to preserve proper
01170        * locking order when grabbing the channel lock */
01171       ao2_unlock(pvt);
01172 
01173       /* Look, no deadlock avoidance, hooray! */
01174       ast_channel_lock(chan);
01175       ao2_lock(pvt);
01176       if (pvt->owner == chan) {
01177          /* done */
01178          break;
01179       }
01180 
01181       /* If the owner changed while everything was unlocked, no problem,
01182        * just start over and everthing will work.  This is rare, do not be
01183        * confused by this loop and think this it is an expensive operation.
01184        * The majority of the calls to this function will never involve multiple
01185        * executions of this loop. */
01186       ast_channel_unlock(chan);
01187       ast_channel_unref(chan);
01188       ao2_unlock(pvt);
01189    }
01190 
01191    /* If owner exists, it is locked and reffed */
01192    return pvt->owner;
01193 }

static void jingle_set_owner ( struct jingle_session session,
struct ast_channel chan 
) [static]

Set the channel owner on the jingle_session object and related objects.

Definition at line 655 of file chan_motif.c.

References ast_channel_uniqueid(), ast_rtp_instance_set_channel_id(), jingle_session::owner, jingle_session::rtp, and jingle_session::vrtp.

Referenced by jingle_fixup(), jingle_hangup(), and jingle_new().

00656 {
00657    session->owner = chan;
00658    if (session->rtp) {
00659       ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
00660    }
00661    if (session->vrtp) {
00662       ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
00663    }
00664 }

static int jingle_set_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance rtp,
struct ast_rtp_instance vrtp,
struct ast_rtp_instance tpeer,
const struct ast_format_cap cap,
int  nat_active 
) [static]

Function called by RTP engine to change where the remote party should send media.

Definition at line 641 of file chan_motif.c.

00642 {
00643    return -1;
00644 }

static int jingle_write ( struct ast_channel ast,
struct ast_frame f 
) [static]

Function called by core to write frames.

Definition at line 1697 of file chan_motif.c.

References ast_channel_nativeformats(), ast_channel_readformat(), ast_channel_tech_pvt(), ast_channel_writeformat(), ast_format_cap_get_names(), ast_format_cap_iscompatible_format(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log, ast_rtp_instance_write(), ast_str_alloca, ast_frame_subclass::format, ast_frame::frametype, LOG_WARNING, jingle_session::rtp, session, ast_frame::subclass, and jingle_session::vrtp.

01698 {
01699    struct jingle_session *session = ast_channel_tech_pvt(ast);
01700    int res = 0;
01701 
01702    switch (frame->frametype) {
01703    case AST_FRAME_VOICE:
01704       if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
01705          struct ast_str *codec_buf = ast_str_alloca(64);
01706 
01707          ast_log(LOG_WARNING,
01708             "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01709             ast_format_get_name(frame->subclass.format),
01710             ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
01711             ast_format_get_name(ast_channel_readformat(ast)),
01712             ast_format_get_name(ast_channel_writeformat(ast)));
01713          return 0;
01714       }
01715       if (session && session->rtp) {
01716          res = ast_rtp_instance_write(session->rtp, frame);
01717       }
01718       break;
01719    case AST_FRAME_VIDEO:
01720       if (session && session->vrtp) {
01721          res = ast_rtp_instance_write(session->vrtp, frame);
01722       }
01723       break;
01724    default:
01725       ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
01726          frame->frametype);
01727       return 0;
01728    }
01729 
01730    return res;
01731 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 2725 of file chan_motif.c.

References accountcode, ACO_EXACT, aco_info_destroy(), aco_info_init(), aco_option_register, aco_option_register_custom, aco_process_config(), ao2_cleanup, ao2_global_obj_release, ast_channel_register(), ast_format_cap_alloc, ast_format_cap_append_by_type(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_log, AST_MEDIA_TYPE_AUDIO, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, ast_rtp_glue_register, ast_rtp_glue_unregister(), ast_sched_context_create(), ast_sched_context_destroy(), ast_sched_start_thread(), jingle_endpoint::cap, ast_channel_tech::capabilities, context, custom_connection_handler(), custom_group_handler(), custom_transport_handler(), DEFAULT_MAX_ICE_CANDIDATES, DEFAULT_MAX_PAYLOADS, end, FLDSET, globals, language, LOG_ERROR, jingle_endpoint::maxicecandidates, jingle_endpoint::maxpayloads, musicclass, NULL, OPT_CODEC_T, OPT_STRINGFIELD_T, OPT_UINT_T, parkinglot, PARSE_DEFAULT, and STRFLDSET.

02726 {
02727    if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
02728       return AST_MODULE_LOAD_DECLINE;
02729    }
02730 
02731    if (aco_info_init(&cfg_info)) {
02732       ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
02733       goto end;
02734    }
02735 
02736    aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
02737    aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02738    aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02739    aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
02740    aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
02741    aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
02742    aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
02743    aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
02744    aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
02745    aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
02746    aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
02747    aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
02748              FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
02749    aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
02750              FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
02751 
02752    ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
02753 
02754    if (aco_process_config(&cfg_info, 0)) {
02755       ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
02756       aco_info_destroy(&cfg_info);
02757       ao2_cleanup(jingle_tech.capabilities);
02758       jingle_tech.capabilities = NULL;
02759       return AST_MODULE_LOAD_DECLINE;
02760    }
02761 
02762    if (!(sched = ast_sched_context_create())) {
02763       ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
02764       goto end;
02765    }
02766 
02767    if (ast_sched_start_thread(sched)) {
02768       ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
02769       goto end;
02770    }
02771 
02772    ast_rtp_glue_register(&jingle_rtp_glue);
02773 
02774    if (ast_channel_register(&jingle_tech)) {
02775       ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
02776       goto end;
02777    }
02778 
02779    return 0;
02780 
02781 end:
02782    ast_rtp_glue_unregister(&jingle_rtp_glue);
02783 
02784    if (sched) {
02785       ast_sched_context_destroy(sched);
02786    }
02787 
02788    aco_info_destroy(&cfg_info);
02789    ao2_global_obj_release(globals);
02790 
02791    ao2_cleanup(jingle_tech.capabilities);
02792    jingle_tech.capabilities = NULL;
02793 
02794    return AST_MODULE_LOAD_FAILURE;
02795 }

static int reload ( void   )  [static]

Reload module.

Definition at line 2798 of file chan_motif.c.

References aco_process_config(), and ACO_PROCESS_ERROR.

02799 {
02800    if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
02801       return -1;
02802    }
02803 
02804    return 0;
02805 }

static int unload_module ( void   )  [static]


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Motif Jingle Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 2827 of file chan_motif.c.

Definition at line 2827 of file chan_motif.c.

const char channel_type[] = "Motif" [static]

Definition at line 324 of file chan_motif.c.

const char desc[] = "Motif Jingle Channel" [static]

Definition at line 323 of file chan_motif.c.

struct aco_type endpoint_option [static]

Definition at line 544 of file chan_motif.c.

struct aco_type* endpoint_options[] = ACO_TYPES(&endpoint_option)

Definition at line 554 of file chan_motif.c.

Defined handlers for different Jingle actions.

Referenced by jingle_action_hook().

Initial value:

 {
   .filename = "motif.conf",
   .types = ACO_TYPES(&endpoint_option),
}

Definition at line 556 of file chan_motif.c.

Reason text <-> cause code mapping.

Referenced by jingle_action_session_terminate(), and jingle_hangup().

struct ast_rtp_glue jingle_rtp_glue [static]

Local glue for interacting with the RTP engine core.

Definition at line 647 of file chan_motif.c.

struct ast_channel_tech jingle_tech [static]

PBX interface structure for channel registration.

Definition at line 356 of file chan_motif.c.

struct ast_sched_context* sched [static]

Scheduling context for RTCP

Definition at line 332 of file chan_motif.c.


Generated on Thu Apr 16 06:29:45 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6