00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370183 $")
00031
00032 #include "asterisk/astobj2.h"
00033 #include "asterisk/strings.h"
00034 #include "asterisk/ccss.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/taskprocessor.h"
00039 #include "asterisk/event.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/app.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/manager.h"
00044 #include "asterisk/causes.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 static struct ast_sched_thread *cc_sched_thread;
00107
00108
00109
00110
00111 static int core_id_counter;
00112
00113
00114
00115
00116 static struct ast_taskprocessor *cc_core_taskprocessor;
00117
00118
00119
00120 static const char *CC_LOGGER_LEVEL_NAME = "CC";
00121
00122
00123
00124 static int cc_logger_level;
00125
00126
00127
00128 static unsigned int global_cc_max_requests;
00129
00130
00131
00132 static int cc_request_count;
00133
00134 static inline void *cc_ref(void *obj, const char *debug)
00135 {
00136 ao2_t_ref(obj, +1, debug);
00137 return obj;
00138 }
00139
00140 static inline void *cc_unref(void *obj, const char *debug)
00141 {
00142 ao2_t_ref(obj, -1, debug);
00143 return NULL;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 struct ast_cc_config_params {
00153 enum ast_cc_agent_policies cc_agent_policy;
00154 enum ast_cc_monitor_policies cc_monitor_policy;
00155 unsigned int cc_offer_timer;
00156 unsigned int ccnr_available_timer;
00157 unsigned int ccbs_available_timer;
00158 unsigned int cc_recall_timer;
00159 unsigned int cc_max_agents;
00160 unsigned int cc_max_monitors;
00161 char cc_callback_macro[AST_MAX_EXTENSION];
00162 char cc_agent_dialstring[AST_MAX_EXTENSION];
00163 };
00164
00165
00166
00167
00168
00169
00170
00171 enum cc_state {
00172
00173 CC_AVAILABLE,
00174
00175 CC_CALLER_OFFERED,
00176
00177
00178 CC_CALLER_REQUESTED,
00179
00180
00181 CC_ACTIVE,
00182
00183
00184 CC_CALLEE_READY,
00185
00186
00187
00188 CC_CALLER_BUSY,
00189
00190
00191
00192 CC_RECALLING,
00193
00194
00195
00196 CC_COMPLETE,
00197
00198
00199
00200
00201 CC_FAILED,
00202 };
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 struct cc_control_payload {
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 const char *monitor_type;
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 void *private_data;
00248
00249
00250
00251
00252
00253
00254
00255
00256 enum ast_cc_service_type service;
00257
00258
00259
00260
00261
00262
00263
00264
00265 struct ast_cc_config_params config_params;
00266
00267
00268
00269
00270
00271
00272
00273
00274 int parent_interface_id;
00275
00276
00277
00278
00279
00280
00281
00282
00283 char device_name[AST_CHANNEL_NAME];
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 char dialstring[AST_CHANNEL_NAME];
00296 };
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 AST_LIST_HEAD(cc_monitor_tree, ast_cc_monitor);
00315
00316 static const int CC_CORE_INSTANCES_BUCKETS = 17;
00317 static struct ao2_container *cc_core_instances;
00318
00319 struct cc_core_instance {
00320
00321
00322
00323 int core_id;
00324
00325
00326
00327 enum cc_state current_state;
00328
00329
00330
00331 struct ast_cc_agent *agent;
00332
00333
00334
00335 struct cc_monitor_tree *monitors;
00336 };
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 static int __attribute__((format(printf, 3, 0))) cc_request_state_change(enum cc_state state, const int core_id, const char *debug, va_list ap);
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 static struct cc_core_instance *cc_core_init_instance(struct ast_channel *caller_chan,
00370 struct cc_monitor_tree *called_tree, const int core_id, struct cc_control_payload *cc_data);
00371
00372 static const struct {
00373 enum ast_cc_service_type service;
00374 const char *service_string;
00375 } cc_service_to_string_map[] = {
00376 {AST_CC_NONE, "NONE"},
00377 {AST_CC_CCBS, "CCBS"},
00378 {AST_CC_CCNR, "CCNR"},
00379 {AST_CC_CCNL, "CCNL"},
00380 };
00381
00382 static const struct {
00383 enum cc_state state;
00384 const char *state_string;
00385 } cc_state_to_string_map[] = {
00386 {CC_AVAILABLE, "CC is available"},
00387 {CC_CALLER_OFFERED, "CC offered to caller"},
00388 {CC_CALLER_REQUESTED, "CC requested by caller"},
00389 {CC_ACTIVE, "CC accepted by callee"},
00390 {CC_CALLEE_READY, "Callee has become available"},
00391 {CC_CALLER_BUSY, "Callee was ready, but caller is now unavailable"},
00392 {CC_RECALLING, "Caller is attempting to recall"},
00393 {CC_COMPLETE, "Recall complete"},
00394 {CC_FAILED, "CC has failed"},
00395 };
00396
00397 static const char *cc_state_to_string(enum cc_state state)
00398 {
00399 return cc_state_to_string_map[state].state_string;
00400 }
00401
00402 static const char *cc_service_to_string(enum ast_cc_service_type service)
00403 {
00404 return cc_service_to_string_map[service].service_string;
00405 }
00406
00407 static int cc_core_instance_hash_fn(const void *obj, const int flags)
00408 {
00409 const struct cc_core_instance *core_instance = obj;
00410 return core_instance->core_id;
00411 }
00412
00413 static int cc_core_instance_cmp_fn(void *obj, void *arg, int flags)
00414 {
00415 struct cc_core_instance *core_instance1 = obj;
00416 struct cc_core_instance *core_instance2 = arg;
00417
00418 return core_instance1->core_id == core_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
00419 }
00420
00421 static struct cc_core_instance *find_cc_core_instance(const int core_id)
00422 {
00423 struct cc_core_instance finder = {.core_id = core_id,};
00424
00425 return ao2_t_find(cc_core_instances, &finder, OBJ_POINTER, "Finding a core_instance");
00426 }
00427
00428 struct cc_callback_helper {
00429 ao2_callback_fn *function;
00430 void *args;
00431 const char *type;
00432 };
00433
00434 static int cc_agent_callback_helper(void *obj, void *args, int flags)
00435 {
00436 struct cc_core_instance *core_instance = obj;
00437 struct cc_callback_helper *helper = args;
00438
00439 if (strcmp(core_instance->agent->callbacks->type, helper->type)) {
00440 return 0;
00441 }
00442
00443 return helper->function(core_instance->agent, helper->args, flags);
00444 }
00445
00446 struct ast_cc_agent *ast_cc_agent_callback(int flags, ao2_callback_fn *function, void *args, const char * const type)
00447 {
00448 struct cc_callback_helper helper = {.function = function, .args = args, .type = type};
00449 struct cc_core_instance *core_instance;
00450 if ((core_instance = ao2_t_callback(cc_core_instances, flags, cc_agent_callback_helper, &helper,
00451 "Calling provided agent callback function"))) {
00452 struct ast_cc_agent *agent = cc_ref(core_instance->agent, "An outside entity needs the agent");
00453 cc_unref(core_instance, "agent callback done with the core_instance");
00454 return agent;
00455 }
00456 return NULL;
00457 }
00458
00459 enum match_flags {
00460
00461
00462
00463 MATCH_NO_REQUEST = (1 << 0),
00464
00465
00466
00467 MATCH_REQUEST = (1 << 1),
00468 };
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 static int match_agent(void *obj, void *arg, void *data, int flags)
00483 {
00484 struct cc_core_instance *core_instance = obj;
00485 const char *name = arg;
00486 unsigned long match_flags = *(unsigned long *)data;
00487 int possible_match = 0;
00488
00489 if ((match_flags & MATCH_NO_REQUEST) && core_instance->current_state < CC_CALLER_REQUESTED) {
00490 possible_match = 1;
00491 }
00492
00493 if ((match_flags & MATCH_REQUEST) && core_instance->current_state >= CC_CALLER_REQUESTED) {
00494 possible_match = 1;
00495 }
00496
00497 if (!possible_match) {
00498 return 0;
00499 }
00500
00501 if (!strcmp(core_instance->agent->device_name, name)) {
00502 return CMP_MATCH | CMP_STOP;
00503 }
00504 return 0;
00505 }
00506
00507 struct count_agents_cb_data {
00508 int count;
00509 int core_id_exception;
00510 };
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 static int count_agents_cb(void *obj, void *arg, void *data, int flags)
00521 {
00522 struct cc_core_instance *core_instance = obj;
00523 const char *name = arg;
00524 struct count_agents_cb_data *cb_data = data;
00525
00526 if (cb_data->core_id_exception == core_instance->core_id) {
00527 ast_log_dynamic_level(cc_logger_level, "Found agent with core_id %d but not counting it toward total\n", core_instance->core_id);
00528 return 0;
00529 }
00530
00531 if (core_instance->current_state >= CC_CALLER_REQUESTED && !strcmp(core_instance->agent->device_name, name)) {
00532 cb_data->count++;
00533 }
00534 return 0;
00535 }
00536
00537 #define CC_OFFER_TIMER_DEFAULT 20
00538 #define CCNR_AVAILABLE_TIMER_DEFAULT 7200
00539 #define CCBS_AVAILABLE_TIMER_DEFAULT 4800
00540 #define CC_RECALL_TIMER_DEFAULT 20
00541 #define CC_MAX_AGENTS_DEFAULT 5
00542 #define CC_MAX_MONITORS_DEFAULT 5
00543 #define GLOBAL_CC_MAX_REQUESTS_DEFAULT 20
00544
00545 static const struct ast_cc_config_params cc_default_params = {
00546 .cc_agent_policy = AST_CC_AGENT_NEVER,
00547 .cc_monitor_policy = AST_CC_MONITOR_NEVER,
00548 .cc_offer_timer = CC_OFFER_TIMER_DEFAULT,
00549 .ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT,
00550 .ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT,
00551 .cc_recall_timer = CC_RECALL_TIMER_DEFAULT,
00552 .cc_max_agents = CC_MAX_AGENTS_DEFAULT,
00553 .cc_max_monitors = CC_MAX_MONITORS_DEFAULT,
00554 .cc_callback_macro = "",
00555 .cc_agent_dialstring = "",
00556 };
00557
00558 void ast_cc_default_config_params(struct ast_cc_config_params *params)
00559 {
00560 *params = cc_default_params;
00561 }
00562
00563 struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function)
00564 {
00565 #if defined(__AST_DEBUG_MALLOC)
00566 struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
00567 #else
00568 struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
00569 #endif
00570
00571 if (!params) {
00572 return NULL;
00573 }
00574
00575 ast_cc_default_config_params(params);
00576 return params;
00577 }
00578
00579 void ast_cc_config_params_destroy(struct ast_cc_config_params *params)
00580 {
00581 ast_free(params);
00582 }
00583
00584 static enum ast_cc_agent_policies str_to_agent_policy(const char * const value)
00585 {
00586 if (!strcasecmp(value, "never")) {
00587 return AST_CC_AGENT_NEVER;
00588 } else if (!strcasecmp(value, "native")) {
00589 return AST_CC_AGENT_NATIVE;
00590 } else if (!strcasecmp(value, "generic")) {
00591 return AST_CC_AGENT_GENERIC;
00592 } else {
00593 ast_log(LOG_WARNING, "%s is an invalid value for cc_agent_policy. Switching to 'never'\n", value);
00594 return AST_CC_AGENT_NEVER;
00595 }
00596 }
00597
00598 static enum ast_cc_monitor_policies str_to_monitor_policy(const char * const value)
00599 {
00600 if (!strcasecmp(value, "never")) {
00601 return AST_CC_MONITOR_NEVER;
00602 } else if (!strcasecmp(value, "native")) {
00603 return AST_CC_MONITOR_NATIVE;
00604 } else if (!strcasecmp(value, "generic")) {
00605 return AST_CC_MONITOR_GENERIC;
00606 } else if (!strcasecmp(value, "always")) {
00607 return AST_CC_MONITOR_ALWAYS;
00608 } else {
00609 ast_log(LOG_WARNING, "%s is an invalid value for cc_monitor_policy. Switching to 'never'\n", value);
00610 return AST_CC_MONITOR_NEVER;
00611 }
00612 }
00613
00614 static const char *agent_policy_to_str(enum ast_cc_agent_policies policy)
00615 {
00616 switch (policy) {
00617 case AST_CC_AGENT_NEVER:
00618 return "never";
00619 case AST_CC_AGENT_NATIVE:
00620 return "native";
00621 case AST_CC_AGENT_GENERIC:
00622 return "generic";
00623 default:
00624
00625 return "";
00626 }
00627 }
00628
00629 static const char *monitor_policy_to_str(enum ast_cc_monitor_policies policy)
00630 {
00631 switch (policy) {
00632 case AST_CC_MONITOR_NEVER:
00633 return "never";
00634 case AST_CC_MONITOR_NATIVE:
00635 return "native";
00636 case AST_CC_MONITOR_GENERIC:
00637 return "generic";
00638 case AST_CC_MONITOR_ALWAYS:
00639 return "always";
00640 default:
00641
00642 return "";
00643 }
00644 }
00645 int ast_cc_get_param(struct ast_cc_config_params *params, const char * const name,
00646 char *buf, size_t buf_len)
00647 {
00648 const char *value = NULL;
00649
00650 if (!strcasecmp(name, "cc_callback_macro")) {
00651 value = ast_get_cc_callback_macro(params);
00652 } else if (!strcasecmp(name, "cc_agent_policy")) {
00653 value = agent_policy_to_str(ast_get_cc_agent_policy(params));
00654 } else if (!strcasecmp(name, "cc_monitor_policy")) {
00655 value = monitor_policy_to_str(ast_get_cc_monitor_policy(params));
00656 } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00657 value = ast_get_cc_agent_dialstring(params);
00658 }
00659 if (value) {
00660 ast_copy_string(buf, value, buf_len);
00661 return 0;
00662 }
00663
00664
00665
00666
00667
00668 if (!strcasecmp(name, "cc_offer_timer")) {
00669 snprintf(buf, buf_len, "%u", ast_get_cc_offer_timer(params));
00670 } else if (!strcasecmp(name, "ccnr_available_timer")) {
00671 snprintf(buf, buf_len, "%u", ast_get_ccnr_available_timer(params));
00672 } else if (!strcasecmp(name, "ccbs_available_timer")) {
00673 snprintf(buf, buf_len, "%u", ast_get_ccbs_available_timer(params));
00674 } else if (!strcasecmp(name, "cc_max_agents")) {
00675 snprintf(buf, buf_len, "%u", ast_get_cc_max_agents(params));
00676 } else if (!strcasecmp(name, "cc_max_monitors")) {
00677 snprintf(buf, buf_len, "%u", ast_get_cc_max_monitors(params));
00678 } else if (!strcasecmp(name, "cc_recall_timer")) {
00679 snprintf(buf, buf_len, "%u", ast_get_cc_recall_timer(params));
00680 } else {
00681 ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00682 return -1;
00683 }
00684
00685 return 0;
00686 }
00687
00688 int ast_cc_set_param(struct ast_cc_config_params *params, const char * const name,
00689 const char * const value)
00690 {
00691 unsigned int value_as_uint;
00692 if (!strcasecmp(name, "cc_agent_policy")) {
00693 return ast_set_cc_agent_policy(params, str_to_agent_policy(value));
00694 } else if (!strcasecmp(name, "cc_monitor_policy")) {
00695 return ast_set_cc_monitor_policy(params, str_to_monitor_policy(value));
00696 } else if (!strcasecmp(name, "cc_agent_dialstring")) {
00697 ast_set_cc_agent_dialstring(params, value);
00698 } else if (!strcasecmp(name, "cc_callback_macro")) {
00699 ast_set_cc_callback_macro(params, value);
00700 return 0;
00701 }
00702
00703 if (!sscanf(value, "%30u", &value_as_uint) == 1) {
00704 return -1;
00705 }
00706
00707 if (!strcasecmp(name, "cc_offer_timer")) {
00708 ast_set_cc_offer_timer(params, value_as_uint);
00709 } else if (!strcasecmp(name, "ccnr_available_timer")) {
00710 ast_set_ccnr_available_timer(params, value_as_uint);
00711 } else if (!strcasecmp(name, "ccbs_available_timer")) {
00712 ast_set_ccbs_available_timer(params, value_as_uint);
00713 } else if (!strcasecmp(name, "cc_max_agents")) {
00714 ast_set_cc_max_agents(params, value_as_uint);
00715 } else if (!strcasecmp(name, "cc_max_monitors")) {
00716 ast_set_cc_max_monitors(params, value_as_uint);
00717 } else if (!strcasecmp(name, "cc_recall_timer")) {
00718 ast_set_cc_recall_timer(params, value_as_uint);
00719 } else {
00720 ast_log(LOG_WARNING, "%s is not a valid CC parameter. Ignoring.\n", name);
00721 return -1;
00722 }
00723
00724 return 0;
00725 }
00726
00727 int ast_cc_is_config_param(const char * const name)
00728 {
00729 return (!strcasecmp(name, "cc_agent_policy") ||
00730 !strcasecmp(name, "cc_monitor_policy") ||
00731 !strcasecmp(name, "cc_offer_timer") ||
00732 !strcasecmp(name, "ccnr_available_timer") ||
00733 !strcasecmp(name, "ccbs_available_timer") ||
00734 !strcasecmp(name, "cc_max_agents") ||
00735 !strcasecmp(name, "cc_max_monitors") ||
00736 !strcasecmp(name, "cc_callback_macro") ||
00737 !strcasecmp(name, "cc_agent_dialstring") ||
00738 !strcasecmp(name, "cc_recall_timer"));
00739 }
00740
00741 void ast_cc_copy_config_params(struct ast_cc_config_params *dest, const struct ast_cc_config_params *src)
00742 {
00743 *dest = *src;
00744 }
00745
00746 enum ast_cc_agent_policies ast_get_cc_agent_policy(struct ast_cc_config_params *config)
00747 {
00748 return config->cc_agent_policy;
00749 }
00750
00751 int ast_set_cc_agent_policy(struct ast_cc_config_params *config, enum ast_cc_agent_policies value)
00752 {
00753
00754
00755
00756 if (value < AST_CC_AGENT_NEVER || value > AST_CC_AGENT_GENERIC) {
00757 return -1;
00758 }
00759 config->cc_agent_policy = value;
00760 return 0;
00761 }
00762
00763 enum ast_cc_monitor_policies ast_get_cc_monitor_policy(struct ast_cc_config_params *config)
00764 {
00765 return config->cc_monitor_policy;
00766 }
00767
00768 int ast_set_cc_monitor_policy(struct ast_cc_config_params *config, enum ast_cc_monitor_policies value)
00769 {
00770
00771
00772
00773 if (value < AST_CC_MONITOR_NEVER || value > AST_CC_MONITOR_ALWAYS) {
00774 return -1;
00775 }
00776 config->cc_monitor_policy = value;
00777 return 0;
00778 }
00779
00780 unsigned int ast_get_cc_offer_timer(struct ast_cc_config_params *config)
00781 {
00782 return config->cc_offer_timer;
00783 }
00784
00785 void ast_set_cc_offer_timer(struct ast_cc_config_params *config, unsigned int value)
00786 {
00787
00788 if (value == 0) {
00789 ast_log(LOG_WARNING, "0 is an invalid value for cc_offer_timer. Retaining value as %u\n", config->cc_offer_timer);
00790 return;
00791 }
00792 config->cc_offer_timer = value;
00793 }
00794
00795 unsigned int ast_get_ccnr_available_timer(struct ast_cc_config_params *config)
00796 {
00797 return config->ccnr_available_timer;
00798 }
00799
00800 void ast_set_ccnr_available_timer(struct ast_cc_config_params *config, unsigned int value)
00801 {
00802
00803 if (value == 0) {
00804 ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->ccnr_available_timer);
00805 return;
00806 }
00807 config->ccnr_available_timer = value;
00808 }
00809
00810 unsigned int ast_get_cc_recall_timer(struct ast_cc_config_params *config)
00811 {
00812 return config->cc_recall_timer;
00813 }
00814
00815 void ast_set_cc_recall_timer(struct ast_cc_config_params *config, unsigned int value)
00816 {
00817
00818 if (value == 0) {
00819 ast_log(LOG_WARNING, "0 is an invalid value for ccnr_available_timer. Retaining value as %u\n", config->cc_recall_timer);
00820 return;
00821 }
00822 config->cc_recall_timer = value;
00823 }
00824
00825 unsigned int ast_get_ccbs_available_timer(struct ast_cc_config_params *config)
00826 {
00827 return config->ccbs_available_timer;
00828 }
00829
00830 void ast_set_ccbs_available_timer(struct ast_cc_config_params *config, unsigned int value)
00831 {
00832
00833 if (value == 0) {
00834 ast_log(LOG_WARNING, "0 is an invalid value for ccbs_available_timer. Retaining value as %u\n", config->ccbs_available_timer);
00835 return;
00836 }
00837 config->ccbs_available_timer = value;
00838 }
00839
00840 const char *ast_get_cc_agent_dialstring(struct ast_cc_config_params *config)
00841 {
00842 return config->cc_agent_dialstring;
00843 }
00844
00845 void ast_set_cc_agent_dialstring(struct ast_cc_config_params *config, const char *const value)
00846 {
00847 if (ast_strlen_zero(value)) {
00848 config->cc_agent_dialstring[0] = '\0';
00849 } else {
00850 ast_copy_string(config->cc_agent_dialstring, value, sizeof(config->cc_agent_dialstring));
00851 }
00852 }
00853
00854 unsigned int ast_get_cc_max_agents(struct ast_cc_config_params *config)
00855 {
00856 return config->cc_max_agents;
00857 }
00858
00859 void ast_set_cc_max_agents(struct ast_cc_config_params *config, unsigned int value)
00860 {
00861 config->cc_max_agents = value;
00862 }
00863
00864 unsigned int ast_get_cc_max_monitors(struct ast_cc_config_params *config)
00865 {
00866 return config->cc_max_monitors;
00867 }
00868
00869 void ast_set_cc_max_monitors(struct ast_cc_config_params *config, unsigned int value)
00870 {
00871 config->cc_max_monitors = value;
00872 }
00873
00874 const char *ast_get_cc_callback_macro(struct ast_cc_config_params *config)
00875 {
00876 return config->cc_callback_macro;
00877 }
00878
00879 void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * const value)
00880 {
00881 if (ast_strlen_zero(value)) {
00882 config->cc_callback_macro[0] = '\0';
00883 } else {
00884 ast_copy_string(config->cc_callback_macro, value, sizeof(config->cc_callback_macro));
00885 }
00886 }
00887
00888 struct cc_monitor_backend {
00889 AST_LIST_ENTRY(cc_monitor_backend) next;
00890 const struct ast_cc_monitor_callbacks *callbacks;
00891 };
00892
00893 AST_RWLIST_HEAD_STATIC(cc_monitor_backends, cc_monitor_backend);
00894
00895 int ast_cc_monitor_register(const struct ast_cc_monitor_callbacks *callbacks)
00896 {
00897 struct cc_monitor_backend *backend = ast_calloc(1, sizeof(*backend));
00898
00899 if (!backend) {
00900 return -1;
00901 }
00902
00903 backend->callbacks = callbacks;
00904
00905 AST_RWLIST_WRLOCK(&cc_monitor_backends);
00906 AST_RWLIST_INSERT_TAIL(&cc_monitor_backends, backend, next);
00907 AST_RWLIST_UNLOCK(&cc_monitor_backends);
00908 return 0;
00909 }
00910
00911 static const struct ast_cc_monitor_callbacks *find_monitor_callbacks(const char * const type)
00912 {
00913 struct cc_monitor_backend *backend;
00914 const struct ast_cc_monitor_callbacks *callbacks = NULL;
00915
00916 AST_RWLIST_RDLOCK(&cc_monitor_backends);
00917 AST_RWLIST_TRAVERSE(&cc_monitor_backends, backend, next) {
00918 if (!strcmp(backend->callbacks->type, type)) {
00919 ast_log_dynamic_level(cc_logger_level, "Returning monitor backend %s\n", backend->callbacks->type);
00920 callbacks = backend->callbacks;
00921 break;
00922 }
00923 }
00924 AST_RWLIST_UNLOCK(&cc_monitor_backends);
00925 return callbacks;
00926 }
00927
00928 void ast_cc_monitor_unregister(const struct ast_cc_monitor_callbacks *callbacks)
00929 {
00930 struct cc_monitor_backend *backend;
00931 AST_RWLIST_WRLOCK(&cc_monitor_backends);
00932 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_monitor_backends, backend, next) {
00933 if (backend->callbacks == callbacks) {
00934 AST_RWLIST_REMOVE_CURRENT(next);
00935 ast_free(backend);
00936 break;
00937 }
00938 }
00939 AST_RWLIST_TRAVERSE_SAFE_END;
00940 AST_RWLIST_UNLOCK(&cc_monitor_backends);
00941 }
00942
00943 struct cc_agent_backend {
00944 AST_LIST_ENTRY(cc_agent_backend) next;
00945 const struct ast_cc_agent_callbacks *callbacks;
00946 };
00947
00948 AST_RWLIST_HEAD_STATIC(cc_agent_backends, cc_agent_backend);
00949
00950 int ast_cc_agent_register(const struct ast_cc_agent_callbacks *callbacks)
00951 {
00952 struct cc_agent_backend *backend = ast_calloc(1, sizeof(*backend));
00953
00954 if (!backend) {
00955 return -1;
00956 }
00957
00958 backend->callbacks = callbacks;
00959 AST_RWLIST_WRLOCK(&cc_agent_backends);
00960 AST_RWLIST_INSERT_TAIL(&cc_agent_backends, backend, next);
00961 AST_RWLIST_UNLOCK(&cc_agent_backends);
00962 return 0;
00963 }
00964
00965 void ast_cc_agent_unregister(const struct ast_cc_agent_callbacks *callbacks)
00966 {
00967 struct cc_agent_backend *backend;
00968 AST_RWLIST_WRLOCK(&cc_agent_backends);
00969 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&cc_agent_backends, backend, next) {
00970 if (backend->callbacks == callbacks) {
00971 AST_RWLIST_REMOVE_CURRENT(next);
00972 ast_free(backend);
00973 break;
00974 }
00975 }
00976 AST_RWLIST_TRAVERSE_SAFE_END;
00977 AST_RWLIST_UNLOCK(&cc_agent_backends);
00978 }
00979
00980 static const struct ast_cc_agent_callbacks *find_agent_callbacks(struct ast_channel *chan)
00981 {
00982 struct cc_agent_backend *backend;
00983 const struct ast_cc_agent_callbacks *callbacks = NULL;
00984 struct ast_cc_config_params *cc_params;
00985 char type[32];
00986
00987 cc_params = ast_channel_get_cc_config_params(chan);
00988 if (!cc_params) {
00989 return NULL;
00990 }
00991 switch (ast_get_cc_agent_policy(cc_params)) {
00992 case AST_CC_AGENT_GENERIC:
00993 ast_copy_string(type, "generic", sizeof(type));
00994 break;
00995 case AST_CC_AGENT_NATIVE:
00996 ast_channel_get_cc_agent_type(chan, type, sizeof(type));
00997 break;
00998 default:
00999 ast_log_dynamic_level(cc_logger_level, "Not returning agent callbacks since this channel is configured not to have a CC agent\n");
01000 return NULL;
01001 }
01002
01003 AST_RWLIST_RDLOCK(&cc_agent_backends);
01004 AST_RWLIST_TRAVERSE(&cc_agent_backends, backend, next) {
01005 if (!strcmp(backend->callbacks->type, type)) {
01006 ast_log_dynamic_level(cc_logger_level, "Returning agent backend %s\n", backend->callbacks->type);
01007 callbacks = backend->callbacks;
01008 break;
01009 }
01010 }
01011 AST_RWLIST_UNLOCK(&cc_agent_backends);
01012 return callbacks;
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024 static int cc_generic_is_device_available(enum ast_device_state state)
01025 {
01026 return state == AST_DEVICE_NOT_INUSE || state == AST_DEVICE_UNKNOWN;
01027 }
01028
01029 static int cc_generic_monitor_request_cc(struct ast_cc_monitor *monitor, int *available_timer_id);
01030 static int cc_generic_monitor_suspend(struct ast_cc_monitor *monitor);
01031 static int cc_generic_monitor_unsuspend(struct ast_cc_monitor *monitor);
01032 static int cc_generic_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id);
01033 static void cc_generic_monitor_destructor(void *private_data);
01034
01035 static struct ast_cc_monitor_callbacks generic_monitor_cbs = {
01036 .type = "generic",
01037 .request_cc = cc_generic_monitor_request_cc,
01038 .suspend = cc_generic_monitor_suspend,
01039 .unsuspend = cc_generic_monitor_unsuspend,
01040 .cancel_available_timer = cc_generic_monitor_cancel_available_timer,
01041 .destructor = cc_generic_monitor_destructor,
01042 };
01043
01044 struct ao2_container *generic_monitors;
01045
01046 struct generic_monitor_instance {
01047 int core_id;
01048 int is_suspended;
01049 int monitoring;
01050 AST_LIST_ENTRY(generic_monitor_instance) next;
01051 };
01052
01053 struct generic_monitor_instance_list {
01054 const char *device_name;
01055 enum ast_device_state current_state;
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 int fit_for_recall;
01072 struct ast_event_sub *sub;
01073 AST_LIST_HEAD_NOLOCK(, generic_monitor_instance) list;
01074 };
01075
01076
01077
01078
01079 struct generic_monitor_pvt {
01080
01081
01082
01083
01084 const char *device_name;
01085
01086
01087
01088
01089
01090
01091 int core_id;
01092 };
01093
01094 static int generic_monitor_hash_fn(const void *obj, const int flags)
01095 {
01096 const struct generic_monitor_instance_list *generic_list = obj;
01097 return ast_str_hash(generic_list->device_name);
01098 }
01099
01100 static int generic_monitor_cmp_fn(void *obj, void *arg, int flags)
01101 {
01102 const struct generic_monitor_instance_list *generic_list1 = obj;
01103 const struct generic_monitor_instance_list *generic_list2 = arg;
01104
01105 return !strcmp(generic_list1->device_name, generic_list2->device_name) ? CMP_MATCH | CMP_STOP : 0;
01106 }
01107
01108 static struct generic_monitor_instance_list *find_generic_monitor_instance_list(const char * const device_name)
01109 {
01110 struct generic_monitor_instance_list finder = {0};
01111 char *uppertech = ast_strdupa(device_name);
01112 ast_tech_to_upper(uppertech);
01113 finder.device_name = uppertech;
01114
01115 return ao2_t_find(generic_monitors, &finder, OBJ_POINTER, "Finding generic monitor instance list");
01116 }
01117
01118 static void generic_monitor_instance_list_destructor(void *obj)
01119 {
01120 struct generic_monitor_instance_list *generic_list = obj;
01121 struct generic_monitor_instance *generic_instance;
01122
01123 generic_list->sub = ast_event_unsubscribe(generic_list->sub);
01124 while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
01125 ast_free(generic_instance);
01126 }
01127 ast_free((char *)generic_list->device_name);
01128 }
01129
01130 static void generic_monitor_devstate_cb(const struct ast_event *event, void *userdata);
01131 static struct generic_monitor_instance_list *create_new_generic_list(struct ast_cc_monitor *monitor)
01132 {
01133 struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
01134 generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
01135 char * device_name;
01136
01137 if (!generic_list) {
01138 return NULL;
01139 }
01140
01141 if (!(device_name = ast_strdup(monitor->interface->device_name))) {
01142 cc_unref(generic_list, "Failed to strdup the monitor's device name");
01143 return NULL;
01144 }
01145 ast_tech_to_upper(device_name);
01146 generic_list->device_name = device_name;
01147
01148 if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
01149 generic_monitor_devstate_cb, "Requesting CC", NULL,
01150 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, monitor->interface->device_name,
01151 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
01152 AST_EVENT_IE_END))) {
01153 cc_unref(generic_list, "Failed to subscribe to device state");
01154 return NULL;
01155 }
01156 generic_list->current_state = ast_device_state(monitor->interface->device_name);
01157 ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
01158 return generic_list;
01159 }
01160
01161 struct generic_tp_cb_data {
01162 const char *device_name;
01163 enum ast_device_state new_state;
01164 };
01165
01166 static int generic_monitor_devstate_tp_cb(void *data)
01167 {
01168 struct generic_tp_cb_data *gtcd = data;
01169 enum ast_device_state new_state = gtcd->new_state;
01170 enum ast_device_state previous_state = gtcd->new_state;
01171 const char *monitor_name = gtcd->device_name;
01172 struct generic_monitor_instance_list *generic_list;
01173 struct generic_monitor_instance *generic_instance;
01174
01175 if (!(generic_list = find_generic_monitor_instance_list(monitor_name))) {
01176
01177
01178
01179
01180 ast_free((char *) gtcd->device_name);
01181 ast_free(gtcd);
01182 return 0;
01183 }
01184
01185 if (generic_list->current_state == new_state) {
01186
01187 cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01188 ast_free((char *) gtcd->device_name);
01189 ast_free(gtcd);
01190 return 0;
01191 }
01192
01193 previous_state = generic_list->current_state;
01194 generic_list->current_state = new_state;
01195
01196 if (cc_generic_is_device_available(new_state) &&
01197 (previous_state == AST_DEVICE_INUSE || previous_state == AST_DEVICE_UNAVAILABLE ||
01198 previous_state == AST_DEVICE_BUSY)) {
01199 AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01200 if (!generic_instance->is_suspended && generic_instance->monitoring) {
01201 generic_instance->monitoring = 0;
01202 generic_list->fit_for_recall = 1;
01203 ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01204 break;
01205 }
01206 }
01207 }
01208 cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
01209 ast_free((char *) gtcd->device_name);
01210 ast_free(gtcd);
01211 return 0;
01212 }
01213
01214 static void generic_monitor_devstate_cb(const struct ast_event *event, void *userdata)
01215 {
01216
01217
01218
01219
01220
01221 struct generic_tp_cb_data *gtcd = ast_calloc(1, sizeof(*gtcd));
01222
01223 if (!gtcd) {
01224 return;
01225 }
01226
01227 if (!(gtcd->device_name = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE)))) {
01228 ast_free(gtcd);
01229 return;
01230 }
01231 gtcd->new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01232
01233 if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, gtcd)) {
01234 ast_free((char *)gtcd->device_name);
01235 ast_free(gtcd);
01236 }
01237 }
01238
01239 int ast_cc_available_timer_expire(const void *data)
01240 {
01241 struct ast_cc_monitor *monitor = (struct ast_cc_monitor *) data;
01242 int res;
01243 monitor->available_timer_id = -1;
01244 res = ast_cc_monitor_failed(monitor->core_id, monitor->interface->device_name, "Available timer expired for monitor");
01245 cc_unref(monitor, "Unref reference from scheduler\n");
01246 return res;
01247 }
01248
01249 static int cc_generic_monitor_request_cc(struct ast_cc_monitor *monitor, int *available_timer_id)
01250 {
01251 struct generic_monitor_instance_list *generic_list;
01252 struct generic_monitor_instance *generic_instance;
01253 struct generic_monitor_pvt *gen_mon_pvt;
01254 enum ast_cc_service_type service = monitor->service_offered;
01255 int when;
01256
01257
01258
01259
01260
01261 if (!(gen_mon_pvt = ast_calloc(1, sizeof(*gen_mon_pvt)))) {
01262 return -1;
01263 }
01264
01265 if (!(gen_mon_pvt->device_name = ast_strdup(monitor->interface->device_name))) {
01266 ast_free(gen_mon_pvt);
01267 return -1;
01268 }
01269
01270 gen_mon_pvt->core_id = monitor->core_id;
01271
01272 monitor->private_data = gen_mon_pvt;
01273
01274 if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01275 if (!(generic_list = create_new_generic_list(monitor))) {
01276 return -1;
01277 }
01278 }
01279
01280 if (!(generic_instance = ast_calloc(1, sizeof(*generic_instance)))) {
01281
01282
01283
01284 cc_unref(generic_list, "Generic monitor instance failed to allocate");
01285 return -1;
01286 }
01287 generic_instance->core_id = monitor->core_id;
01288 generic_instance->monitoring = 1;
01289 AST_LIST_INSERT_TAIL(&generic_list->list, generic_instance, next);
01290 when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
01291 ast_get_ccnr_available_timer(monitor->interface->config_params);
01292
01293 *available_timer_id = ast_sched_thread_add(cc_sched_thread, when * 1000,
01294 ast_cc_available_timer_expire, cc_ref(monitor, "Give the scheduler a monitor reference"));
01295 if (*available_timer_id == -1) {
01296 cc_unref(monitor, "Failed to schedule available timer. (monitor)");
01297 cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
01298 return -1;
01299 }
01300
01301
01302
01303 if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
01304 generic_list->fit_for_recall = 0;
01305 }
01306 ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
01307 monitor->interface->device_name);
01308 cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
01309 return 0;
01310 }
01311
01312 static int cc_generic_monitor_suspend(struct ast_cc_monitor *monitor)
01313 {
01314 struct generic_monitor_instance_list *generic_list;
01315 struct generic_monitor_instance *generic_instance;
01316 enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01317
01318 if (!(generic_list = find_generic_monitor_instance_list(monitor->interface->device_name))) {
01319 return -1;
01320 }
01321
01322
01323 AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01324 if (generic_instance->core_id == monitor->core_id) {
01325 generic_instance->is_suspended = 1;
01326 break;
01327 }
01328 }
01329
01330
01331
01332
01333 if (!cc_generic_is_device_available(state)) {
01334 cc_unref(generic_list, "Device is in use. Nothing to do. Unref generic list.");
01335 return 0;
01336 }
01337
01338
01339
01340
01341
01342
01343 AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01344 if (!generic_instance->is_suspended) {
01345 ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
01346 break;
01347 }
01348 }
01349 cc_unref(generic_list, "Done with generic list in suspend callback");
01350 return 0;
01351 }
01352
01353 static int cc_generic_monitor_unsuspend(struct ast_cc_monitor *monitor)
01354 {
01355 struct generic_monitor_instance *generic_instance;
01356 struct generic_monitor_instance_list *generic_list = find_generic_monitor_instance_list(monitor->interface->device_name);
01357 enum ast_device_state state = ast_device_state(monitor->interface->device_name);
01358
01359 if (!generic_list) {
01360 return -1;
01361 }
01362
01363
01364
01365 if (cc_generic_is_device_available(state)) {
01366 ast_cc_monitor_callee_available(monitor->core_id, "Generic monitored party has become available");
01367 }
01368
01369
01370 AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01371 if (generic_instance->core_id == monitor->core_id) {
01372 generic_instance->is_suspended = 0;
01373 generic_instance->monitoring = 1;
01374 break;
01375 }
01376 }
01377 cc_unref(generic_list, "Done with generic list in cc_generic_monitor_unsuspend");
01378 return 0;
01379 }
01380
01381 static int cc_generic_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id)
01382 {
01383 ast_assert(sched_id != NULL);
01384
01385 if (*sched_id == -1) {
01386 return 0;
01387 }
01388
01389 ast_log_dynamic_level(cc_logger_level, "Core %d: Canceling generic monitor available timer for monitor %s\n",
01390 monitor->core_id, monitor->interface->device_name);
01391 if (!ast_sched_thread_del(cc_sched_thread, *sched_id)) {
01392 cc_unref(monitor, "Remove scheduler's reference to the monitor");
01393 }
01394 *sched_id = -1;
01395 return 0;
01396 }
01397
01398 static void cc_generic_monitor_destructor(void *private_data)
01399 {
01400 struct generic_monitor_pvt *gen_mon_pvt = private_data;
01401 struct generic_monitor_instance_list *generic_list;
01402 struct generic_monitor_instance *generic_instance;
01403
01404 if (!private_data) {
01405
01406
01407
01408
01409
01410 return;
01411 }
01412
01413 ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying generic monitor %s\n",
01414 gen_mon_pvt->core_id, gen_mon_pvt->device_name);
01415
01416 if (!(generic_list = find_generic_monitor_instance_list(gen_mon_pvt->device_name))) {
01417
01418
01419
01420
01421 ast_free((char *)gen_mon_pvt->device_name);
01422 ast_free(gen_mon_pvt);
01423 return;
01424 }
01425
01426 AST_LIST_TRAVERSE_SAFE_BEGIN(&generic_list->list, generic_instance, next) {
01427 if (generic_instance->core_id == gen_mon_pvt->core_id) {
01428 AST_LIST_REMOVE_CURRENT(next);
01429 ast_free(generic_instance);
01430 break;
01431 }
01432 }
01433 AST_LIST_TRAVERSE_SAFE_END;
01434
01435 if (AST_LIST_EMPTY(&generic_list->list)) {
01436
01437
01438
01439 ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
01440 } else {
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451 if (generic_list->fit_for_recall
01452 && cc_generic_is_device_available(generic_list->current_state)) {
01453 AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
01454 if (!generic_instance->is_suspended && generic_instance->monitoring) {
01455 ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
01456 "availability due to other instance's failure.");
01457 break;
01458 }
01459 }
01460 }
01461 }
01462 cc_unref(generic_list, "Done with generic list in generic monitor destructor");
01463 ast_free((char *)gen_mon_pvt->device_name);
01464 ast_free(gen_mon_pvt);
01465 }
01466
01467 static void cc_interface_destroy(void *data)
01468 {
01469 struct ast_cc_interface *interface = data;
01470 ast_log_dynamic_level(cc_logger_level, "Destroying cc interface %s\n", interface->device_name);
01471 ast_cc_config_params_destroy(interface->config_params);
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490 struct extension_child_dialstring {
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506 char original_dialstring[AST_CHANNEL_NAME];
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525 char device_name[AST_CHANNEL_NAME];
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540 int is_valid;
01541 AST_LIST_ENTRY(extension_child_dialstring) next;
01542 };
01543
01544
01545
01546
01547 struct extension_monitor_pvt {
01548 AST_LIST_HEAD_NOLOCK(, extension_child_dialstring) child_dialstrings;
01549 };
01550
01551 static void cc_extension_monitor_destructor(void *private_data)
01552 {
01553 struct extension_monitor_pvt *extension_pvt = private_data;
01554 struct extension_child_dialstring *child_dialstring;
01555
01556
01557 if (!extension_pvt) {
01558 return;
01559 }
01560
01561 while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
01562 ast_free(child_dialstring);
01563 }
01564 ast_free(extension_pvt);
01565 }
01566
01567 static void cc_monitor_destroy(void *data)
01568 {
01569 struct ast_cc_monitor *monitor = data;
01570
01571
01572
01573
01574
01575
01576 ast_log_dynamic_level(cc_logger_level, "Core %d: Calling destructor for monitor %s\n",
01577 monitor->core_id, monitor->interface->device_name);
01578 if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
01579 cc_extension_monitor_destructor(monitor->private_data);
01580 }
01581 if (monitor->callbacks) {
01582 monitor->callbacks->destructor(monitor->private_data);
01583 }
01584 cc_unref(monitor->interface, "Unreffing tree's reference to interface");
01585 ast_free(monitor->dialstring);
01586 }
01587
01588 static void cc_interface_tree_destroy(void *data)
01589 {
01590 struct cc_monitor_tree *cc_interface_tree = data;
01591 struct ast_cc_monitor *monitor;
01592 while ((monitor = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
01593 if (monitor->callbacks) {
01594 monitor->callbacks->cancel_available_timer(monitor, &monitor->available_timer_id);
01595 }
01596 cc_unref(monitor, "Destroying all monitors");
01597 }
01598 AST_LIST_HEAD_DESTROY(cc_interface_tree);
01599 }
01600
01601
01602
01603
01604
01605 static int dialed_cc_interface_counter;
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616 struct dialed_cc_interfaces {
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632 unsigned int dial_parent_id;
01633
01634
01635
01636
01637
01638
01639
01640
01641 int core_id;
01642
01643
01644
01645
01646
01647 char ignore;
01648
01649
01650
01651
01652
01653
01654
01655 char is_original_caller;
01656
01657
01658
01659 struct cc_monitor_tree *interface_tree;
01660 };
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674 static void dialed_cc_interfaces_destroy(void *data)
01675 {
01676 struct dialed_cc_interfaces *cc_interfaces = data;
01677 cc_unref(cc_interfaces->interface_tree, "Unref dial's ref to monitor tree");
01678 ast_free(cc_interfaces);
01679 }
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694 static void *dialed_cc_interfaces_duplicate(void *data)
01695 {
01696 struct dialed_cc_interfaces *old_cc_interfaces = data;
01697 struct dialed_cc_interfaces *new_cc_interfaces = ast_calloc(1, sizeof(*new_cc_interfaces));
01698 if (!new_cc_interfaces) {
01699 return NULL;
01700 }
01701 new_cc_interfaces->ignore = old_cc_interfaces->ignore;
01702 new_cc_interfaces->dial_parent_id = old_cc_interfaces->dial_parent_id;
01703 new_cc_interfaces->is_original_caller = 0;
01704 cc_ref(old_cc_interfaces->interface_tree, "New ref due to duplication of monitor tree");
01705 new_cc_interfaces->core_id = old_cc_interfaces->core_id;
01706 new_cc_interfaces->interface_tree = old_cc_interfaces->interface_tree;
01707 return new_cc_interfaces;
01708 }
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719 static const const struct ast_datastore_info dialed_cc_interfaces_info = {
01720 .type = "Dial CC Interfaces",
01721 .duplicate = dialed_cc_interfaces_duplicate,
01722 .destroy = dialed_cc_interfaces_destroy,
01723 };
01724
01725 static struct extension_monitor_pvt *extension_monitor_pvt_init(void)
01726 {
01727 struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
01728 if (!ext_pvt) {
01729 return NULL;
01730 }
01731 AST_LIST_HEAD_INIT_NOLOCK(&ext_pvt->child_dialstrings);
01732 return ext_pvt;
01733 }
01734
01735 void ast_cc_extension_monitor_add_dialstring(struct ast_channel *incoming, const char * const dialstring, const char * const device_name)
01736 {
01737 struct ast_datastore *cc_datastore;
01738 struct dialed_cc_interfaces *cc_interfaces;
01739 struct ast_cc_monitor *monitor;
01740 struct extension_monitor_pvt *extension_pvt;
01741 struct extension_child_dialstring *child_dialstring;
01742 struct cc_monitor_tree *interface_tree;
01743 int id;
01744
01745 ast_channel_lock(incoming);
01746 if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
01747 ast_channel_unlock(incoming);
01748 return;
01749 }
01750
01751 cc_interfaces = cc_datastore->data;
01752 interface_tree = cc_interfaces->interface_tree;
01753 id = cc_interfaces->dial_parent_id;
01754 ast_channel_unlock(incoming);
01755
01756 AST_LIST_LOCK(interface_tree);
01757 AST_LIST_TRAVERSE(interface_tree, monitor, next) {
01758 if (monitor->id == id) {
01759 break;
01760 }
01761 }
01762
01763 if (!monitor) {
01764 AST_LIST_UNLOCK(interface_tree);
01765 return;
01766 }
01767
01768 extension_pvt = monitor->private_data;
01769 if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
01770 AST_LIST_UNLOCK(interface_tree);
01771 return;
01772 }
01773 ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
01774 ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
01775 child_dialstring->is_valid = 1;
01776 AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
01777 AST_LIST_UNLOCK(interface_tree);
01778 }
01779
01780 static void cc_extension_monitor_change_is_valid(struct cc_core_instance *core_instance, unsigned int parent_id, const char * const device_name, int is_valid)
01781 {
01782 struct ast_cc_monitor *monitor_iter;
01783 struct extension_monitor_pvt *extension_pvt;
01784 struct extension_child_dialstring *child_dialstring;
01785
01786 AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
01787 if (monitor_iter->id == parent_id) {
01788 break;
01789 }
01790 }
01791
01792 if (!monitor_iter) {
01793 return;
01794 }
01795 extension_pvt = monitor_iter->private_data;
01796
01797 AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
01798 if (!strcmp(child_dialstring->device_name, device_name)) {
01799 child_dialstring->is_valid = is_valid;
01800 break;
01801 }
01802 }
01803 }
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819 static struct ast_cc_monitor *cc_extension_monitor_init(const char * const exten, const char * const context, const unsigned int parent_id)
01820 {
01821 struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
01822 struct ast_cc_interface *cc_interface;
01823 struct ast_cc_monitor *monitor;
01824
01825 ast_str_set(&str, 0, "%s@%s", exten, context);
01826
01827 if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + ast_str_strlen(str), cc_interface_destroy,
01828 "Allocating new ast_cc_interface"))) {
01829 return NULL;
01830 }
01831
01832 if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
01833 cc_unref(cc_interface, "failed to allocate the monitor, so unref the interface");
01834 return NULL;
01835 }
01836
01837 if (!(monitor->private_data = extension_monitor_pvt_init())) {
01838 cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
01839 cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
01840 }
01841
01842 monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
01843 monitor->parent_id = parent_id;
01844 cc_interface->monitor_type = "extension";
01845 cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
01846 strcpy(cc_interface->device_name, ast_str_buffer(str));
01847 monitor->interface = cc_interface;
01848 ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %d and parent %d\n", cc_interface->device_name, monitor->id, monitor->parent_id);
01849 return monitor;
01850 }
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868 static int cc_interfaces_datastore_init(struct ast_channel *chan) {
01869 struct dialed_cc_interfaces *interfaces;
01870 struct ast_cc_monitor *monitor;
01871 struct ast_datastore *dial_cc_datastore;
01872
01873
01874
01875
01876
01877
01878
01879
01880 if (!ast_cc_request_is_within_limits()) {
01881 return 0;
01882 }
01883
01884 if (!(interfaces = ast_calloc(1, sizeof(*interfaces)))) {
01885 return -1;
01886 }
01887
01888 if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten), S_OR(chan->macrocontext, chan->context), 0))) {
01889 ast_free(interfaces);
01890 return -1;
01891 }
01892
01893 if (!(dial_cc_datastore = ast_datastore_alloc(&dialed_cc_interfaces_info, NULL))) {
01894 cc_unref(monitor, "Could not allocate the dialed interfaces datastore. Unreffing monitor");
01895 ast_free(interfaces);
01896 return -1;
01897 }
01898
01899 if (!(interfaces->interface_tree = ao2_t_alloc(sizeof(*interfaces->interface_tree), cc_interface_tree_destroy,
01900 "Allocate monitor tree"))) {
01901 ast_datastore_free(dial_cc_datastore);
01902 cc_unref(monitor, "Could not allocate monitor tree on dialed interfaces datastore. Unreffing monitor");
01903 ast_free(interfaces);
01904 return -1;
01905 }
01906
01907
01908 AST_LIST_HEAD_INIT(interfaces->interface_tree);
01909 AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
01910 cc_ref(monitor, "List's reference to extension monitor");
01911 dial_cc_datastore->data = interfaces;
01912 dial_cc_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01913 interfaces->dial_parent_id = monitor->id;
01914 interfaces->core_id = monitor->core_id = ast_atomic_fetchadd_int(&core_id_counter, +1);
01915 interfaces->is_original_caller = 1;
01916 ast_channel_lock(chan);
01917 ast_channel_datastore_add(chan, dial_cc_datastore);
01918 ast_channel_unlock(chan);
01919 cc_unref(monitor, "Unreffing allocation's reference");
01920 return 0;
01921 }
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946 static void call_destructor_with_no_monitor(const char * const monitor_type, void *private_data)
01947 {
01948 const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
01949
01950 if (!monitor_callbacks) {
01951 return;
01952 }
01953
01954 monitor_callbacks->destructor(private_data);
01955 }
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982 static struct ast_cc_monitor *cc_device_monitor_init(const char * const device_name, const char * const dialstring, const struct cc_control_payload *cc_data, int core_id)
01983 {
01984 struct ast_cc_interface *cc_interface;
01985 struct ast_cc_monitor *monitor;
01986 size_t device_name_len = strlen(device_name);
01987 int parent_id = cc_data->parent_interface_id;
01988
01989 if (!(cc_interface = ao2_t_alloc(sizeof(*cc_interface) + device_name_len, cc_interface_destroy,
01990 "Allocating new ast_cc_interface"))) {
01991 return NULL;
01992 }
01993
01994 if (!(cc_interface->config_params = ast_cc_config_params_init())) {
01995 cc_unref(cc_interface, "Failed to allocate config params, unref interface");
01996 return NULL;
01997 }
01998
01999 if (!(monitor = ao2_t_alloc(sizeof(*monitor), cc_monitor_destroy, "Allocating new ast_cc_monitor"))) {
02000 cc_unref(cc_interface, "Failed to allocate monitor, unref interface");
02001 return NULL;
02002 }
02003
02004 if (!(monitor->dialstring = ast_strdup(dialstring))) {
02005 cc_unref(monitor, "Failed to copy dialable name. Unref monitor");
02006 cc_unref(cc_interface, "Failed to copy dialable name");
02007 return NULL;
02008 }
02009
02010 if (!(monitor->callbacks = find_monitor_callbacks(cc_data->monitor_type))) {
02011 cc_unref(monitor, "Failed to find monitor callbacks. Unref monitor");
02012 cc_unref(cc_interface, "Failed to find monitor callbacks");
02013 return NULL;
02014 }
02015
02016 strcpy(cc_interface->device_name, device_name);
02017 monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
02018 monitor->parent_id = parent_id;
02019 monitor->core_id = core_id;
02020 monitor->service_offered = cc_data->service;
02021 monitor->private_data = cc_data->private_data;
02022 cc_interface->monitor_type = cc_data->monitor_type;
02023 cc_interface->monitor_class = AST_CC_DEVICE_MONITOR;
02024 monitor->interface = cc_interface;
02025 monitor->available_timer_id = -1;
02026 ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
02027 ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %d and parent %d\n",
02028 monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
02029 return monitor;
02030 }
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048 void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel *outbound, void *frame_data)
02049 {
02050 char *device_name;
02051 char *dialstring;
02052 struct ast_cc_monitor *monitor;
02053 struct ast_datastore *cc_datastore;
02054 struct dialed_cc_interfaces *cc_interfaces;
02055 struct cc_control_payload *cc_data = frame_data;
02056 struct cc_core_instance *core_instance;
02057
02058 device_name = cc_data->device_name;
02059 dialstring = cc_data->dialstring;
02060
02061 ast_channel_lock(inbound);
02062 if (!(cc_datastore = ast_channel_datastore_find(inbound, &dialed_cc_interfaces_info, NULL))) {
02063 ast_log(LOG_WARNING, "Unable to retrieve CC datastore while processing CC frame from '%s'. CC services will be unavailable.\n", device_name);
02064 ast_channel_unlock(inbound);
02065 call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02066 return;
02067 }
02068
02069 cc_interfaces = cc_datastore->data;
02070
02071 if (cc_interfaces->ignore) {
02072 ast_channel_unlock(inbound);
02073 call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02074 return;
02075 }
02076
02077 if (!cc_interfaces->is_original_caller) {
02078
02079
02080
02081
02082
02083 ast_channel_unlock(inbound);
02084 ast_indicate_data(inbound, AST_CONTROL_CC, cc_data, sizeof(*cc_data));
02085 return;
02086 }
02087
02088 core_instance = find_cc_core_instance(cc_interfaces->core_id);
02089 if (!core_instance) {
02090 core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
02091 cc_interfaces->core_id, cc_data);
02092 if (!core_instance) {
02093 cc_interfaces->ignore = 1;
02094 ast_channel_unlock(inbound);
02095 call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02096 return;
02097 }
02098 }
02099
02100 ast_channel_unlock(inbound);
02101
02102
02103
02104
02105
02106
02107
02108 AST_LIST_LOCK(cc_interfaces->interface_tree);
02109 AST_LIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
02110 if (!strcmp(monitor->interface->device_name, device_name)) {
02111 ast_log_dynamic_level(cc_logger_level, "Core %d: Device %s sent us multiple CC control frames. Ignoring those beyond the first.\n",
02112 core_instance->core_id, device_name);
02113 AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02114 cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02115 call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02116 return;
02117 }
02118 }
02119 AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02120
02121 if (!(monitor = cc_device_monitor_init(device_name, dialstring, cc_data, core_instance->core_id))) {
02122 ast_log(LOG_WARNING, "Unable to create CC device interface for '%s'. CC services will be unavailable on this interface.\n", device_name);
02123 cc_unref(core_instance, "Returning early from ast_handle_cc_control_frame. Unref core_instance");
02124 call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
02125 return;
02126 }
02127
02128 AST_LIST_LOCK(cc_interfaces->interface_tree);
02129 cc_ref(monitor, "monitor tree's reference to the monitor");
02130 AST_LIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
02131 AST_LIST_UNLOCK(cc_interfaces->interface_tree);
02132
02133 cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
02134
02135 manager_event(EVENT_FLAG_CC, "CCAvailable",
02136 "CoreID: %d\r\n"
02137 "Callee: %s\r\n"
02138 "Service: %s\r\n",
02139 cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
02140 );
02141
02142 cc_unref(core_instance, "Done with core_instance after handling CC control frame");
02143 cc_unref(monitor, "Unref reference from allocating monitor");
02144 }
02145
02146 int ast_cc_call_init(struct ast_channel *chan, int *ignore_cc)
02147 {
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168 struct ast_datastore *cc_interfaces_datastore;
02169 struct dialed_cc_interfaces *interfaces;
02170 struct ast_cc_monitor *monitor;
02171 struct ast_cc_config_params *cc_params;
02172
02173 ast_channel_lock(chan);
02174
02175 cc_params = ast_channel_get_cc_config_params(chan);
02176 if (!cc_params) {
02177 ast_channel_unlock(chan);
02178 return -1;
02179 }
02180 if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_NEVER) {
02181
02182
02183 *ignore_cc = 1;
02184 ast_channel_unlock(chan);
02185 ast_log_dynamic_level(cc_logger_level, "Agent policy for %s is 'never'. CC not possible\n", chan->name);
02186 return 0;
02187 }
02188
02189 if (!(cc_interfaces_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02190
02191 ast_channel_unlock(chan);
02192 return cc_interfaces_datastore_init(chan);
02193 }
02194 interfaces = cc_interfaces_datastore->data;
02195 ast_channel_unlock(chan);
02196
02197 if (interfaces->ignore) {
02198
02199 *ignore_cc = 1;
02200 ast_log_dynamic_level(cc_logger_level, "Datastore is present with ignore flag set. Ignoring CC offers on this call\n");
02201 return 0;
02202 }
02203
02204
02205 if (!(monitor = cc_extension_monitor_init(S_OR(chan->macroexten, chan->exten),
02206 S_OR(chan->macrocontext, chan->context), interfaces->dial_parent_id))) {
02207 return -1;
02208 }
02209 monitor->core_id = interfaces->core_id;
02210 AST_LIST_LOCK(interfaces->interface_tree);
02211 cc_ref(monitor, "monitor tree's reference to the monitor");
02212 AST_LIST_INSERT_TAIL(interfaces->interface_tree, monitor, next);
02213 AST_LIST_UNLOCK(interfaces->interface_tree);
02214 interfaces->dial_parent_id = monitor->id;
02215 cc_unref(monitor, "Unref monitor's allocation reference");
02216 return 0;
02217 }
02218
02219 int ast_cc_request_is_within_limits(void)
02220 {
02221 return cc_request_count < global_cc_max_requests;
02222 }
02223
02224 int ast_cc_get_current_core_id(struct ast_channel *chan)
02225 {
02226 struct ast_datastore *datastore;
02227 struct dialed_cc_interfaces *cc_interfaces;
02228 int core_id_return;
02229
02230 ast_channel_lock(chan);
02231 if (!(datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
02232 ast_channel_unlock(chan);
02233 return -1;
02234 }
02235
02236 cc_interfaces = datastore->data;
02237 core_id_return = cc_interfaces->ignore ? -1 : cc_interfaces->core_id;
02238 ast_channel_unlock(chan);
02239 return core_id_return;
02240
02241 }
02242
02243 static long count_agents(const char * const caller, const int core_id_exception)
02244 {
02245 struct count_agents_cb_data data = {.core_id_exception = core_id_exception,};
02246
02247 ao2_t_callback_data(cc_core_instances, OBJ_NODATA, count_agents_cb, (char *)caller, &data, "Counting agents");
02248 ast_log_dynamic_level(cc_logger_level, "Counted %d agents\n", data.count);
02249 return data.count;
02250 }
02251
02252 static void kill_duplicate_offers(char *caller)
02253 {
02254 unsigned long match_flags = MATCH_NO_REQUEST;
02255 struct ao2_iterator *dups_iter;
02256
02257
02258
02259
02260
02261 dups_iter = ao2_t_callback_data(cc_core_instances, OBJ_MULTIPLE | OBJ_UNLINK,
02262 match_agent, caller, &match_flags, "Killing duplicate offers");
02263 if (dups_iter) {
02264
02265 ao2_iterator_destroy(dups_iter);
02266 }
02267 }
02268
02269 static void check_callback_sanity(const struct ast_cc_agent_callbacks *callbacks)
02270 {
02271 ast_assert(callbacks->init != NULL);
02272 ast_assert(callbacks->start_offer_timer != NULL);
02273 ast_assert(callbacks->stop_offer_timer != NULL);
02274 ast_assert(callbacks->respond != NULL);
02275 ast_assert(callbacks->status_request != NULL);
02276 ast_assert(callbacks->start_monitoring != NULL);
02277 ast_assert(callbacks->callee_available != NULL);
02278 ast_assert(callbacks->destructor != NULL);
02279 }
02280
02281 static void agent_destroy(void *data)
02282 {
02283 struct ast_cc_agent *agent = data;
02284
02285 if (agent->callbacks) {
02286 agent->callbacks->destructor(agent);
02287 }
02288 ast_cc_config_params_destroy(agent->cc_params);
02289 }
02290
02291 static struct ast_cc_agent *cc_agent_init(struct ast_channel *caller_chan,
02292 const char * const caller_name, const int core_id,
02293 struct cc_monitor_tree *interface_tree)
02294 {
02295 struct ast_cc_agent *agent;
02296 struct ast_cc_config_params *cc_params;
02297
02298 if (!(agent = ao2_t_alloc(sizeof(*agent) + strlen(caller_name), agent_destroy,
02299 "Allocating new ast_cc_agent"))) {
02300 return NULL;
02301 }
02302
02303 agent->core_id = core_id;
02304 strcpy(agent->device_name, caller_name);
02305
02306 cc_params = ast_channel_get_cc_config_params(caller_chan);
02307 if (!cc_params) {
02308 cc_unref(agent, "Could not get channel config params.");
02309 return NULL;
02310 }
02311 if (!(agent->cc_params = ast_cc_config_params_init())) {
02312 cc_unref(agent, "Could not init agent config params.");
02313 return NULL;
02314 }
02315 ast_cc_copy_config_params(agent->cc_params, cc_params);
02316
02317 if (!(agent->callbacks = find_agent_callbacks(caller_chan))) {
02318 cc_unref(agent, "Could not find agent callbacks.");
02319 return NULL;
02320 }
02321 check_callback_sanity(agent->callbacks);
02322
02323 if (agent->callbacks->init(agent, caller_chan)) {
02324 cc_unref(agent, "Agent init callback failed.");
02325 return NULL;
02326 }
02327 ast_log_dynamic_level(cc_logger_level, "Core %d: Created an agent for caller %s\n",
02328 agent->core_id, agent->device_name);
02329 return agent;
02330 }
02331
02332
02333 static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
02334 static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent);
02335 static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent);
02336 static void cc_generic_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason);
02337 static int cc_generic_agent_status_request(struct ast_cc_agent *agent);
02338 static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent);
02339 static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent);
02340 static int cc_generic_agent_recall(struct ast_cc_agent *agent);
02341 static void cc_generic_agent_destructor(struct ast_cc_agent *agent);
02342
02343 static struct ast_cc_agent_callbacks generic_agent_callbacks = {
02344 .type = "generic",
02345 .init = cc_generic_agent_init,
02346 .start_offer_timer = cc_generic_agent_start_offer_timer,
02347 .stop_offer_timer = cc_generic_agent_stop_offer_timer,
02348 .respond = cc_generic_agent_respond,
02349 .status_request = cc_generic_agent_status_request,
02350 .stop_ringing = cc_generic_agent_stop_ringing,
02351 .start_monitoring = cc_generic_agent_start_monitoring,
02352 .callee_available = cc_generic_agent_recall,
02353 .destructor = cc_generic_agent_destructor,
02354 };
02355
02356 struct cc_generic_agent_pvt {
02357
02358
02359
02360
02361
02362
02363
02364
02365 struct ast_event_sub *sub;
02366
02367
02368
02369 int offer_timer_id;
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379 char cid_num[AST_CHANNEL_NAME];
02380
02381
02382
02383
02384
02385
02386
02387 char cid_name[AST_CHANNEL_NAME];
02388
02389
02390
02391
02392
02393
02394
02395 char exten[AST_CHANNEL_NAME];
02396
02397
02398
02399
02400
02401
02402
02403 char context[AST_CHANNEL_NAME];
02404 };
02405
02406 static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
02407 {
02408 struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
02409
02410 if (!generic_pvt) {
02411 return -1;
02412 }
02413
02414 generic_pvt->offer_timer_id = -1;
02415 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
02416 ast_copy_string(generic_pvt->cid_num, chan->caller.id.number.str, sizeof(generic_pvt->cid_num));
02417 }
02418 if (chan->caller.id.name.valid && chan->caller.id.name.str) {
02419 ast_copy_string(generic_pvt->cid_name, chan->caller.id.name.str, sizeof(generic_pvt->cid_name));
02420 }
02421 ast_copy_string(generic_pvt->exten, S_OR(chan->macroexten, chan->exten), sizeof(generic_pvt->exten));
02422 ast_copy_string(generic_pvt->context, S_OR(chan->macrocontext, chan->context), sizeof(generic_pvt->context));
02423 agent->private_data = generic_pvt;
02424 ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
02425 return 0;
02426 }
02427
02428 static int offer_timer_expire(const void *data)
02429 {
02430 struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
02431 struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02432 ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
02433 agent->core_id);
02434 agent_pvt->offer_timer_id = -1;
02435 ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
02436 cc_unref(agent, "Remove scheduler's reference to the agent");
02437 return 0;
02438 }
02439
02440 static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent)
02441 {
02442 int when;
02443 int sched_id;
02444 struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02445
02446 ast_assert(cc_sched_thread != NULL);
02447 ast_assert(agent->cc_params != NULL);
02448
02449 when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
02450 ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
02451 agent->core_id, when);
02452 if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
02453 return -1;
02454 }
02455 generic_pvt->offer_timer_id = sched_id;
02456 return 0;
02457 }
02458
02459 static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent)
02460 {
02461 struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02462
02463 if (generic_pvt->offer_timer_id != -1) {
02464 if (!ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id)) {
02465 cc_unref(agent, "Remove scheduler's reference to the agent");
02466 }
02467 generic_pvt->offer_timer_id = -1;
02468 }
02469 return 0;
02470 }
02471
02472 static void cc_generic_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
02473 {
02474
02475
02476
02477 return;
02478 }
02479
02480 static int cc_generic_agent_status_request(struct ast_cc_agent *agent)
02481 {
02482 ast_cc_agent_status_response(agent->core_id, ast_device_state(agent->device_name));
02483 return 0;
02484 }
02485
02486 static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent)
02487 {
02488 struct ast_channel *recall_chan = ast_channel_get_by_name_prefix(agent->device_name, strlen(agent->device_name));
02489
02490 if (!recall_chan) {
02491 return 0;
02492 }
02493
02494 ast_softhangup(recall_chan, AST_SOFTHANGUP_EXPLICIT);
02495 return 0;
02496 }
02497
02498 static int generic_agent_devstate_unsubscribe(void *data)
02499 {
02500 struct ast_cc_agent *agent = data;
02501 struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02502
02503 if (generic_pvt->sub != NULL) {
02504 generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
02505 }
02506 cc_unref(agent, "Done unsubscribing from devstate");
02507 return 0;
02508 }
02509
02510 static void generic_agent_devstate_cb(const struct ast_event *event, void *userdata)
02511 {
02512 struct ast_cc_agent *agent = userdata;
02513 enum ast_device_state new_state;
02514
02515 new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
02516 if (!cc_generic_is_device_available(new_state)) {
02517
02518 return;
02519 }
02520
02521
02522 if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
02523 cc_ref(agent, "ref agent for device state unsubscription"))) {
02524 cc_unref(agent, "Unref agent unsubscribing from devstate failed");
02525 }
02526 ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
02527 }
02528
02529 static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
02530 {
02531 struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02532 struct ast_str *str = ast_str_alloca(128);
02533
02534 ast_assert(generic_pvt->sub == NULL);
02535 ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
02536 agent->device_name);
02537
02538 if (!(generic_pvt->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
02539 generic_agent_devstate_cb, ast_str_buffer(str), agent,
02540 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->device_name,
02541 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
02542 AST_EVENT_IE_END))) {
02543 return -1;
02544 }
02545 return 0;
02546 }
02547
02548 static void *generic_recall(void *data)
02549 {
02550 struct ast_cc_agent *agent = data;
02551 struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
02552 const char *interface = S_OR(ast_get_cc_agent_dialstring(agent->cc_params), ast_strdupa(agent->device_name));
02553 const char *tech;
02554 char *target;
02555 int reason;
02556 struct ast_channel *chan;
02557 const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
02558 unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
02559
02560 tech = interface;
02561 if ((target = strchr(interface, '/'))) {
02562 *target++ = '\0';
02563 }
02564 if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
02565
02566
02567 ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
02568 agent->core_id, agent->device_name, reason);
02569 ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
02570 return NULL;
02571 }
02572
02573
02574
02575
02576
02577
02578 ast_setup_cc_recall_datastore(chan, agent->core_id);
02579 ast_cc_agent_set_interfaces_chanvar(chan);
02580
02581 ast_copy_string(chan->exten, generic_pvt->exten, sizeof(chan->exten));
02582 ast_copy_string(chan->context, generic_pvt->context, sizeof(chan->context));
02583 chan->priority = 1;
02584
02585 pbx_builtin_setvar_helper(chan, "CC_EXTEN", generic_pvt->exten);
02586 pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);
02587
02588 if (!ast_strlen_zero(callback_macro)) {
02589 ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
02590 agent->core_id, agent->device_name);
02591 if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
02592 ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
02593 ast_hangup(chan);
02594 return NULL;
02595 }
02596 }
02597 if (ast_pbx_start(chan)) {
02598 ast_cc_failed(agent->core_id, "PBX failed to start for %s.", agent->device_name);
02599 ast_hangup(chan);
02600 return NULL;
02601 }
02602 ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling",
02603 agent->device_name);
02604 return NULL;
02605 }
02606
02607 static int cc_generic_agent_recall(struct ast_cc_agent *agent)
02608 {
02609 pthread_t clotho;
02610 enum ast_device_state current_state = ast_device_state(agent->device_name);
02611
02612 if (!cc_generic_is_device_available(current_state)) {
02613
02614
02615
02616 ast_cc_agent_caller_busy(agent->core_id, "Generic agent caller %s is busy", agent->device_name);
02617 return 0;
02618 }
02619 ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
02620 return 0;
02621 }
02622
02623 static void cc_generic_agent_destructor(struct ast_cc_agent *agent)
02624 {
02625 struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
02626
02627 if (!agent_pvt) {
02628
02629 return;
02630 }
02631
02632 cc_generic_agent_stop_offer_timer(agent);
02633 if (agent_pvt->sub) {
02634 agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
02635 }
02636
02637 ast_free(agent_pvt);
02638 }
02639
02640 static void cc_core_instance_destructor(void *data)
02641 {
02642 struct cc_core_instance *core_instance = data;
02643 ast_log_dynamic_level(cc_logger_level, "Core %d: Destroying core instance\n", core_instance->core_id);
02644 if (core_instance->agent) {
02645 cc_unref(core_instance->agent, "Core instance is done with the agent now");
02646 }
02647 if (core_instance->monitors) {
02648 core_instance->monitors = cc_unref(core_instance->monitors, "Core instance is done with interface list");
02649 }
02650 }
02651
02652 static struct cc_core_instance *cc_core_init_instance(struct ast_channel *caller_chan,
02653 struct cc_monitor_tree *called_tree, const int core_id, struct cc_control_payload *cc_data)
02654 {
02655 char caller[AST_CHANNEL_NAME];
02656 struct cc_core_instance *core_instance;
02657 struct ast_cc_config_params *cc_params;
02658 long agent_count;
02659 int recall_core_id;
02660
02661 ast_channel_get_device_name(caller_chan, caller, sizeof(caller));
02662 cc_params = ast_channel_get_cc_config_params(caller_chan);
02663 if (!cc_params) {
02664 ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
02665 caller);
02666 return NULL;
02667 }
02668
02669
02670
02671 if (ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02672 kill_duplicate_offers(caller);
02673 }
02674
02675 ast_cc_is_recall(caller_chan, &recall_core_id, NULL);
02676 agent_count = count_agents(caller, recall_core_id);
02677 if (agent_count >= ast_get_cc_max_agents(cc_params)) {
02678 ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
02679 return NULL;
02680 }
02681
02682
02683 if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
02684 ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
02685 return NULL;
02686 }
02687
02688
02689 if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
02690 return NULL;
02691 }
02692
02693 core_instance->core_id = core_id;
02694 if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
02695 cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
02696 return NULL;
02697 }
02698
02699 core_instance->monitors = cc_ref(called_tree, "Core instance getting ref to monitor tree");
02700
02701 ao2_t_link(cc_core_instances, core_instance, "Link core instance into container");
02702
02703 return core_instance;
02704 }
02705
02706 struct cc_state_change_args {
02707 struct cc_core_instance *core_instance;
02708 enum cc_state state;
02709 int core_id;
02710 char debug[1];
02711 };
02712
02713 static int is_state_change_valid(enum cc_state current_state, const enum cc_state new_state, struct ast_cc_agent *agent)
02714 {
02715 int is_valid = 0;
02716 switch (new_state) {
02717 case CC_AVAILABLE:
02718 ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
02719 agent->core_id, new_state);
02720 break;
02721 case CC_CALLER_OFFERED:
02722 if (current_state == CC_AVAILABLE) {
02723 is_valid = 1;
02724 }
02725 break;
02726 case CC_CALLER_REQUESTED:
02727 if (current_state == CC_CALLER_OFFERED ||
02728 (current_state == CC_AVAILABLE && ast_test_flag(agent, AST_CC_AGENT_SKIP_OFFER))) {
02729 is_valid = 1;
02730 }
02731 break;
02732 case CC_ACTIVE:
02733 if (current_state == CC_CALLER_REQUESTED || current_state == CC_CALLER_BUSY) {
02734 is_valid = 1;
02735 }
02736 break;
02737 case CC_CALLEE_READY:
02738 if (current_state == CC_ACTIVE) {
02739 is_valid = 1;
02740 }
02741 break;
02742 case CC_CALLER_BUSY:
02743 if (current_state == CC_CALLEE_READY) {
02744 is_valid = 1;
02745 }
02746 break;
02747 case CC_RECALLING:
02748 if (current_state == CC_CALLEE_READY) {
02749 is_valid = 1;
02750 }
02751 break;
02752 case CC_COMPLETE:
02753 if (current_state == CC_RECALLING) {
02754 is_valid = 1;
02755 }
02756 break;
02757 case CC_FAILED:
02758 is_valid = 1;
02759 break;
02760 default:
02761 ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
02762 agent->core_id, new_state);
02763 break;
02764 }
02765
02766 return is_valid;
02767 }
02768
02769 static int cc_available(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02770 {
02771
02772 ast_log(LOG_WARNING, "Someone requested to change to CC_AVAILABLE? Ignoring.\n");
02773 return -1;
02774 }
02775
02776 static int cc_caller_offered(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02777 {
02778 if (core_instance->agent->callbacks->start_offer_timer(core_instance->agent)) {
02779 ast_cc_failed(core_instance->core_id, "Failed to start the offer timer for %s\n",
02780 core_instance->agent->device_name);
02781 return -1;
02782 }
02783 manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
02784 "CoreID: %d\r\n"
02785 "Caller: %s\r\n"
02786 "Expires: %u\r\n",
02787 core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
02788 ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
02789 core_instance->core_id, core_instance->agent->device_name);
02790 return 0;
02791 }
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809 static int has_device_monitors(struct cc_core_instance *core_instance)
02810 {
02811 struct ast_cc_monitor *iter;
02812 int res = 0;
02813
02814 AST_LIST_TRAVERSE(core_instance->monitors, iter, next) {
02815 if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02816 res = 1;
02817 break;
02818 }
02819 }
02820
02821 return res;
02822 }
02823
02824 static void request_cc(struct cc_core_instance *core_instance)
02825 {
02826 struct ast_cc_monitor *monitor_iter;
02827 AST_LIST_LOCK(core_instance->monitors);
02828 AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02829 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02830 if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
02831 AST_LIST_REMOVE_CURRENT(next);
02832 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02833 monitor_iter->interface->device_name, 1);
02834 cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
02835 } else {
02836 manager_event(EVENT_FLAG_CC, "CCRequested",
02837 "CoreID: %d\r\n"
02838 "Caller: %s\r\n"
02839 "Callee: %s\r\n",
02840 core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
02841 }
02842 }
02843 }
02844 AST_LIST_TRAVERSE_SAFE_END;
02845
02846 if (!has_device_monitors(core_instance)) {
02847 ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
02848 }
02849 AST_LIST_UNLOCK(core_instance->monitors);
02850 }
02851
02852 static int cc_caller_requested(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02853 {
02854 if (!ast_cc_request_is_within_limits()) {
02855 ast_log(LOG_WARNING, "Cannot request CC since there is no more room for requests\n");
02856 core_instance->agent->callbacks->respond(core_instance->agent,
02857 AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY);
02858 ast_cc_failed(core_instance->core_id, "Too many requests in the system");
02859 return -1;
02860 }
02861 core_instance->agent->callbacks->stop_offer_timer(core_instance->agent);
02862 request_cc(core_instance);
02863 return 0;
02864 }
02865
02866 static void unsuspend(struct cc_core_instance *core_instance)
02867 {
02868 struct ast_cc_monitor *monitor_iter;
02869 AST_LIST_LOCK(core_instance->monitors);
02870 AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02871 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02872 if (monitor_iter->callbacks->unsuspend(monitor_iter)) {
02873 AST_LIST_REMOVE_CURRENT(next);
02874 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02875 monitor_iter->interface->device_name, 1);
02876 cc_unref(monitor_iter, "unsuspend failed. Unref list's reference to monitor");
02877 }
02878 }
02879 }
02880 AST_LIST_TRAVERSE_SAFE_END;
02881
02882 if (!has_device_monitors(core_instance)) {
02883 ast_cc_failed(core_instance->core_id, "All device monitors failed to unsuspend CC");
02884 }
02885 AST_LIST_UNLOCK(core_instance->monitors);
02886 }
02887
02888 static int cc_active(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02889 {
02890
02891
02892
02893
02894
02895 if (previous_state == CC_CALLER_REQUESTED) {
02896 core_instance->agent->callbacks->respond(core_instance->agent,
02897 AST_CC_AGENT_RESPONSE_SUCCESS);
02898 manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
02899 "CoreID: %d\r\n"
02900 "Caller: %s\r\n",
02901 core_instance->core_id, core_instance->agent->device_name);
02902 } else if (previous_state == CC_CALLER_BUSY) {
02903 manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
02904 "CoreID: %d\r\n"
02905 "Caller: %s\r\n",
02906 core_instance->core_id, core_instance->agent->device_name);
02907 unsuspend(core_instance);
02908 }
02909
02910 return 0;
02911 }
02912
02913 static int cc_callee_ready(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02914 {
02915 core_instance->agent->callbacks->callee_available(core_instance->agent);
02916 return 0;
02917 }
02918
02919 static void suspend(struct cc_core_instance *core_instance)
02920 {
02921 struct ast_cc_monitor *monitor_iter;
02922 AST_LIST_LOCK(core_instance->monitors);
02923 AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02924 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02925 if (monitor_iter->callbacks->suspend(monitor_iter)) {
02926 AST_LIST_REMOVE_CURRENT(next);
02927 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02928 monitor_iter->interface->device_name, 1);
02929 cc_unref(monitor_iter, "suspend failed. Unref list's reference to monitor");
02930 }
02931 }
02932 }
02933 AST_LIST_TRAVERSE_SAFE_END;
02934
02935 if (!has_device_monitors(core_instance)) {
02936 ast_cc_failed(core_instance->core_id, "All device monitors failed to suspend CC");
02937 }
02938 AST_LIST_UNLOCK(core_instance->monitors);
02939 }
02940
02941 static int cc_caller_busy(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02942 {
02943
02944
02945
02946 suspend(core_instance);
02947 core_instance->agent->callbacks->start_monitoring(core_instance->agent);
02948 manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
02949 "CoreID: %d\r\n"
02950 "Caller: %s\r\n",
02951 core_instance->core_id, core_instance->agent->device_name);
02952 return 0;
02953 }
02954
02955 static void cancel_available_timer(struct cc_core_instance *core_instance)
02956 {
02957 struct ast_cc_monitor *monitor_iter;
02958 AST_LIST_LOCK(core_instance->monitors);
02959 AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
02960 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
02961 if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
02962 AST_LIST_REMOVE_CURRENT(next);
02963 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
02964 monitor_iter->interface->device_name, 1);
02965 cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
02966 }
02967 }
02968 }
02969 AST_LIST_TRAVERSE_SAFE_END;
02970
02971 if (!has_device_monitors(core_instance)) {
02972 ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
02973 }
02974 AST_LIST_UNLOCK(core_instance->monitors);
02975 }
02976
02977 static int cc_recalling(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02978 {
02979
02980
02981 cancel_available_timer(core_instance);
02982 manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
02983 "CoreID: %d\r\n"
02984 "Caller: %s\r\n",
02985 core_instance->core_id, core_instance->agent->device_name);
02986 return 0;
02987 }
02988
02989 static int cc_complete(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
02990 {
02991
02992
02993 manager_event(EVENT_FLAG_CC, "CCRecallComplete",
02994 "CoreID: %d\r\n"
02995 "Caller: %s\r\n",
02996 core_instance->core_id, core_instance->agent->device_name);
02997 ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
02998 return 0;
02999 }
03000
03001 static int cc_failed(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
03002 {
03003 manager_event(EVENT_FLAG_CC, "CCFailure",
03004 "CoreID: %d\r\n"
03005 "Caller: %s\r\n"
03006 "Reason: %s\r\n",
03007 core_instance->core_id, core_instance->agent->device_name, args->debug);
03008 ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
03009 return 0;
03010 }
03011
03012 static int (* const state_change_funcs [])(struct cc_core_instance *, struct cc_state_change_args *, enum cc_state previous_state) = {
03013 [CC_AVAILABLE] = cc_available,
03014 [CC_CALLER_OFFERED] = cc_caller_offered,
03015 [CC_CALLER_REQUESTED] = cc_caller_requested,
03016 [CC_ACTIVE] = cc_active,
03017 [CC_CALLEE_READY] = cc_callee_ready,
03018 [CC_CALLER_BUSY] = cc_caller_busy,
03019 [CC_RECALLING] = cc_recalling,
03020 [CC_COMPLETE] = cc_complete,
03021 [CC_FAILED] = cc_failed,
03022 };
03023
03024 static int cc_do_state_change(void *datap)
03025 {
03026 struct cc_state_change_args *args = datap;
03027 struct cc_core_instance *core_instance;
03028 enum cc_state previous_state;
03029 int res;
03030
03031 ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
03032 args->core_id, args->state, args->debug);
03033
03034 core_instance = args->core_instance;
03035
03036 if (!is_state_change_valid(core_instance->current_state, args->state, core_instance->agent)) {
03037 ast_log_dynamic_level(cc_logger_level, "Core %d: Invalid state change requested. Cannot go from %s to %s\n",
03038 args->core_id, cc_state_to_string(core_instance->current_state), cc_state_to_string(args->state));
03039 if (args->state == CC_CALLER_REQUESTED) {
03040
03041
03042
03043
03044 core_instance->agent->callbacks->respond(core_instance->agent,
03045 AST_CC_AGENT_RESPONSE_FAILURE_INVALID);
03046 }
03047 ast_free(args);
03048 cc_unref(core_instance, "Unref core instance from when it was found earlier");
03049 return -1;
03050 }
03051
03052
03053 previous_state = core_instance->current_state;
03054 core_instance->current_state = args->state;
03055 res = state_change_funcs[core_instance->current_state](core_instance, args, previous_state);
03056
03057 ast_free(args);
03058 cc_unref(core_instance, "Unref since state change has completed");
03059 return res;
03060 }
03061
03062 static int cc_request_state_change(enum cc_state state, const int core_id, const char *debug, va_list ap)
03063 {
03064 int res;
03065 int debuglen;
03066 char dummy[1];
03067 va_list aq;
03068 struct cc_core_instance *core_instance;
03069 struct cc_state_change_args *args;
03070
03071
03072
03073 va_copy(aq, ap);
03074
03075
03076
03077 debuglen = vsnprintf(dummy, sizeof(dummy), debug, aq) + 1;
03078 va_end(aq);
03079
03080 if (!(args = ast_calloc(1, sizeof(*args) + debuglen))) {
03081 return -1;
03082 }
03083
03084 core_instance = find_cc_core_instance(core_id);
03085 if (!core_instance) {
03086 ast_log_dynamic_level(cc_logger_level, "Core %d: Unable to find core instance.\n",
03087 core_id);
03088 ast_free(args);
03089 return -1;
03090 }
03091
03092 args->core_instance = core_instance;
03093 args->state = state;
03094 args->core_id = core_id;
03095 vsnprintf(args->debug, debuglen, debug, ap);
03096
03097 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_do_state_change, args);
03098 if (res) {
03099 cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03100 ast_free(args);
03101 }
03102 return res;
03103 }
03104
03105 struct cc_recall_ds_data {
03106 int core_id;
03107 char ignore;
03108 char nested;
03109 struct cc_monitor_tree *interface_tree;
03110 };
03111
03112 static void *cc_recall_ds_duplicate(void *data)
03113 {
03114 struct cc_recall_ds_data *old_data = data;
03115 struct cc_recall_ds_data *new_data = ast_calloc(1, sizeof(*new_data));
03116
03117 if (!new_data) {
03118 return NULL;
03119 }
03120 new_data->interface_tree = cc_ref(old_data->interface_tree, "Bump refcount of monitor tree for recall datastore duplicate");
03121 new_data->core_id = old_data->core_id;
03122 new_data->nested = 1;
03123 return new_data;
03124 }
03125
03126 static void cc_recall_ds_destroy(void *data)
03127 {
03128 struct cc_recall_ds_data *recall_data = data;
03129 recall_data->interface_tree = cc_unref(recall_data->interface_tree, "Unref recall monitor tree");
03130 ast_free(recall_data);
03131 }
03132
03133 static const struct ast_datastore_info recall_ds_info = {
03134 .type = "cc_recall",
03135 .duplicate = cc_recall_ds_duplicate,
03136 .destroy = cc_recall_ds_destroy,
03137 };
03138
03139 int ast_setup_cc_recall_datastore(struct ast_channel *chan, const int core_id)
03140 {
03141 struct ast_datastore *recall_datastore = ast_datastore_alloc(&recall_ds_info, NULL);
03142 struct cc_recall_ds_data *recall_data;
03143 struct cc_core_instance *core_instance;
03144
03145 if (!recall_datastore) {
03146 return -1;
03147 }
03148
03149 if (!(recall_data = ast_calloc(1, sizeof(*recall_data)))) {
03150 ast_datastore_free(recall_datastore);
03151 return -1;
03152 }
03153
03154 if (!(core_instance = find_cc_core_instance(core_id))) {
03155 ast_free(recall_data);
03156 ast_datastore_free(recall_datastore);
03157 return -1;
03158 }
03159
03160 recall_data->interface_tree = cc_ref(core_instance->monitors,
03161 "Bump refcount for monitor tree for recall datastore");
03162 recall_data->core_id = core_id;
03163 recall_datastore->data = recall_data;
03164 recall_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
03165 ast_channel_lock(chan);
03166 ast_channel_datastore_add(chan, recall_datastore);
03167 ast_channel_unlock(chan);
03168 cc_unref(core_instance, "Recall datastore set up. No need for core_instance ref");
03169 return 0;
03170 }
03171
03172 int ast_cc_is_recall(struct ast_channel *chan, int *core_id, const char * const monitor_type)
03173 {
03174 struct ast_datastore *recall_datastore;
03175 struct cc_recall_ds_data *recall_data;
03176 struct cc_monitor_tree *interface_tree;
03177 char device_name[AST_CHANNEL_NAME];
03178 struct ast_cc_monitor *device_monitor;
03179 int core_id_candidate;
03180
03181 ast_assert(core_id != NULL);
03182
03183 *core_id = -1;
03184
03185 ast_channel_lock(chan);
03186 if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03187
03188 ast_channel_unlock(chan);
03189 return 0;
03190 }
03191
03192 recall_data = recall_datastore->data;
03193
03194 if (recall_data->ignore) {
03195
03196
03197
03198
03199 ast_channel_unlock(chan);
03200 return 0;
03201 }
03202
03203 if (!recall_data->nested) {
03204
03205
03206
03207
03208
03209
03210 *core_id = recall_data->core_id;
03211 ast_channel_unlock(chan);
03212 return 1;
03213 }
03214
03215 if (ast_strlen_zero(monitor_type)) {
03216
03217
03218
03219
03220
03221 ast_channel_unlock(chan);
03222 return 0;
03223 }
03224
03225 interface_tree = recall_data->interface_tree;
03226 ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03227
03228
03229
03230
03231
03232 core_id_candidate = recall_data->core_id;
03233 ast_channel_unlock(chan);
03234
03235
03236
03237
03238
03239 AST_LIST_LOCK(interface_tree);
03240 AST_LIST_TRAVERSE(interface_tree, device_monitor, next) {
03241 if (!strcmp(device_monitor->interface->device_name, device_name) &&
03242 !strcmp(device_monitor->interface->monitor_type, monitor_type)) {
03243
03244 *core_id = core_id_candidate;
03245 AST_LIST_UNLOCK(interface_tree);
03246 return 1;
03247 }
03248 }
03249 AST_LIST_UNLOCK(interface_tree);
03250 return 0;
03251 }
03252
03253 struct ast_cc_monitor *ast_cc_get_monitor_by_recall_core_id(const int core_id, const char * const device_name)
03254 {
03255 struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03256 struct ast_cc_monitor *monitor_iter;
03257
03258 if (!core_instance) {
03259 return NULL;
03260 }
03261
03262 AST_LIST_LOCK(core_instance->monitors);
03263 AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03264 if (!strcmp(monitor_iter->interface->device_name, device_name)) {
03265
03266 cc_ref(monitor_iter, "Hand the requester of the monitor a reference");
03267 break;
03268 }
03269 }
03270 AST_LIST_UNLOCK(core_instance->monitors);
03271 cc_unref(core_instance, "Done with core instance ref in ast_cc_get_monitor_by_recall_core_id");
03272 return monitor_iter;
03273 }
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292 static void cc_unique_append(struct ast_str *str, const char *dialstring)
03293 {
03294 char dialstring_search[AST_CHANNEL_NAME];
03295
03296 if (ast_strlen_zero(dialstring)) {
03297
03298 return;
03299 }
03300 snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
03301 if (strstr(ast_str_buffer(str), dialstring_search)) {
03302 return;
03303 }
03304 ast_str_append(&str, 0, "%s", dialstring_search);
03305 }
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322 static void build_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, struct ast_str *str)
03323 {
03324 struct extension_monitor_pvt *extension_pvt;
03325 struct extension_child_dialstring *child_dialstring;
03326 struct ast_cc_monitor *monitor_iter = starting_point;
03327 int top_level_id = starting_point->id;
03328 size_t length;
03329
03330
03331 ast_str_truncate(str, 0);
03332
03333
03334
03335
03336
03337 extension_pvt = starting_point->private_data;
03338 AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
03339 if (child_dialstring->is_valid) {
03340 cc_unique_append(str, child_dialstring->original_dialstring);
03341 }
03342 }
03343
03344
03345 while ((monitor_iter = AST_LIST_NEXT(monitor_iter, next))) {
03346 if (monitor_iter->parent_id == top_level_id) {
03347 cc_unique_append(str, monitor_iter->dialstring);
03348 }
03349 }
03350
03351
03352
03353
03354 length = ast_str_strlen(str);
03355 if (length) {
03356 ast_str_truncate(str, length - 1);
03357 }
03358 if (length <= 1) {
03359
03360 ast_log(LOG_ERROR, "CC_INTERFACES is empty. starting device_name:'%s'\n",
03361 starting_point->interface->device_name);
03362 }
03363 }
03364
03365 int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan)
03366 {
03367 struct ast_datastore *recall_datastore;
03368 struct cc_monitor_tree *interface_tree;
03369 struct ast_cc_monitor *monitor;
03370 struct cc_recall_ds_data *recall_data;
03371 struct ast_str *str = ast_str_create(64);
03372 int core_id;
03373
03374 if (!str) {
03375 return -1;
03376 }
03377
03378 ast_channel_lock(chan);
03379 if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03380 ast_channel_unlock(chan);
03381 ast_free(str);
03382 return -1;
03383 }
03384 recall_data = recall_datastore->data;
03385 interface_tree = recall_data->interface_tree;
03386 core_id = recall_data->core_id;
03387 ast_channel_unlock(chan);
03388
03389 AST_LIST_LOCK(interface_tree);
03390 monitor = AST_LIST_FIRST(interface_tree);
03391 build_cc_interfaces_chanvar(monitor, str);
03392 AST_LIST_UNLOCK(interface_tree);
03393
03394 pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03395 ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03396 core_id, ast_str_buffer(str));
03397
03398 ast_free(str);
03399 return 0;
03400 }
03401
03402 int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const extension)
03403 {
03404 struct ast_datastore *recall_datastore;
03405 struct cc_monitor_tree *interface_tree;
03406 struct ast_cc_monitor *monitor_iter;
03407 struct cc_recall_ds_data *recall_data;
03408 struct ast_str *str = ast_str_create(64);
03409 int core_id;
03410
03411 if (!str) {
03412 return -1;
03413 }
03414
03415 ast_channel_lock(chan);
03416 if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03417 ast_channel_unlock(chan);
03418 ast_free(str);
03419 return -1;
03420 }
03421 recall_data = recall_datastore->data;
03422 interface_tree = recall_data->interface_tree;
03423 core_id = recall_data->core_id;
03424 ast_channel_unlock(chan);
03425
03426 AST_LIST_LOCK(interface_tree);
03427 AST_LIST_TRAVERSE(interface_tree, monitor_iter, next) {
03428 if (!strcmp(monitor_iter->interface->device_name, extension)) {
03429 break;
03430 }
03431 }
03432
03433 if (!monitor_iter) {
03434
03435
03436
03437
03438 AST_LIST_UNLOCK(interface_tree);
03439 ast_free(str);
03440 return -1;
03441 }
03442
03443 build_cc_interfaces_chanvar(monitor_iter, str);
03444 AST_LIST_UNLOCK(interface_tree);
03445
03446 pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
03447 ast_log_dynamic_level(cc_logger_level, "Core %d: CC_INTERFACES set to %s\n",
03448 core_id, ast_str_buffer(str));
03449
03450 ast_free(str);
03451 return 0;
03452 }
03453
03454 void ast_ignore_cc(struct ast_channel *chan)
03455 {
03456 struct ast_datastore *cc_datastore;
03457 struct ast_datastore *cc_recall_datastore;
03458 struct dialed_cc_interfaces *cc_interfaces;
03459 struct cc_recall_ds_data *recall_cc_data;
03460
03461 ast_channel_lock(chan);
03462 if ((cc_datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL))) {
03463 cc_interfaces = cc_datastore->data;
03464 cc_interfaces->ignore = 1;
03465 }
03466
03467 if ((cc_recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03468 recall_cc_data = cc_recall_datastore->data;
03469 recall_cc_data->ignore = 1;
03470 }
03471 ast_channel_unlock(chan);
03472 }
03473
03474 static __attribute__((format(printf, 2, 3))) int cc_offer(const int core_id, const char * const debug, ...)
03475 {
03476 va_list ap;
03477 int res;
03478
03479 va_start(ap, debug);
03480 res = cc_request_state_change(CC_CALLER_OFFERED, core_id, debug, ap);
03481 va_end(ap);
03482 return res;
03483 }
03484
03485 int ast_cc_offer(struct ast_channel *caller_chan)
03486 {
03487 int core_id;
03488 int res = -1;
03489 struct ast_datastore *datastore;
03490 struct dialed_cc_interfaces *cc_interfaces;
03491 char cc_is_offerable;
03492
03493 ast_channel_lock(caller_chan);
03494 if (!(datastore = ast_channel_datastore_find(caller_chan, &dialed_cc_interfaces_info, NULL))) {
03495 ast_channel_unlock(caller_chan);
03496 return res;
03497 }
03498
03499 cc_interfaces = datastore->data;
03500 cc_is_offerable = cc_interfaces->is_original_caller;
03501 core_id = cc_interfaces->core_id;
03502 ast_channel_unlock(caller_chan);
03503
03504 if (cc_is_offerable) {
03505 res = cc_offer(core_id, "CC offered to caller %s", caller_chan->name);
03506 }
03507 return res;
03508 }
03509
03510 int ast_cc_agent_accept_request(int core_id, const char * const debug, ...)
03511 {
03512 va_list ap;
03513 int res;
03514
03515 va_start(ap, debug);
03516 res = cc_request_state_change(CC_CALLER_REQUESTED, core_id, debug, ap);
03517 va_end(ap);
03518 return res;
03519 }
03520
03521 int ast_cc_monitor_request_acked(int core_id, const char * const debug, ...)
03522 {
03523 va_list ap;
03524 int res;
03525
03526 va_start(ap, debug);
03527 res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03528 va_end(ap);
03529 return res;
03530 }
03531
03532 int ast_cc_monitor_callee_available(const int core_id, const char * const debug, ...)
03533 {
03534 va_list ap;
03535 int res;
03536
03537 va_start(ap, debug);
03538 res = cc_request_state_change(CC_CALLEE_READY, core_id, debug, ap);
03539 va_end(ap);
03540 return res;
03541 }
03542
03543 int ast_cc_agent_caller_busy(int core_id, const char * debug, ...)
03544 {
03545 va_list ap;
03546 int res;
03547
03548 va_start(ap, debug);
03549 res = cc_request_state_change(CC_CALLER_BUSY, core_id, debug, ap);
03550 va_end(ap);
03551 return res;
03552 }
03553
03554 int ast_cc_agent_caller_available(int core_id, const char * const debug, ...)
03555 {
03556 va_list ap;
03557 int res;
03558
03559 va_start(ap, debug);
03560 res = cc_request_state_change(CC_ACTIVE, core_id, debug, ap);
03561 va_end(ap);
03562 return res;
03563 }
03564
03565 int ast_cc_agent_recalling(int core_id, const char * const debug, ...)
03566 {
03567 va_list ap;
03568 int res;
03569
03570 va_start(ap, debug);
03571 res = cc_request_state_change(CC_RECALLING, core_id, debug, ap);
03572 va_end(ap);
03573 return res;
03574 }
03575
03576 int ast_cc_completed(struct ast_channel *chan, const char * const debug, ...)
03577 {
03578 struct ast_datastore *recall_datastore;
03579 struct cc_recall_ds_data *recall_data;
03580 int core_id;
03581 va_list ap;
03582 int res;
03583
03584 ast_channel_lock(chan);
03585 if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
03586
03587 ast_channel_unlock(chan);
03588 return -1;
03589 }
03590 recall_data = recall_datastore->data;
03591 if (recall_data->nested || recall_data->ignore) {
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602 ast_channel_unlock(chan);
03603 return -1;
03604 }
03605 core_id = recall_data->core_id;
03606 ast_channel_unlock(chan);
03607 va_start(ap, debug);
03608 res = cc_request_state_change(CC_COMPLETE, core_id, debug, ap);
03609 va_end(ap);
03610 return res;
03611 }
03612
03613 int ast_cc_failed(int core_id, const char * const debug, ...)
03614 {
03615 va_list ap;
03616 int res;
03617
03618 va_start(ap, debug);
03619 res = cc_request_state_change(CC_FAILED, core_id, debug, ap);
03620 va_end(ap);
03621 return res;
03622 }
03623
03624 struct ast_cc_monitor_failure_data {
03625 const char *device_name;
03626 char *debug;
03627 int core_id;
03628 };
03629
03630 static int cc_monitor_failed(void *data)
03631 {
03632 struct ast_cc_monitor_failure_data *failure_data = data;
03633 struct cc_core_instance *core_instance;
03634 struct ast_cc_monitor *monitor_iter;
03635
03636 core_instance = find_cc_core_instance(failure_data->core_id);
03637 if (!core_instance) {
03638
03639 ast_log_dynamic_level(cc_logger_level,
03640 "Core %d: Could not find core instance for device %s '%s'\n",
03641 failure_data->core_id, failure_data->device_name, failure_data->debug);
03642 ast_free((char *) failure_data->device_name);
03643 ast_free((char *) failure_data->debug);
03644 ast_free(failure_data);
03645 return -1;
03646 }
03647
03648 AST_LIST_LOCK(core_instance->monitors);
03649 AST_LIST_TRAVERSE_SAFE_BEGIN(core_instance->monitors, monitor_iter, next) {
03650 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
03651 if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
03652 AST_LIST_REMOVE_CURRENT(next);
03653 cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
03654 monitor_iter->interface->device_name, 1);
03655 monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
03656 manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
03657 "CoreID: %d\r\n"
03658 "Callee: %s\r\n",
03659 monitor_iter->core_id, monitor_iter->interface->device_name);
03660 cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
03661 }
03662 }
03663 }
03664 AST_LIST_TRAVERSE_SAFE_END;
03665
03666 if (!has_device_monitors(core_instance)) {
03667 ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
03668 }
03669 AST_LIST_UNLOCK(core_instance->monitors);
03670 cc_unref(core_instance, "Finished with core_instance in cc_monitor_failed\n");
03671
03672 ast_free((char *) failure_data->device_name);
03673 ast_free((char *) failure_data->debug);
03674 ast_free(failure_data);
03675 return 0;
03676 }
03677
03678 int ast_cc_monitor_failed(int core_id, const char *const monitor_name, const char * const debug, ...)
03679 {
03680 struct ast_cc_monitor_failure_data *failure_data;
03681 int res;
03682 va_list ap;
03683
03684 if (!(failure_data = ast_calloc(1, sizeof(*failure_data)))) {
03685 return -1;
03686 }
03687
03688 if (!(failure_data->device_name = ast_strdup(monitor_name))) {
03689 ast_free(failure_data);
03690 return -1;
03691 }
03692
03693 va_start(ap, debug);
03694 if (ast_vasprintf(&failure_data->debug, debug, ap) == -1) {
03695 va_end(ap);
03696 ast_free((char *)failure_data->device_name);
03697 ast_free(failure_data);
03698 return -1;
03699 }
03700 va_end(ap);
03701
03702 failure_data->core_id = core_id;
03703
03704 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_monitor_failed, failure_data);
03705 if (res) {
03706 ast_free((char *)failure_data->device_name);
03707 ast_free((char *)failure_data->debug);
03708 ast_free(failure_data);
03709 }
03710 return res;
03711 }
03712
03713 static int cc_status_request(void *data)
03714 {
03715 struct cc_core_instance *core_instance= data;
03716 int res;
03717
03718 res = core_instance->agent->callbacks->status_request(core_instance->agent);
03719 cc_unref(core_instance, "Status request finished. Unref core instance");
03720 return res;
03721 }
03722
03723 int ast_cc_monitor_status_request(int core_id)
03724 {
03725 int res;
03726 struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03727
03728 if (!core_instance) {
03729 return -1;
03730 }
03731
03732 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_request, core_instance);
03733 if (res) {
03734 cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03735 }
03736 return res;
03737 }
03738
03739 static int cc_stop_ringing(void *data)
03740 {
03741 struct cc_core_instance *core_instance = data;
03742 int res = 0;
03743
03744 if (core_instance->agent->callbacks->stop_ringing) {
03745 res = core_instance->agent->callbacks->stop_ringing(core_instance->agent);
03746 }
03747
03748
03749
03750
03751
03752
03753
03754 ast_cc_monitor_request_acked(core_instance->core_id, "Agent %s asked to stop ringing. Be prepared to be recalled again.",
03755 core_instance->agent->device_name);
03756 cc_unref(core_instance, "Stop ringing finished. Unref core_instance");
03757 return res;
03758 }
03759
03760 int ast_cc_monitor_stop_ringing(int core_id)
03761 {
03762 int res;
03763 struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03764
03765 if (!core_instance) {
03766 return -1;
03767 }
03768
03769 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_stop_ringing, core_instance);
03770 if (res) {
03771 cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03772 }
03773 return res;
03774 }
03775
03776 static int cc_party_b_free(void *data)
03777 {
03778 struct cc_core_instance *core_instance = data;
03779 int res = 0;
03780
03781 if (core_instance->agent->callbacks->party_b_free) {
03782 res = core_instance->agent->callbacks->party_b_free(core_instance->agent);
03783 }
03784 cc_unref(core_instance, "Party B free finished. Unref core_instance");
03785 return res;
03786 }
03787
03788 int ast_cc_monitor_party_b_free(int core_id)
03789 {
03790 int res;
03791 struct cc_core_instance *core_instance = find_cc_core_instance(core_id);
03792
03793 if (!core_instance) {
03794 return -1;
03795 }
03796
03797 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_party_b_free, core_instance);
03798 if (res) {
03799 cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03800 }
03801 return res;
03802 }
03803
03804 struct cc_status_response_args {
03805 struct cc_core_instance *core_instance;
03806 enum ast_device_state devstate;
03807 };
03808
03809 static int cc_status_response(void *data)
03810 {
03811 struct cc_status_response_args *args = data;
03812 struct cc_core_instance *core_instance = args->core_instance;
03813 struct ast_cc_monitor *monitor_iter;
03814 enum ast_device_state devstate = args->devstate;
03815
03816 ast_free(args);
03817
03818 AST_LIST_LOCK(core_instance->monitors);
03819 AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
03820 if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR &&
03821 monitor_iter->callbacks->status_response) {
03822 monitor_iter->callbacks->status_response(monitor_iter, devstate);
03823 }
03824 }
03825 AST_LIST_UNLOCK(core_instance->monitors);
03826 cc_unref(core_instance, "Status response finished. Unref core instance");
03827 return 0;
03828 }
03829
03830 int ast_cc_agent_status_response(int core_id, enum ast_device_state devstate)
03831 {
03832 struct cc_status_response_args *args;
03833 struct cc_core_instance *core_instance;
03834 int res;
03835
03836 args = ast_calloc(1, sizeof(*args));
03837 if (!args) {
03838 return -1;
03839 }
03840
03841 core_instance = find_cc_core_instance(core_id);
03842 if (!core_instance) {
03843 ast_free(args);
03844 return -1;
03845 }
03846
03847 args->core_instance = core_instance;
03848 args->devstate = devstate;
03849
03850 res = ast_taskprocessor_push(cc_core_taskprocessor, cc_status_response, args);
03851 if (res) {
03852 cc_unref(core_instance, "Unref core instance. ast_taskprocessor_push failed");
03853 ast_free(args);
03854 }
03855 return res;
03856 }
03857
03858 static int cc_build_payload(struct ast_channel *chan, struct ast_cc_config_params *cc_params,
03859 const char *monitor_type, const char * const device_name, const char * dialstring,
03860 enum ast_cc_service_type service, void *private_data, struct cc_control_payload *payload)
03861 {
03862 struct ast_datastore *datastore;
03863 struct dialed_cc_interfaces *cc_interfaces;
03864 int dial_parent_id;
03865
03866 ast_channel_lock(chan);
03867 datastore = ast_channel_datastore_find(chan, &dialed_cc_interfaces_info, NULL);
03868 if (!datastore) {
03869 ast_channel_unlock(chan);
03870 return -1;
03871 }
03872 cc_interfaces = datastore->data;
03873 dial_parent_id = cc_interfaces->dial_parent_id;
03874 ast_channel_unlock(chan);
03875
03876 payload->monitor_type = monitor_type;
03877 payload->private_data = private_data;
03878 payload->service = service;
03879 ast_cc_copy_config_params(&payload->config_params, cc_params);
03880 payload->parent_interface_id = dial_parent_id;
03881 ast_copy_string(payload->device_name, device_name, sizeof(payload->device_name));
03882 ast_copy_string(payload->dialstring, dialstring, sizeof(payload->dialstring));
03883 return 0;
03884 }
03885
03886 int ast_queue_cc_frame(struct ast_channel *chan, const char *monitor_type,
03887 const char * const dialstring, enum ast_cc_service_type service, void *private_data)
03888 {
03889 struct ast_frame frame = {0,};
03890 char device_name[AST_CHANNEL_NAME];
03891 int retval;
03892 struct ast_cc_config_params *cc_params;
03893
03894 cc_params = ast_channel_get_cc_config_params(chan);
03895 if (!cc_params) {
03896 return -1;
03897 }
03898 ast_channel_get_device_name(chan, device_name, sizeof(device_name));
03899 if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
03900 ast_log(LOG_NOTICE, "Not queuing a CC frame for device %s since it already has its maximum monitors allocated\n", device_name);
03901 return -1;
03902 }
03903
03904 if (ast_cc_build_frame(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, &frame)) {
03905
03906 return -1;
03907 }
03908 retval = ast_queue_frame(chan, &frame);
03909 ast_frfree(&frame);
03910 return retval;
03911 }
03912
03913 int ast_cc_build_frame(struct ast_channel *chan, struct ast_cc_config_params *cc_params,
03914 const char *monitor_type, const char * const device_name,
03915 const char * const dialstring, enum ast_cc_service_type service, void *private_data,
03916 struct ast_frame *frame)
03917 {
03918 struct cc_control_payload *payload = ast_calloc(1, sizeof(*payload));
03919
03920 if (!payload) {
03921 return -1;
03922 }
03923 if (cc_build_payload(chan, cc_params, monitor_type, device_name, dialstring, service, private_data, payload)) {
03924
03925 ast_free(payload);
03926 return -1;
03927 }
03928 frame->frametype = AST_FRAME_CONTROL;
03929 frame->subclass.integer = AST_CONTROL_CC;
03930 frame->data.ptr = payload;
03931 frame->datalen = sizeof(*payload);
03932 frame->mallocd = AST_MALLOCD_DATA;
03933 return 0;
03934 }
03935
03936 void ast_cc_call_failed(struct ast_channel *incoming, struct ast_channel *outgoing, const char * const dialstring)
03937 {
03938 char device_name[AST_CHANNEL_NAME];
03939 struct cc_control_payload payload;
03940 struct ast_cc_config_params *cc_params;
03941
03942 if (outgoing->hangupcause != AST_CAUSE_BUSY && outgoing->hangupcause != AST_CAUSE_CONGESTION) {
03943
03944
03945
03946 return;
03947 }
03948
03949 cc_params = ast_channel_get_cc_config_params(outgoing);
03950 if (!cc_params) {
03951 return;
03952 }
03953 if (ast_get_cc_monitor_policy(cc_params) != AST_CC_MONITOR_GENERIC) {
03954
03955
03956
03957 return;
03958 }
03959
03960 ast_channel_get_device_name(outgoing, device_name, sizeof(device_name));
03961 if (cc_build_payload(outgoing, cc_params, AST_CC_GENERIC_MONITOR_TYPE, device_name,
03962 dialstring, AST_CC_CCBS, NULL, &payload)) {
03963
03964 return;
03965 }
03966 ast_handle_cc_control_frame(incoming, outgoing, &payload);
03967 }
03968
03969 void ast_cc_busy_interface(struct ast_channel *inbound, struct ast_cc_config_params *cc_params,
03970 const char *monitor_type, const char * const device_name, const char * const dialstring, void *private_data)
03971 {
03972 struct cc_control_payload payload;
03973 if (cc_build_payload(inbound, cc_params, monitor_type, device_name, dialstring, AST_CC_CCBS, private_data, &payload)) {
03974
03975 call_destructor_with_no_monitor(monitor_type, private_data);
03976 return;
03977 }
03978 ast_handle_cc_control_frame(inbound, NULL, &payload);
03979 }
03980
03981 int ast_cc_callback(struct ast_channel *inbound, const char * const tech, const char * const dest, ast_cc_callback_fn callback)
03982 {
03983 const struct ast_channel_tech *chantech = ast_get_channel_tech(tech);
03984
03985 if (chantech && chantech->cc_callback) {
03986 chantech->cc_callback(inbound, dest, callback);
03987 }
03988
03989 return 0;
03990 }
03991
03992 static const char *ccreq_app = "CallCompletionRequest";
03993
03994 static int ccreq_exec(struct ast_channel *chan, const char *data)
03995 {
03996 struct cc_core_instance *core_instance;
03997 char device_name[AST_CHANNEL_NAME];
03998 unsigned long match_flags;
03999 int res;
04000
04001 ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04002
04003 match_flags = MATCH_NO_REQUEST;
04004 if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionRequest"))) {
04005 ast_log_dynamic_level(cc_logger_level, "Couldn't find a core instance for caller %s\n", device_name);
04006 pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04007 pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NO_CORE_INSTANCE");
04008 return 0;
04009 }
04010
04011 ast_log_dynamic_level(cc_logger_level, "Core %d: Found core_instance for caller %s\n",
04012 core_instance->core_id, device_name);
04013
04014 if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04015 ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest is only for generic agent types.\n",
04016 core_instance->core_id);
04017 pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04018 pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "NOT_GENERIC");
04019 cc_unref(core_instance, "Unref core_instance since CallCompletionRequest was called with native agent");
04020 return 0;
04021 }
04022
04023 if (!ast_cc_request_is_within_limits()) {
04024 ast_log_dynamic_level(cc_logger_level, "Core %d: CallCompletionRequest failed. Too many requests in the system\n",
04025 core_instance->core_id);
04026 ast_cc_failed(core_instance->core_id, "Too many CC requests\n");
04027 pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", "FAIL");
04028 pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "TOO_MANY_REQUESTS");
04029 cc_unref(core_instance, "Unref core_instance since too many CC requests");
04030 return 0;
04031 }
04032
04033 res = ast_cc_agent_accept_request(core_instance->core_id, "CallCompletionRequest called by caller %s for core_id %d", device_name, core_instance->core_id);
04034 pbx_builtin_setvar_helper(chan, "CC_REQUEST_RESULT", res ? "FAIL" : "SUCCESS");
04035 if (res) {
04036 pbx_builtin_setvar_helper(chan, "CC_REQUEST_REASON", "UNSPECIFIED");
04037 }
04038
04039 cc_unref(core_instance, "Done with CallCompletionRequest");
04040 return 0;
04041 }
04042
04043 static const char *cccancel_app = "CallCompletionCancel";
04044
04045 static int cccancel_exec(struct ast_channel *chan, const char *data)
04046 {
04047 struct cc_core_instance *core_instance;
04048 char device_name[AST_CHANNEL_NAME];
04049 unsigned long match_flags;
04050 int res;
04051
04052 ast_channel_get_device_name(chan, device_name, sizeof(device_name));
04053
04054 match_flags = MATCH_REQUEST;
04055 if (!(core_instance = ao2_t_callback_data(cc_core_instances, 0, match_agent, device_name, &match_flags, "Find core instance for CallCompletionCancel"))) {
04056 ast_log_dynamic_level(cc_logger_level, "Cannot find CC transaction to cancel for caller %s\n", device_name);
04057 pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04058 pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NO_CORE_INSTANCE");
04059 return 0;
04060 }
04061
04062 if (strcmp(core_instance->agent->callbacks->type, "generic")) {
04063 ast_log(LOG_WARNING, "CallCompletionCancel may only be used for calles with a generic agent\n");
04064 cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04065 pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", "FAIL");
04066 pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "NOT_GENERIC");
04067 return 0;
04068 }
04069 res = ast_cc_failed(core_instance->core_id, "Call completion request Cancelled for core ID %d by caller %s",
04070 core_instance->core_id, device_name);
04071 cc_unref(core_instance, "Unref core instance found during CallCompletionCancel");
04072 pbx_builtin_setvar_helper(chan, "CC_CANCEL_RESULT", res ? "FAIL" : "SUCCESS");
04073 if (res) {
04074 pbx_builtin_setvar_helper(chan, "CC_CANCEL_REASON", "UNSPECIFIED");
04075 }
04076 return 0;
04077 }
04078
04079 struct count_monitors_cb_data {
04080 const char *device_name;
04081 const char *monitor_type;
04082 int count;
04083 };
04084
04085 static int count_monitors_cb(void *obj, void *arg, int flags)
04086 {
04087 struct cc_core_instance *core_instance = obj;
04088 struct count_monitors_cb_data *cb_data = arg;
04089 const char *device_name = cb_data->device_name;
04090 const char *monitor_type = cb_data->monitor_type;
04091 struct ast_cc_monitor *monitor_iter;
04092
04093 AST_LIST_LOCK(core_instance->monitors);
04094 AST_LIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
04095 if (!strcmp(monitor_iter->interface->device_name, device_name) &&
04096 !strcmp(monitor_iter->interface->monitor_type, monitor_type)) {
04097 cb_data->count++;
04098 break;
04099 }
04100 }
04101 AST_LIST_UNLOCK(core_instance->monitors);
04102 return 0;
04103 }
04104
04105 int ast_cc_monitor_count(const char * const name, const char * const type)
04106 {
04107 struct count_monitors_cb_data data = {.device_name = name, .monitor_type = type,};
04108
04109 ao2_t_callback(cc_core_instances, OBJ_NODATA, count_monitors_cb, &data, "Counting agents");
04110 ast_log_dynamic_level(cc_logger_level, "Counted %d monitors\n", data.count);
04111 return data.count;
04112 }
04113
04114 static void initialize_cc_max_requests(void)
04115 {
04116 struct ast_config *cc_config;
04117 const char *cc_max_requests_str;
04118 struct ast_flags config_flags = {0,};
04119 char *endptr;
04120
04121 cc_config = ast_config_load2("ccss.conf", "ccss", config_flags);
04122 if (!cc_config || cc_config == CONFIG_STATUS_FILEINVALID) {
04123 ast_log(LOG_WARNING, "Could not find valid ccss.conf file. Using cc_max_requests default\n");
04124 global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04125 return;
04126 }
04127
04128 if (!(cc_max_requests_str = ast_variable_retrieve(cc_config, "general", "cc_max_requests"))) {
04129 ast_config_destroy(cc_config);
04130 global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04131 return;
04132 }
04133
04134 global_cc_max_requests = strtol(cc_max_requests_str, &endptr, 10);
04135
04136 if (!ast_strlen_zero(endptr)) {
04137 ast_log(LOG_WARNING, "Invalid input given for cc_max_requests. Using default\n");
04138 global_cc_max_requests = GLOBAL_CC_MAX_REQUESTS_DEFAULT;
04139 }
04140
04141 ast_config_destroy(cc_config);
04142 return;
04143 }
04144
04145 static void cc_cli_print_monitor_stats(struct ast_cc_monitor *monitor, int fd, int parent_id)
04146 {
04147 struct ast_cc_monitor *child_monitor_iter = monitor;
04148 if (!monitor) {
04149 return;
04150 }
04151
04152 ast_cli(fd, "\t\t|-->%s", monitor->interface->device_name);
04153 if (monitor->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
04154 ast_cli(fd, "(%s)", cc_service_to_string(monitor->service_offered));
04155 }
04156 ast_cli(fd, "\n");
04157
04158 while ((child_monitor_iter = AST_LIST_NEXT(child_monitor_iter, next))) {
04159 if (child_monitor_iter->parent_id == monitor->id) {
04160 cc_cli_print_monitor_stats(child_monitor_iter, fd, child_monitor_iter->id);
04161 }
04162 }
04163 }
04164
04165 static int print_stats_cb(void *obj, void *arg, int flags)
04166 {
04167 int *cli_fd = arg;
04168 struct cc_core_instance *core_instance = obj;
04169
04170 ast_cli(*cli_fd, "%d\t\t%s\t\t%s\n", core_instance->core_id, core_instance->agent->device_name,
04171 cc_state_to_string(core_instance->current_state));
04172 AST_LIST_LOCK(core_instance->monitors);
04173 cc_cli_print_monitor_stats(AST_LIST_FIRST(core_instance->monitors), *cli_fd, 0);
04174 AST_LIST_UNLOCK(core_instance->monitors);
04175 return 0;
04176 }
04177
04178 static int cc_cli_output_status(void *data)
04179 {
04180 int *cli_fd = data;
04181 int count = ao2_container_count(cc_core_instances);
04182
04183 if (!count) {
04184 ast_cli(*cli_fd, "There are currently no active call completion transactions\n");
04185 } else {
04186 ast_cli(*cli_fd, "%d Call completion transactions\n", count);
04187 ast_cli(*cli_fd, "Core ID\t\tCaller\t\t\t\tStatus\n");
04188 ast_cli(*cli_fd, "----------------------------------------------------------------------------\n");
04189 ao2_t_callback(cc_core_instances, OBJ_NODATA, print_stats_cb, cli_fd, "Printing stats to CLI");
04190 }
04191 ast_free(cli_fd);
04192 return 0;
04193 }
04194
04195 static char *handle_cc_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04196 {
04197 int *cli_fd;
04198
04199 switch (cmd) {
04200 case CLI_INIT:
04201 e->command = "cc report status";
04202 e->usage =
04203 "Usage: cc report status\n"
04204 " Report the current status of any ongoing CC transactions\n";
04205 return NULL;
04206 case CLI_GENERATE:
04207 return NULL;
04208 }
04209
04210 if (a->argc != 3) {
04211 return CLI_SHOWUSAGE;
04212 }
04213
04214 cli_fd = ast_malloc(sizeof(*cli_fd));
04215 if (!cli_fd) {
04216 return CLI_FAILURE;
04217 }
04218
04219 *cli_fd = a->fd;
04220
04221 if (ast_taskprocessor_push(cc_core_taskprocessor, cc_cli_output_status, cli_fd)) {
04222 ast_free(cli_fd);
04223 return CLI_FAILURE;
04224 }
04225 return CLI_SUCCESS;
04226 }
04227
04228 static int kill_cores(void *obj, void *arg, int flags)
04229 {
04230 int *core_id = arg;
04231 struct cc_core_instance *core_instance = obj;
04232
04233 if (!core_id || (core_instance->core_id == *core_id)) {
04234 ast_cc_failed(core_instance->core_id, "CC transaction canceled administratively\n");
04235 }
04236 return 0;
04237 }
04238
04239 static char *complete_core_id(const char *line, const char *word, int pos, int state)
04240 {
04241 int which = 0;
04242 int wordlen = strlen(word);
04243 char *ret = NULL;
04244 struct ao2_iterator core_iter = ao2_iterator_init(cc_core_instances, 0);
04245 struct cc_core_instance *core_instance;
04246
04247 for (; (core_instance = ao2_t_iterator_next(&core_iter, "Next core instance"));
04248 cc_unref(core_instance, "CLI tab completion iteration")) {
04249 char core_id_str[20];
04250 snprintf(core_id_str, sizeof(core_id_str), "%d", core_instance->core_id);
04251 if (!strncmp(word, core_id_str, wordlen) && ++which > state) {
04252 ret = ast_strdup(core_id_str);
04253 cc_unref(core_instance, "Found a matching core ID for CLI tab-completion");
04254 break;
04255 }
04256 }
04257 ao2_iterator_destroy(&core_iter);
04258
04259 return ret;
04260 }
04261
04262 static char *handle_cc_kill(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04263 {
04264 static const char * const option[] = { "core", "all", NULL };
04265
04266 switch (cmd) {
04267 case CLI_INIT:
04268 e->command = "cc cancel";
04269 e->usage =
04270 "Usage: cc cancel can be used in two ways.\n"
04271 " 1. 'cc cancel core [core ID]' will cancel the CC transaction with\n"
04272 " core ID equal to the specified core ID.\n"
04273 " 2. 'cc cancel all' will cancel all active CC transactions.\n";
04274 return NULL;
04275 case CLI_GENERATE:
04276 if (a->pos == 2) {
04277 return ast_cli_complete(a->word, option, a->n);
04278 }
04279 if (a->pos == 3) {
04280 return complete_core_id(a->line, a->word, a->pos, a->n);
04281 }
04282 return NULL;
04283 }
04284
04285 if (a->argc == 4) {
04286 int core_id;
04287 char *endptr;
04288 if (strcasecmp(a->argv[2], "core")) {
04289 return CLI_SHOWUSAGE;
04290 }
04291 core_id = strtol(a->argv[3], &endptr, 10);
04292 if ((errno != 0 && core_id == 0) || (endptr == a->argv[3])) {
04293 return CLI_SHOWUSAGE;
04294 }
04295 ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, &core_id, "CLI Killing Core Id");
04296 } else if (a->argc == 3) {
04297 if (strcasecmp(a->argv[2], "all")) {
04298 return CLI_SHOWUSAGE;
04299 }
04300 ao2_t_callback(cc_core_instances, OBJ_NODATA, kill_cores, NULL, "CLI Killing all CC cores");
04301 } else {
04302 return CLI_SHOWUSAGE;
04303 }
04304
04305 return CLI_SUCCESS;
04306 }
04307
04308 static struct ast_cli_entry cc_cli[] = {
04309 AST_CLI_DEFINE(handle_cc_status, "Reports CC stats"),
04310 AST_CLI_DEFINE(handle_cc_kill, "Kill a CC transaction"),
04311 };
04312
04313 int ast_cc_init(void)
04314 {
04315 int res;
04316
04317 if (!(cc_core_instances = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04318 cc_core_instance_hash_fn, cc_core_instance_cmp_fn,
04319 "Create core instance container"))) {
04320 return -1;
04321 }
04322 if (!(generic_monitors = ao2_t_container_alloc(CC_CORE_INSTANCES_BUCKETS,
04323 generic_monitor_hash_fn, generic_monitor_cmp_fn,
04324 "Create generic monitor container"))) {
04325 return -1;
04326 }
04327 if (!(cc_core_taskprocessor = ast_taskprocessor_get("CCSS core", TPS_REF_DEFAULT))) {
04328 return -1;
04329 }
04330 if (!(cc_sched_thread = ast_sched_thread_create())) {
04331 return -1;
04332 }
04333 res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL);
04334 res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL);
04335 res |= ast_cc_monitor_register(&generic_monitor_cbs);
04336 res |= ast_cc_agent_register(&generic_agent_callbacks);
04337 ast_cli_register_multiple(cc_cli, ARRAY_LEN(cc_cli));
04338 cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME);
04339 dialed_cc_interface_counter = 1;
04340 initialize_cc_max_requests();
04341 return res;
04342 }