== AsteriskSource/TmpFile == == 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. */ }}}