Add a manual page explaining the format of /etc/manpath.config.
[dragonfly/vkernel-mp.git] / usr.sbin / i4b / isdnmonitor / main.c
blobe9bd6ea3ec75047c5361d5a4bf146733673d7ec2
1 /*
2 * Copyright (c) 1998,1999 Martin Husemann. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 * 4. Altered versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software and/or documentation.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 *---------------------------------------------------------------------------
33 * i4b daemon - network monitor client
34 * -----------------------------------
36 * $Id: main.c,v 1.35 2000/08/24 11:48:57 hm Exp $
38 * $FreeBSD: src/usr.sbin/i4b/isdnmonitor/main.c,v 1.7.2.1 2001/08/01 17:45:06 obrien Exp $
39 * $DragonFly: src/usr.sbin/i4b/isdnmonitor/main.c,v 1.5 2005/11/25 01:58:52 swildner Exp $
41 * last edit-date: [Mon Dec 13 21:52:11 1999]
43 *---------------------------------------------------------------------------*/
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <signal.h>
50 #include <time.h>
51 #include <errno.h>
52 #ifndef WIN32
53 #include <unistd.h>
54 #include <netdb.h>
55 #endif
56 #include <sys/types.h>
57 #ifndef WIN32
58 #include <sys/socket.h>
59 #include <sys/ioctl.h>
60 #include <sys/un.h>
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
63 #else
64 #include <stdarg.h>
65 #include <windows.h>
66 extern char *optarg;
67 int getopt(int nargc, char * const nargv[], const char *ostr);
68 #define close(f) closesocket(f)
69 #define sleep(s) Sleep(s*1000)
70 #define vsnprintf _vsnprintf
71 #define ssize_t long
72 #endif
73 #ifdef ERROR
74 #undef ERROR
75 #endif
77 #define MAIN
78 #include "monprivate.h"
79 #undef MAIN
81 #ifndef AF_LOCAL
82 #define AF_LOCAL AF_UNIX
83 #endif
85 #ifdef DEBUG
86 #include <ctype.h>
87 #endif
89 #include "monitor.h"
92 * Local function prototypes
94 static int connect_local(char *sockpath);
95 static int connect_remote(char *host, int portno);
96 static void usage();
97 static void mloop();
98 static void handle_input();
99 static void print_menu();
100 static void print_logevent(time_t tstamp, int prio, char * what, char * msg);
101 static void print_charge(time_t tstamp, int controller, int channel, int units, int estimated);
102 static void print_connect(time_t tstamp, int dir, int controller, int channel, char * cfgname, char * devname, char * remphone, char * locphone);
103 static void print_disconnect(time_t tstamp, int controller, int channel);
104 static void print_updown(time_t tstamp, int contoller, int channel, int isup);
105 static void handle_event(u_int8_t *msg, int len);
106 #ifdef DEBUG
107 static void dump_event(u_int8_t *msg, int len, int readflag);
108 #endif
110 static ssize_t sock_read(int fd, void *buf, size_t nbytes);
111 static ssize_t sock_write(int fd, void *buf, size_t nbytes);
113 static void mprintf(char *fmt, ...);
116 * Global variables
118 static int debug = 0;
119 #define DBG_DUMPALL 0x01
120 #define DBG_PSEND 0x02
122 static int monsock = -1;
123 static int state = ST_INIT;
124 static int sub_state = 0;
125 static int sub_state_count = 0;
127 static int isdn_major = 0;
128 static int isdn_minor = 0;
129 static u_int32_t rights = 0;
131 static char *logfilename = NULL;
132 static FILE *lfp = NULL;
134 /*---------------------------------------------------------------------------
135 * Display usage and exit
136 *---------------------------------------------------------------------------*/
137 static void
138 usage(void)
140 fprintf(stderr, "\n");
141 fprintf(stderr, "isdnmonitor - version %02d.%02d.%d, %s %s (protocol %02d.%02d)\n", VERSION, REL, STEP, __DATE__, __TIME__, MPROT_VERSION, MPROT_REL);
142 #ifdef FOREIGN
143 fprintf(stderr, " usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-p port]\n");
144 #else
145 fprintf(stderr, " usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-l path] [-p port]\n");
146 #endif
147 fprintf(stderr, " -c switch to curses fullscreen output\n");
148 fprintf(stderr, " -d <val> debug flags (see source ...)\n");
149 fprintf(stderr, " -dn no debug output on fullscreen display\n");
150 fprintf(stderr, " -f <name> filename to log output to\n");
151 fprintf(stderr, " -h <host> hostname/address to connect to\n");
152 #ifndef FOREIGN
153 fprintf(stderr, " -l <path> pathname to local domain socket to connect to\n");
154 #endif
155 fprintf(stderr, " -p <port> portnumber to use to connect to remote host\n");
156 exit(1);
159 /*---------------------------------------------------------------------------
160 * Parse command line, startup monitor client
161 *---------------------------------------------------------------------------*/
163 main(int argc, char **argv)
165 int i;
167 #ifdef WIN32
168 WSADATA wsCaps;
169 WSAStartup(MAKEWORD(2, 0), &wsCaps);
170 #endif
172 portno = DEF_MONPORT;
173 devbuf[0] = '\0';
175 #ifndef FOREIGN
176 while((i = getopt(argc, argv, "cd:f:h:p:l:")) != -1)
177 #else
178 while((i = getopt(argc, argv, "cd:f:h:p:")) != -1)
179 #endif
181 switch(i)
183 case 'c':
184 fullscreen = 1;
185 break;
186 case 'd':
187 if(*optarg == 'n')
189 debug_noscreen = 1;
191 else
193 if((sscanf(optarg, "%i", &debug)) != 1)
194 usage();
196 break;
197 case 'f':
198 logfilename = optarg;
199 break;
200 case 'h':
201 hostname = optarg;
202 break;
203 #ifndef FOREIGN
204 case 'l':
205 sockpath = optarg;
206 break;
207 #endif
208 case 'p':
209 if((sscanf(optarg, "%i", &portno)) != 1)
210 usage();
211 break;
212 default:
213 usage();
214 break;
218 #ifndef FOREIGN
219 if(hostname && sockpath)
221 fprintf(stderr, "Error: can not use local socket path on remote machine\n"
222 "conflicting options -h and -l!\n");
223 return 1;
226 if(sockpath)
228 monsock = connect_local(sockpath);
230 else if(hostname)
231 #else
232 if(hostname)
233 #endif
236 monsock = connect_remote(hostname, portno);
238 else
240 usage();
243 if(monsock == -1)
245 fprintf(stderr, "Could not connect to i4b isdn daemon.\n");
246 return 1;
249 if(logfilename != NULL)
251 if((lfp = fopen(logfilename, "w")) == NULL)
253 fprintf(stderr, "could not open logfile [%s], %s\n", logfilename, strerror(errno));
254 exit(1);
258 #ifndef WIN32
259 signal(SIGPIPE, SIG_IGN);
260 #endif
262 mloop();
264 close(monsock);
266 return 0;
269 /*---------------------------------------------------------------------------
270 * Connect via tcp/ip.
271 * Return socket if successfull, -1 on error.
272 ---------------------------------------------------------------------------*/
273 static int
274 connect_remote(char *host, int portno)
276 struct sockaddr_in sa;
277 struct hostent *h;
278 int remotesockfd;
280 h = gethostbyname(host);
282 if(!h)
284 fprintf(stderr, "could not resolve hostname '%s'\n", host);
285 exit(1);
288 remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
290 if(remotesockfd == -1)
292 fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno));
293 exit(1);
296 memset(&sa, 0, sizeof(sa));
298 #ifdef BSD4_4
299 sa.sin_len = sizeof(sa);
300 #endif
301 sa.sin_family = AF_INET;
302 sa.sin_port = htons(portno);
304 memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof(sa.sin_addr.s_addr));
306 if(connect(remotesockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
308 fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno));
309 exit(1);
312 return remotesockfd;
315 #ifndef FOREIGN
316 /*---------------------------------------------------------------------------
317 * Connect local.
318 * Return socket on success, -1 on failure.
319 *---------------------------------------------------------------------------*/
320 static int
321 connect_local(char *sockpath)
323 int s;
324 struct sockaddr_un sa;
326 /* check path length */
327 if(strlen(sockpath) >= sizeof(sa.sun_path))
329 fprintf(stderr, "pathname to long for local socket: %s\n",
330 sockpath);
331 exit(1);
334 /* create and setup socket */
335 s = socket(AF_LOCAL, SOCK_STREAM, 0);
337 if(s == -1)
339 fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno));
340 exit(1);
343 memset(&sa, 0, sizeof(sa));
345 sa.sun_len = sizeof(sa);
346 sa.sun_family = AF_LOCAL;
347 strcpy(sa.sun_path, sockpath);
349 if(connect(s, (struct sockaddr *)&sa, sizeof(sa)))
351 fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", sockpath, strerror(errno));
354 return s;
356 #endif
358 /*---------------------------------------------------------------------------*
359 * data from keyboard available, read and process it
360 *---------------------------------------------------------------------------*/
361 #ifndef WIN32
362 static void
363 kbdrdhdl(void)
365 int ch = getch();
367 switch(ch)
369 case 0x0c: /* control L */
370 wrefresh(curscr);
371 break;
373 case '\n':
374 case '\r':
375 do_menu();
376 break;
379 #endif
381 /*---------------------------------------------------------------------------
382 * main event loop
383 *---------------------------------------------------------------------------*/
384 static void
385 mloop(void)
387 for(;;)
389 fd_set rd, wr, ex;
391 FD_ZERO(&rd);
392 FD_ZERO(&wr);
393 FD_ZERO(&ex);
394 FD_SET(fileno(stdin), &rd);
395 FD_SET(monsock, &rd);
397 select(monsock+1, &rd, &wr, &ex, NULL);
399 if(FD_ISSET(fileno(stdin), &rd))
401 #ifndef WIN32
402 if(fullscreen && curses_ready)
403 kbdrdhdl();
404 else
405 #endif
406 if(!fullscreen)
407 handle_input();
408 else
409 getchar();
412 if(FD_ISSET(monsock, &rd))
414 u_int8_t buf[8192];
415 int bytes, ret;
417 /* Network transfer may deliver two or more packets concatenated.
418 * Peek at the header and read only one event at a time... */
420 bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK);
422 if(bytes == 0)
424 close(monsock);
426 #ifndef WIN32
427 if(curses_ready)
429 endwin();
430 curses_ready = 0;
432 #endif
434 mprintf("remote isdnd has closed our connection\n");
435 exit(0);
437 else if(bytes < 0)
439 fprintf(stderr, "recv error: %s\n", strerror(errno));
440 close(monsock);
441 exit(1);
444 if (bytes < I4B_MON_EVNT_HDR)
445 continue; /* errh? something must be wrong... */
447 bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN);
449 if(bytes >= sizeof(buf))
451 fprintf(stderr, "mloop: socket recv buffer overflow %d!\n", bytes);
452 break;
455 /* now we know the size, it fits, so lets read it! */
457 ret = sock_read(monsock, buf, bytes);
459 if(ret == 0)
461 close(monsock);
462 #ifndef WIN32
463 if(curses_ready)
464 endwin();
465 #endif
466 mprintf("remote isdnd has closed our connection\n");
467 exit(0);
469 else if(ret < 0)
471 mprintf("error reading from isdnd: %s", strerror(errno));
472 break;
474 #ifdef DEBUG
475 if(debug & DBG_DUMPALL)
476 dump_event(buf, ret, 1);
477 #endif
478 handle_event(buf, ret);
483 #ifdef DEBUG
485 * Dump a complete event packet.
487 static void
488 dump_event(u_int8_t *msg, int len, int read)
490 int i;
492 if(read)
493 mprintf("read from socket:");
494 else
495 mprintf("write to socket:");
497 for(i = 0; i < len; i++)
499 if(i % 8 == 0)
500 mprintf("\n%02d: ", i);
501 mprintf("0x%02x %c ", msg[i], isprint(msg[i]) ? msg[i] : '.');
503 mprintf("\n");
505 #endif
507 static void
508 print_logevent(time_t tstamp, int prio, char * what, char * msg)
510 char buf[256];
511 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
512 mprintf("log: %s prio %d what=%s msg=%s\n", buf, prio, what, msg);
514 #ifndef WIN32
515 if(fullscreen)
517 if((!debug_noscreen) || (debug_noscreen && (((strcmp(what, "DBG"))) != 0)))
520 * FreeBSD-current integrated ncurses. Since then it is no longer possible
521 * to write to the last column in the logfilewindow without causing an
522 * automatic newline to occur resulting in a blank line in that window.
524 #ifdef __DragonFly__
525 #include <osreldate.h>
526 #endif
527 #if defined(__DragonFly__)
528 #warning "FreeBSD ncurses is buggy: write to last column = auto newline!"
529 wprintw(lower_w, "%s %s %-.*s\n", buf, what,
530 COLS-((strlen(buf))+(strlen(what))+3), msg);
531 #else
532 wprintw(lower_w, "%s %s %-.*s\n", buf, what,
533 (int)(COLS-((strlen(buf))+(strlen(what))+2)), msg);
534 #endif
535 wrefresh(lower_w);
538 #endif
541 static void
542 print_charge(time_t tstamp, int controller, int channel, int units, int estimated)
544 char buf[256];
545 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
546 mprintf("%s: controller %d, channel %d, charge = %d%s\n",
547 buf, controller, channel, units, estimated ? " (estimated)" : "");
548 #ifndef WIN32
549 if(fullscreen)
551 if(estimated)
552 display_ccharge(CHPOS(controller, channel), units);
553 else
554 display_charge(CHPOS(controller, channel), units);
556 #endif
560 * Print a connect event.
561 * A real monitor would allocate state info for "channel" on this
562 * event.
564 * Parameters:
565 * tstamp: server time of event
566 * outgoing: 0 = incoming, 1 = outgoing
567 * controller: controller number
568 * channel: channel no, used to identify this connection until disconnect
569 * cfgname: name of config entry/connection
570 * devname: device used (e.g. isp0)
571 * remphone: phone no of remote side
572 * locphone: local phone no
574 static void
575 print_connect(time_t tstamp, int outgoing, int controller, int channel,
576 char *cfgname, char *devname, char *remphone, char *locphone)
578 char buf[256];
580 if(channel == 0)
581 remstate[controller].ch1state = 1;
582 else
583 remstate[controller].ch2state = 1;
585 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
587 if(outgoing)
588 mprintf("%s: calling out to '%s' [from msn: '%s']",
589 buf, remphone, locphone);
590 else
591 mprintf("%s: incoming call from '%s' [to msn: '%s']",
592 buf, remphone, locphone);
593 mprintf(", controller %d, channel %d, config '%s' on device '%s'\n",
594 controller, channel, cfgname, devname);
596 #ifndef WIN32
597 if(fullscreen)
598 display_connect(CHPOS(controller, channel), outgoing, cfgname, remphone, devname);
599 #endif
603 * Print a disconnect event.
604 * A real monitor could free the "per connection" state
605 * for this channel now
607 static void
608 print_disconnect(time_t tstamp, int controller, int channel)
610 char buf[256];
612 if(channel == 0)
613 remstate[controller].ch1state = 0;
614 else
615 remstate[controller].ch2state = 0;
617 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
619 mprintf("%s: controller %d, channel %d disconnected\n",
620 buf, controller, channel);
622 #ifndef WIN32
623 if(fullscreen)
624 display_disconnect(CHPOS(controller, channel));
625 #endif
629 * Print an up- or down event
631 static void
632 print_updown(time_t tstamp, int controller, int channel, int isup)
634 char buf[256];
635 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
636 mprintf("%s: channel %d is %s\n",
637 buf, channel, isup ? "up" : "down");
641 * Print l1 / l2 status
643 static void
644 print_l12stat(time_t tstamp, int controller, int layer, int state)
646 char buf[256];
647 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
649 mprintf("%s: layer %d change on controller %d: %s\n",
650 buf, layer, controller, state ? "up" : "down");
651 #ifndef WIN32
652 if(fullscreen)
653 display_l12stat(controller, layer, state);
654 #endif
658 * Print TEI
660 static void
661 print_tei(time_t tstamp, int controller, int tei)
663 char buf[256];
664 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
666 mprintf("%s: controller %d, TEI is %d\n",
667 buf, controller, tei);
669 #ifndef WIN32
670 if(fullscreen)
671 display_tei(controller, tei);
672 #endif
676 * Print accounting information
678 static void
679 print_acct(time_t tstamp, int controller, int channel, int obytes, int obps,
680 int ibytes, int ibps)
682 char buf[256];
683 strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
685 mprintf("%s: controller %d, channel %d: %d obytes, %d obps, %d ibytes, %d ibps\n",
686 buf, controller, channel, obytes, obps, ibytes, ibps);
687 #ifndef WIN32
688 if(fullscreen)
689 display_acct(CHPOS(controller, channel), obytes, obps, ibytes, ibps);
690 #endif
693 static void
694 print_initialization(void)
696 #ifndef WIN32
697 if(fullscreen)
699 if(curses_ready == 0)
700 init_screen();
702 else
703 #endif
705 print_menu();
710 * Dispatch one message received from the daemon.
712 static void
713 handle_event(u_int8_t *msg, int len)
715 u_int8_t cmd[I4B_MON_ICLIENT_SIZE];
716 int local;
717 u_int32_t net;
718 u_int32_t mask;
719 u_int32_t who;
720 static int first = 1;
722 switch(state)
724 case ST_INIT: /* initial data */
726 isdn_major = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMAJOR);
727 isdn_minor = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMINOR);
728 nctrl = I4B_GET_2B(msg, I4B_MON_IDATA_NUMCTRL);
729 nentries = I4B_GET_2B(msg, I4B_MON_IDATA_NUMENTR);
730 rights = I4B_GET_4B(msg, I4B_MON_IDATA_CLACCESS);
732 mprintf("remote protocol version is %02d.%02d\n", isdn_major, isdn_minor);
734 if(isdn_major != MPROT_VERSION || isdn_minor != MPROT_REL)
736 fprintf(stderr, "ERROR, remote protocol version mismatch:\n");
737 fprintf(stderr, "\tremote major version is %02d, local major version is %02d\n", isdn_major, MPROT_VERSION);
738 fprintf(stderr, "\tremote minor version is %02d, local minor version is %02d\n", isdn_minor, MPROT_REL);
739 exit(1);
742 mprintf("our rights = 0x%x\n", rights);
744 sub_state = 0;
745 first = 1;
747 if(nctrl > 0)
749 state = ST_ICTRL;
751 else if(nentries > 0)
753 state = ST_IDEV;
755 else
757 state = ST_ANYEV;
758 sleep(2);
759 print_initialization();
762 /* set maximum event mask */
763 I4B_PREP_CMD(cmd, I4B_MON_CCMD_SETMASK);
764 I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMAJOR, MPROT_VERSION);
765 I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMINOR, MPROT_REL);
766 I4B_PUT_4B(cmd, I4B_MON_ICLIENT_EVENTS, ~0U);
768 #ifdef DEBUG
769 if(debug & DBG_DUMPALL)
770 dump_event(cmd, sizeof(cmd), 0);
771 #endif
773 if((sock_write(monsock, cmd, sizeof(cmd))) == -1)
775 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
776 exit(1);
778 break;
780 case ST_ICTRL: /* initial controller list */
781 if(first)
783 first = 0;
784 mprintf("%d controller(s) found:\n", nctrl);
786 mprintf("\tcontroller %d: %s\n", sub_state++, msg+I4B_MON_ICTRL_NAME);
788 if(sub_state >= nctrl)
790 sub_state = 0;
791 first = 1;
792 if(nentries > 0)
794 state = ST_IDEV; /* end of list reached */
796 else
798 state = ST_ANYEV;
799 sleep(2);
800 print_initialization();
803 break;
805 case ST_IDEV: /* initial entry devicename list */
806 if(first)
808 first = 0;
809 mprintf("%d entries found:\n", nentries);
812 mprintf("\tentry %d: device %s\n", sub_state++, msg+I4B_MON_IDEV_NAME);
814 strcat(devbuf, msg+I4B_MON_IDEV_NAME);
815 /* strcat(devbuf, " "); */
817 if(sub_state >= nentries)
819 first = 1;
820 state = ST_ANYEV; /* end of list reached */
821 sub_state = 0;
822 sleep(2);
823 print_initialization();
825 break;
827 case ST_ANYEV: /* any event */
828 switch(I4B_GET_2B(msg, I4B_MON_EVNT))
830 case I4B_MON_DRINI_CODE:
831 state = ST_RIGHT; /* list of rights entries will follow */
832 sub_state = 0;
833 sub_state_count = I4B_GET_2B(msg, I4B_MON_DRINI_COUNT);
834 mprintf("monitor rights:\n");
835 break;
837 case I4B_MON_DCINI_CODE:
838 state = ST_CONNS;
839 sub_state = 0;
840 sub_state_count = I4B_GET_2B(msg, I4B_MON_DCINI_COUNT);
841 mprintf("monitor connections:\n");
842 break;
844 case I4B_MON_LOGEVNT_CODE:
845 print_logevent(I4B_GET_4B(msg, I4B_MON_LOGEVNT_TSTAMP),
846 I4B_GET_4B(msg, I4B_MON_LOGEVNT_PRIO),
847 msg+I4B_MON_LOGEVNT_WHAT,
848 msg+I4B_MON_LOGEVNT_MSG);
849 break;
851 case I4B_MON_CHRG_CODE:
852 print_charge(I4B_GET_4B(msg, I4B_MON_CHRG_TSTAMP),
853 I4B_GET_4B(msg, I4B_MON_CHRG_CTRL),
854 I4B_GET_4B(msg, I4B_MON_CHRG_CHANNEL),
855 I4B_GET_4B(msg, I4B_MON_CHRG_UNITS),
856 I4B_GET_4B(msg, I4B_MON_CHRG_ESTIMATED));
857 break;
859 case I4B_MON_CONNECT_CODE:
860 print_connect(
861 I4B_GET_4B(msg, I4B_MON_CONNECT_TSTAMP),
862 I4B_GET_4B(msg, I4B_MON_CONNECT_DIR),
863 I4B_GET_4B(msg, I4B_MON_CONNECT_CTRL),
864 I4B_GET_4B(msg, I4B_MON_CONNECT_CHANNEL),
865 msg+I4B_MON_CONNECT_CFGNAME,
866 msg+I4B_MON_CONNECT_DEVNAME,
867 msg+I4B_MON_CONNECT_REMPHONE,
868 msg+I4B_MON_CONNECT_LOCPHONE);
869 break;
871 case I4B_MON_DISCONNECT_CODE:
872 print_disconnect(
873 I4B_GET_4B(msg, I4B_MON_DISCONNECT_TSTAMP),
874 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CTRL),
875 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CHANNEL));
876 break;
878 case I4B_MON_UPDOWN_CODE:
879 print_updown(
880 I4B_GET_4B(msg, I4B_MON_UPDOWN_TSTAMP),
881 I4B_GET_4B(msg, I4B_MON_UPDOWN_CTRL),
882 I4B_GET_4B(msg, I4B_MON_UPDOWN_CHANNEL),
883 I4B_GET_4B(msg, I4B_MON_UPDOWN_ISUP));
884 break;
885 case I4B_MON_L12STAT_CODE:
886 print_l12stat(
887 I4B_GET_4B(msg, I4B_MON_L12STAT_TSTAMP),
888 I4B_GET_4B(msg, I4B_MON_L12STAT_CTRL),
889 I4B_GET_4B(msg, I4B_MON_L12STAT_LAYER),
890 I4B_GET_4B(msg, I4B_MON_L12STAT_STATE));
891 break;
892 case I4B_MON_TEI_CODE:
893 print_tei(
894 I4B_GET_4B(msg, I4B_MON_TEI_TSTAMP),
895 I4B_GET_4B(msg, I4B_MON_TEI_CTRL),
896 I4B_GET_4B(msg, I4B_MON_TEI_TEI));
897 break;
898 case I4B_MON_ACCT_CODE:
899 print_acct(
900 I4B_GET_4B(msg, I4B_MON_ACCT_TSTAMP),
901 I4B_GET_4B(msg, I4B_MON_ACCT_CTRL),
902 I4B_GET_4B(msg, I4B_MON_ACCT_CHAN),
903 I4B_GET_4B(msg, I4B_MON_ACCT_OBYTES),
904 I4B_GET_4B(msg, I4B_MON_ACCT_OBPS),
905 I4B_GET_4B(msg, I4B_MON_ACCT_IBYTES),
906 I4B_GET_4B(msg, I4B_MON_ACCT_IBPS));
907 break;
908 default:
909 mprintf("unknown event code: %d\n", I4B_GET_2B(msg, I4B_MON_EVNT));
911 break;
913 case ST_RIGHT: /* one record in a list of monitor rights */
914 rights = I4B_GET_4B(msg, I4B_MON_DR_RIGHTS);
915 net = I4B_GET_4B(msg, I4B_MON_DR_NET);
916 mask = I4B_GET_4B(msg, I4B_MON_DR_MASK);
917 local = I4B_GET_1B(msg, I4B_MON_DR_LOCAL);
919 if(local)
921 mprintf("\tlocal: rights = %x\n", rights);
923 else
925 mprintf("\tfrom: %d.%d.%d.%d, mask %d.%d.%d.%d, rights = %x\n",
926 (net >> 24) & 0x00ff, (net >> 16) & 0x00ff, (net >> 8) & 0x00ff, net & 0x00ff,
927 (mask >> 24) & 0x00ff, (mask >> 16) & 0x00ff, (mask >> 8) & 0x00ff, mask & 0x00ff,
928 rights);
931 sub_state++;
933 if(sub_state >= sub_state_count)
935 state = ST_ANYEV;
936 print_initialization();
938 break;
940 case ST_CONNS:
941 who = I4B_GET_4B(msg, I4B_MON_DC_WHO);
942 rights = I4B_GET_4B(msg, I4B_MON_DC_RIGHTS);
944 mprintf("\tfrom: %d.%d.%d.%d, rights = %x\n",
945 (who >> 24) & 0x00ff, (who >> 16) & 0x00ff, (who >> 8) & 0x00ff, who & 0x00ff,
946 rights);
948 sub_state++;
950 if(sub_state >= sub_state_count)
952 state = ST_ANYEV;
953 print_initialization();
955 break;
957 default:
958 mprintf("unknown event from remote: local state = %d, evnt = %x, len = %d\n",
959 state, I4B_GET_2B(msg, I4B_MON_EVNT), len);
964 * Process input from user
966 static void
967 handle_input(void)
969 char buf[1024];
970 int channel, controller;
972 fgets(buf, sizeof(buf), stdin);
974 switch(atoi(buf))
976 case 1:
978 u_int8_t cmd[I4B_MON_DUMPRIGHTS_SIZE];
979 I4B_PREP_CMD(cmd, I4B_MON_DUMPRIGHTS_CODE);
980 #ifdef DEBUG
981 if(debug & DBG_DUMPALL)
982 dump_event(cmd, I4B_MON_DUMPRIGHTS_SIZE, 0);
983 #endif
985 if((sock_write(monsock, cmd, I4B_MON_DUMPRIGHTS_SIZE)) == -1)
987 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
988 exit(1);
991 break;
993 case 2:
995 u_int8_t cmd[I4B_MON_DUMPMCONS_SIZE];
996 I4B_PREP_CMD(cmd, I4B_MON_DUMPMCONS_CODE);
997 #ifdef DEBUG
998 if(debug & DBG_DUMPALL)
999 dump_event(cmd, I4B_MON_DUMPMCONS_CODE, 0);
1000 #endif
1002 if((sock_write(monsock, cmd, I4B_MON_DUMPMCONS_SIZE)) == -1)
1004 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1005 exit(1);
1008 break;
1010 case 3:
1012 u_int8_t cmd[I4B_MON_CFGREREAD_SIZE];
1013 I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE);
1014 #ifdef DEBUG
1015 if(debug & DBG_DUMPALL)
1016 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0);
1017 #endif
1019 if((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1)
1021 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1022 exit(1);
1025 break;
1027 case 4:
1029 u_int8_t cmd[I4B_MON_HANGUP_SIZE];
1030 I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
1032 printf("Which controller you wish to hangup? ");
1033 fgets(buf, sizeof(buf), stdin);
1034 controller = atoi(buf);
1035 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, controller);
1037 printf("Which channel do you wish to hangup? ");
1038 fgets(buf, sizeof(buf), stdin);
1039 channel = atoi(buf);
1040 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, channel);
1042 #ifdef DEBUG
1043 if(debug & DBG_DUMPALL)
1044 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1045 #endif
1047 if((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1049 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1050 exit(1);
1053 break;
1055 case 9:
1056 close(monsock);
1057 exit(0);
1058 break;
1060 default:
1061 print_menu();
1062 break;
1066 void
1067 reread(void)
1069 u_int8_t cmd[I4B_MON_CFGREREAD_SIZE];
1070 I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE);
1071 #ifdef DEBUG
1072 if(debug & DBG_DUMPALL)
1073 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0);
1074 #endif
1075 if((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1)
1077 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1078 exit(1);
1082 void
1083 hangup(int ctrl, int chan)
1085 u_int8_t cmd[I4B_MON_HANGUP_SIZE];
1087 I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
1088 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, ctrl);
1089 I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, chan);
1091 #ifdef DEBUG
1092 if(debug & DBG_DUMPALL)
1093 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1094 #endif
1096 if((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1098 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1099 exit(1);
1104 * Display menu
1106 static void
1107 print_menu(void)
1109 if(!fullscreen)
1111 printf("Menu: <1> display rights, <2> display monitor connections,\n");
1112 printf(" <3> reread config file, <4> hangup \n");
1113 printf(" <9> quit isdnmonitor\n");
1114 fflush(stdout);
1118 static ssize_t
1119 sock_read(int fd, void *buf, size_t nbytes)
1121 size_t nleft;
1122 ssize_t nread;
1123 unsigned char *ptr;
1125 ptr = buf;
1126 nleft = nbytes;
1128 while(nleft > 0)
1130 if((nread = read(fd, ptr, nleft)) < 0)
1132 if(errno == EINTR)
1134 nread = 0;
1136 else
1138 return(-1);
1141 else if(nread == 0)
1143 break; /* EOF */
1146 nleft -= nread;
1147 ptr += nread;
1149 return(nbytes - nleft);
1152 static ssize_t
1153 sock_write(int fd, void *buf, size_t nbytes)
1155 size_t nleft;
1156 ssize_t nwritten;
1157 unsigned char *ptr;
1159 ptr = buf;
1160 nleft = nbytes;
1162 while(nleft > 0)
1164 if((nwritten = write(fd, ptr, nleft)) <= 0)
1166 if(errno == EINTR)
1168 nwritten = 0;
1170 else
1172 return(-1);
1176 nleft -= nwritten;
1177 ptr += nwritten;
1179 return(nbytes);
1182 static void
1183 mprintf(char *fmt, ...)
1185 #define PRBUFLEN 1024
1186 char buffer[PRBUFLEN];
1187 va_list ap;
1189 va_start(ap, fmt);
1190 vsnprintf(buffer, PRBUFLEN-1, fmt, ap);
1191 va_end(ap);
1193 if(!fullscreen || (fullscreen && (!curses_ready)))
1194 printf("%s", buffer);
1196 if(logfilename != NULL)
1198 fprintf(lfp, "%s", buffer);
1199 fflush(lfp);
1203 /* EOF */