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

wait_our_turn


* 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 이 있는 경우
    • QUEUE_STRATEGY_RINGALL 이면 avl = 1
    • 아니면
      • 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



temp


* 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

AddQueueMember
Dynamically adds queue members 
AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]])

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

AddQueueMember(techsupport|SIP/3000) 

* 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:
  \code
  static AST_LIST_HEAD_STATIC(entry_list, entry);
  \endcode

  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:
  \code
  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)
  }
  \endcode
  \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)
  \li AST_LIST_INSERT_AFTER()
  \li AST_LIST_INSERT_HEAD()
  \li AST_LIST_INSERT_TAIL()
*/

/*!
  \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.0132 sec