// Author: Ricardas Stoma // Company: Kolmisoft // Year: 2013 // About: Script checks terminator availability // DEFINITIONS #define SCRIPT_VERSION "1.1" #define SCRIPT_NAME "m2_terminator_check" #define MAX_THR 4 #define SIPSAK_TIMEOUT 3 #define PROXY_NAME "kamailio" #include "m2_functions.c" // FUNCTION DECLARATIONS int get_terminators(); void threads_execution(int n); void *check_terminator_status(void *arg); void update_terminator_status(int id, int status); void check_if_proxy_configured(); void check_if_proxy_running(); // GLOBAL VARIABLES typedef struct terminators_struct { int id; char server_ip[128]; int port; int status; FILE *f; char TMP_FILE[1024]; } terminators_t; pthread_t thread[MAX_THR]; terminators_t *terminator; int terminator_count = 0; int k = 0; char server_id_str[64] = ""; int server_id = 0; int proxy_is_configured = 0; int proxy_is_running = 0; // MAIN FUNCTION int main(int argc, char *argv[]) { int i = 0; m2_init("Starting M2 Terminator Check Script\n"); // check if proxy server is configured in M2 check_if_proxy_configured(); // check if proxy is running check_if_proxy_running(); if (proxy_is_configured == 1 && proxy_is_running == 0) { m2_log("Proxy is configured in GUI but " PROXY_NAME " is not running on this server\n"); m2_log("Terminator check can only be executed on proxy server\n"); exit(0); } // check server ip only when script is running in freeswitch servers if (proxy_is_configured != 1) { // try another location if (m2_get_variable("server_id", server_id_str)) { exit(1); } server_id = atoi(server_id_str); // just to be sure if (server_id == 0) { m2_log("Warning server_id is not set in " CONFPATH ". Default value will be used (server_id = 1)\n"); server_id = 1; } } // get terminator data m2_log("Fetching terminator data from database\n"); if (get_terminators()) { exit(1); } if (terminator_count == 0) { m2_log("No suitable terminators were found\n"); exit(1); } m2_log("Checking terminator availability\n"); int c = 0; c = terminator_count / MAX_THR; for (i = 0; i < c; i++) { threads_execution(MAX_THR); } threads_execution(terminator_count - c * MAX_THR); for (i = 0; i < terminator_count; i++) { if (terminator[i].status == 1) { m2_log("Updating terminator: [%d] %s:%d ALIVE = 1\n", terminator[i].id, terminator[i].server_ip, terminator[i].port); update_terminator_status(i, 1); } else { m2_log("Updating terminator: [%d] %s:%d ALIVE = 0\n", terminator[i].id, terminator[i].server_ip, terminator[i].port); update_terminator_status(i, 0); } } if (terminator) { free(terminator); terminator = NULL; } m2_log("Script finished\n"); pthread_exit(NULL); return 0; } // get terminator data from database int get_terminators() { MYSQL_RES *result; MYSQL_ROW row; // get all devices that are checked for monitoring char sqlcmd[2048] = ""; if (proxy_is_configured) { sprintf(sqlcmd, "SELECT id, ipaddr, port FROM devices WHERE periodic_check = 1 AND tp = 1 AND tp_active = 1"); } else { sprintf(sqlcmd, "SELECT id, ipaddr, port FROM devices WHERE periodic_check = 1 AND server_id = %d AND tp = 1 AND tp_active = 1", server_id); } if (m2_mysql_query(sqlcmd)) { return 1; } result = mysql_store_result(&mysql); if (result) { while ((row = mysql_fetch_row(result)) != NULL) { if (row[0] && row[1] && row[2]) { terminator = realloc(terminator, (terminator_count + 1) * sizeof(terminators_t)); terminator[terminator_count].id = atoi(row[0]); terminator[terminator_count].port = atoi(row[2]); terminator[terminator_count].status = 0; strcpy(terminator[terminator_count].server_ip, row[1]); terminator_count++; } } mysql_free_result(result); } return 0; } void threads_execution(int n) { int thr_error = 0; int i = 0; for (i = 0; i < n; i++) { thr_error = pthread_create(&thread[i], NULL, check_terminator_status, (void *)(intptr_t)k); if (thr_error) { m2_log("ERROR; return code from pthread_create() is %d\n", thr_error); exit(1); } k++; } for (i = 0; i < n; i++) { pthread_join(thread[i], NULL); } } void *check_terminator_status(void *arg) { char buffer[64] = ""; char cmd[2048] = ""; char popen_arg[1064]; int i; i = (intptr_t)arg; sprintf(terminator[i].TMP_FILE, "/tmp/m2_terminator_check_terminator_id_%d.txt", terminator[i].id); // clear tmp file sprintf(cmd, "echo '' > %s &> /dev/null", terminator[i].TMP_FILE); system(cmd); // send SIP OPTIONS request to terminator (in background) sprintf(cmd, "timeout %d sipsak -H localhost -s sip:101@%s:%d -v > %s", SIPSAK_TIMEOUT, terminator[i].server_ip, terminator[i].port, terminator[i].TMP_FILE); system(cmd); // open file that contains SIP response long int size = 0; terminator[i].f = fopen(terminator[i].TMP_FILE, "r"); if (terminator[i].f == NULL) { m2_log("Cannot open %s\n", terminator[i].TMP_FILE); exit(1); } fseek(terminator[i].f, 0L, SEEK_END); size = ftell(terminator[i].f); fclose(terminator[i].f); // check if file is not empty if (size > 0) { // check if file contains any SIP response (it should include 'SIP/2.0' in the response) sprintf(popen_arg, "cat %s | grep 'SIP/2.0' | wc -l", terminator[i].TMP_FILE); FILE *pipe = popen(popen_arg, "r"); if (pipe == NULL) { m2_log("Cannot open %s\n", terminator[i].TMP_FILE); pthread_exit(NULL); exit(1); } fgets(buffer, 64, pipe); if (atoi(buffer) > 0) { terminator[i].status = 1; pclose(pipe); } else { terminator[i].status = 0; pclose(pipe); } } pthread_exit(NULL); } void update_terminator_status(int id, int status) { char sqlcmd[1024] = ""; sprintf(sqlcmd, "UPDATE devices SET alive = %d WHERE id = %d", status, terminator[id].id); if (m2_mysql_query(sqlcmd)) { exit(1); } } void check_if_proxy_configured() { MYSQL_RES *result; MYSQL_ROW row; if (m2_mysql_query("SELECT COUNT(*) FROM servers WHERE server_type = 'proxy' AND active = 1")) { return; } result = mysql_store_result(&mysql); if (result) { while ((row = mysql_fetch_row(result)) != NULL) { if (row[0]) { proxy_is_configured = atoi(row[0]); } } mysql_free_result(result); } } void check_if_proxy_running() { char buffer[128] = ""; // count how many processes exists with the same path FILE *pipe = popen("ps -ef | grep -v grep | grep -v '/bin/sh -c' | grep -v launcher.sh | grep " PROXY_NAME " | wc -l", "r"); fgets(buffer, 64, pipe); // if more than one, exit current process if (atoi(buffer) > 1) { proxy_is_running = 1; m2_log(PROXY_NAME " is running\n"); } pclose(pipe); }