Sat Apr 26 2014 22:01:32

Asterisk developer's documentation


chan_motif.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2012, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \author Joshua Colp <jcolp@digium.com>
00022  *
00023  * \brief Motif Jingle Channel Driver
00024  *
00025  * \extref Iksemel http://iksemel.jabberstudio.org/
00026  *
00027  * \ingroup channel_drivers
00028  */
00029 
00030 /*** MODULEINFO
00031    <depend>iksemel</depend>
00032    <depend>res_xmpp</depend>
00033    <use type="external">openssl</use>
00034    <support_level>core</support_level>
00035  ***/
00036 
00037 #include "asterisk.h"
00038 
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397744 $")
00040 
00041 #include <sys/socket.h>
00042 #include <fcntl.h>
00043 #include <netdb.h>
00044 #include <netinet/in.h>
00045 #include <arpa/inet.h>
00046 #include <sys/signal.h>
00047 #include <iksemel.h>
00048 #include <pthread.h>
00049 
00050 #include "asterisk/lock.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/config_options.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/pbx.h"
00055 #include "asterisk/sched.h"
00056 #include "asterisk/io.h"
00057 #include "asterisk/rtp_engine.h"
00058 #include "asterisk/acl.h"
00059 #include "asterisk/callerid.h"
00060 #include "asterisk/file.h"
00061 #include "asterisk/cli.h"
00062 #include "asterisk/app.h"
00063 #include "asterisk/musiconhold.h"
00064 #include "asterisk/manager.h"
00065 #include "asterisk/stringfields.h"
00066 #include "asterisk/utils.h"
00067 #include "asterisk/causes.h"
00068 #include "asterisk/astobj.h"
00069 #include "asterisk/abstract_jb.h"
00070 #include "asterisk/xmpp.h"
00071 
00072 /*! \brief Default maximum number of ICE candidates we will offer */
00073 #define DEFAULT_MAX_ICE_CANDIDATES "10"
00074 
00075 /*! \brief Default maximum number of payloads we will offer */
00076 #define DEFAULT_MAX_PAYLOADS "30"
00077 
00078 /*! \brief Number of buckets for endpoints */
00079 #define ENDPOINT_BUCKETS 37
00080 
00081 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
00082 #define SESSION_BUCKETS 37
00083 
00084 /*! \brief Namespace for Jingle itself */
00085 #define JINGLE_NS "urn:xmpp:jingle:1"
00086 
00087 /*! \brief Namespace for Jingle RTP sessions */
00088 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
00089 
00090 /*! \brief Namespace for Jingle RTP info */
00091 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
00092 
00093 /*! \brief Namespace for Jingle ICE-UDP */
00094 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
00095 
00096 /*! \brief Namespace for Google Talk ICE-UDP */
00097 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
00098 
00099 /*! \brief Namespace for Google Talk Raw UDP */
00100 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
00101 
00102 /*! \brief Namespace for Google Session */
00103 #define GOOGLE_SESSION_NS "http://www.google.com/session"
00104 
00105 /*! \brief Namespace for Google Phone description */
00106 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
00107 
00108 /*! \brief Namespace for Google Video description */
00109 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
00110 
00111 /*! \brief Namespace for XMPP stanzas */
00112 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
00113 
00114 /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */
00115 enum jingle_transport {
00116    JINGLE_TRANSPORT_ICE_UDP = 3,   /*!< XEP-0176 */
00117    JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
00118    JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
00119    JINGLE_TRANSPORT_NONE = 0,      /*!< No transport specified */
00120 };
00121 
00122 /*! \brief Endpoint state information */
00123 struct jingle_endpoint_state {
00124    struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
00125 };
00126 
00127 /*! \brief Endpoint which contains configuration information and active sessions */
00128 struct jingle_endpoint {
00129    AST_DECLARE_STRING_FIELDS(
00130       AST_STRING_FIELD(name);              /*!< Name of the endpoint */
00131       AST_STRING_FIELD(context);           /*!< Context to place incoming calls into */
00132       AST_STRING_FIELD(accountcode);       /*!< Account code */
00133       AST_STRING_FIELD(language);          /*!< Default language for prompts */
00134       AST_STRING_FIELD(musicclass);        /*!< Configured music on hold class */
00135       AST_STRING_FIELD(parkinglot);        /*!< Configured parking lot */
00136       );
00137    struct ast_xmpp_client *connection;     /*!< Connection to use for traffic */
00138    iksrule *rule;                          /*!< Active matching rule */
00139    unsigned int maxicecandidates;          /*!< Maximum number of ICE candidates we will offer */
00140    unsigned int maxpayloads;               /*!< Maximum number of payloads we will offer */
00141    struct ast_codec_pref prefs;            /*!< Codec preferences */
00142    struct ast_format_cap *cap;             /*!< Formats to use */
00143    ast_group_t callgroup;                  /*!< Call group */
00144    ast_group_t pickupgroup;                /*!< Pickup group */
00145    enum jingle_transport transport;        /*!< Default transport to use on outgoing sessions */
00146    struct jingle_endpoint_state *state;    /*!< Endpoint state information */
00147 };
00148 
00149 /*! \brief Session which contains information about an active session */
00150 struct jingle_session {
00151    AST_DECLARE_STRING_FIELDS(
00152       AST_STRING_FIELD(sid);        /*!< Session identifier */
00153       AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
00154       AST_STRING_FIELD(video_name); /*!< Name of the video content */
00155       );
00156    struct jingle_endpoint_state *state;  /*!< Endpoint we are associated with */
00157    struct ast_xmpp_client *connection;   /*!< Connection to use for traffic */
00158    enum jingle_transport transport;      /*!< Transport type to use for this session */
00159    unsigned int maxicecandidates;        /*!< Maximum number of ICE candidates we will offer */
00160    unsigned int maxpayloads;             /*!< Maximum number of payloads we will offer */
00161    char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
00162    char remote[XMPP_MAX_JIDLEN];         /*!< Identifier of the remote party */
00163    iksrule *rule;                        /*!< Session matching rule */
00164    struct ast_codec_pref prefs;          /*!< Codec preferences */
00165    struct ast_channel *owner;            /*!< Master Channel */
00166    struct ast_rtp_instance *rtp;         /*!< RTP audio session */
00167    struct ast_rtp_instance *vrtp;        /*!< RTP video session */
00168    struct ast_format_cap *cap;           /*!< Local codec capabilities */
00169    struct ast_format_cap *jointcap;      /*!< Joint codec capabilities */
00170    struct ast_format_cap *peercap;       /*!< Peer codec capabilities */
00171    unsigned int outgoing:1;              /*!< Whether this is an outgoing leg or not */
00172    unsigned int gone:1;                  /*!< In the eyes of Jingle this session is already gone */
00173    struct ast_callid *callid;            /*!< Bound session call-id */
00174 };
00175 
00176 static const char desc[] = "Motif Jingle Channel";
00177 static const char channel_type[] = "Motif";
00178 
00179 struct jingle_config {
00180    struct ao2_container *endpoints; /*!< Configured endpoints */
00181 };
00182 
00183 static AO2_GLOBAL_OBJ_STATIC(globals);
00184 
00185 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
00186 
00187 /* \brief Asterisk core interaction functions */
00188 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00189 static int jingle_sendtext(struct ast_channel *ast, const char *text);
00190 static int jingle_digit_begin(struct ast_channel *ast, char digit);
00191 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00192 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
00193 static int jingle_hangup(struct ast_channel *ast);
00194 static int jingle_answer(struct ast_channel *ast);
00195 static struct ast_frame *jingle_read(struct ast_channel *ast);
00196 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
00197 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00198 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00199 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
00200 
00201 /*! \brief Action handlers */
00202 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00203 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00204 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00205 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00206 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00207 
00208 /*! \brief PBX interface structure for channel registration */
00209 static struct ast_channel_tech jingle_tech = {
00210    .type = "Motif",
00211    .description = "Motif Jingle Channel Driver",
00212    .requester = jingle_request,
00213    .send_text = jingle_sendtext,
00214    .send_digit_begin = jingle_digit_begin,
00215    .send_digit_end = jingle_digit_end,
00216    .bridge = ast_rtp_instance_bridge,
00217    .call = jingle_call,
00218    .hangup = jingle_hangup,
00219    .answer = jingle_answer,
00220    .read = jingle_read,
00221    .write = jingle_write,
00222    .write_video = jingle_write,
00223    .exception = jingle_read,
00224    .indicate = jingle_indicate,
00225    .fixup = jingle_fixup,
00226    .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00227 };
00228 
00229 /*! \brief Defined handlers for different Jingle actions */
00230 static const struct jingle_action_handler {
00231    const char *action;
00232    void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00233 } jingle_action_handlers[] = {
00234    /* Jingle actions */
00235    { "session-initiate", jingle_action_session_initiate, },
00236    { "transport-info", jingle_action_transport_info, },
00237    { "session-accept", jingle_action_session_accept, },
00238    { "session-info", jingle_action_session_info, },
00239    { "session-terminate", jingle_action_session_terminate, },
00240    /* Google-V1 actions */
00241    { "initiate", jingle_action_session_initiate, },
00242    { "candidates", jingle_action_transport_info, },
00243    { "accept", jingle_action_session_accept, },
00244    { "terminate", jingle_action_session_terminate, },
00245    { "reject", jingle_action_session_terminate, },
00246 };
00247 
00248 /*! \brief Reason text <-> cause code mapping */
00249 static const struct jingle_reason_mapping {
00250    const char *reason;
00251    int cause;
00252 } jingle_reason_mappings[] = {
00253    { "busy", AST_CAUSE_BUSY, },
00254    { "cancel", AST_CAUSE_CALL_REJECTED, },
00255    { "connectivity-error", AST_CAUSE_INTERWORKING, },
00256    { "decline", AST_CAUSE_CALL_REJECTED, },
00257    { "expired", AST_CAUSE_NO_USER_RESPONSE, },
00258    { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
00259    { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
00260    { "general-error", AST_CAUSE_CONGESTION, },
00261    { "gone", AST_CAUSE_NORMAL_CLEARING, },
00262    { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00263    { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00264    { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
00265    { "success", AST_CAUSE_NORMAL_CLEARING, },
00266    { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
00267    { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00268    { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
00269 };
00270 
00271 /*! \brief Hashing function for Jingle sessions */
00272 static int jingle_session_hash(const void *obj, const int flags)
00273 {
00274    const struct jingle_session *session = obj;
00275    const char *sid = obj;
00276 
00277    return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
00278 }
00279 
00280 /*! \brief Comparator function for Jingle sessions */
00281 static int jingle_session_cmp(void *obj, void *arg, int flags)
00282 {
00283    struct jingle_session *session1 = obj, *session2 = arg;
00284    const char *sid = arg;
00285 
00286    return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
00287 }
00288 
00289 /*! \brief Destructor for Jingle endpoint state */
00290 static void jingle_endpoint_state_destructor(void *obj)
00291 {
00292    struct jingle_endpoint_state *state = obj;
00293 
00294    ao2_ref(state->sessions, -1);
00295 }
00296 
00297 /*! \brief Destructor for Jingle endpoints */
00298 static void jingle_endpoint_destructor(void *obj)
00299 {
00300    struct jingle_endpoint *endpoint = obj;
00301 
00302    if (endpoint->rule) {
00303       iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
00304    }
00305 
00306    if (endpoint->connection) {
00307       ast_xmpp_client_unref(endpoint->connection);
00308    }
00309 
00310    ast_format_cap_destroy(endpoint->cap);
00311 
00312    ao2_ref(endpoint->state, -1);
00313 
00314    ast_string_field_free_memory(endpoint);
00315 }
00316 
00317 /*! \brief Find function for Jingle endpoints */
00318 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
00319 {
00320    return ao2_find(tmp_container, category, OBJ_KEY);
00321 }
00322 
00323 /*! \brief Allocator function for Jingle endpoint state */
00324 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
00325 {
00326    struct jingle_endpoint_state *state;
00327 
00328    if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
00329       return NULL;
00330    }
00331 
00332    if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
00333       ao2_ref(state, -1);
00334       return NULL;
00335    }
00336 
00337    return state;
00338 }
00339 
00340 /*! \brief State find/create function */
00341 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
00342 {
00343    RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00344    RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
00345 
00346    if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
00347       return jingle_endpoint_state_create();
00348    }
00349 
00350    ao2_ref(endpoint->state, +1);
00351    return endpoint->state;
00352 }
00353 
00354 /*! \brief Allocator function for Jingle endpoints */
00355 static void *jingle_endpoint_alloc(const char *cat)
00356 {
00357    struct jingle_endpoint *endpoint;
00358 
00359    if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
00360       return NULL;
00361    }
00362 
00363    if (ast_string_field_init(endpoint, 512)) {
00364       ao2_ref(endpoint, -1);
00365       return NULL;
00366    }
00367 
00368    if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
00369       ao2_ref(endpoint, -1);
00370       return NULL;
00371    }
00372 
00373    ast_string_field_set(endpoint, name, cat);
00374 
00375    endpoint->cap = ast_format_cap_alloc_nolock();
00376    endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
00377 
00378    return endpoint;
00379 }
00380 
00381 /*! \brief Hashing function for Jingle endpoints */
00382 static int jingle_endpoint_hash(const void *obj, const int flags)
00383 {
00384    const struct jingle_endpoint *endpoint = obj;
00385    const char *name = obj;
00386 
00387    return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
00388 }
00389 
00390 /*! \brief Comparator function for Jingle endpoints */
00391 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
00392 {
00393    struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
00394    const char *name = arg;
00395 
00396    return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
00397 }
00398 
00399 static struct aco_type endpoint_option = {
00400    .type = ACO_ITEM,
00401    .category_match = ACO_BLACKLIST,
00402    .category = "^general$",
00403    .item_alloc = jingle_endpoint_alloc,
00404    .item_find = jingle_endpoint_find,
00405    .item_offset = offsetof(struct jingle_config, endpoints),
00406 };
00407 
00408 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
00409 
00410 struct aco_file jingle_conf = {
00411    .filename = "motif.conf",
00412    .types = ACO_TYPES(&endpoint_option),
00413 };
00414 
00415 /*! \brief Destructor for Jingle sessions */
00416 static void jingle_session_destructor(void *obj)
00417 {
00418    struct jingle_session *session = obj;
00419 
00420    if (session->rule) {
00421       iks_filter_remove_rule(session->connection->filter, session->rule);
00422    }
00423 
00424    if (session->connection) {
00425       ast_xmpp_client_unref(session->connection);
00426    }
00427 
00428    if (session->rtp) {
00429       ast_rtp_instance_stop(session->rtp);
00430       ast_rtp_instance_destroy(session->rtp);
00431    }
00432 
00433    if (session->vrtp) {
00434       ast_rtp_instance_stop(session->vrtp);
00435       ast_rtp_instance_destroy(session->vrtp);
00436    }
00437 
00438    ast_format_cap_destroy(session->cap);
00439    ast_format_cap_destroy(session->jointcap);
00440    ast_format_cap_destroy(session->peercap);
00441 
00442    if (session->callid) {
00443       ast_callid_unref(session->callid);
00444    }
00445 
00446    ast_string_field_free_memory(session);
00447 }
00448 
00449 /*! \brief Destructor called when module configuration goes away */
00450 static void jingle_config_destructor(void *obj)
00451 {
00452    struct jingle_config *cfg = obj;
00453    ao2_cleanup(cfg->endpoints);
00454 }
00455 
00456 /*! \brief Allocator called when module configuration should appear */
00457 static void *jingle_config_alloc(void)
00458 {
00459    struct jingle_config *cfg;
00460 
00461    if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
00462       return NULL;
00463    }
00464 
00465    if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
00466       ao2_ref(cfg, -1);
00467       return NULL;
00468    }
00469 
00470    return cfg;
00471 }
00472 
00473 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
00474            .files = ACO_FILES(&jingle_conf),
00475    );
00476 
00477 /*! \brief Function called by RTP engine to get local RTP peer */
00478 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
00479 {
00480    struct jingle_session *session = ast_channel_tech_pvt(chan);
00481    enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
00482 
00483    if (!session->rtp) {
00484       return AST_RTP_GLUE_RESULT_FORBID;
00485    }
00486 
00487    ao2_ref(session->rtp, +1);
00488    *instance = session->rtp;
00489 
00490    return res;
00491 }
00492 
00493 /*! \brief Function called by RTP engine to get peer capabilities */
00494 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
00495 {
00496 }
00497 
00498 /*! \brief Function called by RTP engine to change where the remote party should send media */
00499 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)
00500 {
00501    return -1;
00502 }
00503 
00504 /*! \brief Local glue for interacting with the RTP engine core */
00505 static struct ast_rtp_glue jingle_rtp_glue = {
00506    .type = "Motif",
00507    .get_rtp_info = jingle_get_rtp_peer,
00508    .get_codec = jingle_get_codec,
00509    .update_peer = jingle_set_rtp_peer,
00510 };
00511 
00512 /*! \brief Internal helper function which enables video support on a sesson if possible */
00513 static void jingle_enable_video(struct jingle_session *session)
00514 {
00515    struct ast_sockaddr tmp;
00516    struct ast_rtp_engine_ice *ice;
00517 
00518    /* If video is already present don't do anything */
00519    if (session->vrtp) {
00520       return;
00521    }
00522 
00523    /* If there are no configured video codecs do not turn video support on, it just won't work */
00524    if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
00525       return;
00526    }
00527 
00528    ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00529 
00530    if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00531       return;
00532    }
00533 
00534    ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
00535 
00536    ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
00537    ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
00538    ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
00539 
00540    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
00541       ice->stop(session->vrtp);
00542    }
00543 }
00544 
00545 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
00546 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
00547 {
00548    struct jingle_session *session;
00549    struct ast_callid *callid;
00550    struct ast_sockaddr tmp;
00551 
00552    if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
00553       return NULL;
00554    }
00555 
00556    callid = ast_read_threadstorage_callid();
00557    session->callid = (callid ? callid : ast_create_callid());
00558 
00559    if (ast_string_field_init(session, 512)) {
00560       ao2_ref(session, -1);
00561       return NULL;
00562    }
00563 
00564    if (!ast_strlen_zero(from)) {
00565       ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
00566       ast_copy_string(session->remote, from, sizeof(session->remote));
00567    }
00568 
00569    if (ast_strlen_zero(sid)) {
00570       ast_string_field_build(session, sid, "%08lx%08lx", ast_random(), ast_random());
00571       session->outgoing = 1;
00572       ast_string_field_set(session, audio_name, "audio");
00573       ast_string_field_set(session, video_name, "video");
00574    } else {
00575       ast_string_field_set(session, sid, sid);
00576    }
00577 
00578    ao2_ref(endpoint->state, +1);
00579    session->state = endpoint->state;
00580    ao2_ref(endpoint->connection, +1);
00581    session->connection = endpoint->connection;
00582    session->transport = endpoint->transport;
00583 
00584    if (!(session->cap = ast_format_cap_alloc_nolock()) ||
00585        !(session->jointcap = ast_format_cap_alloc_nolock()) ||
00586        !(session->peercap = ast_format_cap_alloc_nolock()) ||
00587        !session->callid) {
00588       ao2_ref(session, -1);
00589       return NULL;
00590    }
00591 
00592    ast_format_cap_copy(session->cap, endpoint->cap);
00593 
00594    /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
00595     * that we want IPv4 */
00596    ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00597 
00598    /* Sessions always carry audio, but video is optional so don't enable it here */
00599    if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00600       ao2_ref(session, -1);
00601       return NULL;
00602    }
00603    ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
00604    ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
00605 
00606    memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
00607 
00608    session->maxicecandidates = endpoint->maxicecandidates;
00609    session->maxpayloads = endpoint->maxpayloads;
00610 
00611    return session;
00612 }
00613 
00614 /*! \brief Function called to create a new Jingle Asterisk channel */
00615 static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const char *linkedid, const char *cid_name)
00616 {
00617    struct ast_channel *chan;
00618    const char *str = S_OR(title, session->remote);
00619    struct ast_format tmpfmt;
00620 
00621    if (ast_format_cap_is_empty(session->cap)) {
00622       return NULL;
00623    }
00624 
00625    if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) {
00626       return NULL;
00627    }
00628 
00629    ast_channel_tech_set(chan, &jingle_tech);
00630    ast_channel_tech_pvt_set(chan, session);
00631    session->owner = chan;
00632 
00633    ast_channel_callid_set(chan, session->callid);
00634 
00635    ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
00636    ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
00637 
00638    if (session->rtp) {
00639       struct ast_rtp_engine_ice *ice;
00640 
00641       ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
00642       ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
00643       ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
00644 
00645       if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
00646            (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
00647           (ice = ast_rtp_instance_get_ice(session->rtp))) {
00648          /* We stop built in ICE support because we need to fall back to old old old STUN support */
00649          ice->stop(session->rtp);
00650       }
00651    }
00652 
00653    if (state == AST_STATE_RING) {
00654       ast_channel_rings_set(chan, 1);
00655    }
00656 
00657    ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
00658 
00659    ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
00660    ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
00661    ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
00662    ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
00663    ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
00664 
00665    ao2_lock(endpoint);
00666 
00667    ast_channel_callgroup_set(chan, endpoint->callgroup);
00668    ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
00669 
00670    if (!ast_strlen_zero(endpoint->accountcode)) {
00671       ast_channel_accountcode_set(chan, endpoint->accountcode);
00672    }
00673 
00674    if (!ast_strlen_zero(endpoint->language)) {
00675       ast_channel_language_set(chan, endpoint->language);
00676    }
00677 
00678    if (!ast_strlen_zero(endpoint->musicclass)) {
00679       ast_channel_musicclass_set(chan, endpoint->musicclass);
00680    }
00681 
00682    ast_channel_context_set(chan, endpoint->context);
00683    if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
00684       ast_channel_exten_set(chan, endpoint->name);
00685    } else {
00686       ast_channel_exten_set(chan, "s");
00687    }
00688    ast_channel_priority_set(chan, 1);
00689 
00690    ao2_unlock(endpoint);
00691 
00692    return chan;
00693 }
00694 
00695 /*! \brief Internal helper function which sends a response */
00696 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
00697 {
00698    iks *response;
00699 
00700    if (!(response = iks_new("iq"))) {
00701       ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
00702       return;
00703    }
00704 
00705    iks_insert_attrib(response, "type", "result");
00706    iks_insert_attrib(response, "from", connection->jid->full);
00707    iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00708    iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00709 
00710    ast_xmpp_client_send(connection, response);
00711 
00712    iks_delete(response);
00713 }
00714 
00715 /*! \brief Internal helper function which sends an error response */
00716 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
00717 {
00718    iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
00719 
00720    if (!(response = iks_new("iq")) ||
00721        !(error = iks_new("error")) ||
00722        !(reason = iks_new(reasonstr))) {
00723       ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
00724       goto end;
00725    }
00726 
00727    iks_insert_attrib(response, "type", "error");
00728    iks_insert_attrib(response, "from", connection->jid->full);
00729    iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00730    iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00731 
00732    iks_insert_attrib(error, "type", type);
00733    iks_insert_node(error, reason);
00734 
00735    if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
00736       iks_insert_node(error, reason2);
00737    }
00738 
00739    iks_insert_node(response, error);
00740 
00741    ast_xmpp_client_send(connection, response);
00742 end:
00743    iks_delete(reason2);
00744    iks_delete(reason);
00745    iks_delete(error);
00746    iks_delete(response);
00747 }
00748 
00749 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
00750 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
00751 {
00752    struct ast_rtp_engine_ice *ice;
00753    struct ao2_container *local_candidates;
00754    struct ao2_iterator it;
00755    struct ast_rtp_engine_ice_candidate *candidate;
00756    int i = 0, res = 0;
00757 
00758    if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00759       ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
00760       return -1;
00761    }
00762 
00763    iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
00764    iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
00765    iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
00766 
00767    it = ao2_iterator_init(local_candidates, 0);
00768 
00769    while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00770       iks *local_candidate;
00771       char tmp[30];
00772 
00773       if (!(local_candidate = iks_new("candidate"))) {
00774          res = -1;
00775          ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
00776          break;
00777       }
00778 
00779       snprintf(tmp, sizeof(tmp), "%d", candidate->id);
00780       iks_insert_attrib(local_candidate, "component", tmp);
00781       snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
00782       iks_insert_attrib(local_candidate, "foundation", tmp);
00783       iks_insert_attrib(local_candidate, "generation", "0");
00784       iks_insert_attrib(local_candidate, "network", "0");
00785       snprintf(tmp, sizeof(tmp), "%04lx", ast_random() & 0xffff);
00786       iks_insert_attrib(local_candidate, "id", tmp);
00787       iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
00788       iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
00789       snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
00790       iks_insert_attrib(local_candidate, "priority", tmp);
00791       iks_insert_attrib(local_candidate, "protocol", "udp");
00792 
00793       if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
00794          iks_insert_attrib(local_candidate, "type", "host");
00795       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
00796          iks_insert_attrib(local_candidate, "type", "srflx");
00797       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
00798          iks_insert_attrib(local_candidate, "type", "relay");
00799       }
00800 
00801       iks_insert_node(transport, local_candidate);
00802       candidates[i++] = local_candidate;
00803    }
00804 
00805    ao2_iterator_destroy(&it);
00806    ao2_ref(local_candidates, -1);
00807 
00808    return res;
00809 }
00810 
00811 /*! \brief Internal helper function which adds Google candidates to a transport node */
00812 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)
00813 {
00814    struct ast_rtp_engine_ice *ice;
00815    struct ao2_container *local_candidates;
00816    struct ao2_iterator it;
00817    struct ast_rtp_engine_ice_candidate *candidate;
00818    int i = 0, res = 0;
00819 
00820    if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00821       ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
00822       return -1;
00823    }
00824 
00825    if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
00826       iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
00827    }
00828 
00829    it = ao2_iterator_init(local_candidates, 0);
00830 
00831    while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00832       iks *local_candidate;
00833       /* In Google land a username is 16 bytes, explicitly */
00834       char ufrag[17] = "";
00835 
00836       if (!(local_candidate = iks_new("candidate"))) {
00837          res = -1;
00838          ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
00839          break;
00840       }
00841 
00842       if (candidate->id == 1) {
00843          iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
00844       } else if (candidate->id == 2) {
00845          iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
00846       } else {
00847          iks_delete(local_candidate);
00848          continue;
00849       }
00850 
00851       iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
00852       iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
00853 
00854       if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
00855          iks_insert_attrib(local_candidate, "preference", "0.95");
00856          iks_insert_attrib(local_candidate, "type", "local");
00857       } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
00858          iks_insert_attrib(local_candidate, "preference", "0.9");
00859          iks_insert_attrib(local_candidate, "type", "stun");
00860       }
00861 
00862       iks_insert_attrib(local_candidate, "protocol", "udp");
00863       iks_insert_attrib(local_candidate, "network", "0");
00864       snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
00865       iks_insert_attrib(local_candidate, "username", ufrag);
00866       iks_insert_attrib(local_candidate, "generation", "0");
00867 
00868       if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
00869          iks_insert_attrib(local_candidate, "password", "");
00870          iks_insert_attrib(local_candidate, "foundation", "0");
00871          iks_insert_attrib(local_candidate, "component", "1");
00872       } else {
00873          iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
00874       }
00875 
00876       /* You may notice a lack of relay support up above - this is because we don't support it for use with
00877        * the Google talk transport due to their arcane support. */
00878 
00879       iks_insert_node(transport, local_candidate);
00880       candidates[i++] = local_candidate;
00881    }
00882 
00883    ao2_iterator_destroy(&it);
00884    ao2_ref(local_candidates, -1);
00885 
00886    return res;
00887 }
00888 
00889 /*! \brief Internal function which sends a session-terminate message */
00890 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
00891 {
00892    iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
00893 
00894    if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
00895        !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
00896       ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
00897       goto end;
00898    }
00899 
00900    iks_insert_attrib(iq, "to", session->remote);
00901    iks_insert_attrib(iq, "type", "set");
00902    iks_insert_attrib(iq, "id", session->connection->mid);
00903    ast_xmpp_increment_mid(session->connection->mid);
00904 
00905    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
00906       iks_insert_attrib(jingle, "type", "terminate");
00907       iks_insert_attrib(jingle, "id", session->sid);
00908       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
00909       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
00910    } else {
00911       iks_insert_attrib(jingle, "action", "session-terminate");
00912       iks_insert_attrib(jingle, "sid", session->sid);
00913       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
00914    }
00915 
00916    iks_insert_node(iq, jingle);
00917    iks_insert_node(jingle, reason);
00918    iks_insert_node(reason, text);
00919 
00920    ast_xmpp_client_send(session->connection, iq);
00921 
00922 end:
00923    iks_delete(text);
00924    iks_delete(reason);
00925    iks_delete(jingle);
00926    iks_delete(iq);
00927 }
00928 
00929 /*! \brief Internal function which sends a session-info message */
00930 static void jingle_send_session_info(struct jingle_session *session, const char *info)
00931 {
00932    iks *iq = NULL, *jingle = NULL, *text = NULL;
00933 
00934    /* Google-V1 has no way to send informational messages so don't even bother trying */
00935    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
00936       return;
00937    }
00938 
00939    if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
00940       ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
00941       goto end;
00942    }
00943 
00944    iks_insert_attrib(iq, "to", session->remote);
00945    iks_insert_attrib(iq, "type", "set");
00946    iks_insert_attrib(iq, "id", session->connection->mid);
00947    ast_xmpp_increment_mid(session->connection->mid);
00948 
00949    iks_insert_attrib(jingle, "action", "session-info");
00950    iks_insert_attrib(jingle, "sid", session->sid);
00951    iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
00952    iks_insert_node(iq, jingle);
00953    iks_insert_node(jingle, text);
00954 
00955    ast_xmpp_client_send(session->connection, iq);
00956 
00957 end:
00958    iks_delete(text);
00959    iks_delete(jingle);
00960    iks_delete(iq);
00961 }
00962 
00963 /*! \internal
00964  *
00965  * \brief Locks both pvt and pvt owner if owner is present.
00966  *
00967  * \note This function gives a ref to pvt->owner if it is present and locked.
00968  *       This reference must be decremented after pvt->owner is unlocked.
00969  *
00970  * \note This function will never give you up,
00971  * \note This function will never let you down.
00972  * \note This function will run around and desert you.
00973  *
00974  * \pre pvt is not locked
00975  * \post pvt is locked
00976  * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
00977  *
00978  * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
00979  */
00980 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
00981 {
00982    struct ast_channel *chan;
00983 
00984    /* Locking is simple when it is done right.  If you see a deadlock resulting
00985     * in this function, it is not this function's fault, Your problem exists elsewhere.
00986     * This function is perfect... seriously. */
00987    for (;;) {
00988       /* First, get the channel and grab a reference to it */
00989       ao2_lock(pvt);
00990       chan = pvt->owner;
00991       if (chan) {
00992          /* The channel can not go away while we hold the pvt lock.
00993           * Give the channel a ref so it will not go away after we let
00994           * the pvt lock go. */
00995          ast_channel_ref(chan);
00996       } else {
00997          /* no channel, return pvt locked */
00998          return NULL;
00999       }
01000 
01001       /* We had to hold the pvt lock while getting a ref to the owner channel
01002        * but now we have to let this lock go in order to preserve proper
01003        * locking order when grabbing the channel lock */
01004       ao2_unlock(pvt);
01005 
01006       /* Look, no deadlock avoidance, hooray! */
01007       ast_channel_lock(chan);
01008       ao2_lock(pvt);
01009       if (pvt->owner == chan) {
01010          /* done */
01011          break;
01012       }
01013 
01014       /* If the owner changed while everything was unlocked, no problem,
01015        * just start over and everthing will work.  This is rare, do not be
01016        * confused by this loop and think this it is an expensive operation.
01017        * The majority of the calls to this function will never involve multiple
01018        * executions of this loop. */
01019       ast_channel_unlock(chan);
01020       ast_channel_unref(chan);
01021       ao2_unlock(pvt);
01022    }
01023 
01024    /* If owner exists, it is locked and reffed */
01025    return pvt->owner;
01026 }
01027 
01028 /*! \brief Helper function which queues a hangup frame with cause code */
01029 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
01030 {
01031    struct ast_channel *chan;
01032 
01033    if ((chan = jingle_session_lock_full(session))) {
01034       ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
01035       ast_queue_hangup_with_cause(chan, cause);
01036       ast_channel_unlock(chan);
01037       ast_channel_unref(chan);
01038    }
01039    ao2_unlock(session);
01040 }
01041 
01042 /*! \brief Internal function which sends a transport-info message */
01043 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
01044 {
01045    iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
01046    iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
01047    int i, res = 0;
01048 
01049    if (!(iq = iks_new("iq")) ||
01050        !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01051       iks_delete(iq);
01052       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01053       ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
01054       return;
01055    }
01056 
01057    memset(audio_candidates, 0, sizeof(audio_candidates));
01058    memset(video_candidates, 0, sizeof(video_candidates));
01059 
01060    iks_insert_attrib(iq, "from", session->connection->jid->full);
01061    iks_insert_attrib(iq, "to", from);
01062    iks_insert_attrib(iq, "type", "set");
01063    iks_insert_attrib(iq, "id", session->connection->mid);
01064    ast_xmpp_increment_mid(session->connection->mid);
01065 
01066    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01067       iks_insert_attrib(jingle, "type", "candidates");
01068       iks_insert_attrib(jingle, "id", session->sid);
01069       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01070       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
01071    } else {
01072       iks_insert_attrib(jingle, "action", "transport-info");
01073       iks_insert_attrib(jingle, "sid", session->sid);
01074       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01075    }
01076    iks_insert_node(iq, jingle);
01077 
01078    if (session->rtp) {
01079       if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01080          /* V1 protocol has the candidates directly in the session */
01081          res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
01082       } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
01083          iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
01084          iks_insert_attrib(audio, "name", session->audio_name);
01085          iks_insert_node(jingle, audio);
01086          iks_insert_node(audio, audio_transport);
01087 
01088          if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01089             res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
01090          } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01091             res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
01092                               session->maxicecandidates);
01093          }
01094       } else {
01095          res = -1;
01096       }
01097    }
01098 
01099    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01100       if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
01101          iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
01102          iks_insert_attrib(video, "name", session->video_name);
01103          iks_insert_node(jingle, video);
01104          iks_insert_node(video, video_transport);
01105 
01106          if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01107             res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
01108          } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01109             res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
01110                               session->maxicecandidates);
01111          }
01112       } else {
01113          res = -1;
01114       }
01115    }
01116 
01117    if (!res) {
01118       ast_xmpp_client_send(session->connection, iq);
01119    } else {
01120       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01121    }
01122 
01123    /* Clean up after ourselves */
01124    for (i = 0; i < session->maxicecandidates; i++) {
01125       iks_delete(video_candidates[i]);
01126       iks_delete(audio_candidates[i]);
01127    }
01128 
01129    iks_delete(video_transport);
01130    iks_delete(video);
01131    iks_delete(audio_transport);
01132    iks_delete(audio);
01133    iks_delete(jingle);
01134    iks_delete(iq);
01135 }
01136 
01137 /*! \brief Internal helper function which adds payloads to a description */
01138 static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type)
01139 {
01140    struct ast_format format;
01141    int x = 0, i = 0, res = 0;
01142 
01143    for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
01144       int rtp_code;
01145       iks *payload;
01146       char tmp[32];
01147 
01148       if (!ast_codec_pref_index(&session->prefs, x, &format)) {
01149          break;
01150       }
01151 
01152       if (AST_FORMAT_GET_TYPE(format.id) != type) {
01153          continue;
01154       }
01155 
01156       if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
01157          continue;
01158       }
01159 
01160       if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
01161           (!(payload = iks_new("payload-type")))) {
01162          return -1;
01163       }
01164 
01165       if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01166          iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01167       }
01168 
01169       snprintf(tmp, sizeof(tmp), "%d", rtp_code);
01170       iks_insert_attrib(payload, "id", tmp);
01171       iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
01172       iks_insert_attrib(payload, "channels", "1");
01173 
01174       if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
01175          iks_insert_attrib(payload, "clockrate", "16000");
01176       } else {
01177          snprintf(tmp, sizeof(tmp), "%d", ast_rtp_lookup_sample_rate2(1, &format, 0));
01178          iks_insert_attrib(payload, "clockrate", tmp);
01179       }
01180 
01181       if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
01182          iks *parameter;
01183 
01184          /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
01185          if ((parameter = iks_new("parameter"))) {
01186             iks_insert_attrib(parameter, "name", "width");
01187             iks_insert_attrib(parameter, "value", "640");
01188             iks_insert_node(payload, parameter);
01189          }
01190          if ((parameter = iks_new("parameter"))) {
01191             iks_insert_attrib(parameter, "name", "height");
01192             iks_insert_attrib(parameter, "value", "480");
01193             iks_insert_node(payload, parameter);
01194          }
01195          if ((parameter = iks_new("parameter"))) {
01196             iks_insert_attrib(parameter, "name", "framerate");
01197             iks_insert_attrib(parameter, "value", "30");
01198             iks_insert_node(payload, parameter);
01199          }
01200       }
01201 
01202       iks_insert_node(description, payload);
01203       payloads[i++] = payload;
01204    }
01205    /* If this is for audio and there is room for RFC2833 add it in */
01206    if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
01207       iks *payload;
01208 
01209       if ((payload = iks_new("payload-type"))) {
01210          if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01211             iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01212          }
01213 
01214          iks_insert_attrib(payload, "id", "101");
01215          iks_insert_attrib(payload, "name", "telephone-event");
01216          iks_insert_attrib(payload, "channels", "1");
01217          iks_insert_attrib(payload, "clockrate", "8000");
01218          iks_insert_node(description, payload);
01219          payloads[i++] = payload;
01220       }
01221    }
01222 
01223    return res;
01224 }
01225 
01226 /*! \brief Helper function which adds content to a description */
01227 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
01228                const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
01229 {
01230    int res = 0;
01231 
01232    if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
01233       iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
01234       iks_insert_attrib(content, "name", name);
01235       iks_insert_node(jingle, content);
01236 
01237       iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
01238       if (type == AST_FORMAT_TYPE_AUDIO) {
01239          iks_insert_attrib(description, "media", "audio");
01240       } else if (type == AST_FORMAT_TYPE_VIDEO) {
01241          iks_insert_attrib(description, "media", "video");
01242       } else {
01243          return -1;
01244       }
01245       iks_insert_node(content, description);
01246    } else {
01247       iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
01248       iks_insert_node(jingle, description);
01249    }
01250 
01251    if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
01252       if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01253          iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
01254          iks_insert_node(content, transport);
01255       } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01256          iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
01257          iks_insert_node(content, transport);
01258       }
01259    }
01260 
01261    return res;
01262 }
01263 
01264 /*! \brief Internal function which sends a complete session message */
01265 static void jingle_send_session_action(struct jingle_session *session, const char *action)
01266 {
01267    iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
01268    iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
01269    iks *audio_transport = NULL, *video_transport = NULL;
01270    int i, res = 0;
01271 
01272    if (!(iq = iks_new("iq")) ||
01273        !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01274       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01275       iks_delete(iq);
01276       return;
01277    }
01278 
01279    memset(audio_payloads, 0, sizeof(audio_payloads));
01280    memset(video_payloads, 0, sizeof(video_payloads));
01281 
01282    iks_insert_attrib(iq, "from", session->connection->jid->full);
01283    iks_insert_attrib(iq, "to", session->remote);
01284    iks_insert_attrib(iq, "type", "set");
01285    iks_insert_attrib(iq, "id", session->connection->mid);
01286    ast_xmpp_increment_mid(session->connection->mid);
01287 
01288    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01289       iks_insert_attrib(jingle, "type", action);
01290       iks_insert_attrib(jingle, "id", session->sid);
01291       iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01292    } else {
01293       iks_insert_attrib(jingle, "action", action);
01294       iks_insert_attrib(jingle, "sid", session->sid);
01295       iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01296    }
01297 
01298    if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
01299       iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
01300    }
01301 
01302    iks_insert_node(iq, jingle);
01303 
01304    if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
01305        (audio_transport = iks_new("transport"))) {
01306       res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
01307                 AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
01308    } else {
01309       ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
01310       res = -1;
01311    }
01312 
01313    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01314       if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
01315           (video_transport = iks_new("transport"))) {
01316          res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
01317                    AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
01318       } else {
01319          ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
01320          res = -1;
01321       }
01322    }
01323 
01324    if (!res) {
01325       ast_xmpp_client_send(session->connection, iq);
01326    } else {
01327       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01328    }
01329 
01330    iks_delete(video_transport);
01331    iks_delete(audio_transport);
01332 
01333    for (i = 0; i < session->maxpayloads; i++) {
01334       iks_delete(video_payloads[i]);
01335       iks_delete(audio_payloads[i]);
01336    }
01337 
01338    iks_delete(video_description);
01339    iks_delete(video);
01340    iks_delete(audio_description);
01341    iks_delete(audio);
01342    iks_delete(jingle);
01343    iks_delete(iq);
01344 }
01345 
01346 /*! \brief Internal function which sends a session-inititate message */
01347 static void jingle_send_session_initiate(struct jingle_session *session)
01348 {
01349    jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
01350 }
01351 
01352 /*! \brief Internal function which sends a session-accept message */
01353 static void jingle_send_session_accept(struct jingle_session *session)
01354 {
01355    jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
01356 }
01357 
01358 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
01359 static int jingle_outgoing_hook(void *data, ikspak *pak)
01360 {
01361    struct jingle_session *session = data;
01362    iks *error = iks_find(pak->x, "error"), *redirect;
01363 
01364    /* In all cases this hook is done with */
01365    iks_filter_remove_rule(session->connection->filter, session->rule);
01366    session->rule = NULL;
01367 
01368    ast_callid_threadassoc_add(session->callid);
01369 
01370    /* If no error occurred they accepted our session-initiate message happily */
01371    if (!error) {
01372       struct ast_channel *chan;
01373 
01374       if ((chan = jingle_session_lock_full(session))) {
01375          ast_queue_control(chan, AST_CONTROL_PROCEEDING);
01376          ast_channel_unlock(chan);
01377          ast_channel_unref(chan);
01378       }
01379       ao2_unlock(session);
01380 
01381       jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
01382 
01383       goto end;
01384    }
01385 
01386    /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
01387    session->gone = 1;
01388 
01389    /* Map the error we received to an appropriate cause code and hang up the channel */
01390    if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
01391       iks *to = iks_child(redirect);
01392       char *target;
01393 
01394       if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
01395          /* Make the xmpp: go away if it is present */
01396          if (!strncmp(target, "xmpp:", 5)) {
01397             target += 5;
01398          }
01399 
01400          /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
01401          ast_copy_string(session->remote, target, sizeof(session->remote));
01402 
01403          /* Add a new hook so we can get the status of redirected session */
01404          session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01405                          IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01406 
01407          jingle_send_session_initiate(session);
01408 
01409          session->gone = 0;
01410       } else {
01411          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01412       }
01413    } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
01414       jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
01415    } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
01416       jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
01417    } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
01418       jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01419    } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
01420       jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
01421    } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
01422       /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
01423       session->transport--;
01424 
01425       /* If we still have a viable transport mechanism re-send the session-initiate */
01426       if (session->transport != JINGLE_TRANSPORT_NONE) {
01427          struct ast_rtp_engine_ice *ice;
01428 
01429          if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
01430               (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
01431              (ice = ast_rtp_instance_get_ice(session->rtp))) {
01432             /* We stop built in ICE support because we need to fall back to old old old STUN support */
01433             ice->stop(session->rtp);
01434          }
01435 
01436          /* Re-send the message to the *original* target and not a redirected one */
01437          ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
01438 
01439          session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01440                          IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01441 
01442          jingle_send_session_initiate(session);
01443 
01444          session->gone = 0;
01445       } else {
01446          /* Otherwise we have exhausted all transports */
01447          jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
01448       }
01449    } else {
01450       jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01451    }
01452 
01453 end:
01454    ast_callid_threadassoc_remove();
01455 
01456    return IKS_FILTER_EAT;
01457 }
01458 
01459 /*! \brief Function called by core when we should answer a Jingle session */
01460 static int jingle_answer(struct ast_channel *ast)
01461 {
01462    struct jingle_session *session = ast_channel_tech_pvt(ast);
01463 
01464    /* The channel has already been answered so we don't need to do anything */
01465    if (ast_channel_state(ast) == AST_STATE_UP) {
01466       return 0;
01467    }
01468 
01469    jingle_send_session_accept(session);
01470 
01471    return 0;
01472 }
01473 
01474 /*! \brief Function called by core to read any waiting frames */
01475 static struct ast_frame *jingle_read(struct ast_channel *ast)
01476 {
01477    struct jingle_session *session = ast_channel_tech_pvt(ast);
01478    struct ast_frame *frame = &ast_null_frame;
01479 
01480    switch (ast_channel_fdno(ast)) {
01481    case 0:
01482       if (session->rtp) {
01483          frame = ast_rtp_instance_read(session->rtp, 0);
01484       }
01485       break;
01486    case 1:
01487       if (session->rtp) {
01488          frame = ast_rtp_instance_read(session->rtp, 1);
01489       }
01490       break;
01491    case 2:
01492       if (session->vrtp) {
01493          frame = ast_rtp_instance_read(session->vrtp, 0);
01494       }
01495       break;
01496    case 3:
01497       if (session->vrtp) {
01498          frame = ast_rtp_instance_read(session->vrtp, 1);
01499       }
01500       break;
01501    default:
01502       break;
01503    }
01504 
01505    if (frame && frame->frametype == AST_FRAME_VOICE &&
01506        !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
01507       if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
01508          ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
01509               ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
01510          ast_frfree(frame);
01511          frame = &ast_null_frame;
01512       } else {
01513          ast_debug(1, "Oooh, format changed to %s\n",
01514               ast_getformatname(&frame->subclass.format));
01515          ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
01516          ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
01517          ast_set_read_format(ast, ast_channel_readformat(ast));
01518          ast_set_write_format(ast, ast_channel_writeformat(ast));
01519       }
01520    }
01521 
01522    return frame;
01523 }
01524 
01525 /*! \brief Function called by core to write frames */
01526 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
01527 {
01528    struct jingle_session *session = ast_channel_tech_pvt(ast);
01529    int res = 0;
01530    char buf[256];
01531 
01532    switch (frame->frametype) {
01533    case AST_FRAME_VOICE:
01534       if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
01535          ast_log(LOG_WARNING,
01536             "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01537             ast_getformatname(&frame->subclass.format),
01538             ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
01539             ast_getformatname(ast_channel_readformat(ast)),
01540             ast_getformatname(ast_channel_writeformat(ast)));
01541          return 0;
01542       }
01543       if (session && session->rtp) {
01544          res = ast_rtp_instance_write(session->rtp, frame);
01545       }
01546       break;
01547    case AST_FRAME_VIDEO:
01548       if (session && session->vrtp) {
01549          res = ast_rtp_instance_write(session->vrtp, frame);
01550       }
01551       break;
01552    default:
01553       ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
01554          frame->frametype);
01555       return 0;
01556    }
01557 
01558    return res;
01559 }
01560 
01561 /*! \brief Function called by core to change the underlying owner channel */
01562 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01563 {
01564    struct jingle_session *session = ast_channel_tech_pvt(newchan);
01565 
01566    ao2_lock(session);
01567 
01568    session->owner = newchan;
01569 
01570    ao2_unlock(session);
01571 
01572    return 0;
01573 }
01574 
01575 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
01576 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01577 {
01578    struct jingle_session *session = ast_channel_tech_pvt(ast);
01579    int res = 0;
01580 
01581    switch (condition) {
01582    case AST_CONTROL_RINGING:
01583       if (ast_channel_state(ast) == AST_STATE_RING) {
01584          jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
01585       } else {
01586          res = -1;
01587       }
01588       break;
01589    case AST_CONTROL_BUSY:
01590       if (ast_channel_state(ast) != AST_STATE_UP) {
01591          ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
01592          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01593       } else {
01594          res = -1;
01595       }
01596       break;
01597    case AST_CONTROL_CONGESTION:
01598       if (ast_channel_state(ast) != AST_STATE_UP) {
01599          ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01600          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01601       } else {
01602          res = -1;
01603       }
01604       break;
01605    case AST_CONTROL_INCOMPLETE:
01606       if (ast_channel_state(ast) != AST_STATE_UP) {
01607          ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01608          ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01609       }
01610       break;
01611    case AST_CONTROL_HOLD:
01612       ast_moh_start(ast, data, NULL);
01613       break;
01614    case AST_CONTROL_UNHOLD:
01615       ast_moh_stop(ast);
01616       break;
01617    case AST_CONTROL_SRCUPDATE:
01618       if (session->rtp) {
01619          ast_rtp_instance_update_source(session->rtp);
01620       }
01621       break;
01622    case AST_CONTROL_SRCCHANGE:
01623       if (session->rtp) {
01624          ast_rtp_instance_change_source(session->rtp);
01625       }
01626       break;
01627    case AST_CONTROL_VIDUPDATE:
01628    case AST_CONTROL_UPDATE_RTP_PEER:
01629    case AST_CONTROL_CONNECTED_LINE:
01630       break;
01631    case AST_CONTROL_PVT_CAUSE_CODE:
01632    case -1:
01633       res = -1;
01634       break;
01635    default:
01636       ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01637       res = -1;
01638    }
01639 
01640    return res;
01641 }
01642 
01643 /*! \brief Function called by core to send text to the remote party of the Jingle session */
01644 static int jingle_sendtext(struct ast_channel *chan, const char *text)
01645 {
01646    struct jingle_session *session = ast_channel_tech_pvt(chan);
01647 
01648    return ast_xmpp_client_send_message(session->connection, session->remote, text);
01649 }
01650 
01651 /*! \brief Function called by core to start a DTMF digit */
01652 static int jingle_digit_begin(struct ast_channel *chan, char digit)
01653 {
01654    struct jingle_session *session = ast_channel_tech_pvt(chan);
01655 
01656    if (session->rtp) {
01657       ast_rtp_instance_dtmf_begin(session->rtp, digit);
01658    }
01659 
01660    return 0;
01661 }
01662 
01663 /*! \brief Function called by core to stop a DTMF digit */
01664 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
01665 {
01666    struct jingle_session *session = ast_channel_tech_pvt(ast);
01667 
01668    if (session->rtp) {
01669       ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
01670    }
01671 
01672    return 0;
01673 }
01674 
01675 /*! \brief Function called by core to actually start calling a remote party */
01676 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
01677 {
01678    struct jingle_session *session = ast_channel_tech_pvt(ast);
01679 
01680    ast_setstate(ast, AST_STATE_RING);
01681 
01682    /* Since we have no idea of the remote capabilities use ours for now */
01683    ast_format_cap_copy(session->jointcap, session->cap);
01684 
01685    /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
01686    session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01687                    IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01688 
01689    jingle_send_session_initiate(session);
01690 
01691    return 0;
01692 }
01693 
01694 /*! \brief Function called by core to hang up a Jingle session */
01695 static int jingle_hangup(struct ast_channel *ast)
01696 {
01697    struct jingle_session *session = ast_channel_tech_pvt(ast);
01698 
01699    ao2_lock(session);
01700 
01701    if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
01702       int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
01703       const char *reason = "success";
01704       int i;
01705 
01706       /* Get the appropriate reason and send a session-terminate */
01707       for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
01708          if (jingle_reason_mappings[i].cause == cause) {
01709             reason = jingle_reason_mappings[i].reason;
01710             break;
01711          }
01712       }
01713 
01714       jingle_send_session_terminate(session, reason);
01715    }
01716 
01717    ast_channel_tech_pvt_set(ast, NULL);
01718    session->owner = NULL;
01719 
01720    ao2_unlink(session->state->sessions, session);
01721    ao2_ref(session->state, -1);
01722 
01723    ao2_unlock(session);
01724    ao2_ref(session, -1);
01725 
01726    return 0;
01727 }
01728 
01729 /*! \brief Function called by core to create a new outgoing Jingle session */
01730 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
01731 {
01732    RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01733    RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
01734    char *dialed, target[200] = "";
01735    struct ast_xmpp_buddy *buddy;
01736    struct jingle_session *session;
01737    struct ast_channel *chan;
01738    enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
01739    struct ast_rtp_engine_ice *ice;
01740    AST_DECLARE_APP_ARGS(args,
01741               AST_APP_ARG(name);
01742               AST_APP_ARG(target);
01743       );
01744 
01745    /* We require at a minimum one audio format to be requested */
01746    if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
01747       ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
01748       *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
01749       return NULL;
01750    }
01751 
01752    if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
01753       ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
01754       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01755       return NULL;
01756    }
01757 
01758    /* Parse the given dial string and validate the results */
01759    AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
01760 
01761    if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
01762       ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
01763       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01764       return NULL;
01765    }
01766 
01767    if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
01768       ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
01769       *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01770       return NULL;
01771    }
01772 
01773    ao2_lock(endpoint->state);
01774 
01775    /* If we don't have a connection for the endpoint we can't exactly start a session on it */
01776    if (!endpoint->connection) {
01777       ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
01778       *cause = AST_CAUSE_SWITCH_CONGESTION;
01779       ao2_unlock(endpoint->state);
01780       return NULL;
01781    }
01782 
01783    /* Find the target in the roster so we can choose a resource */
01784    if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
01785       struct ao2_iterator res;
01786       struct ast_xmpp_resource *resource;
01787 
01788       /* Iterate through finding the first viable Jingle capable resource */
01789       res = ao2_iterator_init(buddy->resources, 0);
01790       while ((resource = ao2_iterator_next(&res))) {
01791          if (resource->caps.jingle) {
01792             snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01793             transport = JINGLE_TRANSPORT_ICE_UDP;
01794             break;
01795          } else if (resource->caps.google) {
01796             snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01797             transport = JINGLE_TRANSPORT_GOOGLE_V2;
01798             break;
01799          }
01800          ao2_ref(resource, -1);
01801       }
01802       ao2_iterator_destroy(&res);
01803 
01804       ao2_ref(buddy, -1);
01805    } else {
01806       /* If the target is NOT in the roster use the provided target as-is */
01807       ast_copy_string(target, args.target, sizeof(target));
01808    }
01809 
01810    ao2_unlock(endpoint->state);
01811 
01812    /* If no target was found we can't set up a session */
01813    if (ast_strlen_zero(target)) {
01814       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);
01815       *cause = AST_CAUSE_SWITCH_CONGESTION;
01816       return NULL;
01817    }
01818 
01819    if (!(session = jingle_alloc(endpoint, target, NULL))) {
01820       ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
01821       *cause = AST_CAUSE_SWITCH_CONGESTION;
01822       return NULL;
01823    }
01824 
01825    /* Update the transport if we learned what we should actually use */
01826    if (transport != JINGLE_TRANSPORT_NONE) {
01827       session->transport = transport;
01828       /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
01829    }
01830 
01831    if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
01832       ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
01833       *cause = AST_CAUSE_SWITCH_CONGESTION;
01834       ao2_ref(session, -1);
01835       return NULL;
01836    }
01837 
01838    /* If video was requested try to enable it on the session */
01839    if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
01840       jingle_enable_video(session);
01841    }
01842 
01843    /* As this is outgoing set ourselves as controlling */
01844    if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
01845       ice->ice_lite(session->rtp);
01846    }
01847 
01848    if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
01849       ice->ice_lite(session->vrtp);
01850    }
01851 
01852    /* We purposely don't decrement the session here as there is a reference on the channel */
01853    ao2_link(endpoint->state->sessions, session);
01854 
01855    return chan;
01856 }
01857 
01858 /*! \brief Helper function which handles content descriptions */
01859 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
01860 {
01861    char *media = iks_find_attrib(description, "media");
01862    struct ast_rtp_codecs codecs;
01863    iks *codec;
01864    int othercapability = 0;
01865 
01866    /* Google-V1 is always carrying audio, but just doesn't tell us so */
01867    if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01868       media = "audio";
01869    } else if (ast_strlen_zero(media)) {
01870       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01871       ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
01872       return -1;
01873    }
01874 
01875    /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
01876    if (!strcasecmp(media, "audio")) {
01877       if (!ast_strlen_zero(name)) {
01878          ast_string_field_set(session, audio_name, name);
01879       }
01880       *rtp = session->rtp;
01881       ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
01882       ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
01883    } else if (!strcasecmp(media, "video")) {
01884       if (!ast_strlen_zero(name)) {
01885          ast_string_field_set(session, video_name, name);
01886       }
01887 
01888       jingle_enable_video(session);
01889       *rtp = session->vrtp;
01890 
01891       /* If video is not present cancel this session */
01892       if (!session->vrtp) {
01893          jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01894          ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
01895          return -1;
01896       }
01897 
01898       ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
01899       ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
01900    } else {
01901       /* Unknown media type */
01902       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01903       ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
01904       return -1;
01905    }
01906 
01907    if (ast_rtp_codecs_payloads_initialize(&codecs)) {
01908       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01909       ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
01910       return -1;
01911    }
01912 
01913    /* Iterate the codecs updating the relevant RTP instance as we go */
01914    for (codec = iks_child(description); codec; codec = iks_next(codec)) {
01915       char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
01916       char *clockrate = iks_find_attrib(codec, "clockrate");
01917       int rtp_id, rtp_clockrate;
01918 
01919       if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
01920          ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
01921 
01922          if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
01923             ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
01924          } else {
01925             ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
01926          }
01927       }
01928    }
01929 
01930    ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
01931    ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
01932 
01933    if (ast_format_cap_is_empty(session->jointcap)) {
01934       /* We have no compatible codecs, so terminate the session appropriately */
01935       jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01936       ast_rtp_codecs_payloads_destroy(&codecs);
01937       return -1;
01938    }
01939 
01940    ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
01941    ast_rtp_codecs_payloads_destroy(&codecs);
01942 
01943    return 0;
01944 }
01945 
01946 /*! \brief Helper function which handles ICE-UDP transport information */
01947 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
01948 {
01949    struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
01950    char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
01951    iks *candidate;
01952 
01953    if (!ice) {
01954       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01955       ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
01956       return -1;
01957    }
01958 
01959    if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
01960       ice->set_authentication(rtp, ufrag, pwd);
01961    }
01962 
01963    for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
01964       char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
01965       char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
01966       char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
01967       char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
01968       char *type = iks_find_attrib(candidate, "type");
01969       struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
01970       int real_port;
01971       struct ast_sockaddr remote_address = { { 0, } };
01972 
01973       /* If this candidate is incomplete skip it */
01974       if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
01975           ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
01976           ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
01977          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01978          ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
01979          return -1;
01980       }
01981 
01982       if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
01983           (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
01984           (sscanf(port, "%30d", &real_port) != 1)) {
01985          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01986          ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
01987          return -1;
01988       }
01989 
01990       local_candidate.foundation = foundation;
01991       local_candidate.transport = protocol;
01992 
01993       ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
01994 
01995       /* We only support IPv4 right now */
01996       if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
01997          continue;
01998       }
01999 
02000       ast_sockaddr_set_port(&local_candidate.address, real_port);
02001 
02002       if (!strcasecmp(type, "host")) {
02003          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
02004       } else if (!strcasecmp(type, "srflx")) {
02005          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
02006       } else if (!strcasecmp(type, "relay")) {
02007          local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
02008       } else {
02009          continue;
02010       }
02011 
02012       /* Worst case use the first viable address */
02013       ast_rtp_instance_get_remote_address(rtp, &remote_address);
02014 
02015       if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
02016          ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
02017       }
02018 
02019       ice->add_remote_candidate(rtp, &local_candidate);
02020    }
02021 
02022    ice->start(rtp);
02023 
02024    return 0;
02025 }
02026 
02027 /*! \brief Helper function which handles Google transport information */
02028 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
02029 {
02030    struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
02031    iks *candidate;
02032 
02033    if (!ice) {
02034       jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02035       ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
02036       return -1;
02037    }
02038 
02039    /* If this session has not transitioned to the Google transport do so now */
02040    if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
02041        (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
02042       /* Stop built-in ICE support... we need to fall back to the old old old STUN */
02043       ice->stop(rtp);
02044 
02045       session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02046    }
02047 
02048    for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
02049       char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
02050       char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
02051       char *protocol = iks_find_attrib(candidate, "protocol");
02052       int real_port;
02053       struct ast_sockaddr target = { { 0, } };
02054       /* In Google land the combined value is 32 bytes */
02055       char combined[33] = "";
02056 
02057       /* If this is NOT actually a candidate just skip it */
02058       if (strcasecmp(iks_name(candidate), "candidate") &&
02059           strcasecmp(iks_name(candidate), "p:candidate") &&
02060           strcasecmp(iks_name(candidate), "ses:candidate")) {
02061          continue;
02062       }
02063 
02064       /* If this candidate is incomplete skip it */
02065       if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
02066           ast_strlen_zero(name)) {
02067          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02068          ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
02069          return -1;
02070       }
02071 
02072       /* We only support UDP so skip any other protocols */
02073       if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
02074          continue;
02075       }
02076 
02077       /* We only permit audio and video, not RTCP */
02078       if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
02079          continue;
02080       }
02081 
02082       /* Parse the target information so we can send a STUN request to the candidate */
02083       if (sscanf(port, "%30d", &real_port) != 1) {
02084          jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02085          ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
02086          return -1;
02087       }
02088       ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
02089       ast_sockaddr_set_port(&target, real_port);
02090 
02091       /* Per the STUN support Google talk uses combine the two usernames */
02092       snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
02093 
02094       /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
02095       ast_rtp_instance_stun_request(rtp, &target, combined);
02096    }
02097 
02098    return 0;
02099 }
02100 
02101 /*!
02102  * \brief Helper function which locates content stanzas and interprets them
02103  *
02104  * \note The session *must not* be locked before calling this
02105  */
02106 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
02107 {
02108    iks *content;
02109    unsigned int changed = 0;
02110    struct ast_channel *chan;
02111 
02112    /* Look at the content in the session initiation */
02113    for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
02114       char *name;
02115       struct ast_rtp_instance *rtp = NULL;
02116       iks *description, *transport;
02117 
02118       /* Ignore specific parts if they are known not to be useful */
02119       if (!strcmp(iks_name(content), "conference-info")) {
02120          continue;
02121       }
02122 
02123       name = iks_find_attrib(content, "name");
02124 
02125       if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
02126          /* If this content stanza has no name consider it invalid and move on */
02127          if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
02128             jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02129             ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
02130             return -1;
02131          }
02132 
02133          /* Try to pre-populate which RTP instance this content is relevant to */
02134          if (!strcmp(session->audio_name, name)) {
02135             rtp = session->rtp;
02136          } else if (!strcmp(session->video_name, name)) {
02137             rtp = session->vrtp;
02138          }
02139       } else {
02140          /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
02141          rtp = session->rtp;
02142       }
02143 
02144       /* If description information is available use it */
02145       if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
02146           (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
02147           (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02148           (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
02149           (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02150           (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
02151          /* If we failed to do something with the content description abort immediately */
02152          if (jingle_interpret_description(session, description, name, &rtp)) {
02153             return -1;
02154          }
02155 
02156          /* If we successfully interpret the description then the codecs need updating */
02157          changed = 1;
02158       }
02159 
02160       /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
02161       if (!rtp) {
02162          ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
02163          jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02164          return -1;
02165       }
02166 
02167       /* If ICE UDP transport information is available use it */
02168       if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
02169          if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
02170             return -1;
02171          }
02172       } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
02173             (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
02174             (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
02175             (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
02176          /* If Google transport support is available use it */
02177          if (jingle_interpret_google_transport(session, transport, rtp)) {
02178             return -1;
02179          }
02180       } else if (iks_find(content, "transport")) {
02181          /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
02182          jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
02183          ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
02184          return -1;
02185       }
02186    }
02187 
02188    if (!changed) {
02189       return 0;
02190    }
02191 
02192    if ((chan = jingle_session_lock_full(session))) {
02193       struct ast_format fmt;
02194 
02195       ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
02196       ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
02197       ast_set_read_format(chan, &fmt);
02198       ast_set_write_format(chan, &fmt);
02199 
02200       ast_channel_unlock(chan);
02201       ast_channel_unref(chan);
02202    }
02203    ao2_unlock(session);
02204 
02205    return 0;
02206 }
02207 
02208 /*! \brief Handler function for the 'session-initiate' action */
02209 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02210 {
02211    char *sid;
02212    enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
02213    struct ast_channel *chan;
02214    int res;
02215 
02216    if (session) {
02217       /* This is a duplicate session setup, so respond accordingly */
02218       jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
02219       return;
02220    }
02221 
02222    /* Retrieve the session identifier from the message, note that this may alter the transport */
02223    if ((sid = iks_find_attrib(pak->query, "id"))) {
02224       /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
02225       transport = JINGLE_TRANSPORT_GOOGLE_V1;
02226    } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02227       jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
02228       return;
02229    }
02230 
02231    /* Create a new local session */
02232    if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
02233       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02234       return;
02235    }
02236 
02237    /* If we determined that the transport should change as a result of how we got the SID change it */
02238    if (transport != JINGLE_TRANSPORT_NONE) {
02239       session->transport = transport;
02240    }
02241 
02242    /* Create a new Asterisk channel using the above local session */
02243    if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
02244       ao2_ref(session, -1);
02245       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02246       return;
02247    }
02248 
02249    ao2_link(endpoint->state->sessions, session);
02250 
02251    ast_setstate(chan, AST_STATE_RING);
02252    res = ast_pbx_start(chan);
02253 
02254    switch (res) {
02255    case AST_PBX_FAILED:
02256       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
02257       jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02258       session->gone = 1;
02259       ast_hangup(chan);
02260       break;
02261    case AST_PBX_CALL_LIMIT:
02262       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
02263       jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02264       ast_hangup(chan);
02265       break;
02266    case AST_PBX_SUCCESS:
02267       jingle_send_response(endpoint->connection, pak);
02268 
02269       /* Only send a transport-info message if we successfully interpreted the available content */
02270       if (!jingle_interpret_content(session, pak)) {
02271          jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
02272       }
02273       break;
02274    }
02275 }
02276 
02277 /*! \brief Handler function for the 'transport-info' action */
02278 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02279 {
02280    if (!session) {
02281       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02282                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02283       return;
02284    }
02285 
02286    jingle_interpret_content(session, pak);
02287    jingle_send_response(endpoint->connection, pak);
02288 }
02289 
02290 /*! \brief Handler function for the 'session-accept' action */
02291 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02292 {
02293    struct ast_channel *chan;
02294 
02295    if (!session) {
02296       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02297                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02298       return;
02299    }
02300 
02301 
02302    jingle_interpret_content(session, pak);
02303 
02304    if ((chan = jingle_session_lock_full(session))) {
02305       ast_queue_control(chan, AST_CONTROL_ANSWER);
02306       ast_channel_unlock(chan);
02307       ast_channel_unref(chan);
02308    }
02309    ao2_unlock(session);
02310 
02311    jingle_send_response(endpoint->connection, pak);
02312 }
02313 
02314 /*! \brief Handler function for the 'session-info' action */
02315 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02316 {
02317    struct ast_channel *chan;
02318 
02319    if (!session) {
02320       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02321                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02322       return;
02323    }
02324 
02325    if (!(chan = jingle_session_lock_full(session))) {
02326       ao2_unlock(session);
02327       jingle_send_response(endpoint->connection, pak);
02328       return;
02329    }
02330 
02331    if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
02332       ast_queue_control(chan, AST_CONTROL_RINGING);
02333       if (ast_channel_state(chan) != AST_STATE_UP) {
02334          ast_setstate(chan, AST_STATE_RINGING);
02335       }
02336    } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
02337       ast_queue_control(chan, AST_CONTROL_HOLD);
02338    } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
02339       ast_queue_control(chan, AST_CONTROL_UNHOLD);
02340    }
02341 
02342    ast_channel_unlock(chan);
02343    ast_channel_unref(chan);
02344    ao2_unlock(session);
02345 
02346    jingle_send_response(endpoint->connection, pak);
02347 }
02348 
02349 /*! \brief Handler function for the 'session-terminate' action */
02350 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02351 {
02352    struct ast_channel *chan;
02353    iks *reason, *text;
02354    int cause = AST_CAUSE_NORMAL;
02355    struct ast_control_pvt_cause_code *cause_code;
02356    int data_size = sizeof(*cause_code);
02357 
02358    if (!session) {
02359       jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02360                   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02361       return;
02362    }
02363 
02364    if (!(chan = jingle_session_lock_full(session))) {
02365       ao2_unlock(session);
02366       jingle_send_response(endpoint->connection, pak);
02367       return;
02368    }
02369 
02370    /* Pull the reason text from the session-terminate message and translate it into a cause code */
02371    if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
02372       int i;
02373 
02374       /* Size of the string making up the cause code is "Motif " + text */
02375       data_size += 6 + strlen(iks_name(text));
02376       cause_code = ast_alloca(data_size);
02377       memset(cause_code, 0, data_size);
02378 
02379       /* Get the appropriate cause code mapping for this reason */
02380       for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
02381          if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
02382             cause = jingle_reason_mappings[i].cause;
02383             break;
02384          }
02385       }
02386 
02387       /* Store the technology specific information */
02388       snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
02389    } else {
02390       /* No technology specific information is available */
02391       cause_code = ast_alloca(data_size);
02392       memset(cause_code, 0, data_size);
02393    }
02394 
02395    ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
02396    cause_code->ast_cause = cause;
02397    ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
02398    ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
02399 
02400    ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
02401    ast_queue_hangup_with_cause(chan, cause);
02402    session->gone = 1;
02403 
02404    ast_channel_unlock(chan);
02405    ast_channel_unref(chan);
02406    ao2_unlock(session);
02407 
02408    jingle_send_response(endpoint->connection, pak);
02409 }
02410 
02411 /*! \brief Callback for when a Jingle action is received from an endpoint */
02412 static int jingle_action_hook(void *data, ikspak *pak)
02413 {
02414    char *action;
02415    const char *sid = NULL;
02416    struct jingle_session *session = NULL;
02417    struct jingle_endpoint *endpoint = data;
02418    int i, handled = 0;
02419 
02420    /* We accept both Jingle and Google-V1 */
02421    if (!(action = iks_find_attrib(pak->query, "action")) &&
02422        !(action = iks_find_attrib(pak->query, "type"))) {
02423       /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
02424        * to a message that has no response hook. */
02425       return IKS_FILTER_EAT;
02426    }
02427 
02428    /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
02429     * does not permit us to make this completely safe. */
02430    ao2_ref(endpoint, +1);
02431 
02432    /* If a Jingle session identifier is present use it */
02433    if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02434       /* If a Google-V1 session identifier is present use it */
02435       sid = iks_find_attrib(pak->query, "id");
02436    }
02437 
02438    /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
02439     * this is required or not */
02440    if (!ast_strlen_zero(sid)) {
02441       session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
02442    }
02443 
02444    /* If a session is present associate the callid with this thread */
02445    if (session) {
02446       ast_callid_threadassoc_add(session->callid);
02447    }
02448 
02449    /* Iterate through supported action handlers looking for one that is able to handle this */
02450    for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
02451       if (!strcasecmp(jingle_action_handlers[i].action, action)) {
02452          jingle_action_handlers[i].handler(endpoint, session, pak);
02453          handled = 1;
02454          break;
02455       }
02456    }
02457 
02458    /* If no action handler is present for the action they sent us make it evident */
02459    if (!handled) {
02460       ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
02461    }
02462 
02463    /* If a session was successfully found for this message deref it now since the handler is done */
02464    if (session) {
02465       ast_callid_threadassoc_remove();
02466       ao2_ref(session, -1);
02467    }
02468 
02469    ao2_ref(endpoint, -1);
02470 
02471    return IKS_FILTER_EAT;
02472 }
02473 
02474 /*! \brief Custom handler for groups */
02475 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02476 {
02477    struct jingle_endpoint *endpoint = obj;
02478 
02479    if (!strcasecmp(var->name, "callgroup")) {
02480       endpoint->callgroup = ast_get_group(var->value);
02481    } else if (!strcasecmp(var->name, "pickupgroup")) {
02482       endpoint->pickupgroup = ast_get_group(var->value);
02483    } else {
02484       return -1;
02485    }
02486 
02487    return 0;
02488 }
02489 
02490 /*! \brief Custom handler for connection */
02491 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02492 {
02493    struct jingle_endpoint *endpoint = obj;
02494 
02495    /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
02496     * this will not actually get called, so even if the config turns out to be bogus this is harmless.
02497     */
02498    if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
02499       ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
02500       return -1;
02501    }
02502 
02503    if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
02504                      IKS_RULE_TYPE, IKS_PAK_IQ,
02505                      IKS_RULE_NS, JINGLE_NS,
02506                      IKS_RULE_NS, GOOGLE_SESSION_NS,
02507                      IKS_RULE_DONE))) {
02508       ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
02509       return -1;
02510    }
02511 
02512    return 0;
02513 }
02514 
02515 /*! \brief Custom handler for transport */
02516 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02517 {
02518    struct jingle_endpoint *endpoint = obj;
02519 
02520    if (!strcasecmp(var->value, "ice-udp")) {
02521       endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02522    } else if (!strcasecmp(var->value, "google")) {
02523       endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02524    } else if (!strcasecmp(var->value, "google-v1")) {
02525       endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
02526    } else {
02527       ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
02528       endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02529    }
02530 
02531    return 0;
02532 }
02533 
02534 /*! \brief Load module into PBX, register channel */
02535 static int load_module(void)
02536 {
02537    if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
02538       return AST_MODULE_LOAD_DECLINE;
02539    }
02540 
02541    if (aco_info_init(&cfg_info)) {
02542       ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
02543       goto end;
02544    }
02545 
02546    aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
02547    aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02548    aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02549    aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
02550    aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
02551    aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
02552    aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
02553    aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
02554    aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
02555    aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
02556    aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
02557    aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
02558              FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
02559    aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
02560              FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
02561 
02562    ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
02563 
02564    if (aco_process_config(&cfg_info, 0)) {
02565       ast_log(LOG_ERROR, "Unable to read config file motif.conf. Not loading module.\n");
02566       aco_info_destroy(&cfg_info);
02567       return AST_MODULE_LOAD_DECLINE;
02568    }
02569 
02570    if (!(sched = ast_sched_context_create())) {
02571       ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
02572       goto end;
02573    }
02574 
02575    if (ast_sched_start_thread(sched)) {
02576       ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
02577       goto end;
02578    }
02579 
02580    ast_rtp_glue_register(&jingle_rtp_glue);
02581 
02582    if (ast_channel_register(&jingle_tech)) {
02583       ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
02584       goto end;
02585    }
02586 
02587    return 0;
02588 
02589 end:
02590    ast_rtp_glue_unregister(&jingle_rtp_glue);
02591 
02592    if (sched) {
02593       ast_sched_context_destroy(sched);
02594    }
02595 
02596    aco_info_destroy(&cfg_info);
02597 
02598    return AST_MODULE_LOAD_FAILURE;
02599 }
02600 
02601 /*! \brief Reload module */
02602 static int reload(void)
02603 {
02604    return aco_process_config(&cfg_info, 1);
02605 }
02606 
02607 /*! \brief Unload the jingle channel from Asterisk */
02608 static int unload_module(void)
02609 {
02610    ast_channel_unregister(&jingle_tech);
02611    ast_format_cap_destroy(jingle_tech.capabilities);
02612    jingle_tech.capabilities = NULL;
02613    ast_rtp_glue_unregister(&jingle_rtp_glue);
02614    ast_sched_context_destroy(sched);
02615    aco_info_destroy(&cfg_info);
02616    ao2_global_obj_release(globals);
02617 
02618    return 0;
02619 }
02620 
02621 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
02622       .load = load_module,
02623       .unload = unload_module,
02624       .reload = reload,
02625       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
02626           );