· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Asterisk Source/Tmp File


* static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
  • for (;;) {
    • if (is_our_turn(qe))
    • if (qe->expire && (time(NULL) >= qe->expire)) {
    • stat = get_member_status(qe->parent, qe->max_penalty);
    • leave the queue if no agents, if enabled
    • leave the queue if no reachable agents, if enabled
    • Make a position announcement, if enabled
    • If we have timed out, break out
    • Make a periodic announcement, if enabled
    • If we have timed out, break out
    • Wait a second before checking again
    • If we have timed out, break out
  • }
  • return res

/*! \brief Check if we should start attempting to call queue members
 * The behavior of this function is dependent first on whether autofill is enabled
 * and second on whether the ring strategy is ringall. If autofill is not enabled,
 * then return true if we're the head of the queue. If autofill is enabled, then
 * we count the available members and see if the number of available members is enough
 * that given our position in the queue, we would theoretically be able to connect to
 * one of those available members

* is_our_turn
  • autofill option 이 없는 경우
    • queue 의 head 면 return 1, 아니면 0
  • autofill option 이 있는 경우
    • 아니면
      • available members 의 수를 avl 에 assign
        • AST_DEVICE_INUSE 고 qe->parent->ringinuse 가 아니면 사용중
        • AST_DEVICE_NOT_INUSE 이거나 AST_DEVICE_UNKNOWN 이고 paused 가 아니면 사용가능
      • pending 이 아닌 channel 을 찾음.
      • If the queue entry is within avl the number of available members calls from the top ...

  • our turn 이면 return 1


* static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
  • struct callattempt *outgoing = NULL; the list of calls
  • datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
  • time(&now)
  • memi = ao2_iterator_init(qe->parent->members, 0);
  • while ((cur = ao2_iterator_next(&memi))) {
    • if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
    • } else {
    • }
  • }
  • ++qe->pending
  • ring_one(qe, outgoing, &numbusies)
  • lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
  • peer = lpeer ? lpeer->chan : NULL;
  • if (!peer) {
    • qe->pending = 0
    • if (to) {
      • res = -1
    • } else {
      • res = digit
    • }
  • } else {
    • hangupcalls(outgoing, peer);
    • ast_moh_stop(qe->chan);
    • res = ast_channel_make_compatible(qe->chan, peer);
    • leave_queue(qe);
    • time(&callstart);
    • bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
  • }
  • out:
  • hangupcalls(outgoing, NULL)

* static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)

add queue memebr

Dynamically adds queue members 

Dynamically adds interface to an existing queue (i.e. the interface "logs on" to the queue, as an agent does with AgentCallbackLogin).

queuename - The name of the queue to add a member to
interface - The interface to add to the queue, if not specified, uses the current interface
penalty - Integer greater than or equal to 0, available members with lower penalties will get calls first 
options: j - If the interface is already in the queue and there exists an n+101 priority then it will then jump to this priority. Otherwise it will return an error.
membername - a specific member name to be added


* static int aqm_exec(struct ast_channel *chan, void *data)
  • int res=-1;
  • interface option 이 주어지지 않았으면, 현재 channel 을 사용
  • penalty 값이 숫자가 아니거나, 음수면 penalty 는 0 으로 설정
  • j option 이 주어졌으면 priority_jump = 1;
  • switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
    • case RES_OKAY: res=0; break;
    • case RES_EXISTS: res=0; break;
    • case RES_NOSUCHQUEUE: res=0; break;
    • case RES_OUTOFMEMORY: break;
  • }
  • return res;

* static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
  • struct call_queue *q;
  • struct member *new_member, *old_member;
  • int res = RES_NOSUCHQUEUE;
  • if (!(q = load_realtime_queue(queuename))) return res;
  • if ((old_member = interface_exists(q, interface)) == NULL) {
    • add_to_interfaces(interface);
  • } else
    • interface 와 q->members 의 member 들중에 member->interface 가 match 되는 것이 있으면
    • ao2_ref(old_member, -1);
    • res = RES_EXISTS;
  • }
  • return res;

* static struct member *interface_exists(struct call_queue *q, const char *interface)
  • mem_iter = ao2_iterator_init(q->members, 0);
  • while ((mem = ao2_iterator_next(&mem_iter))) {
    • matching 되는 interface 가 있으면, return mem;
    • ao2_ref(mem, -1);
  • }
  • return NULL;
 * Reference/unreference an object and return the old refcount.
 * \param o A pointer to the object
 * \param delta Value to add to the reference counter.
 * \return The value of the reference counter before the operation.
 * Increase/decrease the reference counter according
 * the value of delta.
 * If the refcount goes to zero, the object is destroyed.
 * \note The object must not be locked by the caller of this function, as
 *       it is invalid to try to unlock it after releasing the reference.
 * \note if we know the pointer to an object, it is because we
 * have a reference count to it, so the only case when the object
 * can go away is when we release our reference, and it is
 * the last one in existence.
int ao2_ref(void *o, int delta);
 * \brief Add an object to a container.
 * \param c the container to operate on.
 * \param newobj the object to be added.
 * \return NULL on errors, other values on success.
 * This function inserts an object in a container according its key.
 * \note Remember to set the key before calling this function.
 * \note This function automatically increases the reference count to
 *       account for the reference to the object that the container now holds.
 * For Asterisk 1.4 only, there is a dirty hack here to ensure that chan_iax2
 * can have objects linked in to the container at the head instead of tail
 * when it is just a linked list.  This is to maintain some existing behavior
 * where the order must be maintained as it was before this conversion so that
 * matching behavior doesn't change.
#define ao2_link(c, o) __ao2_link(c, o, 0)
void *__ao2_link(struct ao2_container *c, void *newobj, int iax2_hack);
 * When we need to walk through a container, we use
 * ao2_iterator to keep track of the current position.
 * Because the navigation is typically done without holding the
 * lock on the container across the loop,
 * objects can be inserted or deleted or moved
 * while we work. As a consequence, there is no guarantee that
 * the we manage to touch all the elements on the list, or it
 * is possible that we touch the same object multiple times.
 * However, within the current hash table container, the following is true:
 *  - It is not possible to miss an object in the container while iterating
 *    unless it gets added after the iteration begins and is added to a bucket
 *    that is before the one the current object is in.  In this case, even if
 *    you locked the container around the entire iteration loop, you still would
 *    not see this object, because it would still be waiting on the container
 *    lock so that it can be added.
 *  - It would be extremely rare to see an object twice.  The only way this can
 *    happen is if an object got unlinked from the container and added again 
 *    during the same iteration.  Furthermore, when the object gets added back,
 *    it has to be in the current or later bucket for it to be seen again.
 * An iterator must be first initialized with ao2_iterator_init(),
 * then we can use o = ao2_iterator_next() to move from one
 * element to the next. Remember that the object returned by
 * ao2_iterator_next() has its refcount incremented,
 * and the reference must be explicitly released when done with it.
 * Example:
 *  struct ao2_container *c = ... // the container we want to iterate on
 *  struct ao2_iterator i;
 *  struct my_obj *o;
 *  i = ao2_iterator_init(c, flags);
 *  while ( (o = ao2_iterator_next(&i)) ) {
 *     ... do something on o ...
 *     ao2_ref(o, -1);
 *  }

struct member_interface {
        char interface[80];
        AST_LIST_ENTRY(member_interface) list;    /*!< Next call queue */

static AST_LIST_HEAD_STATIC(interfaces, member_interface);
* static int add_to_interfaces(const char *interface)
  • interface 가 존재하면 return 0;
  • if ((curint = ast_calloc(1, sizeof(*curint)))) {
    • ast_copy_string(curint->interface, interface, sizeof(curint->interface));
    • AST_LIST_INSERT_HEAD(&interfaces, curint, list);
  • }
  • return 0;
  \brief Defines a structure to be used to hold a list of specified type, statically initialized.
  \param name This will be the name of the defined structure.
  \param type This is the type of each list entry.

  This macro creates a structure definition that can be used
  to hold a list of the entries of type \a type, and allocates an instance
  of it, initialized to be empty.

  Example usage:
  static AST_LIST_HEAD_STATIC(entry_list, entry);

  This would define \c struct \c entry_list, intended to hold a list of
  type \c struct \c entry.

  \brief Loops over (traverses) the entries in a list.
  \param head This is a pointer to the list head structure
  \param var This is the name of the variable that will hold a pointer to the
  current list entry on each iteration. It must be declared before calling
  this macro.
  \param field This is the name of the field (declared using AST_LIST_ENTRY())
  used to link entries of this list together.

  This macro is use to loop over (traverse) the entries in a list. It uses a
  \a for loop, and supplies the enclosed code with a pointer to each list
  entry as it loops. It is typically used as follows:
  static AST_LIST_HEAD(entry_list, list_entry) entries;
  struct list_entry {
        AST_LIST_ENTRY(list_entry) list;
  struct list_entry *current;
  AST_LIST_TRAVERSE(&entries, current, list) {
     (do something with current here)
  \warning If you modify the forward-link pointer contained in the \a current entry while
  inside the loop, the behavior will be unpredictable. At a minimum, the following
  macros will modify the forward-link pointer, and should not be used inside
  AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
  careful consideration of their consequences:
  \li AST_LIST_NEXT() (when used as an lvalue)

  \brief Inserts a list entry at the head of a list.
  \param head This is a pointer to the list head structure
  \param elm This is a pointer to the entry to be inserted.
  \param field This is the name of the field (declared using AST_LIST_ENTRY())
  used to link entries of this list together.

sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-11-04 10:41:51
Processing time 0.0090 sec