core_unreal.h File Reference

Unreal channel derivative framework. More...

#include "asterisk/astobj2.h"
#include "asterisk/channel.h"
#include "asterisk/bridge.h"
#include "asterisk/abstract_jb.h"

Include dependency graph for core_unreal.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_unreal_pvt
 The base pvt structure for local channel derivatives. More...
struct  ast_unreal_pvt_callbacks
 Callbacks that can be provided by concrete implementations of the unreal channel driver that will be called when events occur in the unreal layer. More...

Defines

#define AST_UNREAL_CARETAKER_THREAD   (1 << 0)
#define AST_UNREAL_IS_OUTBOUND(a, b)   ((a) == (b)->chan ? 1 : 0)
#define AST_UNREAL_MOH_INTERCEPT   (1 << 2)
#define AST_UNREAL_NO_OPTIMIZATION   (1 << 1)
#define AST_UNREAL_OPTIMIZE_BEGUN   (1 << 3)

Enumerations

enum  ast_unreal_channel_indicator { AST_UNREAL_OWNER, AST_UNREAL_CHAN }

Functions

struct ast_unreal_pvtast_unreal_alloc (size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
 Allocate the base unreal struct for a derivative.
int ast_unreal_answer (struct ast_channel *ast)
void ast_unreal_call_setup (struct ast_channel *semi1, struct ast_channel *semi2)
 Setup unreal owner and chan channels before initiating call.
int ast_unreal_channel_push_to_bridge (struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
 Push the semi2 unreal channel into a bridge from either member of the unreal pair.
void ast_unreal_destructor (void *vdoomed)
 struct ast_unreal_pvt destructor.
int ast_unreal_digit_begin (struct ast_channel *ast, char digit)
int ast_unreal_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
int ast_unreal_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
int ast_unreal_hangup (struct ast_unreal_pvt *p, struct ast_channel *ast)
 Hangup one end (maybe both ends) of an unreal channel derivative.
int ast_unreal_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
void ast_unreal_lock_all (struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
 Send an unreal pvt in with no locks held and get all locks.
struct ast_channelast_unreal_new_channels (struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, ast_callid callid)
 Create the semi1 and semi2 unreal channels.
int ast_unreal_queryoption (struct ast_channel *ast, int option, void *data, int *datalen)
struct ast_frameast_unreal_read (struct ast_channel *ast)
int ast_unreal_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
int ast_unreal_sendtext (struct ast_channel *ast, const char *text)
int ast_unreal_setoption (struct ast_channel *chan, int option, void *data, int datalen)
int ast_unreal_write (struct ast_channel *ast, struct ast_frame *f)


Detailed Description

Unreal channel derivative framework.

Author:
Richard Mudgett <rmudgett@digium.com>
See Also:

Definition in file core_unreal.h.


Define Documentation

#define AST_UNREAL_CARETAKER_THREAD   (1 << 0)

The ;2 side launched a PBX, was pushed into a bridge, or was masqueraded into an application.

Definition at line 103 of file core_unreal.h.

Referenced by ast_local_setup_bridge(), ast_local_setup_masquerade(), ast_unreal_channel_push_to_bridge(), ast_unreal_hangup(), conf_announce_channel_depart(), conf_announce_channel_push(), local_call(), and local_devicestate().

#define AST_UNREAL_IS_OUTBOUND ( a,
b   )     ((a) == (b)->chan ? 1 : 0)

#define AST_UNREAL_MOH_INTERCEPT   (1 << 2)

Intercept and act on hold/unhold control frames

Definition at line 105 of file core_unreal.h.

Referenced by ast_unreal_indicate(), and local_alloc().

#define AST_UNREAL_NO_OPTIMIZATION   (1 << 1)

#define AST_UNREAL_OPTIMIZE_BEGUN   (1 << 3)

Indicates that an optimization attempt has been started

Definition at line 106 of file core_unreal.h.

Referenced by try_merge_optimize_out(), and try_swap_optimize_out().


Enumeration Type Documentation

Enumerator:
AST_UNREAL_OWNER 
AST_UNREAL_CHAN 

Definition at line 48 of file core_unreal.h.

00048                                   {
00049    AST_UNREAL_OWNER,
00050    AST_UNREAL_CHAN,
00051 };


Function Documentation

struct ast_unreal_pvt* ast_unreal_alloc ( size_t  size,
ao2_destructor_fn  destructor,
struct ast_format_cap cap 
) [read]

Allocate the base unreal struct for a derivative.

Since:
12.0.0
Parameters:
size Size of the unreal struct to allocate.
destructor Destructor callback.
cap Format capabilities to give the unreal private struct.
Return values:
pvt on success.
NULL on error.

Definition at line 891 of file core_unreal.c.

References ao2_alloc, ao2_ref, ast_format_cap_alloc, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, AST_MEDIA_TYPE_UNKNOWN, ast_jb_conf::flags, ast_unreal_pvt::jb_conf, NULL, and ast_unreal_pvt::reqcap.

Referenced by announce_request(), local_alloc(), and media_request_helper().

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 }

int ast_unreal_answer ( struct ast_channel ast  ) 

Unreal channel framework struct ast_channel_tech.answer callback

Definition at line 255 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log, AST_UNREAL_IS_OUTBOUND, LOG_WARNING, and unreal_queue_frame().

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 }

void ast_unreal_call_setup ( struct ast_channel semi1,
struct ast_channel semi2 
)

Setup unreal owner and chan channels before initiating call.

Since:
12.0.0
Parameters:
semi1 Owner channel of unreal channel pair.
semi2 Outgoing channel of unreal channel pair.
Note:
On entry, the semi1 and semi2 channels are already locked.
Returns:
Nothing

Definition at line 657 of file core_unreal.c.

References AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_accountcode(), ast_channel_caller(), ast_channel_cc_params_init(), ast_channel_connected(), ast_channel_datastore_inherit(), ast_channel_dialed(), ast_channel_get_cc_config_params(), ast_channel_hangupcause(), ast_channel_hangupcause_set(), ast_channel_language(), ast_channel_musicclass(), ast_channel_peeraccount(), ast_channel_publish_varset(), ast_channel_redirecting(), ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_varshead(), ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_party_dialed_copy(), ast_party_redirecting_copy(), ast_var_assign(), ast_var_full_name(), ast_var_value(), ast_var_t::entries, ast_var_t::name, and ast_var_t::value.

Referenced by local_call().

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 }

int ast_unreal_channel_push_to_bridge ( struct ast_channel ast,
struct ast_bridge bridge,
unsigned int  flags 
)

Push the semi2 unreal channel into a bridge from either member of the unreal pair.

Since:
12.0.0
Parameters:
ast A member of the unreal channel being pushed
bridge Which bridge we want to push the channel to
flags Feature flags to be set on the bridge channel.
Return values:
0 if the channel is successfully imparted onto the bridge
-1 on failure
Note:
This is equivalent to ast_call() on unreal based channel drivers that are designed to use it instead.

Definition at line 715 of file core_unreal.c.

References ao2_cleanup, ao2_lock, ao2_ref, ao2_unlock, ast_bridge_features_destroy(), ast_bridge_features_new(), ast_bridge_impart(), AST_BRIDGE_IMPART_CHAN_INDEPENDENT, ast_bridge_lock, ast_bridge_unlock, ast_channel_callid(), ast_channel_callid_set(), ast_channel_lock, ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, ast_set_flag, AST_UNREAL_CARETAKER_THREAD, ast_bridge::callid, ast_unreal_pvt::chan, ast_bridge_features::feature_flags, lock, NULL, ast_unreal_pvt::owner, RAII_VAR, SCOPED_AO2LOCK, and SCOPED_CHANNELLOCK.

Referenced by ari_bridges_play_new(), ast_ari_bridges_record(), and bridge_moh_create().

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 }

void ast_unreal_destructor ( void *  vdoomed  ) 

struct ast_unreal_pvt destructor.

Since:
12.0.0
Parameters:
vdoomed Object to destroy.
Returns:
Nothing

Definition at line 883 of file core_unreal.c.

References ao2_cleanup, NULL, and ast_unreal_pvt::reqcap.

Referenced by announce_pvt_destructor(), local_pvt_destructor(), and media_request_helper().

00884 {
00885    struct ast_unreal_pvt *doomed = vdoomed;
00886 
00887    ao2_cleanup(doomed->reqcap);
00888    doomed->reqcap = NULL;
00889 }

int ast_unreal_digit_begin ( struct ast_channel ast,
char  digit 
)

Unreal channel framework struct ast_channel_tech.send_digit_begin callback

Definition at line 566 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_DTMF_BEGIN, AST_UNREAL_IS_OUTBOUND, ast_frame_subclass::integer, ast_frame::subclass, and unreal_queue_frame().

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 }

int ast_unreal_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
)

Unreal channel framework struct ast_channel_tech.send_digit_end callback

Definition at line 588 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_DTMF_END, AST_UNREAL_IS_OUTBOUND, ast_frame_subclass::integer, ast_frame::len, ast_frame::subclass, and unreal_queue_frame().

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 }

int ast_unreal_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
)

Unreal channel framework struct ast_channel_tech.fixup callback

Definition at line 348 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_internal_bridge(), ast_channel_name(), ast_channel_tech_pvt(), ast_check_hangup(), ast_log, ast_queue_hangup(), ast_unreal_pvt::chan, LOG_WARNING, and ast_unreal_pvt::owner.

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 }

int ast_unreal_hangup ( struct ast_unreal_pvt p,
struct ast_channel ast 
)

Hangup one end (maybe both ends) of an unreal channel derivative.

Since:
12.0.0
Parameters:
p Private channel struct (reffed)
ast Channel being hung up. (locked)
Note:
Common hangup code for unreal channels. Derived channels will need to deal with any additional resources.
Return values:
0 on success.
-1 on error.

Definition at line 804 of file core_unreal.c.

References ao2_ref, ao2_unlock, AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_hangupcause(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_name(), ast_channel_tech_pvt_set(), ast_channel_unlock, ast_channel_unref, ast_clear_flag, ast_debug, ast_hangup(), ast_queue_hangup_with_cause(), ast_test_flag, AST_UNREAL_CARETAKER_THREAD, ast_unreal_lock_all(), ast_unreal_pvt::chan, hangup_chan(), NULL, ast_unreal_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), and status.

Referenced by announce_hangup(), local_hangup(), and media_hangup().

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 }

int ast_unreal_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
)

Unreal channel framework struct ast_channel_tech.indicate callback

Definition at line 521 of file core_unreal.c.

References ao2_ref, ast_channel_tech_pvt(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_MASQUERADE_NOTIFY, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, ast_moh_start(), ast_moh_stop(), ast_test_flag, AST_UNREAL_MOH_INTERCEPT, NULL, unreal_colp_redirect_indicate(), and unreal_queue_indicate().

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 }

void ast_unreal_lock_all ( struct ast_unreal_pvt p,
struct ast_channel **  outchan,
struct ast_channel **  outowner 
)

Send an unreal pvt in with no locks held and get all locks.

Note:
NO locks should be held prior to calling this function

The pvt must have a ref held before calling this function

if outchan or outowner is set != NULL after calling this function those channels are locked and reffed.

Batman.

Definition at line 48 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_lock_both, ast_channel_ref, ast_channel_unlock, ast_channel_unref, ast_unreal_pvt::chan, NULL, and ast_unreal_pvt::owner.

Referenced by ast_unreal_hangup(), local_call(), publish_local_bridge_message(), stasis_app_channel_unreal_set_internal(), and unreal_colp_redirect_indicate().

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 }

struct ast_channel* ast_unreal_new_channels ( struct ast_unreal_pvt p,
const struct ast_channel_tech tech,
int  semi1_state,
int  semi2_state,
const char *  exten,
const char *  context,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor,
ast_callid  callid 
) [read]

Create the semi1 and semi2 unreal channels.

Since:
12.0.0
Parameters:
p Unreal channel private struct.
tech Channel technology to use.
semi1_state State to start the semi1(owner) channel in.
semi2_state State to start the semi2(outgoing chan) channel in.
exten Exten to start the chennels in. (NULL if s)
context Context to start the channels in. (NULL if default)
requestor Channel requesting creation. (NULL if none)
callid Thread callid to use.
Return values:
semi1_channel on success.
NULL on error.

Definition at line 920 of file core_unreal.c.

References ao2_cleanup, ao2_ref, ast_alloca, ast_atomic_fetchadd_int(), ast_channel_alloc, ast_channel_callid_set(), ast_channel_cc_params_init(), ast_channel_flags(), ast_channel_get_cc_config_params(), ast_channel_nativeformats_set(), ast_channel_release(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, AST_FLAG_DISABLE_DEVSTATE_CACHE, ast_format_cap_get_format(), ast_jb_configure(), ast_log, ast_set_flag, ast_strlen_zero, ast_unreal_pvt::chan, ast_unreal_pvt::jb_conf, LOG_WARNING, ast_unreal_pvt::name, NULL, ast_unreal_pvt::owner, RAII_VAR, ast_unreal_pvt::reqcap, ast_channel_tech::type, ast_assigned_ids::uniqueid, and ast_assigned_ids::uniqueid2.

Referenced by announce_request(), local_request(), and media_request_helper().

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 }

int ast_unreal_queryoption ( struct ast_channel ast,
int  option,
void *  data,
int *  datalen 
)

Unreal channel framework struct ast_channel_tech.queryoption callback

Definition at line 167 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_bridge_peer(), ast_channel_lock, ast_channel_queryoption(), ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, AST_OPTION_T38_STATE, AST_UNREAL_IS_OUTBOUND, ast_unreal_pvt::chan, and ast_unreal_pvt::owner.

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 }

struct ast_frame* ast_unreal_read ( struct ast_channel ast  )  [read]

Unreal channel framework struct ast_channel_tech.read and struct ast_channel_tech.exception callback

Definition at line 314 of file core_unreal.c.

References ast_null_frame.

00315 {
00316    return &ast_null_frame;
00317 }

int ast_unreal_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
)

Unreal channel framework struct ast_channel_tech.send_html callback

Definition at line 633 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_HTML, AST_UNREAL_IS_OUTBOUND, ast_frame::data, ast_frame::datalen, ast_frame_subclass::integer, ast_frame::ptr, ast_frame::subclass, and unreal_queue_frame().

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 }

int ast_unreal_sendtext ( struct ast_channel ast,
const char *  text 
)

Unreal channel framework struct ast_channel_tech.send_text callback

Definition at line 611 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_TEXT, AST_UNREAL_IS_OUTBOUND, ast_frame::data, ast_frame::datalen, ast_frame::ptr, and unreal_queue_frame().

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 }

int ast_unreal_setoption ( struct ast_channel chan,
int  option,
void *  data,
int  datalen 
)

Unreal channel framework struct ast_channel_tech.setoption callback

Definition at line 98 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_lock, ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, ast_log, AST_OPTION_CHANNEL_WRITE, ast_unreal_pvt::chan, ast_chan_write_info_t::chan, ast_chan_write_info_t::data, ast_chan_write_info_t::function, LOG_ERROR, NULL, ast_unreal_pvt::owner, ast_chan_write_info_t::value, ast_chan_write_info_t::version, and ast_chan_write_info_t::write_fn.

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 }

int ast_unreal_write ( struct ast_channel ast,
struct ast_frame f 
)

Unreal channel framework struct ast_channel_tech.write callback

Definition at line 319 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_UNREAL_IS_OUTBOUND, ast_frame::frametype, got_optimized_out(), and unreal_queue_frame().

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 }


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