static void *SWITCH_THREAD_FUNC limit_remote_thread(switch_thread_t *thread, void *obj) { limit_remote_t *remote = (limit_remote_t*)obj; while (remote->state > REMOTE_OFF) { if (remote->state != REMOTE_UP) { if (esl_connect_timeout(&remote->handle, remote->host, remote->port, remote->username, remote->password, 5000) == ESL_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to remote FreeSWITCH (%s) at %s:%d\n", remote->name, remote->host, remote->port); remote->state = REMOTE_UP; } else { esl_disconnect(&remote->handle); memset(&remote->handle, 0, sizeof(remote->handle)); } } else { if (esl_send_recv_timed(&remote->handle, "api hash_dump limit", 5000) != ESL_SUCCESS) { esl_disconnect(&remote->handle); memset(&remote->handle, 0, sizeof(remote->handle)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Disconnected from remote FreeSWITCH (%s) at %s:%d\n", remote->name, remote->host, remote->port); memset(&remote->handle, 0, sizeof(remote->handle)); remote->state = REMOTE_DOWN; /* Delete all remote tracking entries */ switch_thread_rwlock_wrlock(remote->rwlock); switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, NULL); switch_thread_rwlock_unlock(remote->rwlock); } else { if (!zstr(remote->handle.last_sr_event->body)) { char *data = strdup(remote->handle.last_sr_event->body); char *p = data, *p2; switch_time_t now = switch_epoch_time_now(NULL); while (p && *p) { /* We are getting the limit data as: L/key/usage/rate/interval/last_checked */ if ((p2 = strchr(p, '\n'))) { *p2++ = '\0'; } /* Now p points at the beginning of the current line, p2 at the start of the next one */ if (*p == 'L') { /* Limit data */ char *argv[5]; int argc = switch_split(p+2, '/', argv); if (argc < 5) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "[%s] Protocol error: missing argument in line: %s\n", remote->name, p); } else { limit_hash_item_t *item; switch_thread_rwlock_wrlock(remote->rwlock); if (!(item = switch_core_hash_find(remote->index, argv[0]))) { item = malloc(sizeof(*item)); switch_core_hash_insert(remote->index, argv[0], item); } item->total_usage = atoi(argv[1]); item->rate_usage = atoi(argv[2]); item->interval = atoi(argv[3]); item->last_check = atoi(argv[4]); item->last_update = now; switch_thread_rwlock_unlock(remote->rwlock); } } p = p2; } free(data); /* Now free up anything that wasn't in this update since it means their usage is 0 */ switch_thread_rwlock_wrlock(remote->rwlock); switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, (void*)(intptr_t)now); switch_thread_rwlock_unlock(remote->rwlock); } } } switch_yield(remote->interval * 1000); } remote->thread = NULL; return NULL; }
int main(int argc, char *argv[]) { esl_handle_t handle = {{0}}; int count = 0; const char *line = NULL; char cmd_str[1024] = ""; cli_profile_t *profile = NULL; #ifndef WIN32 char hfile[512] = "/tmp/fs_cli_history"; char cfile[512] = "/etc/fs_cli.conf"; char dft_cfile[512] = "/etc/fs_cli.conf"; #else char hfile[512] = "fs_cli_history"; char cfile[512] = "fs_cli.conf"; char dft_cfile[512] = "fs_cli.conf"; #endif char *home = getenv("HOME"); /* Vars for optargs */ int opt; static struct option options[] = { {"help", 0, 0, 'h'}, {"no-color", 0, 0, 'n'}, {"host", 1, 0, 'H'}, {"port", 1, 0, 'P'}, {"user", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"debug", 1, 0, 'd'}, {"execute", 1, 0, 'x'}, {"loglevel", 1, 0, 'l'}, {"log-uuid", 0, 0, 'U'}, {"quiet", 0, 0, 'q'}, {"batchmode", 0, 0, 'b'}, {"retry", 0, 0, 'r'}, {"interrupt", 0, 0, 'i'}, {"reconnect", 0, 0, 'R'}, {"timeout", 1, 0, 't'}, {"connect-timeout", 1, 0, 'T'}, {0, 0, 0, 0} }; char temp_host[128]; int argv_host = 0; char temp_user[256]; char temp_pass[128]; int argv_pass = 0 ; int argv_user = 0 ; int temp_port = 0; int argv_port = 0; int temp_log = -1; int argv_error = 0; int argv_exec = 0; char argv_command[1024] = ""; char argv_loglevel[128] = ""; int argv_log_uuid = 0; int argv_quiet = 0; int argv_batch = 0; int loops = 2, reconnect = 0; char *ccheck; #ifdef WIN32 feature_level = 0; #else feature_level = 1; #endif if ((ccheck = getenv("FS_CLI_COLOR"))) { is_color = esl_true(ccheck); } strncpy(internal_profile.host, "127.0.0.1", sizeof(internal_profile.host)); strncpy(internal_profile.pass, "ClueCon", sizeof(internal_profile.pass)); strncpy(internal_profile.name, "internal", sizeof(internal_profile.name)); internal_profile.port = 8021; set_fn_keys(&internal_profile); esl_set_string(internal_profile.prompt_color, prompt_color); esl_set_string(internal_profile.input_text_color, input_text_color); esl_set_string(internal_profile.output_text_color, output_text_color); if (home) { snprintf(hfile, sizeof(hfile), "%s/.fs_cli_history", home); snprintf(cfile, sizeof(cfile), "%s/.fs_cli_conf", home); } signal(SIGINT, handle_SIGINT); #ifdef SIGTSTP signal(SIGTSTP, handle_SIGINT); #endif #ifdef SIGQUIT signal(SIGQUIT, handle_SIGQUIT); #endif esl_global_set_default_logger(6); /* default debug level to 6 (info) */ for(;;) { int option_index = 0; opt = getopt_long(argc, argv, "H:P:S:u:p:d:x:l:Ut:T:qrRhib?n", options, &option_index); if (opt == -1) break; switch (opt) { case 'H': esl_set_string(temp_host, optarg); argv_host = 1; break; case 'P': temp_port= atoi(optarg); if (temp_port > 0 && temp_port < 65536) { argv_port = 1; } else { printf("ERROR: Port must be in range 1 - 65535\n"); argv_error = 1; } break; case 'n': is_color = 0; break; case 'u': esl_set_string(temp_user, optarg); argv_user = 1; break; case 'p': esl_set_string(temp_pass, optarg); argv_pass = 1; break; case 'd': temp_log=atoi(optarg); if (temp_log < 0 || temp_log > 7) { printf("ERROR: Debug level should be 0 - 7.\n"); argv_error = 1; } else { esl_global_set_default_logger(temp_log); } break; case 'x': argv_exec = 1; esl_set_string(argv_command, optarg); break; case 'l': esl_set_string(argv_loglevel, optarg); break; case 'U': argv_log_uuid = 1; break; case 'q': argv_quiet = 1; break; case 'b': argv_batch = 1; break; case 'i': allow_ctl_c = 1; break; case 'r': loops += 120; break; case 'R': reconnect = 1; break; case 't': timeout = atoi(optarg); break; case 'T': connect_timeout = atoi(optarg); break; case 'h': case '?': print_banner(stdout, is_color); usage(argv[0]); return 0; } } if (argv_error) { printf("\n"); return usage(argv[0]); } read_config(dft_cfile, cfile); if (optind < argc) { get_profile(argv[optind], &profile); } if (!profile) { if (get_profile("default", &profile)) { esl_log(ESL_LOG_DEBUG, "profile default does not exist using builtin profile\n"); profile = &internal_profile; } } if (temp_log < 0 ) { esl_global_set_default_logger(profile->debug); } if (argv_host) { esl_set_string(profile->host, temp_host); } if (argv_port) { profile->port = (esl_port_t)temp_port; } if (argv_user) { esl_set_string(profile->user, temp_user); } if (argv_pass) { esl_set_string(profile->pass, temp_pass); } if (argv_batch || profile->batch_mode) { profile->batch_mode = 1; feature_level=0; } if (*argv_loglevel) { esl_set_string(profile->loglevel, argv_loglevel); profile->quiet = 0; } if (argv_log_uuid) { profile->log_uuid = 1; } esl_log(ESL_LOG_DEBUG, "Using profile %s [%s]\n", profile->name, profile->host); esl_set_string(prompt_color, profile->prompt_color); esl_set_string(input_text_color, profile->input_text_color); esl_set_string(output_text_color, profile->output_text_color); if (argv_host) { if (argv_port && profile->port != 8021) { snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s:%u@%s> ", profile->host, profile->port, profile->name); } else { snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s@%s> ", profile->host, profile->name); } } else { snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s> ", profile->name); } bare_prompt_str_len = (int)strlen(bare_prompt_str); if (feature_level) { snprintf(prompt_str, sizeof(prompt_str), "%s%s%s", prompt_color, bare_prompt_str, input_text_color); } else { snprintf(prompt_str, sizeof(prompt_str), "%s", bare_prompt_str); } connect: connected = 0; while (--loops > 0) { memset(&handle, 0, sizeof(handle)); if (esl_connect_timeout(&handle, profile->host, profile->port, profile->user, profile->pass, connect_timeout)) { esl_global_set_default_logger(7); esl_log(ESL_LOG_ERROR, "Error Connecting [%s]\n", handle.err); if (loops == 1) { if (!argv_exec) usage(argv[0]); return -1; } else { sleep_s(1); esl_log(ESL_LOG_INFO, "Retrying\n"); } } else { connected = 1; if (temp_log < 0 ) { esl_global_set_default_logger(profile->debug); } else { esl_global_set_default_logger(temp_log); } break; } } if (argv_exec) { const char *err = NULL; snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", argv_command); if (timeout) { esl_status_t status = esl_send_recv_timed(&handle, cmd_str, timeout); if (status != ESL_SUCCESS) { printf("Request timed out.\n"); esl_disconnect(&handle); return -2; } } else { esl_send_recv(&handle, cmd_str); } if (handle.last_sr_event) { if (handle.last_sr_event->body) { printf("%s\n", handle.last_sr_event->body); } else if ((err = esl_event_get_header(handle.last_sr_event, "reply-text")) && !strncasecmp(err, "-err", 3)) { printf("Error: %s!\n", err + 4); } } esl_disconnect(&handle); return 0; } global_handle = &handle; global_profile = profile; if (esl_thread_create_detached(msg_thread_run, &handle) != ESL_SUCCESS) { printf("Error starting thread!\n"); esl_disconnect(&handle); return 0; } #ifdef HAVE_EDITLINE el = el_init(__FILE__, stdin, stdout, stderr); el_set(el, EL_PROMPT, &prompt); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_ADDFN, "f1-key", "F1 KEY PRESS", console_f1key); el_set(el, EL_ADDFN, "f2-key", "F2 KEY PRESS", console_f2key); el_set(el, EL_ADDFN, "f3-key", "F3 KEY PRESS", console_f3key); el_set(el, EL_ADDFN, "f4-key", "F4 KEY PRESS", console_f4key); el_set(el, EL_ADDFN, "f5-key", "F5 KEY PRESS", console_f5key); el_set(el, EL_ADDFN, "f6-key", "F6 KEY PRESS", console_f6key); el_set(el, EL_ADDFN, "f7-key", "F7 KEY PRESS", console_f7key); el_set(el, EL_ADDFN, "f8-key", "F8 KEY PRESS", console_f8key); el_set(el, EL_ADDFN, "f9-key", "F9 KEY PRESS", console_f9key); el_set(el, EL_ADDFN, "f10-key", "F10 KEY PRESS", console_f10key); el_set(el, EL_ADDFN, "f11-key", "F11 KEY PRESS", console_f11key); el_set(el, EL_ADDFN, "f12-key", "F12 KEY PRESS", console_f12key); el_set(el, EL_ADDFN, "EOF-key", "EOF (^D) KEY PRESS", console_eofkey); el_set(el, EL_BIND, "\033OP", "f1-key", NULL); el_set(el, EL_BIND, "\033OQ", "f2-key", NULL); el_set(el, EL_BIND, "\033OR", "f3-key", NULL); el_set(el, EL_BIND, "\033OS", "f4-key", NULL); el_set(el, EL_BIND, "\033OT", "f5-key", NULL); el_set(el, EL_BIND, "\033OU", "f6-key", NULL); el_set(el, EL_BIND, "\033OV", "f7-key", NULL); el_set(el, EL_BIND, "\033OW", "f8-key", NULL); el_set(el, EL_BIND, "\033OX", "f9-key", NULL); el_set(el, EL_BIND, "\033OY", "f10-key", NULL); el_set(el, EL_BIND, "\033OZ", "f11-key", NULL); el_set(el, EL_BIND, "\033O[", "f12-key", NULL); el_set(el, EL_BIND, "\033[11~", "f1-key", NULL); el_set(el, EL_BIND, "\033[12~", "f2-key", NULL); el_set(el, EL_BIND, "\033[13~", "f3-key", NULL); el_set(el, EL_BIND, "\033[14~", "f4-key", NULL); el_set(el, EL_BIND, "\033[15~", "f5-key", NULL); el_set(el, EL_BIND, "\033[17~", "f6-key", NULL); el_set(el, EL_BIND, "\033[18~", "f7-key", NULL); el_set(el, EL_BIND, "\033[19~", "f8-key", NULL); el_set(el, EL_BIND, "\033[20~", "f9-key", NULL); el_set(el, EL_BIND, "\033[21~", "f10-key", NULL); el_set(el, EL_BIND, "\033[23~", "f11-key", NULL); el_set(el, EL_BIND, "\033[24~", "f12-key", NULL); el_set(el, EL_BIND, "\004", "EOF-key", NULL); el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete); el_set(el, EL_BIND, "^I", "ed-complete", NULL); /* "Delete" key. */ el_set(el, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); if (!(myhistory = history_init())) { esl_log(ESL_LOG_ERROR, "history could not be initialized\n"); goto done; } history(myhistory, &ev, H_SETSIZE, 800); el_set(el, EL_HIST, history, myhistory); history(myhistory, &ev, H_LOAD, hfile); el_source(el, NULL); #endif #ifdef WIN32 hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdout != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { wOldColorAttrs = csbiInfo.wAttributes; } #endif if (!argv_quiet && !profile->quiet) { snprintf(cmd_str, sizeof(cmd_str), "log %s\n\n", profile->loglevel); esl_send_recv(&handle, cmd_str); } if (global_profile->batch_mode) { setvbuf(stdout, (char*)NULL, _IONBF, 0); } print_banner(stdout, is_color); esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n"); output_printf("%s\n", handle.last_sr_reply); while (running > 0) { int r; #ifdef HAVE_EDITLINE if (!(global_profile->batch_mode)) { line = el_gets(el, &count); } else { #endif line = basic_gets(&count); #ifdef HAVE_EDITLINE } #endif if (count > 1 && !esl_strlen_zero(line)) { char *p, *cmd = strdup(line); assert(cmd); if ((p = strrchr(cmd, '\r')) || (p = strrchr(cmd, '\n'))) { *p = '\0'; } #ifdef HAVE_EDITLINE history(myhistory, &ev, H_ENTER, line); #endif if ((r = process_command(&handle, cmd))) { running = r; } free(cmd); clear_el_buffer(); } sleep_ms(1); } if (running < 0 && reconnect) { running = 1; loops = 120; goto connect; } #ifdef HAVE_EDITLINE done: history(myhistory, &ev, H_SAVE, hfile); history_end(myhistory); el_end(el); #endif esl_disconnect(&handle); global_handle = NULL; thread_running = 0; return 0; }