Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / isdn / isdnmonitor / main.c
blobb40600673377b6cbcdb512eaea922b73afb3aab1
1 /* $NetBSD: main.c,v 1.10 2008/07/15 17:51:38 perry Exp $ */
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Martin Husemann <martin@NetBSD.org>.
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.
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.
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>
52 extern char *optarg;
53 int 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
63 #define MAIN
64 #include "monprivate.h"
65 #undef MAIN
67 #ifndef AF_LOCAL
68 #define AF_LOCAL AF_UNIX
69 #endif
71 #ifdef DEBUG
72 #include <ctype.h>
73 #endif
75 #include "monitor.h"
78 * Local function prototypes
80 static int connect_local(char *sockpath);
81 static int connect_remote(char *host, int portno);
82 static void usage(void);
83 static void mloop(void);
84 static void handle_input(void);
85 static void print_menu(void);
86 static void print_logevent(time_t tstamp, int prio, char * what, char * msg);
87 static void print_charge(time_t tstamp, int controller, int channel, int units, int estimated);
88 static void print_connect(time_t tstamp, int dir, int controller, int channel, char * cfgname, char * devname, char * remphone, char * locphone);
89 static void print_disconnect(time_t tstamp, int controller, int channel);
90 static void print_updown(time_t tstamp, int contoller, int channel, int isup);
91 static void handle_event(u_int8_t *msg, int len);
92 #ifdef DEBUG
93 static void dump_event(u_int8_t *msg, int len, int readflag);
94 #endif
96 static ssize_t sock_read(int fd, void *buf, size_t nbytes);
97 static ssize_t sock_write(int fd, void *buf, size_t nbytes);
99 static void mprintf(const char *fmt, ...)
100 __attribute__((__format__(__printf__, 1, 2)));
103 * Global variables
105 static int debug = 0;
106 #define DBG_DUMPALL 0x01
107 #define DBG_PSEND 0x02
109 static int monsock = -1;
110 static int state = ST_INIT;
111 static int sub_state = 0;
112 static int sub_state_count = 0;
114 static int isdn_major = 0;
115 static int isdn_minor = 0;
116 static u_int32_t rights = 0;
118 static char *logfilename = NULL;
119 static FILE *lfp = NULL;
121 /*---------------------------------------------------------------------------
122 * Display usage and exit
123 *---------------------------------------------------------------------------*/
124 static void
125 usage()
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);
146 /*---------------------------------------------------------------------------
147 * Parse command line, startup monitor client
148 *---------------------------------------------------------------------------*/
149 int main(int argc, char **argv)
151 int i;
153 #ifdef WIN32
154 WSADATA wsCaps;
155 WSAStartup(MAKEWORD(2, 0), &wsCaps);
156 #endif
158 portno = DEF_MONPORT;
159 devbuf[0] = '\0';
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
167 switch (i)
169 case 'c':
170 fullscreen = 1;
171 break;
172 case 'd':
173 if (*optarg == 'n')
175 debug_noscreen = 1;
177 else
179 if ((sscanf(optarg, "%i", &debug)) != 1)
180 usage();
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;
204 #ifndef FOREIGN
205 if (hostname && sockpath)
207 fprintf(stderr, "Error: can not use local socket path on remote machine\n"
208 "conflicting options -h and -l!\n");
209 return 1;
212 if (sockpath)
214 monsock = connect_local(sockpath);
216 else if (hostname)
217 #else
218 if (hostname)
219 #endif
222 monsock = connect_remote(hostname, portno);
224 else
226 usage();
229 if (monsock == -1)
231 fprintf(stderr, "Could not connect to i4b isdn daemon.\n");
232 return 1;
235 if (logfilename != NULL)
237 if ((lfp = fopen(logfilename, "w")) == NULL)
239 fprintf(stderr, "could not open logfile [%s], %s\n", logfilename, strerror(errno));
240 exit(1);
244 #ifndef WIN32
245 signal(SIGPIPE, SIG_IGN);
246 #endif
248 mloop();
250 close(monsock);
252 return 0;
255 /*---------------------------------------------------------------------------
256 * Connect via tcp/ip.
257 * Return socket if successful, -1 on error.
258 ---------------------------------------------------------------------------*/
259 static int
260 connect_remote(char *host, int portnum)
262 struct sockaddr_in sa;
263 struct hostent *h;
264 int remotesockfd;
266 h = gethostbyname(host);
268 if (!h)
270 fprintf(stderr, "could not resolve hostname '%s'\n", host);
271 exit(1);
274 remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
276 if (remotesockfd == -1)
278 fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno));
279 exit(1);
282 memset(&sa, 0, sizeof(sa));
284 #ifdef BSD4_4
285 sa.sin_len = sizeof(sa);
286 #endif
287 sa.sin_family = AF_INET;
288 sa.sin_port = htons(portnum);
290 memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof(sa.sin_addr.s_addr));
292 if (connect(remotesockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
294 fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno));
295 exit(1);
298 return remotesockfd;
301 #ifndef FOREIGN
302 /*---------------------------------------------------------------------------
303 * Connect local.
304 * Return socket on success, -1 on failure.
305 *---------------------------------------------------------------------------*/
306 static int
307 connect_local(char *clsockpath)
309 int s;
310 struct sockaddr_un sa;
312 /* check path length */
313 if (strlen(clsockpath) >= sizeof(sa.sun_path))
315 fprintf(stderr, "pathname to long for local socket: %s\n",
316 clsockpath);
317 exit(1);
320 /* create and setup socket */
321 s = socket(AF_LOCAL, SOCK_STREAM, 0);
323 if (s == -1)
325 fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno));
326 exit(1);
329 memset(&sa, 0, sizeof(sa));
331 sa.sun_len = sizeof(sa);
332 sa.sun_family = AF_LOCAL;
333 strlcpy(sa.sun_path, clsockpath, sizeof(sa.sun_path));
335 if (connect(s, (struct sockaddr *)&sa, sizeof(sa)))
337 fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", clsockpath, strerror(errno));
340 return s;
342 #endif
344 /*---------------------------------------------------------------------------*
345 * data from keyboard available, read and process it
346 *---------------------------------------------------------------------------*/
347 #ifndef WIN32
348 static void
349 kbdrdhdl(void)
351 int ch = getch();
353 switch (ch)
355 case 0x0c: /* control L */
356 wrefresh(curscr);
357 break;
359 case '\n':
360 case '\r':
361 do_menu();
362 break;
365 #endif
367 /*---------------------------------------------------------------------------
368 * main event loop
369 *---------------------------------------------------------------------------*/
370 static void
371 mloop()
373 struct pollfd set[2];
375 set[0].fd = STDIN_FILENO;
376 set[0].events = POLLIN;
377 set[1].fd = monsock;
378 set[1].events = POLLIN;
379 for (;;)
381 poll(set, 2, INFTIM);
383 if (set[0].revents & POLLIN)
385 #ifndef WIN32
386 if (fullscreen && curses_ready)
387 kbdrdhdl();
388 else
389 #endif
390 if (!fullscreen)
391 handle_input();
392 else
393 getchar();
396 if (set[1].revents & POLLIN)
398 u_int8_t buf[8192];
399 int bytes, ret;
401 /* Network transfer may deliver two or more packets concatenated.
402 * Peek at the header and read only one event at a time... */
404 bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK);
406 if (bytes == 0)
408 close(monsock);
410 #ifndef WIN32
411 if (curses_ready)
413 endwin();
414 curses_ready = 0;
416 #endif
418 mprintf("remote isdnd has closed our connection\n");
419 exit(0);
421 else if (bytes < 0)
423 fprintf(stderr, "recv error: %s\n", strerror(errno));
424 close(monsock);
425 exit(1);
428 if (bytes < I4B_MON_EVNT_HDR)
429 continue; /* errh? something must be wrong... */
431 bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN);
433 if (bytes >= (int)sizeof(buf))
435 fprintf(stderr, "mloop: socket recv buffer overflow %d!\n", bytes);
436 break;
439 /* now we know the size, it fits, so lets read it! */
441 ret = sock_read(monsock, buf, bytes);
443 if (ret == 0)
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);
453 else if (ret < 0)
455 mprintf("error reading from isdnd: %s", strerror(errno));
456 break;
458 #ifdef DEBUG
459 if (debug & DBG_DUMPALL)
460 dump_event(buf, ret, 1);
461 #endif
462 handle_event(buf, ret);
467 #ifdef DEBUG
469 * Dump a complete event packet.
471 static void dump_event(u_int8_t *msg, int len, int doread)
473 int i;
475 if (doread)
476 mprintf("read from socket:");
477 else
478 mprintf("write to socket:");
480 for (i = 0; i < len; i++)
482 if (i % 8 == 0)
483 mprintf("\n%02d: ", i);
484 mprintf("0x%02x %c ", msg[i], isprint(msg[i]) ? msg[i] : '.');
486 mprintf("\n");
488 #endif
490 static void
491 print_logevent(time_t tstamp, int prio, char * what, char * msg)
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);
497 #ifndef WIN32
498 if (fullscreen)
500 if ((!debug_noscreen) || (debug_noscreen && (((strcmp(what, "DBG"))) != 0)))
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.
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);
521 #endif
524 static void
525 print_charge(time_t tstamp, int controller, int channel, int units, int estimated)
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)
534 if (estimated)
535 display_ccharge(CHPOS(controller, channel), units);
536 else
537 display_charge(CHPOS(controller, channel), units);
539 #endif
543 * Print a connect event.
544 * A real monitor would allocate state info for "channel" on this
545 * event.
547 static 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 */
557 char buf[256];
559 if (channel == 0)
560 remstate[controller].ch1state = 1;
561 else
562 remstate[controller].ch2state = 1;
564 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
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);
575 #ifndef WIN32
576 if (fullscreen)
577 display_connect(CHPOS(controller, channel), outgoing, cfgname, remphone, devnam);
578 #endif
582 * Print a disconnect event.
583 * A real monitor could free the "per connection" state
584 * for this channel now
586 static void
587 print_disconnect(time_t tstamp, int controller, int channel)
589 char buf[256];
591 if (channel == 0)
592 remstate[controller].ch1state = 0;
593 else
594 remstate[controller].ch2state = 0;
596 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
598 mprintf("%s: controller %d, channel %d disconnected\n",
599 buf, controller, channel);
601 #ifndef WIN32
602 if (fullscreen)
603 display_disconnect(CHPOS(controller, channel));
604 #endif
608 * Print an up- or down event
610 static void
611 print_updown(time_t tstamp, int controller, int channel, int isup)
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");
620 * Print l1 / l2 status
622 static void
623 print_l12stat(time_t tstamp, int controller, int layer, int status)
625 char buf[256];
626 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
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
637 * Print TEI
639 static void
640 print_tei(time_t tstamp, int controller, int tei)
642 char buf[256];
643 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
645 mprintf("%s: controller %d, TEI is %d\n",
646 buf, controller, tei);
648 #ifndef WIN32
649 if (fullscreen)
650 display_tei(controller, tei);
651 #endif
655 * Print accounting information
657 static void
658 print_acct(time_t tstamp, int controller, int channel, int obytes, int obps,
659 int ibytes, int ibps)
661 char buf[256];
662 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
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
672 static void
673 print_initialization(void)
675 #ifndef WIN32
676 if (fullscreen)
678 if (curses_ready == 0)
679 init_screen();
681 else
682 #endif
684 print_menu();
689 * Dispatch one message received from the daemon.
691 static void
692 handle_event(u_int8_t *msg, int len)
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;
701 switch (state)
703 case ST_INIT: /* initial data */
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);
711 mprintf("remote protocol version is %02d.%02d\n", isdn_major, isdn_minor);
713 if (isdn_major != MPROT_VERSION || isdn_minor != MPROT_REL)
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);
721 mprintf("our rights = 0x%x\n", rights);
723 sub_state = 0;
724 first = 1;
726 if (nctrl > 0)
728 state = ST_ICTRL;
730 else if (nentries > 0)
732 state = ST_IDEV;
734 else
736 state = ST_ANYEV;
737 sleep(2);
738 print_initialization();
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);
747 #ifdef DEBUG
748 if (debug & DBG_DUMPALL)
749 dump_event(cmd, sizeof(cmd), 0);
750 #endif
752 if ((sock_write(monsock, cmd, sizeof(cmd))) == -1)
754 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
755 exit(1);
757 break;
759 case ST_ICTRL: /* initial controller list */
760 if (first)
762 first = 0;
763 mprintf("%d controller(s) found:\n", nctrl);
765 mprintf("\tcontroller %d: %s\n", sub_state++, msg+I4B_MON_ICTRL_NAME);
767 if (sub_state >= nctrl)
769 sub_state = 0;
770 first = 1;
771 if (nentries > 0)
773 state = ST_IDEV; /* end of list reached */
775 else
777 state = ST_ANYEV;
778 sleep(2);
779 print_initialization();
782 break;
784 case ST_IDEV: /* initial entry devicename list */
785 if (first)
787 first = 0;
788 mprintf("%d entries found:\n", nentries);
791 mprintf("\tentry %d: device %s\n", sub_state++, msg+I4B_MON_IDEV_NAME);
793 strlcat(devbuf, msg+I4B_MON_IDEV_NAME, sizeof(devbuf));
794 /* strlcat(devbuf, " ", sizeof(devbuf)); */
796 if (sub_state >= nentries)
798 first = 1;
799 state = ST_ANYEV; /* end of list reached */
800 sub_state = 0;
801 sleep(2);
802 print_initialization();
804 break;
806 case ST_ANYEV: /* any event */
807 switch (I4B_GET_2B(msg, I4B_MON_EVNT))
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;
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;
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;
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;
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;
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;
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));
890 break;
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);
898 if (local)
900 mprintf("\tlocal: rights = %x\n", rights);
902 else
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);
910 sub_state++;
912 if (sub_state >= sub_state_count)
914 state = ST_ANYEV;
915 print_initialization();
917 break;
919 case ST_CONNS:
920 who = I4B_GET_4B(msg, I4B_MON_DC_WHO);
921 rights = I4B_GET_4B(msg, I4B_MON_DC_RIGHTS);
923 mprintf("\tfrom: %d.%d.%d.%d, rights = %x\n",
924 (who >> 24) & 0x00ff, (who >> 16) & 0x00ff, (who >> 8) & 0x00ff, who & 0x00ff,
925 rights);
927 sub_state++;
929 if (sub_state >= sub_state_count)
931 state = ST_ANYEV;
932 print_initialization();
934 break;
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);
943 * Process input from user
945 static void
946 handle_input()
948 char buf[1024];
949 int channel, controller;
951 fgets(buf, sizeof(buf), stdin);
953 switch (atoi(buf))
955 case 1:
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
964 if ((sock_write(monsock, cmd, I4B_MON_DUMPRIGHTS_SIZE)) == -1)
966 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
967 exit(1);
970 break;
972 case 2:
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
981 if ((sock_write(monsock, cmd, I4B_MON_DUMPMCONS_SIZE)) == -1)
983 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
984 exit(1);
987 break;
989 case 3:
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
998 if ((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1)
1000 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1001 exit(1);
1004 break;
1006 case 4:
1008 u_int8_t cmd[I4B_MON_HANGUP_SIZE];
1009 I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
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);
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);
1021 #ifdef DEBUG
1022 if (debug & DBG_DUMPALL)
1023 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1024 #endif
1026 if ((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1028 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1029 exit(1);
1032 break;
1034 case 9:
1035 close(monsock);
1036 exit(0);
1037 break;
1039 default:
1040 print_menu();
1041 break;
1045 void
1046 reread(void)
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)
1056 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1057 exit(1);
1061 void
1062 hangup(int ctrl, int chan)
1064 u_int8_t cmd[I4B_MON_HANGUP_SIZE];
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);
1070 #ifdef DEBUG
1071 if (debug & DBG_DUMPALL)
1072 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1073 #endif
1075 if ((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1077 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1078 exit(1);
1083 * Display menu
1085 static void
1086 print_menu()
1088 if (!fullscreen)
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);
1097 static ssize_t
1098 sock_read(int fd, void *buf, size_t nbytes)
1100 size_t nleft;
1101 ssize_t nread;
1102 unsigned char *ptr;
1104 ptr = buf;
1105 nleft = nbytes;
1107 while(nleft > 0)
1109 if ((nread = read(fd, ptr, nleft)) < 0)
1111 if (errno == EINTR)
1113 nread = 0;
1115 else
1117 return(-1);
1120 else if (nread == 0)
1122 break; /* EOF */
1125 nleft -= nread;
1126 ptr += nread;
1128 return(nbytes - nleft);
1131 static ssize_t
1132 sock_write(int fd, void *buf, size_t nbytes)
1134 size_t nleft;
1135 ssize_t nwritten;
1136 unsigned char *ptr;
1138 ptr = buf;
1139 nleft = nbytes;
1141 while(nleft > 0)
1143 if ((nwritten = write(fd, ptr, nleft)) <= 0)
1145 if (errno == EINTR)
1147 nwritten = 0;
1149 else
1151 return(-1);
1155 nleft -= nwritten;
1156 ptr += nwritten;
1158 return(nbytes);
1161 static void
1162 mprintf(const char *fmt, ...)
1164 #define PRBUFLEN 1024
1165 char buffer[PRBUFLEN];
1166 va_list ap;
1168 va_start(ap, fmt);
1169 vsnprintf(buffer, PRBUFLEN-1, fmt, ap);
1170 va_end(ap);
1172 if (!fullscreen || (fullscreen && (!curses_ready)))
1173 printf("%s", buffer);
1175 if (logfilename != NULL)
1177 fprintf(lfp, "%s", buffer);
1178 fflush(lfp);
1182 /* EOF */