#include #include #include #include #include #include #include "triton.h" #include "events.h" #include "ppp.h" #include "cli.h" #include "utils.h" #include "log.h" #include "memdebug.h" #define CELL_SIZE 128 #define DEF_COLUMNS "ifname,username,calling-sid,ip,rate-limit,type,state,uptime" struct column_t { struct list_head entry; const char *name; const char *desc; void (*print)(const struct ppp_t *ppp, char *buf); }; struct col_t { struct list_head entry; struct column_t *column; int width; }; struct row_t { struct list_head entry; char *match_key; char *order_key; struct list_head cell_list; }; struct cell_t { struct list_head entry; struct col_t *col; char buf[CELL_SIZE + 1]; }; static LIST_HEAD(col_list); void __export cli_show_ses_register(const char *name, const char *desc, void (*print)(const struct ppp_t *ppp, char *buf)) { struct column_t *c = malloc(sizeof(*c)); c->name = name; c->desc = desc; c->print = print; list_add_tail(&c->entry, &col_list); } static void show_ses_help(char * const *f, int f_cnt, void *cli) { struct column_t *col; char buf[129]; cli_send(cli, "show sessions [columns] [order ] [match ] - shows sessions\r\n"); cli_send(cli, "\tcolumns:\r\n"); list_for_each_entry(col, &col_list, entry) { snprintf(buf, 128, "\t\t%s - %s\r\n", col->name, col->desc); cli_send(cli, buf); } } static struct column_t *find_column(const char *name) { struct column_t *col; list_for_each_entry(col, &col_list, entry) { if (strcmp(col->name, name)) continue; return col; } return NULL; } static void free_row(struct row_t *row) { struct cell_t *cell; while (!list_empty(&row->cell_list)) { cell = list_entry(row->cell_list.next, typeof(*cell), entry); list_del(&cell->entry); _free(cell); } _free(row); } static void insert_row(struct list_head *list, struct row_t *row) { struct row_t *row2, *row3; row3 = NULL; list_for_each_entry(row2, list, entry) { if (strcmp(row->order_key, row2->order_key) <= 0) { row3 = row2; break; } } if (row3) list_add_tail(&row->entry, &row3->entry); else list_add_tail(&row->entry, list); } static int show_ses_exec(const char *cmd, char * const *f, int f_cnt, void *cli) { char *columns = NULL; struct column_t *match_key = NULL; char *match_pattern = NULL; struct column_t *order_key = NULL; pcre *re = NULL; const char *pcre_err; int pcre_offset; struct column_t *column; struct col_t *col; struct row_t *row; struct cell_t *cell; char *ptr1, *ptr2; int i, n, total_width, def_columns = 0; struct ppp_t *ppp; char *buf = NULL; LIST_HEAD(c_list); LIST_HEAD(r_list); LIST_HEAD(t_list); for (i = 2; i < f_cnt; i++) { if (!strcmp(f[i], "order")) { if (i == f_cnt - 1) return CLI_CMD_SYNTAX; order_key = find_column(f[++i]); if (!order_key) { cli_sendv(cli, "unknown column %s\r\n", f[i]); return CLI_CMD_OK; } } else if (!strcmp(f[i], "match")) { if (i == f_cnt - 2) return CLI_CMD_SYNTAX; match_key = find_column(f[++i]); if (!match_key) { cli_sendv(cli, "unknown column %s\r\n", f[i]); return CLI_CMD_OK; } match_pattern = f[++i]; } else if (!columns) columns = f[i]; else return CLI_CMD_SYNTAX; } if (match_key) { re = pcre_compile2(match_pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); if (!re) { cli_sendv(cli, "match: %s at %i\r\n", pcre_err, pcre_offset); return CLI_CMD_OK; } } if (!columns) { columns = DEF_COLUMNS; def_columns = 1; } columns = _strdup(columns); ptr1 = columns; while (1) { ptr2 = strchr(ptr1, ','); if (ptr2) *ptr2 = 0; column = find_column(ptr1); if (column) { col = _malloc(sizeof(*col)); col->column = column; col->width = strlen(column->name); list_add_tail(&col->entry, &c_list); } else { if (!def_columns) { cli_sendv(cli, "unknown column %s\r\n", ptr1); _free(columns); goto out; } } if (!ptr2) break; ptr1 = ptr2 + 1; } _free(columns); pthread_rwlock_rdlock(&ppp_lock); list_for_each_entry(ppp, &ppp_list, entry) { row = _malloc(sizeof(*row)); if (!row) goto oom; memset(row, 0, sizeof(*row)); INIT_LIST_HEAD(&row->cell_list); if (match_key || order_key) list_add_tail(&row->entry, &t_list); else list_add_tail(&row->entry, &r_list); list_for_each_entry(col, &c_list, entry) { cell = _malloc(sizeof(*cell)); if (!cell) goto oom; cell->col = col; list_add_tail(&cell->entry, &row->cell_list); col->column->print(ppp, cell->buf); n = strlen(cell->buf); if (n > col->width) col->width = n; if (col->column == order_key) row->order_key = cell->buf; if (col->column == match_key) row->match_key = cell->buf; } } pthread_rwlock_unlock(&ppp_lock); if (order_key || match_key) { while(!list_empty(&t_list)) { row = list_entry(t_list.next, typeof(*row), entry); list_del(&row->entry); if (match_key) { if (pcre_exec(re, NULL, row->match_key, strlen(row->match_key), 0, 0, NULL, 0) < 0) { free_row(row); continue; } } if (order_key) insert_row(&r_list, row); else list_add_tail(&row->entry, &r_list); } } total_width = -1; list_for_each_entry(col, &c_list, entry) total_width += col->width + 3; buf = _malloc(total_width + 3); if (!buf) goto oom; ptr1 = buf; list_for_each_entry(col, &c_list, entry) { n = strlen(col->column->name); if (col->width > n + 1) { ptr2 = ptr1; memset(ptr1, ' ', col->width/2 - n/2 + 1); ptr1 += col->width/2 - n/2 + 1; sprintf(ptr1, "%s", col->column->name); ptr1 = strchr(ptr1, 0); memset(ptr1, ' ', col->width + 2 - (ptr1 - ptr2)); ptr1 += col->width + 2 - (ptr1 - ptr2); *ptr1 = '|'; ptr1++; } else if (col->width > n) { sprintf(ptr1, " %s |", col->column->name); ptr1 = strchr(ptr1, 0); } else { sprintf(ptr1, " %s |", col->column->name); ptr1 = strchr(ptr1, 0); } } strcpy(ptr1 - 1, "\r\n"); cli_send(cli, buf); ptr1 = buf; list_for_each_entry(col, &c_list, entry) { memset(ptr1, '-', col->width + 2); ptr1 += col->width + 2; *ptr1 = '+'; ptr1++; } strcpy(ptr1 - 1, "\r\n"); cli_send(cli, buf); while (!list_empty(&r_list)) { row = list_entry(r_list.next, typeof(*row), entry); ptr1 = buf; list_for_each_entry(cell, &row->cell_list, entry) { ptr2 = ptr1; sprintf(ptr1, " %s ", cell->buf); ptr1 = strchr(ptr1, 0); n = ptr1 - ptr2; if (n - 2 < cell->col->width) { memset(ptr1, ' ', cell->col->width + 2 - (ptr1 - ptr2)); ptr1 += cell->col->width + 2 - (ptr1 - ptr2); } *ptr1 = '|'; ptr1++; } strcpy(ptr1 - 1, "\r\n"); cli_send(cli, buf); list_del(&row->entry); free_row(row); } _free(buf); out: while (!list_empty(&c_list)) { col = list_entry(c_list.next, typeof(*col), entry); list_del(&col->entry); _free(col); } if (re) pcre_free(re); return CLI_CMD_OK; oom: if (buf) _free(buf); while (!list_empty(&t_list)) { row = list_entry(t_list.next, typeof(*row), entry); list_del(&row->entry); free_row(row); } cli_send(cli, "out of memory"); goto out; } static void print_ifname(const struct ppp_t *ppp, char *buf) { snprintf(buf, CELL_SIZE, "%s", ppp->ifname); } static void print_username(const struct ppp_t *ppp, char *buf) { if (ppp->username) snprintf(buf, CELL_SIZE, "%s", ppp->username); else *buf = 0; } static void print_ip(const struct ppp_t *ppp, char *buf) { u_inet_ntoa(ppp->peer_ipaddr, buf); } static void print_type(const struct ppp_t *ppp, char *buf) { snprintf(buf, CELL_SIZE, "%s", ppp->ctrl->name); } static void print_state(const struct ppp_t *ppp, char *buf) { char *state; switch (ppp->state) { case PPP_STATE_STARTING: state = "start"; break; case PPP_STATE_ACTIVE: state = "active"; break; case PPP_STATE_FINISHING: state = "finish"; break; default: state = "unk"; } sprintf(buf, "%s", state); } static void print_uptime(const struct ppp_t *ppp, char *buf) { time_t uptime; int day,hour,min,sec; char time_str[14]; if (ppp->stop_time) uptime = ppp->stop_time - ppp->start_time; else { time(&uptime); uptime -= ppp->start_time; } day = uptime/ (24*60*60); uptime %= (24*60*60); hour = uptime / (60*60); uptime %= (60*60); min = uptime / 60; sec = uptime % 60; if (day) snprintf(time_str, 13, "%i.%02i:%02i:%02i", day, hour, min, sec); else snprintf(time_str, 13, "%02i:%02i:%02i", hour, min, sec); sprintf(buf, "%s", time_str); } static void print_calling_sid(const struct ppp_t *ppp, char *buf) { snprintf(buf, CELL_SIZE, "%s", ppp->ctrl->calling_station_id); } static void print_called_sid(const struct ppp_t *ppp, char *buf) { snprintf(buf, CELL_SIZE, "%s", ppp->ctrl->called_station_id); } static void print_sid(const struct ppp_t *ppp, char *buf) { snprintf(buf, CELL_SIZE, "%s", ppp->sessionid); } void __init init(void) { cli_register_simple_cmd2(show_ses_exec, show_ses_help, 2, "show", "sessions"); cli_show_ses_register("ifname", "interface name", print_ifname); cli_show_ses_register("username", "user name", print_username); cli_show_ses_register("ip", "IP address", print_ip); cli_show_ses_register("type", "VPN type", print_type); cli_show_ses_register("state", "state of session", print_state); cli_show_ses_register("uptime", "uptime", print_uptime); cli_show_ses_register("calling-sid", "calling station id", print_calling_sid); cli_show_ses_register("called-sid", "called station id", print_called_sid); cli_show_ses_register("sid", "session id", print_sid); }