1/* $NetBSD: main.c,v 1.11 2009/04/16 05:56:33 lukem Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Martin Husemann <martin@NetBSD.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <stdarg.h> 35#include <string.h> 36#include <signal.h> 37#include <time.h> 38#include <errno.h> 39#ifndef WIN32 40#include <unistd.h> 41#include <netdb.h> 42#endif 43#include <sys/types.h> 44#ifndef WIN32 45#include <sys/socket.h> 46#include <sys/ioctl.h> 47#include <sys/un.h> 48#include <netinet/in.h> 49#include <arpa/inet.h> 50#else 51#include <windows.h> 52extern char *optarg; 53int getopt(int nargc, char * const nargv[], const char *ostr); 54#define close(f) closesocket(f) 55#define sleep(s) Sleep(s*1000) 56#define vsnprintf _vsnprintf 57#define ssize_t long 58#endif 59#ifdef ERROR 60#undef ERROR 61#endif 62 63#define MAIN 64#include "monprivate.h" 65#undef MAIN 66 67#ifndef AF_LOCAL 68#define AF_LOCAL AF_UNIX 69#endif 70 71#ifdef DEBUG 72#include <ctype.h> 73#endif 74 75#include "monitor.h" 76 77/* 78 * Local function prototypes 79 */ 80static int connect_local(char *sockpath); 81static int connect_remote(char *host, int portno); 82__dead static void usage(void); 83static void mloop(void); 84static void handle_input(void); 85static void print_menu(void); 86static void print_logevent(time_t tstamp, int prio, char * what, char * msg); 87static void print_charge(time_t tstamp, int controller, int channel, int units, int estimated); 88static void print_connect(time_t tstamp, int dir, int controller, int channel, char * cfgname, char * devname, char * remphone, char * locphone); 89static void print_disconnect(time_t tstamp, int controller, int channel); 90static void print_updown(time_t tstamp, int contoller, int channel, int isup); 91static void handle_event(u_int8_t *msg, int len); 92#ifdef DEBUG 93static void dump_event(u_int8_t *msg, int len, int readflag); 94#endif 95 96static ssize_t sock_read(int fd, void *buf, size_t nbytes); 97static ssize_t sock_write(int fd, void *buf, size_t nbytes); 98 99static void mprintf(const char *fmt, ...) 100 __attribute__((__format__(__printf__, 1, 2))); 101 102/* 103 * Global variables 104 */ 105static int debug = 0; 106#define DBG_DUMPALL 0x01 107#define DBG_PSEND 0x02 108 109static int monsock = -1; 110static int state = ST_INIT; 111static int sub_state = 0; 112static int sub_state_count = 0; 113 114static int isdn_major = 0; 115static int isdn_minor = 0; 116static u_int32_t rights = 0; 117 118static char *logfilename = NULL; 119static FILE *lfp = NULL; 120 121/*--------------------------------------------------------------------------- 122 * Display usage and exit 123 *---------------------------------------------------------------------------*/ 124static void 125usage(void) 126{ 127 fprintf(stderr, "\n"); 128 fprintf(stderr, "isdnmonitor - version %02d.%02d.%d, (protocol %02d.%02d)\n", VERSION, REL, STEP, MPROT_VERSION, MPROT_REL); 129#ifdef FOREIGN 130 fprintf(stderr, " usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-p port]\n"); 131#else 132 fprintf(stderr, " usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-l path] [-p port]\n"); 133#endif 134 fprintf(stderr, " -c switch to curses fullscreen output\n"); 135 fprintf(stderr, " -d <val> debug flags (see source ...)\n"); 136 fprintf(stderr, " -dn no debug output on fullscreen display\n"); 137 fprintf(stderr, " -f <name> filename to log output to\n"); 138 fprintf(stderr, " -h <host> hostname/address to connect to\n"); 139#ifndef FOREIGN 140 fprintf(stderr, " -l <path> pathname to local domain socket to connect to\n"); 141#endif 142 fprintf(stderr, " -p <port> portnumber to use to connect to remote host\n"); 143 exit(1); 144} 145 146/*--------------------------------------------------------------------------- 147 * Parse command line, startup monitor client 148 *---------------------------------------------------------------------------*/ 149int main(int argc, char **argv) 150{ 151 int i; 152 153#ifdef WIN32 154 WSADATA wsCaps; 155 WSAStartup(MAKEWORD(2, 0), &wsCaps); 156#endif 157 158 portno = DEF_MONPORT; 159 devbuf[0] = '\0'; 160 161#ifndef FOREIGN 162 while((i = getopt(argc, argv, "cd:f:h:p:l:")) != -1) 163#else 164 while((i = getopt(argc, argv, "cd:f:h:p:")) != -1) 165#endif 166 { 167 switch (i) 168 { 169 case 'c': 170 fullscreen = 1; 171 break; 172 case 'd': 173 if (*optarg == 'n') 174 { 175 debug_noscreen = 1; 176 } 177 else 178 { 179 if ((sscanf(optarg, "%i", &debug)) != 1) 180 usage(); 181 } 182 break; 183 case 'f': 184 logfilename = optarg; 185 break; 186 case 'h': 187 hostname = optarg; 188 break; 189#ifndef FOREIGN 190 case 'l': 191 sockpath = optarg; 192 break; 193#endif 194 case 'p': 195 if ((sscanf(optarg, "%i", &portno)) != 1) 196 usage(); 197 break; 198 default: 199 usage(); 200 break; 201 } 202 } 203 204#ifndef FOREIGN 205 if (hostname && sockpath) 206 { 207 fprintf(stderr, "Error: can not use local socket path on remote machine\n" 208 "conflicting options -h and -l!\n"); 209 return 1; 210 } 211 212 if (sockpath) 213 { 214 monsock = connect_local(sockpath); 215 } 216 else if (hostname) 217#else 218 if (hostname) 219#endif 220 221 { 222 monsock = connect_remote(hostname, portno); 223 } 224 else 225 { 226 usage(); 227 } 228 229 if (monsock == -1) 230 { 231 fprintf(stderr, "Could not connect to i4b isdn daemon.\n"); 232 return 1; 233 } 234 235 if (logfilename != NULL) 236 { 237 if ((lfp = fopen(logfilename, "w")) == NULL) 238 { 239 fprintf(stderr, "could not open logfile [%s], %s\n", logfilename, strerror(errno)); 240 exit(1); 241 } 242 } 243 244#ifndef WIN32 245 signal(SIGPIPE, SIG_IGN); 246#endif 247 248 mloop(); 249 250 close(monsock); 251 252 return 0; 253} 254 255/*--------------------------------------------------------------------------- 256 * Connect via tcp/ip. 257 * Return socket if successful, -1 on error. 258 ---------------------------------------------------------------------------*/ 259static int 260connect_remote(char *host, int portnum) 261{ 262 struct sockaddr_in sa; 263 struct hostent *h; 264 int remotesockfd; 265 266 h = gethostbyname(host); 267 268 if (!h) 269 { 270 fprintf(stderr, "could not resolve hostname '%s'\n", host); 271 exit(1); 272 } 273 274 remotesockfd = socket(AF_INET, SOCK_STREAM, 0); 275 276 if (remotesockfd == -1) 277 { 278 fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno)); 279 exit(1); 280 } 281 282 memset(&sa, 0, sizeof(sa)); 283 284#ifdef BSD4_4 285 sa.sin_len = sizeof(sa); 286#endif 287 sa.sin_family = AF_INET; 288 sa.sin_port = htons(portnum); 289 290 memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof(sa.sin_addr.s_addr)); 291 292 if (connect(remotesockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) 293 { 294 fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno)); 295 exit(1); 296 } 297 298 return remotesockfd; 299} 300 301#ifndef FOREIGN 302/*--------------------------------------------------------------------------- 303 * Connect local. 304 * Return socket on success, -1 on failure. 305 *---------------------------------------------------------------------------*/ 306static int 307connect_local(char *clsockpath) 308{ 309 int s; 310 struct sockaddr_un sa; 311 312 /* check path length */ 313 if (strlen(clsockpath) >= sizeof(sa.sun_path)) 314 { 315 fprintf(stderr, "pathname to long for local socket: %s\n", 316 clsockpath); 317 exit(1); 318 } 319 320 /* create and setup socket */ 321 s = socket(AF_LOCAL, SOCK_STREAM, 0); 322 323 if (s == -1) 324 { 325 fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno)); 326 exit(1); 327 } 328 329 memset(&sa, 0, sizeof(sa)); 330 331 sa.sun_len = sizeof(sa); 332 sa.sun_family = AF_LOCAL; 333 strlcpy(sa.sun_path, clsockpath, sizeof(sa.sun_path)); 334 335 if (connect(s, (struct sockaddr *)&sa, sizeof(sa))) 336 { 337 fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", clsockpath, strerror(errno)); 338 } 339 340 return s; 341} 342#endif 343 344/*---------------------------------------------------------------------------* 345 * data from keyboard available, read and process it 346 *---------------------------------------------------------------------------*/ 347#ifndef WIN32 348static void 349kbdrdhdl(void) 350{ 351 int ch = getch(); 352 353 switch (ch) 354 { 355 case 0x0c: /* control L */ 356 wrefresh(curscr); 357 break; 358 359 case '\n': 360 case '\r': 361 do_menu(); 362 break; 363 } 364} 365#endif 366 367/*--------------------------------------------------------------------------- 368 * main event loop 369 *---------------------------------------------------------------------------*/ 370static void 371mloop() 372{ 373 struct pollfd set[2]; 374 375 set[0].fd = STDIN_FILENO; 376 set[0].events = POLLIN; 377 set[1].fd = monsock; 378 set[1].events = POLLIN; 379 for (;;) 380 { 381 poll(set, 2, INFTIM); 382 383 if (set[0].revents & POLLIN) 384 { 385#ifndef WIN32 386 if (fullscreen && curses_ready) 387 kbdrdhdl(); 388 else 389#endif 390 if (!fullscreen) 391 handle_input(); 392 else 393 getchar(); 394 } 395 396 if (set[1].revents & POLLIN) 397 { 398 u_int8_t buf[8192]; 399 int bytes, ret; 400 401 /* Network transfer may deliver two or more packets concatenated. 402 * Peek at the header and read only one event at a time... */ 403 404 bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK); 405 406 if (bytes == 0) 407 { 408 close(monsock); 409 410#ifndef WIN32 411 if (curses_ready) 412 { 413 endwin(); 414 curses_ready = 0; 415 } 416#endif 417 418 mprintf("remote isdnd has closed our connection\n"); 419 exit(0); 420 } 421 else if (bytes < 0) 422 { 423 fprintf(stderr, "recv error: %s\n", strerror(errno)); 424 close(monsock); 425 exit(1); 426 } 427 428 if (bytes < I4B_MON_EVNT_HDR) 429 continue; /* errh? something must be wrong... */ 430 431 bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN); 432 433 if (bytes >= (int)sizeof(buf)) 434 { 435 fprintf(stderr, "mloop: socket recv buffer overflow %d!\n", bytes); 436 break; 437 } 438 439 /* now we know the size, it fits, so lets read it! */ 440 441 ret = sock_read(monsock, buf, bytes); 442 443 if (ret == 0) 444 { 445 close(monsock); 446#ifndef WIN32 447 if (curses_ready) 448 endwin(); 449#endif 450 mprintf("remote isdnd has closed our connection\n"); 451 exit(0); 452 } 453 else if (ret < 0) 454 { 455 mprintf("error reading from isdnd: %s", strerror(errno)); 456 break; 457 } 458#ifdef DEBUG 459 if (debug & DBG_DUMPALL) 460 dump_event(buf, ret, 1); 461#endif 462 handle_event(buf, ret); 463 } 464 } 465} 466 467#ifdef DEBUG 468/* 469 * Dump a complete event packet. 470 */ 471static void dump_event(u_int8_t *msg, int len, int doread) 472{ 473 int i; 474 475 if (doread) 476 mprintf("read from socket:"); 477 else 478 mprintf("write to socket:"); 479 480 for (i = 0; i < len; i++) 481 { 482 if (i % 8 == 0) 483 mprintf("\n%02d: ", i); 484 mprintf("0x%02x %c ", msg[i], isprint(msg[i]) ? msg[i] : '.'); 485 } 486 mprintf("\n"); 487} 488#endif 489 490static void 491print_logevent(time_t tstamp, int prio, char * what, char * msg) 492{ 493 char buf[256]; 494 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 495 mprintf("log: %s prio %d what=%s msg=%s\n", buf, prio, what, msg); 496 497#ifndef WIN32 498 if (fullscreen) 499 { 500 if ((!debug_noscreen) || (debug_noscreen && (((strcmp(what, "DBG"))) != 0))) 501 { 502/* 503 * FreeBSD-current integrated ncurses. Since then it is no longer possible 504 * to write to the last column in the logfilewindow without causing an 505 * automatic newline to occur resulting in a blank line in that window. 506 */ 507#ifdef __FreeBSD__ 508#include <osreldate.h> 509#endif 510#if defined(__FreeBSD_version) && __FreeBSD_version >= 400009 511#warning "FreeBSD ncurses is buggy: write to last column = auto newline!" 512 wprintw(lower_w, "%s %s %-.*s\n", buf, what, 513 COLS-((strlen(buf))+(strlen(what))+3), msg); 514#else 515 wprintw(lower_w, "%s %s %-.*s\n", buf, what, 516 (int)(COLS-((strlen(buf))+(strlen(what))+2)), msg); 517#endif 518 wrefresh(lower_w); 519 } 520 } 521#endif 522} 523 524static void 525print_charge(time_t tstamp, int controller, int channel, int units, int estimated) 526{ 527 char buf[256]; 528 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 529 mprintf("%s: controller %d, channel %d, charge = %d%s\n", 530 buf, controller, channel, units, estimated ? " (estimated)" : ""); 531#ifndef WIN32 532 if (fullscreen) 533 { 534 if (estimated) 535 display_ccharge(CHPOS(controller, channel), units); 536 else 537 display_charge(CHPOS(controller, channel), units); 538 } 539#endif 540} 541 542/* 543 * Print a connect event. 544 * A real monitor would allocate state info for "channel" on this 545 * event. 546 */ 547static void print_connect( 548 time_t tstamp, /* server time of event */ 549 int outgoing, /* 0 = incoming, 1 = outgoing */ 550 int controller, /* controller number */ 551 int channel, /* channel no, used to identify this connection until disconnect */ 552 char * cfgname, /* name of config entry/connection */ 553 char * devnam, /* device used (e.g. isp0) */ 554 char * remphone, /* phone no of remote side */ 555 char * locphone) /* local phone no */ 556{ 557 char buf[256]; 558 559 if (channel == 0) 560 remstate[controller].ch1state = 1; 561 else 562 remstate[controller].ch2state = 1; 563 564 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 565 566 if (outgoing) 567 mprintf("%s: calling out to '%s' [from msn: '%s']", 568 buf, remphone, locphone); 569 else 570 mprintf("%s: incoming call from '%s' [to msn: '%s']", 571 buf, remphone, locphone); 572 mprintf(", controller %d, channel %d, config '%s' on device '%s'\n", 573 controller, channel, cfgname, devnam); 574 575#ifndef WIN32 576 if (fullscreen) 577 display_connect(CHPOS(controller, channel), outgoing, cfgname, remphone, devnam); 578#endif 579} 580 581/* 582 * Print a disconnect event. 583 * A real monitor could free the "per connection" state 584 * for this channel now 585 */ 586static void 587print_disconnect(time_t tstamp, int controller, int channel) 588{ 589 char buf[256]; 590 591 if (channel == 0) 592 remstate[controller].ch1state = 0; 593 else 594 remstate[controller].ch2state = 0; 595 596 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 597 598 mprintf("%s: controller %d, channel %d disconnected\n", 599 buf, controller, channel); 600 601#ifndef WIN32 602 if (fullscreen) 603 display_disconnect(CHPOS(controller, channel)); 604#endif 605} 606 607/* 608 * Print an up- or down event 609 */ 610static void 611print_updown(time_t tstamp, int controller, int channel, int isup) 612{ 613 char buf[256]; 614 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 615 mprintf("%s: channel %d is %s\n", 616 buf, channel, isup ? "up" : "down"); 617} 618 619/* 620 * Print l1 / l2 status 621 */ 622static void 623print_l12stat(time_t tstamp, int controller, int layer, int status) 624{ 625 char buf[256]; 626 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 627 628 mprintf("%s: layer %d change on controller %d: %s\n", 629 buf, layer, controller, status ? "up" : "down"); 630#ifndef WIN32 631 if (fullscreen) 632 display_l12stat(controller, layer, status); 633#endif 634} 635 636/* 637 * Print TEI 638 */ 639static void 640print_tei(time_t tstamp, int controller, int tei) 641{ 642 char buf[256]; 643 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 644 645 mprintf("%s: controller %d, TEI is %d\n", 646 buf, controller, tei); 647 648#ifndef WIN32 649 if (fullscreen) 650 display_tei(controller, tei); 651#endif 652} 653 654/* 655 * Print accounting information 656 */ 657static void 658print_acct(time_t tstamp, int controller, int channel, int obytes, int obps, 659 int ibytes, int ibps) 660{ 661 char buf[256]; 662 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp)); 663 664 mprintf("%s: controller %d, channel %d: %d obytes, %d obps, %d ibytes, %d ibps\n", 665 buf, controller, channel, obytes, obps, ibytes, ibps); 666#ifndef WIN32 667 if (fullscreen) 668 display_acct(CHPOS(controller, channel), obytes, obps, ibytes, ibps); 669#endif 670} 671 672static void 673print_initialization(void) 674{ 675#ifndef WIN32 676 if (fullscreen) 677 { 678 if (curses_ready == 0) 679 init_screen(); 680 } 681 else 682#endif 683 { 684 print_menu(); 685 } 686} 687 688/* 689 * Dispatch one message received from the daemon. 690 */ 691static void 692handle_event(u_int8_t *msg, int len) 693{ 694 u_int8_t cmd[I4B_MON_ICLIENT_SIZE]; 695 int local; 696 u_int32_t net; 697 u_int32_t mask; 698 u_int32_t who; 699 static int first = 1; 700 701 switch (state) 702 { 703 case ST_INIT: /* initial data */ 704 705 isdn_major = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMAJOR); 706 isdn_minor = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMINOR); 707 nctrl = I4B_GET_2B(msg, I4B_MON_IDATA_NUMCTRL); 708 nentries = I4B_GET_2B(msg, I4B_MON_IDATA_NUMENTR); 709 rights = I4B_GET_4B(msg, I4B_MON_IDATA_CLACCESS); 710 711 mprintf("remote protocol version is %02d.%02d\n", isdn_major, isdn_minor); 712 713 if (isdn_major != MPROT_VERSION || isdn_minor != MPROT_REL) 714 { 715 fprintf(stderr, "ERROR, remote protocol version mismatch:\n"); 716 fprintf(stderr, "\tremote major version is %02d, local major version is %02d\n", isdn_major, MPROT_VERSION); 717 fprintf(stderr, "\tremote minor version is %02d, local minor version is %02d\n", isdn_minor, MPROT_REL); 718 exit(1); 719 } 720 721 mprintf("our rights = 0x%x\n", rights); 722 723 sub_state = 0; 724 first = 1; 725 726 if (nctrl > 0) 727 { 728 state = ST_ICTRL; 729 } 730 else if (nentries > 0) 731 { 732 state = ST_IDEV; 733 } 734 else 735 { 736 state = ST_ANYEV; 737 sleep(2); 738 print_initialization(); 739 } 740 741 /* set maximum event mask */ 742 I4B_PREP_CMD(cmd, I4B_MON_CCMD_SETMASK); 743 I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMAJOR, MPROT_VERSION); 744 I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMINOR, MPROT_REL); 745 I4B_PUT_4B(cmd, I4B_MON_ICLIENT_EVENTS, ~0U); 746 747#ifdef DEBUG 748 if (debug & DBG_DUMPALL) 749 dump_event(cmd, sizeof(cmd), 0); 750#endif 751 752 if ((sock_write(monsock, cmd, sizeof(cmd))) == -1) 753 { 754 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 755 exit(1); 756 } 757 break; 758 759 case ST_ICTRL: /* initial controller list */ 760 if (first) 761 { 762 first = 0; 763 mprintf("%d controller(s) found:\n", nctrl); 764 } 765 mprintf("\tcontroller %d: %s\n", sub_state++, msg+I4B_MON_ICTRL_NAME); 766 767 if (sub_state >= nctrl) 768 { 769 sub_state = 0; 770 first = 1; 771 if (nentries > 0) 772 { 773 state = ST_IDEV; /* end of list reached */ 774 } 775 else 776 { 777 state = ST_ANYEV; 778 sleep(2); 779 print_initialization(); 780 } 781 } 782 break; 783 784 case ST_IDEV: /* initial entry devicename list */ 785 if (first) 786 { 787 first = 0; 788 mprintf("%d entries found:\n", nentries); 789 } 790 791 mprintf("\tentry %d: device %s\n", sub_state++, msg+I4B_MON_IDEV_NAME); 792 793 strlcat(devbuf, msg+I4B_MON_IDEV_NAME, sizeof(devbuf)); 794 /* strlcat(devbuf, " ", sizeof(devbuf)); */ 795 796 if (sub_state >= nentries) 797 { 798 first = 1; 799 state = ST_ANYEV; /* end of list reached */ 800 sub_state = 0; 801 sleep(2); 802 print_initialization(); 803 } 804 break; 805 806 case ST_ANYEV: /* any event */ 807 switch (I4B_GET_2B(msg, I4B_MON_EVNT)) 808 { 809 case I4B_MON_DRINI_CODE: 810 state = ST_RIGHT; /* list of rights entries will follow */ 811 sub_state = 0; 812 sub_state_count = I4B_GET_2B(msg, I4B_MON_DRINI_COUNT); 813 mprintf("monitor rights:\n"); 814 break; 815 816 case I4B_MON_DCINI_CODE: 817 state = ST_CONNS; 818 sub_state = 0; 819 sub_state_count = I4B_GET_2B(msg, I4B_MON_DCINI_COUNT); 820 mprintf("monitor connections:\n"); 821 break; 822 823 case I4B_MON_LOGEVNT_CODE: 824 print_logevent(I4B_GET_4B(msg, I4B_MON_LOGEVNT_TSTAMP), 825 I4B_GET_4B(msg, I4B_MON_LOGEVNT_PRIO), 826 msg+I4B_MON_LOGEVNT_WHAT, 827 msg+I4B_MON_LOGEVNT_MSG); 828 break; 829 830 case I4B_MON_CHRG_CODE: 831 print_charge(I4B_GET_4B(msg, I4B_MON_CHRG_TSTAMP), 832 I4B_GET_4B(msg, I4B_MON_CHRG_CTRL), 833 I4B_GET_4B(msg, I4B_MON_CHRG_CHANNEL), 834 I4B_GET_4B(msg, I4B_MON_CHRG_UNITS), 835 I4B_GET_4B(msg, I4B_MON_CHRG_ESTIMATED)); 836 break; 837 838 case I4B_MON_CONNECT_CODE: 839 print_connect( 840 I4B_GET_4B(msg, I4B_MON_CONNECT_TSTAMP), 841 I4B_GET_4B(msg, I4B_MON_CONNECT_DIR), 842 I4B_GET_4B(msg, I4B_MON_CONNECT_CTRL), 843 I4B_GET_4B(msg, I4B_MON_CONNECT_CHANNEL), 844 msg+I4B_MON_CONNECT_CFGNAME, 845 msg+I4B_MON_CONNECT_DEVNAME, 846 msg+I4B_MON_CONNECT_REMPHONE, 847 msg+I4B_MON_CONNECT_LOCPHONE); 848 break; 849 850 case I4B_MON_DISCONNECT_CODE: 851 print_disconnect( 852 I4B_GET_4B(msg, I4B_MON_DISCONNECT_TSTAMP), 853 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CTRL), 854 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CHANNEL)); 855 break; 856 857 case I4B_MON_UPDOWN_CODE: 858 print_updown( 859 I4B_GET_4B(msg, I4B_MON_UPDOWN_TSTAMP), 860 I4B_GET_4B(msg, I4B_MON_UPDOWN_CTRL), 861 I4B_GET_4B(msg, I4B_MON_UPDOWN_CHANNEL), 862 I4B_GET_4B(msg, I4B_MON_UPDOWN_ISUP)); 863 break; 864 case I4B_MON_L12STAT_CODE: 865 print_l12stat( 866 I4B_GET_4B(msg, I4B_MON_L12STAT_TSTAMP), 867 I4B_GET_4B(msg, I4B_MON_L12STAT_CTRL), 868 I4B_GET_4B(msg, I4B_MON_L12STAT_LAYER), 869 I4B_GET_4B(msg, I4B_MON_L12STAT_STATE)); 870 break; 871 case I4B_MON_TEI_CODE: 872 print_tei( 873 I4B_GET_4B(msg, I4B_MON_TEI_TSTAMP), 874 I4B_GET_4B(msg, I4B_MON_TEI_CTRL), 875 I4B_GET_4B(msg, I4B_MON_TEI_TEI)); 876 break; 877 case I4B_MON_ACCT_CODE: 878 print_acct( 879 I4B_GET_4B(msg, I4B_MON_ACCT_TSTAMP), 880 I4B_GET_4B(msg, I4B_MON_ACCT_CTRL), 881 I4B_GET_4B(msg, I4B_MON_ACCT_CHAN), 882 I4B_GET_4B(msg, I4B_MON_ACCT_OBYTES), 883 I4B_GET_4B(msg, I4B_MON_ACCT_OBPS), 884 I4B_GET_4B(msg, I4B_MON_ACCT_IBYTES), 885 I4B_GET_4B(msg, I4B_MON_ACCT_IBPS)); 886 break; 887 default: 888 mprintf("unknown event code: %d\n", I4B_GET_2B(msg, I4B_MON_EVNT)); 889 } 890 break; 891 892 case ST_RIGHT: /* one record in a list of monitor rights */ 893 rights = I4B_GET_4B(msg, I4B_MON_DR_RIGHTS); 894 net = I4B_GET_4B(msg, I4B_MON_DR_NET); 895 mask = I4B_GET_4B(msg, I4B_MON_DR_MASK); 896 local = I4B_GET_1B(msg, I4B_MON_DR_LOCAL); 897 898 if (local) 899 { 900 mprintf("\tlocal: rights = %x\n", rights); 901 } 902 else 903 { 904 mprintf("\tfrom: %d.%d.%d.%d, mask %d.%d.%d.%d, rights = %x\n", 905 (net >> 24) & 0x00ff, (net >> 16) & 0x00ff, (net >> 8) & 0x00ff, net & 0x00ff, 906 (mask >> 24) & 0x00ff, (mask >> 16) & 0x00ff, (mask >> 8) & 0x00ff, mask & 0x00ff, 907 rights); 908 } 909 910 sub_state++; 911 912 if (sub_state >= sub_state_count) 913 { 914 state = ST_ANYEV; 915 print_initialization(); 916 } 917 break; 918 919 case ST_CONNS: 920 who = I4B_GET_4B(msg, I4B_MON_DC_WHO); 921 rights = I4B_GET_4B(msg, I4B_MON_DC_RIGHTS); 922 923 mprintf("\tfrom: %d.%d.%d.%d, rights = %x\n", 924 (who >> 24) & 0x00ff, (who >> 16) & 0x00ff, (who >> 8) & 0x00ff, who & 0x00ff, 925 rights); 926 927 sub_state++; 928 929 if (sub_state >= sub_state_count) 930 { 931 state = ST_ANYEV; 932 print_initialization(); 933 } 934 break; 935 936 default: 937 mprintf("unknown event from remote: local state = %d, evnt = %x, len = %d\n", 938 state, I4B_GET_2B(msg, I4B_MON_EVNT), len); 939 } 940} 941 942/* 943 * Process input from user 944 */ 945static void 946handle_input() 947{ 948 char buf[1024]; 949 int channel, controller; 950 951 fgets(buf, sizeof(buf), stdin); 952 953 switch (atoi(buf)) 954 { 955 case 1: 956 { 957 u_int8_t cmd[I4B_MON_DUMPRIGHTS_SIZE]; 958 I4B_PREP_CMD(cmd, I4B_MON_DUMPRIGHTS_CODE); 959#ifdef DEBUG 960 if (debug & DBG_DUMPALL) 961 dump_event(cmd, I4B_MON_DUMPRIGHTS_SIZE, 0); 962#endif 963 964 if ((sock_write(monsock, cmd, I4B_MON_DUMPRIGHTS_SIZE)) == -1) 965 { 966 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 967 exit(1); 968 } 969 } 970 break; 971 972 case 2: 973 { 974 u_int8_t cmd[I4B_MON_DUMPMCONS_SIZE]; 975 I4B_PREP_CMD(cmd, I4B_MON_DUMPMCONS_CODE); 976#ifdef DEBUG 977 if (debug & DBG_DUMPALL) 978 dump_event(cmd, I4B_MON_DUMPMCONS_CODE, 0); 979#endif 980 981 if ((sock_write(monsock, cmd, I4B_MON_DUMPMCONS_SIZE)) == -1) 982 { 983 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 984 exit(1); 985 } 986 } 987 break; 988 989 case 3: 990 { 991 u_int8_t cmd[I4B_MON_CFGREREAD_SIZE]; 992 I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE); 993#ifdef DEBUG 994 if (debug & DBG_DUMPALL) 995 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0); 996#endif 997 998 if ((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1) 999 { 1000 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 1001 exit(1); 1002 } 1003 } 1004 break; 1005 1006 case 4: 1007 { 1008 u_int8_t cmd[I4B_MON_HANGUP_SIZE]; 1009 I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE); 1010 1011 printf("Which controller you wish to hangup? "); 1012 fgets(buf, sizeof(buf), stdin); 1013 controller = atoi(buf); 1014 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, controller); 1015 1016 printf("Which channel do you wish to hangup? "); 1017 fgets(buf, sizeof(buf), stdin); 1018 channel = atoi(buf); 1019 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, channel); 1020 1021#ifdef DEBUG 1022 if (debug & DBG_DUMPALL) 1023 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0); 1024#endif 1025 1026 if ((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1) 1027 { 1028 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 1029 exit(1); 1030 } 1031 } 1032 break; 1033 1034 case 9: 1035 close(monsock); 1036 exit(0); 1037 break; 1038 1039 default: 1040 print_menu(); 1041 break; 1042 } 1043} 1044 1045void 1046reread(void) 1047{ 1048 u_int8_t cmd[I4B_MON_CFGREREAD_SIZE]; 1049 I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE); 1050#ifdef DEBUG 1051 if (debug & DBG_DUMPALL) 1052 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0); 1053#endif 1054 if ((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1) 1055 { 1056 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 1057 exit(1); 1058 } 1059} 1060 1061void 1062hangup(int ctrl, int chan) 1063{ 1064 u_int8_t cmd[I4B_MON_HANGUP_SIZE]; 1065 1066 I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE); 1067 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, ctrl); 1068 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, chan); 1069 1070#ifdef DEBUG 1071 if (debug & DBG_DUMPALL) 1072 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0); 1073#endif 1074 1075 if ((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1) 1076 { 1077 fprintf(stderr, "sock_write failed: %s\n", strerror(errno)); 1078 exit(1); 1079 } 1080} 1081 1082/* 1083 * Display menu 1084 */ 1085static void 1086print_menu() 1087{ 1088 if (!fullscreen) 1089 { 1090 printf("Menu: <1> display rights, <2> display monitor connections,\n"); 1091 printf(" <3> reread config file, <4> hangup \n"); 1092 printf(" <9> quit isdnmonitor\n"); 1093 fflush(stdout); 1094 } 1095} 1096 1097static ssize_t 1098sock_read(int fd, void *buf, size_t nbytes) 1099{ 1100 size_t nleft; 1101 ssize_t nread; 1102 unsigned char *ptr; 1103 1104 ptr = buf; 1105 nleft = nbytes; 1106 1107 while(nleft > 0) 1108 { 1109 if ((nread = read(fd, ptr, nleft)) < 0) 1110 { 1111 if (errno == EINTR) 1112 { 1113 nread = 0; 1114 } 1115 else 1116 { 1117 return(-1); 1118 } 1119 } 1120 else if (nread == 0) 1121 { 1122 break; /* EOF */ 1123 } 1124 1125 nleft -= nread; 1126 ptr += nread; 1127 } 1128 return(nbytes - nleft); 1129} 1130 1131static ssize_t 1132sock_write(int fd, void *buf, size_t nbytes) 1133{ 1134 size_t nleft; 1135 ssize_t nwritten; 1136 unsigned char *ptr; 1137 1138 ptr = buf; 1139 nleft = nbytes; 1140 1141 while(nleft > 0) 1142 { 1143 if ((nwritten = write(fd, ptr, nleft)) <= 0) 1144 { 1145 if (errno == EINTR) 1146 { 1147 nwritten = 0; 1148 } 1149 else 1150 { 1151 return(-1); 1152 } 1153 } 1154 1155 nleft -= nwritten; 1156 ptr += nwritten; 1157 } 1158 return(nbytes); 1159} 1160 1161static void 1162mprintf(const char *fmt, ...) 1163{ 1164#define PRBUFLEN 1024 1165 char buffer[PRBUFLEN]; 1166 va_list ap; 1167 1168 va_start(ap, fmt); 1169 vsnprintf(buffer, PRBUFLEN-1, fmt, ap); 1170 va_end(ap); 1171 1172 if (!fullscreen || (fullscreen && (!curses_ready))) 1173 printf("%s", buffer); 1174 1175 if (logfilename != NULL) 1176 { 1177 fprintf(lfp, "%s", buffer); 1178 fflush(lfp); 1179 } 1180} 1181 1182/* EOF */ 1183