core_unreal.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013 Digium, Inc.
00005  *
00006  * Richard Mudgett <rmudgett@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 /*!
00020  * \file
00021  * \brief Unreal channel derivatives framework for channel drivers like local channels.
00022  *
00023  * \author Richard Mudgett <rmudgett@digium.com>
00024  *
00025  * See Also:
00026  * \arg \ref AstCREDITS
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 432834 $")
00036 
00037 #include "asterisk/causes.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/stasis_channels.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/musiconhold.h"
00042 #include "asterisk/astobj2.h"
00043 #include "asterisk/bridge.h"
00044 #include "asterisk/core_unreal.h"
00045 
00046 static unsigned int name_sequence = 0;
00047 
00048 void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
00049 {
00050    struct ast_channel *chan = NULL;
00051    struct ast_channel *owner = NULL;
00052 
00053    ao2_lock(p);
00054    for (;;) {
00055       if (p->chan) {
00056          chan = p->chan;
00057          ast_channel_ref(chan);
00058       }
00059       if (p->owner) {
00060          owner = p->owner;
00061          ast_channel_ref(owner);
00062       }
00063       ao2_unlock(p);
00064 
00065       /* if we don't have both channels, then this is very easy */
00066       if (!owner || !chan) {
00067          if (owner) {
00068             ast_channel_lock(owner);
00069          } else if(chan) {
00070             ast_channel_lock(chan);
00071          }
00072       } else {
00073          /* lock both channels first, then get the pvt lock */
00074          ast_channel_lock_both(chan, owner);
00075       }
00076       ao2_lock(p);
00077 
00078       /* Now that we have all the locks, validate that nothing changed */
00079       if (p->owner != owner || p->chan != chan) {
00080          if (owner) {
00081             ast_channel_unlock(owner);
00082             owner = ast_channel_unref(owner);
00083          }
00084          if (chan) {
00085             ast_channel_unlock(chan);
00086             chan = ast_channel_unref(chan);
00087          }
00088          continue;
00089       }
00090 
00091       break;
00092    }
00093    *outowner = p->owner;
00094    *outchan = p->chan;
00095 }
00096 
00097 /* Called with ast locked */
00098 int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
00099 {
00100    int res = 0;
00101    struct ast_unreal_pvt *p;
00102    struct ast_channel *otherchan = NULL;
00103    ast_chan_write_info_t *write_info;
00104    char *info_data;
00105 
00106    if (option != AST_OPTION_CHANNEL_WRITE) {
00107       return -1;
00108    }
00109 
00110    write_info = data;
00111 
00112    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00113       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00114       return -1;
00115    }
00116 
00117    info_data = write_info->data;
00118    if (!strcmp(write_info->function, "CHANNEL")) {
00119       if (!strncasecmp(info_data, "hangup_handler_", 15)) {
00120          /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
00121          return 0;
00122       }
00123 
00124       /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
00125       if (!strcasecmp(info_data, "accountcode")) {
00126          info_data = "peeraccount";
00127       } else if (!strcasecmp(info_data, "peeraccount")) {
00128          info_data = "accountcode";
00129       }
00130    }
00131 
00132    /* get the tech pvt */
00133    if (!(p = ast_channel_tech_pvt(ast))) {
00134       return -1;
00135    }
00136    ao2_ref(p, 1);
00137    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00138 
00139    /* get the channel we are supposed to write to */
00140    ao2_lock(p);
00141    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00142    if (!otherchan || otherchan == write_info->chan) {
00143       res = -1;
00144       otherchan = NULL;
00145       ao2_unlock(p);
00146       goto setoption_cleanup;
00147    }
00148    ast_channel_ref(otherchan);
00149 
00150    /* clear the pvt lock before grabbing the channel */
00151    ao2_unlock(p);
00152 
00153    ast_channel_lock(otherchan);
00154    res = write_info->write_fn(otherchan, write_info->function, info_data, write_info->value);
00155    ast_channel_unlock(otherchan);
00156 
00157 setoption_cleanup:
00158    ao2_ref(p, -1);
00159    if (otherchan) {
00160       ast_channel_unref(otherchan);
00161    }
00162    ast_channel_lock(ast); /* Lock back before we leave */
00163    return res;
00164 }
00165 
00166 /* Called with ast locked */
00167 int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
00168 {
00169    struct ast_unreal_pvt *p;
00170    struct ast_channel *peer;
00171    struct ast_channel *other;
00172    int res = 0;
00173 
00174    if (option != AST_OPTION_T38_STATE) {
00175       /* AST_OPTION_T38_STATE is the only supported option at this time */
00176       return -1;
00177    }
00178 
00179    /* for some reason the channel is not locked in channel.c when this function is called */
00180    if (!(p = ast_channel_tech_pvt(ast))) {
00181       return -1;
00182    }
00183 
00184    ao2_lock(p);
00185    other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00186    if (!other) {
00187       ao2_unlock(p);
00188       return -1;
00189    }
00190    ast_channel_ref(other);
00191    ao2_unlock(p);
00192    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00193 
00194    peer = ast_channel_bridge_peer(other);
00195    if (peer) {
00196       res = ast_channel_queryoption(peer, option, data, datalen, 0);
00197       ast_channel_unref(peer);
00198    }
00199    ast_channel_unref(other);
00200    ast_channel_lock(ast); /* Lock back before we leave */
00201 
00202    return res;
00203 }
00204 
00205 /*!
00206  * \brief queue a frame onto either the p->owner or p->chan
00207  *
00208  * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
00209  * decremented after this function is called.  This is a side effect of the deadlock
00210  * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
00211  * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
00212  * during deadlock avoidance.
00213  */
00214 static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
00215    struct ast_channel *us, int us_locked)
00216 {
00217    struct ast_channel *other;
00218 
00219    /* Recalculate outbound channel */
00220    other = isoutbound ? p->owner : p->chan;
00221    if (!other) {
00222       return 0;
00223    }
00224 
00225    /* do not queue media frames if a generator is on both unreal channels */
00226    if (us
00227       && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
00228       && ast_channel_generator(us)
00229       && ast_channel_generator(other)) {
00230       return 0;
00231    }
00232 
00233    /* grab a ref on the channel before unlocking the pvt,
00234     * other can not go away from us now regardless of locking */
00235    ast_channel_ref(other);
00236    if (us && us_locked) {
00237       ast_channel_unlock(us);
00238    }
00239    ao2_unlock(p);
00240 
00241    if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00242       ast_setstate(other, AST_STATE_RINGING);
00243    }
00244    ast_queue_frame(other, f);
00245 
00246    other = ast_channel_unref(other);
00247    if (us && us_locked) {
00248       ast_channel_lock(us);
00249    }
00250    ao2_lock(p);
00251 
00252    return 0;
00253 }
00254 
00255 int ast_unreal_answer(struct ast_channel *ast)
00256 {
00257    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00258    int isoutbound;
00259    int res = -1;
00260 
00261    if (!p) {
00262       return -1;
00263    }
00264 
00265    ao2_ref(p, 1);
00266    ao2_lock(p);
00267    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00268    if (isoutbound) {
00269       /* Pass along answer since somebody answered us */
00270       struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00271 
00272       res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
00273    } else {
00274       ast_log(LOG_WARNING, "Huh?  %s is being asked to answer?\n",
00275          ast_channel_name(ast));
00276    }
00277    ao2_unlock(p);
00278    ao2_ref(p, -1);
00279    return res;
00280 }
00281 
00282 /*!
00283  * \internal
00284  * \brief Check and optimize out the unreal channels between bridges.
00285  * \since 12.0.0
00286  *
00287  * \param ast Channel writing a frame into the unreal channels.
00288  * \param p Unreal channel private.
00289  *
00290  * \note It is assumed that ast is locked.
00291  * \note It is assumed that p is locked.
00292  *
00293  * \retval 0 if unreal channels were not optimized out.
00294  * \retval non-zero if unreal channels were optimized out.
00295  */
00296 static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
00297 {
00298    int res = 0;
00299 
00300    /* Do a few conditional checks early on just to see if this optimization is possible */
00301    if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
00302       return res;
00303    }
00304 
00305    if (ast == p->owner) {
00306       res = ast_bridge_unreal_optimize_out(p->owner, p->chan, p);
00307    } else if (ast == p->chan) {
00308       res = ast_bridge_unreal_optimize_out(p->chan, p->owner, p);
00309    }
00310 
00311    return res;
00312 }
00313 
00314 struct ast_frame  *ast_unreal_read(struct ast_channel *ast)
00315 {
00316    return &ast_null_frame;
00317 }
00318 
00319 int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
00320 {
00321    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00322    int res = -1;
00323 
00324    if (!p) {
00325       return -1;
00326    }
00327 
00328    /* Just queue for delivery to the other side */
00329    ao2_ref(p, 1);
00330    ao2_lock(p);
00331    switch (f->frametype) {
00332    case AST_FRAME_VOICE:
00333    case AST_FRAME_VIDEO:
00334       if (got_optimized_out(ast, p)) {
00335          break;
00336       }
00337       /* fall through */
00338    default:
00339       res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
00340       break;
00341    }
00342    ao2_unlock(p);
00343    ao2_ref(p, -1);
00344 
00345    return res;
00346 }
00347 
00348 int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00349 {
00350    struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
00351    struct ast_bridge *bridge_owner;
00352    struct ast_bridge *bridge_chan;
00353 
00354    if (!p) {
00355       return -1;
00356    }
00357 
00358    ao2_lock(p);
00359 
00360    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00361       ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
00362       ao2_unlock(p);
00363       return -1;
00364    }
00365    if (p->owner == oldchan) {
00366       p->owner = newchan;
00367    } else {
00368       p->chan = newchan;
00369    }
00370 
00371    if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
00372       ao2_unlock(p);
00373       return 0;
00374    }
00375 
00376    /* Do not let a masquerade cause an unreal channel to be bridged to itself! */
00377    bridge_owner = ast_channel_internal_bridge(p->owner);
00378    bridge_chan = ast_channel_internal_bridge(p->chan);
00379    if (bridge_owner && bridge_owner == bridge_chan) {
00380       ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
00381          ast_channel_name(newchan));
00382       ao2_unlock(p);
00383       ast_queue_hangup(newchan);
00384       return -1;
00385    }
00386 
00387    ao2_unlock(p);
00388    return 0;
00389 }
00390 
00391 /*!
00392  * \internal
00393  * \brief Queue up a frame representing the indication as a control frame.
00394  * \since 12.0.0
00395  *
00396  * \param p Unreal private structure.
00397  * \param ast Channel indicating the condition.
00398  * \param condition What is being indicated.
00399  * \param data Extra data.
00400  * \param datalen Length of extra data.
00401  *
00402  * \retval 0 on success.
00403  * \retval AST_T38_REQUEST_PARMS if successful and condition is AST_CONTROL_T38_PARAMETERS.
00404  * \retval -1 on error.
00405  */
00406 static int unreal_queue_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)
00407 {
00408    int res = 0;
00409    int isoutbound;
00410 
00411    ao2_lock(p);
00412    /*
00413     * Block -1 stop tones events if we are to be optimized out.  We
00414     * don't need a flurry of these events on an unreal channel chain
00415     * when initially connected to slow the optimization process.
00416     */
00417    if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
00418       struct ast_frame f = {
00419          .frametype = AST_FRAME_CONTROL,
00420          .subclass.integer = condition,
00421          .data.ptr = (void *) data,
00422          .datalen = datalen,
00423       };
00424 
00425       isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00426       res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
00427       if (!res
00428          && condition == AST_CONTROL_T38_PARAMETERS
00429          && datalen == sizeof(struct ast_control_t38_parameters)) {
00430          const struct ast_control_t38_parameters *parameters = data;
00431 
00432          if (parameters->request_response == AST_T38_REQUEST_PARMS) {
00433             res = AST_T38_REQUEST_PARMS;
00434          }
00435       }
00436    } else {
00437       ast_debug(4, "Blocked indication %d\n", condition);
00438    }
00439    ao2_unlock(p);
00440 
00441    return res;
00442 }
00443 
00444 /*!
00445  * \internal
00446  * \brief Handle COLP and redirecting conditions.
00447  * \since 12.0.0
00448  *
00449  * \param p Unreal private structure.
00450  * \param ast Channel indicating the condition.
00451  * \param condition What is being indicated.
00452  *
00453  * \retval 0 on success.
00454  * \retval -1 on error.
00455  */
00456 static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
00457 {
00458    struct ast_channel *my_chan;
00459    struct ast_channel *my_owner;
00460    struct ast_channel *this_channel;
00461    struct ast_channel *the_other_channel;
00462    int isoutbound;
00463    int res = 0;
00464    unsigned char frame_data[1024];
00465    struct ast_frame f = {
00466       .frametype = AST_FRAME_CONTROL,
00467       .subclass.integer = condition,
00468       .data.ptr = frame_data,
00469    };
00470 
00471    /*
00472     * A connected line update frame may only contain a partial
00473     * amount of data, such as just a source, or just a ton, and not
00474     * the full amount of information.  However, the collected
00475     * information is all stored in the outgoing channel's
00476     * connectedline structure, so when receiving a connected line
00477     * update on an outgoing unreal channel, we need to transmit the
00478     * collected connected line information instead of whatever
00479     * happens to be in this control frame.  The same applies for
00480     * redirecting information, which is why it is handled here as
00481     * well.
00482     */
00483    ast_channel_unlock(ast);
00484    ast_unreal_lock_all(p, &my_chan, &my_owner);
00485    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00486    if (isoutbound) {
00487       this_channel = p->chan;
00488       the_other_channel = p->owner;
00489    } else {
00490       this_channel = p->owner;
00491       the_other_channel = p->chan;
00492    }
00493    if (the_other_channel) {
00494       if (condition == AST_CONTROL_CONNECTED_LINE) {
00495          ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel),
00496             ast_channel_connected(this_channel));
00497          f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
00498             ast_channel_connected(this_channel), NULL);
00499       } else {
00500          f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
00501             ast_channel_redirecting(this_channel), NULL);
00502       }
00503    }
00504    if (my_chan) {
00505       ast_channel_unlock(my_chan);
00506       ast_channel_unref(my_chan);
00507    }
00508    if (my_owner) {
00509       ast_channel_unlock(my_owner);
00510       ast_channel_unref(my_owner);
00511    }
00512    if (the_other_channel) {
00513       res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00514    }
00515    ao2_unlock(p);
00516    ast_channel_lock(ast);
00517 
00518    return res;
00519 }
00520 
00521 int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00522 {
00523    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00524    int res = 0;
00525 
00526    if (!p) {
00527       return -1;
00528    }
00529 
00530    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00531 
00532    switch (condition) {
00533    case AST_CONTROL_MASQUERADE_NOTIFY:
00534       /*
00535        * Always block this because this is the channel being
00536        * masqueraded; not anything down the chain.
00537        */
00538       break;
00539    case AST_CONTROL_CONNECTED_LINE:
00540    case AST_CONTROL_REDIRECTING:
00541       res = unreal_colp_redirect_indicate(p, ast, condition);
00542       break;
00543    case AST_CONTROL_HOLD:
00544       if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
00545          ast_moh_start(ast, data, NULL);
00546          break;
00547       }
00548       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00549       break;
00550    case AST_CONTROL_UNHOLD:
00551       if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
00552          ast_moh_stop(ast);
00553          break;
00554       }
00555       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00556       break;
00557    default:
00558       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00559       break;
00560    }
00561 
00562    ao2_ref(p, -1);
00563    return res;
00564 }
00565 
00566 int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
00567 {
00568    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00569    int res = -1;
00570    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00571    int isoutbound;
00572 
00573    if (!p) {
00574       return -1;
00575    }
00576 
00577    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00578    ao2_lock(p);
00579    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00580    f.subclass.integer = digit;
00581    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00582    ao2_unlock(p);
00583    ao2_ref(p, -1);
00584 
00585    return res;
00586 }
00587 
00588 int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00589 {
00590    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00591    int res = -1;
00592    struct ast_frame f = { AST_FRAME_DTMF_END, };
00593    int isoutbound;
00594 
00595    if (!p) {
00596       return -1;
00597    }
00598 
00599    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00600    ao2_lock(p);
00601    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00602    f.subclass.integer = digit;
00603    f.len = duration;
00604    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00605    ao2_unlock(p);
00606    ao2_ref(p, -1);
00607 
00608    return res;
00609 }
00610 
00611 int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
00612 {
00613    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00614    int res = -1;
00615    struct ast_frame f = { AST_FRAME_TEXT, };
00616    int isoutbound;
00617 
00618    if (!p) {
00619       return -1;
00620    }
00621 
00622    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00623    ao2_lock(p);
00624    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00625    f.data.ptr = (char *) text;
00626    f.datalen = strlen(text) + 1;
00627    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00628    ao2_unlock(p);
00629    ao2_ref(p, -1);
00630    return res;
00631 }
00632 
00633 int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00634 {
00635    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00636    int res = -1;
00637    struct ast_frame f = { AST_FRAME_HTML, };
00638    int isoutbound;
00639 
00640    if (!p) {
00641       return -1;
00642    }
00643 
00644    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00645    ao2_lock(p);
00646    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00647    f.subclass.integer = subclass;
00648    f.data.ptr = (char *)data;
00649    f.datalen = datalen;
00650    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00651    ao2_unlock(p);
00652    ao2_ref(p, -1);
00653 
00654    return res;
00655 }
00656 
00657 void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
00658 {
00659    struct ast_var_t *varptr;
00660    struct ast_var_t *clone_var;
00661 
00662    ast_channel_stage_snapshot(semi2);
00663 
00664    /*
00665     * Note that cid_num and cid_name aren't passed in the
00666     * ast_channel_alloc calls in ast_unreal_new_channels().  It's
00667     * done here instead.
00668     */
00669    ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));
00670 
00671    ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
00672 
00673    /* Crossover the CallerID and conected-line to cross the unreal bridge. */
00674    ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
00675    ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
00676 
00677    ast_channel_language_set(semi2, ast_channel_language(semi1));
00678 
00679    /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
00680    ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1));
00681    ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1));
00682 
00683    ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
00684 
00685    ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
00686 
00687    /*
00688     * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
00689     * set on the queue/dial call request in the dialplan.
00690     */
00691    if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
00692       ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
00693    }
00694 
00695    /*
00696     * Copy the channel variables from the semi1 channel to the
00697     * outgoing channel.
00698     *
00699     * Note that due to certain assumptions, they MUST be in the
00700     * same order.
00701     */
00702    AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
00703       clone_var = ast_var_assign(varptr->name, varptr->value);
00704       if (clone_var) {
00705          AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
00706          ast_channel_publish_varset(semi2, ast_var_full_name(clone_var),
00707             ast_var_value(clone_var));
00708       }
00709    }
00710    ast_channel_datastore_inherit(semi1, semi2);
00711 
00712    ast_channel_stage_snapshot_done(semi2);
00713 }
00714 
00715 int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
00716 {
00717    struct ast_bridge_features *features;
00718    struct ast_channel *chan;
00719    struct ast_channel *owner;
00720    ast_callid bridge_callid;
00721    RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);
00722 
00723    ast_bridge_lock(bridge);
00724    bridge_callid = bridge->callid;
00725    ast_bridge_unlock(bridge);
00726 
00727    {
00728       SCOPED_CHANNELLOCK(lock, ast);
00729       p = ast_channel_tech_pvt(ast);
00730       if (!p) {
00731          return -1;
00732       }
00733       ao2_ref(p, +1);
00734    }
00735 
00736    {
00737       SCOPED_AO2LOCK(lock, p);
00738       chan = p->chan;
00739       if (!chan) {
00740          return -1;
00741       }
00742 
00743       owner = p->owner;
00744       if (!owner) {
00745          return -1;
00746       }
00747 
00748       ast_channel_ref(chan);
00749       ast_channel_ref(owner);
00750    }
00751 
00752    if (bridge_callid) {
00753       ast_callid chan_callid;
00754       ast_callid owner_callid;
00755 
00756       /* chan side call ID setting */
00757       ast_channel_lock(chan);
00758 
00759       chan_callid = ast_channel_callid(chan);
00760       if (!chan_callid) {
00761          ast_channel_callid_set(chan, bridge_callid);
00762       }
00763       ast_channel_unlock(chan);
00764 
00765       /* owner side call ID setting */
00766       ast_channel_lock(owner);
00767 
00768       owner_callid = ast_channel_callid(owner);
00769       if (!owner_callid) {
00770          ast_channel_callid_set(owner, bridge_callid);
00771       }
00772 
00773       ast_channel_unlock(owner);
00774    }
00775 
00776    /* We are done with the owner now that its call ID matches the bridge */
00777    ast_channel_unref(owner);
00778    owner = NULL;
00779 
00780    features = ast_bridge_features_new();
00781    if (!features) {
00782       ast_channel_unref(chan);
00783       return -1;
00784    }
00785 
00786    ast_set_flag(&features->feature_flags, flags);
00787 
00788    /* Impart the semi2 channel into the bridge */
00789    if (ast_bridge_impart(bridge, chan, NULL, features,
00790       AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
00791       ast_bridge_features_destroy(features);
00792       ast_channel_unref(chan);
00793       return -1;
00794    }
00795 
00796    ao2_lock(p);
00797    ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
00798    ao2_unlock(p);
00799    ast_channel_unref(chan);
00800 
00801    return 0;
00802 }
00803 
00804 int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
00805 {
00806    int hangup_chan = 0;
00807    int res = 0;
00808    int cause;
00809    struct ast_channel *owner = NULL;
00810    struct ast_channel *chan = NULL;
00811 
00812    /* the pvt isn't going anywhere, it has a ref */
00813    ast_channel_unlock(ast);
00814 
00815    /* lock everything */
00816    ast_unreal_lock_all(p, &chan, &owner);
00817 
00818    if (ast != chan && ast != owner) {
00819       res = -1;
00820       goto unreal_hangup_cleanup;
00821    }
00822 
00823    cause = ast_channel_hangupcause(ast);
00824 
00825    if (ast == p->chan) {
00826       /* Outgoing side is hanging up. */
00827       ast_clear_flag(p, AST_UNREAL_CARETAKER_THREAD);
00828       p->chan = NULL;
00829       if (p->owner) {
00830          const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00831 
00832          if (status) {
00833             ast_channel_hangupcause_set(p->owner, cause);
00834             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00835          }
00836          ast_queue_hangup_with_cause(p->owner, cause);
00837       }
00838    } else {
00839       /* Owner side is hanging up. */
00840       p->owner = NULL;
00841       if (p->chan) {
00842          if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
00843             ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
00844             ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
00845                ast_channel_name(p->chan));
00846          }
00847          if (!ast_test_flag(p, AST_UNREAL_CARETAKER_THREAD)) {
00848             /*
00849              * Need to actually hangup p->chan since nothing else is taking
00850              * care of it.
00851              */
00852             hangup_chan = 1;
00853          } else {
00854             ast_queue_hangup_with_cause(p->chan, cause);
00855          }
00856       }
00857    }
00858 
00859    /* this is one of our locked channels, doesn't matter which */
00860    ast_channel_tech_pvt_set(ast, NULL);
00861    ao2_ref(p, -1);
00862 
00863 unreal_hangup_cleanup:
00864    ao2_unlock(p);
00865    if (owner) {
00866       ast_channel_unlock(owner);
00867       ast_channel_unref(owner);
00868    }
00869    if (chan) {
00870       ast_channel_unlock(chan);
00871       if (hangup_chan) {
00872          ast_hangup(chan);
00873       }
00874       ast_channel_unref(chan);
00875    }
00876 
00877    /* leave with the channel locked that came in */
00878    ast_channel_lock(ast);
00879 
00880    return res;
00881 }
00882 
00883 void ast_unreal_destructor(void *vdoomed)
00884 {
00885    struct ast_unreal_pvt *doomed = vdoomed;
00886 
00887    ao2_cleanup(doomed->reqcap);
00888    doomed->reqcap = NULL;
00889 }
00890 
00891 struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
00892 {
00893    struct ast_unreal_pvt *unreal;
00894 
00895    static const struct ast_jb_conf jb_conf = {
00896       .flags = 0,
00897       .max_size = -1,
00898       .resync_threshold = -1,
00899       .impl = "",
00900       .target_extra = -1,
00901    };
00902 
00903    unreal = ao2_alloc(size, destructor);
00904    if (!unreal) {
00905       return NULL;
00906    }
00907 
00908    unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
00909    if (!unreal->reqcap) {
00910       ao2_ref(unreal, -1);
00911       return NULL;
00912    }
00913    ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);
00914 
00915    memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
00916 
00917    return unreal;
00918 }
00919 
00920 struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
00921    const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
00922    const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
00923    const struct ast_channel *requestor, ast_callid callid)
00924 {
00925    struct ast_channel *owner;
00926    struct ast_channel *chan;
00927    RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
00928    struct ast_assigned_ids id1 = {NULL, NULL};
00929    struct ast_assigned_ids id2 = {NULL, NULL};
00930    int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
00931 
00932    /* set unique ids for the two channels */
00933    if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
00934       id1.uniqueid = assignedids->uniqueid;
00935       id2.uniqueid = assignedids->uniqueid2;
00936    }
00937 
00938    /* if id1 given but not id2, use default of id1;2 */
00939    if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
00940       char *uniqueid2;
00941 
00942       uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
00943       strcpy(uniqueid2, id1.uniqueid);/* Safe */
00944       strcat(uniqueid2, ";2");/* Safe */
00945       id2.uniqueid = uniqueid2;
00946    }
00947 
00948    /*
00949     * Allocate two new Asterisk channels
00950     *
00951     * Make sure that the ;2 channel gets the same linkedid as ;1.
00952     * You can't pass linkedid to both allocations since if linkedid
00953     * isn't set, then each channel will generate its own linkedid.
00954     */
00955    owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
00956       exten, context, &id1, requestor, 0,
00957       "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
00958    if (!owner) {
00959       ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
00960       return NULL;
00961    }
00962 
00963    if (callid) {
00964       ast_channel_callid_set(owner, callid);
00965    }
00966 
00967    ast_channel_tech_set(owner, tech);
00968    ao2_ref(p, +1);
00969    ast_channel_tech_pvt_set(owner, p);
00970 
00971    ast_channel_nativeformats_set(owner, p->reqcap);
00972 
00973    /* Determine our read/write format and set it on each channel */
00974    fmt = ast_format_cap_get_format(p->reqcap, 0);
00975    if (!fmt) {
00976       ast_channel_tech_pvt_set(owner, NULL);
00977       ao2_ref(p, -1);
00978       ast_channel_unlock(owner);
00979       ast_channel_release(owner);
00980       return NULL;
00981    }
00982 
00983    ast_channel_set_writeformat(owner, fmt);
00984    ast_channel_set_rawwriteformat(owner, fmt);
00985    ast_channel_set_readformat(owner, fmt);
00986    ast_channel_set_rawreadformat(owner, fmt);
00987 
00988    ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
00989 
00990    ast_jb_configure(owner, &p->jb_conf);
00991 
00992    if (ast_channel_cc_params_init(owner, requestor
00993       ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
00994       ast_channel_tech_pvt_set(owner, NULL);
00995       ao2_ref(p, -1);
00996       ast_channel_tech_pvt_set(owner, NULL);
00997       ast_channel_unlock(owner);
00998       ast_channel_release(owner);
00999       return NULL;
01000    }
01001 
01002    p->owner = owner;
01003    ast_channel_unlock(owner);
01004 
01005    chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
01006       exten, context, &id2, owner, 0,
01007       "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
01008    if (!chan) {
01009       ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
01010       ast_channel_tech_pvt_set(owner, NULL);
01011       ao2_ref(p, -1);
01012       ast_channel_tech_pvt_set(owner, NULL);
01013       ast_channel_release(owner);
01014       return NULL;
01015    }
01016 
01017    if (callid) {
01018       ast_channel_callid_set(chan, callid);
01019    }
01020 
01021    ast_channel_tech_set(chan, tech);
01022    ao2_ref(p, +1);
01023    ast_channel_tech_pvt_set(chan, p);
01024 
01025    ast_channel_nativeformats_set(chan, p->reqcap);
01026 
01027    /* Format was already determined when setting up owner */
01028    ast_channel_set_writeformat(chan, fmt);
01029    ast_channel_set_rawwriteformat(chan, fmt);
01030    ast_channel_set_readformat(chan, fmt);
01031    ast_channel_set_rawreadformat(chan, fmt);
01032 
01033    ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
01034 
01035    p->chan = chan;
01036    ast_channel_unlock(chan);
01037 
01038    return owner;
01039 }

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