Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / isdn / isdnd / monitor.c
blob1a68ae1eed8ba85ae2a5ede1c272063f1abdf886
1 /* $NetBSD: monitor.c,v 1.15 2008/04/28 20:24:16 martin 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 "isdnd.h"
34 #ifndef I4B_EXTERNAL_MONITOR
37 * dummy version of routines needed by config file parser
38 * (config files should be valid with and without external montioring
39 * support compiled into the daemon)
42 void monitor_clear_rights()
43 { }
45 int monitor_start_rights(const char *clientspec)
46 { return I4BMAR_OK; }
48 void monitor_add_rights(int rights_mask)
49 { }
51 void monitor_fixup_rights()
52 { }
54 #else
56 #include "monitor.h"
57 #include <sys/socket.h>
58 #include <sys/un.h>
59 #ifndef I4B_NOTCPIP_MONITOR
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <netdb.h>
63 #endif
66 static TAILQ_HEAD(rights_q, monitor_rights) rights = TAILQ_HEAD_INITIALIZER(rights);
68 static struct monitor_rights * local_rights = NULL; /* entry for local socket */
70 /* for each active monitor connection we have one of this: */
72 struct monitor_connection {
73 TAILQ_ENTRY(monitor_connection) connections;
74 int sock; /* socket for this connection */
75 int rights; /* active rights for this connection */
76 int events; /* bitmask of events client is interested in */
77 char source[FILENAME_MAX];
80 static TAILQ_HEAD(connections_tq, monitor_connection) connections = TAILQ_HEAD_INITIALIZER(connections);
82 /* local prototypes */
83 struct monitor_rights * monitor_next_rights(const struct monitor_rights *r);
84 static int cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb);
85 static int monitor_command(struct monitor_connection *con, int fd, int rights);
86 static void cmd_dump_rights(int fd, int rights, u_int8_t *cmd, const char * source);
87 static void cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source);
88 static void cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source);
89 static void cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source);
90 static void monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes);
91 static int anybody(int mask);
92 static void hangup_channel(int controller, int channel, const char *source);
93 static ssize_t sock_read(int fd, void *buf, size_t nbytes);
94 static ssize_t sock_write(int fd, void *buf, size_t nbytes);
97 * Due to the way we structure config files, the rights for an external
98 * monitor might be stated in multiple steps. First a call to
99 * monitor_start_rights opens an entry. Further (optional) calls to
100 * montior_add_rights assemble additional rights for this "current"
101 * entry. When closing the sys-file section of the config file, the
102 * "current" entry becomes invalid.
104 static struct monitor_rights * cur_add_entry = NULL;
106 /*---------------------------------------------------------------------------
107 * Initialize the monitor server module. This affects only active
108 * connections, the access rights are not modified here!
109 *---------------------------------------------------------------------------*/
110 void
111 monitor_init(void)
113 struct monitor_connection * con;
114 accepted = 0;
115 while ((con = TAILQ_FIRST(&connections)) != NULL)
117 TAILQ_REMOVE(&connections, con, connections);
118 free(con);
122 /*---------------------------------------------------------------------------
123 * Prepare for exit
124 *---------------------------------------------------------------------------*/
125 void
126 monitor_exit(void)
128 struct monitor_connection *c;
130 /* Close all open connections. */
131 while((c = TAILQ_FIRST(&connections)) != NULL) {
132 close(c->sock);
133 TAILQ_REMOVE(&connections, c, connections);
134 free(c);
138 /*---------------------------------------------------------------------------
139 * Initialize access rights. No active connections are affected!
140 *---------------------------------------------------------------------------*/
141 void
142 monitor_clear_rights(void)
144 struct monitor_rights *r;
145 while ((r = TAILQ_FIRST(&rights)) != NULL) {
146 TAILQ_REMOVE(&rights, r, list);
147 free(r);
149 cur_add_entry = NULL;
150 local_rights = NULL;
153 /*---------------------------------------------------------------------------
154 * Add an entry to the access lists. The clientspec either is
155 * the name of the local socket or a host- or networkname or
156 * numeric ip/host-bit-len spec.
157 *---------------------------------------------------------------------------*/
159 monitor_start_rights(const char *clientspec)
161 struct monitor_rights r;
163 /* initialize the new rights entry */
165 memset(&r, 0, sizeof r);
167 /* check clientspec */
169 if (*clientspec == '/')
171 struct sockaddr_un sa;
173 /* this is a local socket spec, check if we already have one */
175 if (local_rights != NULL)
176 return I4BMAR_DUP;
178 /* does it fit in a local socket address? */
180 if (strlen(clientspec) > sizeof sa.sun_path)
181 return I4BMAR_LENGTH;
183 r.local = 1;
184 strlcpy(r.name, clientspec, sizeof(r.name));
186 #ifndef I4B_NOTCPIP_MONITOR
189 else
191 /* remote entry, parse host/net and cidr */
193 struct monitor_rights * rp;
194 char hostname[FILENAME_MAX];
195 char *p;
197 p = strchr(clientspec, '/');
199 if (!p)
201 struct hostent *host;
202 u_int32_t hn;
204 /* must be a host spec */
206 r.mask = ~0;
207 host = gethostbyname(clientspec);
209 if (!host)
210 return I4BMAR_NOIP;
212 memcpy(&hn, host->h_addr_list[0], sizeof hn);
213 r.net = (u_int32_t)ntohl(hn);
215 else if (p[1])
217 /* must be net/cidr spec */
219 int l;
220 struct netent *net;
221 u_int32_t s = ~0U;
222 int num = strtol(p+1, NULL, 10);
224 if (num < 0 || num > 32)
225 return I4BMAR_CIDR;
227 s >>= num;
228 s ^= ~0U;
229 l = p - clientspec;
231 if (l >= (int)sizeof hostname)
232 return I4BMAR_LENGTH;
234 strncpy(hostname, clientspec, l);
236 hostname[l] = '\0';
238 net = getnetbyname(hostname);
240 if (net == NULL)
241 r.net = (u_int32_t)inet_network(hostname);
242 else
243 r.net = (u_int32_t)net->n_net;
245 r.mask = s;
246 r.net &= s;
248 else
250 return I4BMAR_CIDR;
253 /* check for duplicate entry */
255 for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
257 if (rp->mask == r.mask &&
258 rp->net == r.net &&
259 rp->local == r.local)
261 return I4BMAR_DUP;
264 #endif
267 r.rights = 0;
269 /* entry ok, add it to the collection */
271 cur_add_entry = malloc(sizeof(r));
272 memcpy(cur_add_entry, &r, sizeof(r));
273 TAILQ_INSERT_TAIL(&rights, cur_add_entry, list);
275 if (r.local)
276 local_rights = cur_add_entry;
278 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor = %s", clientspec)));
280 return I4BMAR_OK;
283 /*---------------------------------------------------------------------------
284 * Add rights to the currently constructed entry - if any.
285 *---------------------------------------------------------------------------*/
286 void
287 monitor_add_rights(int rights_mask)
289 if (cur_add_entry == NULL)
290 return; /* noone under construction */
292 cur_add_entry->rights |= rights_mask;
294 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-access = 0x%x", rights_mask)));
297 /*---------------------------------------------------------------------------
298 * All rights have been added now. Sort the to get most specific
299 * host/net masks first, so we can travel the list and use the first
300 * match for actual rights.
301 *---------------------------------------------------------------------------*/
302 void
303 monitor_fixup_rights(void)
305 struct monitor_rights * cur, * test, * next;
307 /* no more rights may be added to the current entry */
309 cur_add_entry = NULL;
311 /* sort the rights */
312 for (next = NULL, cur = TAILQ_FIRST(&rights); cur != NULL; cur = next)
314 next = TAILQ_NEXT(cur, list);
315 for (test = TAILQ_FIRST(&rights); test != NULL && test != cur; test = TAILQ_NEXT(test, list))
317 if (cmp_rights(cur, test) > 0) {
318 /* move cur up the list and insert before test */
319 TAILQ_REMOVE(&rights, cur, list);
320 if (test == TAILQ_FIRST(&rights))
321 TAILQ_INSERT_HEAD(&rights, cur, list);
322 else
323 TAILQ_INSERT_BEFORE(test, cur, list);
324 break;
330 /*---------------------------------------------------------------------------
331 * comparator for rights
332 *---------------------------------------------------------------------------*/
333 static int
334 cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb)
336 u_int32_t mask;
338 /* local sorts first */
340 if (pa->local)
341 return -1;
343 /* which is the less specific netmask? */
345 mask = pa->mask;
347 if ((pb->mask & mask) == 0)
348 mask = pb->mask;
350 /* are the entries disjunct? */
352 if ((pa->net & mask) != (pb->net & mask))
354 /* simply compare net part of address */
355 return ((pa->net & mask) < (pb->net & mask)) ? -1 : 1;
358 /* One entry is part of the others net. We already now "mask" is
359 * the netmask of the less specific (i.e. greater) one */
361 return (pa->mask == mask) ? 1 : -1;
364 #ifndef I4B_NOTCPIP_MONITOR
365 /*---------------------------------------------------------------------------
366 * Check if access rights for a remote socket are specified and
367 * create this socket. Return -1 otherwise.
368 *---------------------------------------------------------------------------*/
370 monitor_create_remote_socket(int portno)
372 struct sockaddr_in sa;
373 int val;
374 int remotesockfd;
376 remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
378 if (remotesockfd == -1)
380 logit(LL_MER, "could not create remote monitor socket: %s", strerror(errno));
381 return(-1);
384 val = 1;
386 if (setsockopt(remotesockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val))
388 logit(LL_MER, "could not setsockopt: %s", strerror(errno));
389 return(-1);
392 memset(&sa, 0, sizeof sa);
393 sa.sin_len = sizeof sa;
394 sa.sin_family = AF_INET;
395 sa.sin_port = htons(portno);
396 sa.sin_addr.s_addr = htonl(INADDR_ANY);
398 if (bind(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1)
400 logit(LL_MER, "could not bind remote monitor socket to port %d: %s", portno, strerror(errno));
401 return(-1);
404 if (listen(remotesockfd, 0))
406 logit(LL_MER, "could not listen on monitor socket: %s", strerror(errno));
407 return(-1);
410 return(remotesockfd);
412 #endif
414 /*---------------------------------------------------------------------------
415 * Check if access rights for a local socket are specified and
416 * create this socket. Return -1 otherwise.
417 *---------------------------------------------------------------------------*/
419 monitor_create_local_socket(void)
421 int s;
422 struct sockaddr_un sa;
424 /* check for a local entry */
426 if (local_rights == NULL)
427 return(-1);
429 /* create and setup socket */
431 s = socket(AF_LOCAL, SOCK_STREAM, 0);
433 if (s == -1)
435 logit(LL_MER, "could not create local monitor socket, errno = %d", errno);
436 return(-1);
439 unlink(local_rights->name);
441 memset(&sa, 0, sizeof sa);
442 sa.sun_len = sizeof sa;
443 sa.sun_family = AF_LOCAL;
444 strlcpy(sa.sun_path, local_rights->name, sizeof(sa.sun_path));
446 if (bind(s, (struct sockaddr *)&sa, SUN_LEN(&sa)))
448 logit(LL_MER, "could not bind local monitor socket [%s], errno = %d", local_rights->name, errno);
449 return(-1);
452 chmod(local_rights->name, 0600);
454 if (listen(s, 0))
456 logit(LL_MER, "could not listen on local monitor socket, errno = %d", errno);
457 return(-1);
460 return(s);
463 /*---------------------------------------------------------------------------
464 * Prepare a fd_set for a select call. Add all our local
465 * filedescriptors to the set, increment max_fd if appropriate.
466 *---------------------------------------------------------------------------*/
467 void
468 monitor_prepselect(fd_set *selset, int *max_fd)
470 struct monitor_connection * con;
472 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
474 int fd = con->sock;
476 if (fd > *max_fd)
477 *max_fd = fd;
479 FD_SET(fd, selset);
483 /*---------------------------------------------------------------------------
484 * Check if the result from a select call indicates something
485 * to do for us.
486 *---------------------------------------------------------------------------*/
487 void
488 monitor_handle_input(fd_set *selset)
490 struct monitor_connection * con, * next;
492 for (next = NULL, con = TAILQ_FIRST(&connections); con != NULL; con = next)
494 int fd = con->sock;
495 next = TAILQ_NEXT(con, connections);
497 if (FD_ISSET(fd, selset))
499 /* handle command from this client */
501 if (monitor_command(con, fd, con->rights) != 0)
503 /* broken or closed connection */
505 char source[FILENAME_MAX];
507 strlcpy(source, con->source, sizeof(source));
508 TAILQ_REMOVE(&connections, con, connections);
509 free(con);
510 logit(LL_DMN, "monitor closed from %s", source );
515 /* all connections gone? */
517 if (TAILQ_FIRST(&connections) == NULL)
518 accepted = 0;
521 /*---------------------------------------------------------------------------
522 * Try new incoming connection on the given socket.
523 * Setup client descriptor and send initial data.
524 *---------------------------------------------------------------------------*/
525 void
526 monitor_handle_connect(int sockfd, int is_local)
528 struct monitor_connection *con;
529 struct monitor_rights *rp;
530 struct isdn_ctrl_state *ctrl;
531 struct cfg_entry *cfe;
532 int n;
534 #ifndef I4B_NOTCPIP_MONITOR
535 struct sockaddr_in ia;
536 u_int32_t ha = 0;
537 #endif
539 struct sockaddr_un ua;
540 socklen_t s;
541 u_int8_t idata[I4B_MON_IDATA_SIZE];
542 int fd = -1, r_mask, t_events;
543 char source[FILENAME_MAX];
545 /* accept the connection */
547 if (is_local)
549 s = sizeof ua;
550 fd = accept(sockfd, (struct sockaddr *)&ua, &s);
551 strlcpy(source, "local", sizeof(source));
553 #ifndef I4B_NOTCPIP_MONITOR
555 else
557 struct hostent *hp;
559 s = sizeof ia;
560 fd = accept(sockfd, (struct sockaddr *)&ia, &s);
562 hp = gethostbyaddr((char *)&ia.sin_addr, 4, AF_INET);
564 if (hp == NULL)
565 snprintf(source, sizeof source, "%s (%s)", inet_ntoa(ia.sin_addr), inet_ntoa(ia.sin_addr));
566 else
567 snprintf(source, sizeof source, "%s (%s)", hp->h_name, inet_ntoa(ia.sin_addr));
569 memcpy(&ha, &ia.sin_addr.s_addr, sizeof ha);
571 ha = ntohl(ha);
572 #endif
575 /* check the access rights of this connection */
577 r_mask = 0;
579 for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
581 if (rp->local)
583 if (is_local)
585 r_mask = rp->rights;
586 break;
589 #ifndef I4B_NOTCPIP_MONITOR
591 else
593 if ((ha & rp->mask) == rp->net)
595 r_mask = rp->rights;
596 break;
598 #endif
602 if (r_mask == 0)
604 /* no rights - go away */
605 logit(LL_MER, "monitor access denied from %s", source);
606 close(fd);
607 return;
610 accepted = 1;
612 con = malloc(sizeof(struct monitor_connection));
613 memset(con, 0, sizeof *con);
614 TAILQ_INSERT_TAIL(&connections, con, connections);
615 con->sock = fd;
616 con->rights = r_mask;
617 strlcpy(con->source, source, sizeof(con->source));
619 logit(LL_DMN, "monitor opened from %s rights 0x%x", source, r_mask);
621 /* send initial data */
622 I4B_PREP_CMD(idata, I4B_MON_IDATA_CODE);
623 I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMAJOR, MPROT_VERSION);
624 I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMINOR, MPROT_REL);
625 n = count_ctrl_states();
626 I4B_PUT_2B(idata, I4B_MON_IDATA_NUMCTRL, n);
627 n = count_cfg_entries();
628 I4B_PUT_2B(idata, I4B_MON_IDATA_NUMENTR, n);
629 I4B_PUT_4B(idata, I4B_MON_IDATA_CLACCESS, r_mask);
631 if ((sock_write(fd, idata, sizeof idata)) == -1)
633 logit(LL_MER, "monitor_handle_connect: sock_write 1 error - %s", strerror(errno));
636 for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
637 u_int8_t ictrl[I4B_MON_ICTRL_SIZE];
638 char ctrl_desc[100];
640 snprintf(ctrl_desc, sizeof(ctrl_desc), "%s: %s",
641 ctrl->device_name, ctrl->controller);
643 I4B_PREP_CMD(ictrl, I4B_MON_ICTRL_CODE);
644 I4B_PUT_STR(ictrl, I4B_MON_ICTRL_NAME, ctrl_desc);
645 I4B_PUT_2B(ictrl, I4B_MON_ICTRL_BUSID, ctrl->isdnif);
646 I4B_PUT_4B(ictrl, I4B_MON_ICTRL_FLAGS, 0);
647 I4B_PUT_2B(ictrl, I4B_MON_ICTRL_NCHAN, 2);
649 if ((sock_write(fd, ictrl, sizeof ictrl)) == -1)
651 logit(LL_MER, "monitor_handle_connect: sock_write 2 error - %s", strerror(errno));
656 /* send device names from entries */
658 for (cfe = get_first_cfg_entry(); cfe; cfe = NEXT_CFE(cfe)) {
659 u_int8_t ictrl[I4B_MON_IDEV_SIZE];
660 char nbuf[64];
662 snprintf(nbuf, sizeof(nbuf), "%s%d ", cfe->usrdevicename, cfe->usrdeviceunit);
664 I4B_PREP_CMD(ictrl, I4B_MON_IDEV_CODE);
665 /*XXX*/ I4B_PUT_2B(ictrl, I4B_MON_IDEV_STATE, 1);
666 I4B_PUT_STR(ictrl, I4B_MON_IDEV_NAME, nbuf);
668 if ((sock_write(fd, ictrl, sizeof ictrl)) == -1)
670 logit(LL_MER, "monitor_handle_connect: sock_write 3 error - %s", strerror(errno));
674 /*XXX*/ t_events = con->events;
675 /*XXX*/ con->events = -1;
677 /* current state of controller(s) */
679 for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
680 monitor_evnt_tei(ctrl->isdnif, ctrl->tei);
681 monitor_evnt_l12stat(ctrl->isdnif, LAYER_ONE, ctrl->l1stat);
682 monitor_evnt_l12stat(ctrl->isdnif, LAYER_TWO, ctrl->l2stat);
685 /* current state of entries */
687 for (cfe = get_first_cfg_entry(); cfe; cfe = NEXT_CFE(cfe)) {
689 if (cfe->state == ST_CONNECTED)
691 monitor_evnt_connect(cfe);
692 monitor_evnt_acct(cfe);
693 monitor_evnt_charge(cfe, cfe->charge, 1);
697 /*XXX*/ con->events = t_events;
701 /*---------------------------------------------------------------------------
702 * dump all monitor rights
703 *---------------------------------------------------------------------------*/
704 static void
705 cmd_dump_rights(int fd, int r_mask, u_int8_t *cmd, const char *source)
707 struct monitor_rights * r;
708 int num_rights;
709 u_int8_t drini[I4B_MON_DRINI_SIZE];
710 u_int8_t dr[I4B_MON_DR_SIZE];
712 for (num_rights = 0, r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
713 num_rights++;
715 I4B_PREP_EVNT(drini, I4B_MON_DRINI_CODE);
716 I4B_PUT_2B(drini, I4B_MON_DRINI_COUNT, num_rights);
718 if ((sock_write(fd, drini, sizeof drini)) == -1)
720 logit(LL_MER, "cmd_dump_rights: sock_write 1 error - %s", strerror(errno));
723 for (r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
725 I4B_PREP_EVNT(dr, I4B_MON_DR_CODE);
726 I4B_PUT_4B(dr, I4B_MON_DR_RIGHTS, r->rights);
727 I4B_PUT_4B(dr, I4B_MON_DR_NET, r->net);
728 I4B_PUT_4B(dr, I4B_MON_DR_MASK, r->mask);
729 I4B_PUT_1B(dr, I4B_MON_DR_LOCAL, r->local);
730 if ((sock_write(fd, dr, sizeof dr)) == -1)
732 logit(LL_MER, "cmd_dump_rights: sock_write 2 error - %s", strerror(errno));
737 /*---------------------------------------------------------------------------
738 * rescan config file
739 *---------------------------------------------------------------------------*/
740 static void
741 cmd_reread_cfg(int fd, int _rights, u_int8_t *cmd, const char * source)
743 rereadconfig(42);
746 /*---------------------------------------------------------------------------
747 * drop one connection
748 *---------------------------------------------------------------------------*/
749 static void
750 cmd_hangup(int fd, int _rights, u_int8_t *cmd, const char * source)
752 int channel = I4B_GET_4B(cmd, I4B_MON_HANGUP_CHANNEL);
753 int ctrl = I4B_GET_4B(cmd, I4B_MON_HANGUP_CTRL);
755 hangup_channel(ctrl, channel, source);
758 /*---------------------------------------------------------------------------
759 * dump all active monitor connections
760 *---------------------------------------------------------------------------*/
761 static void
762 cmd_dump_mcons(int fd, int _rights, u_int8_t *cmd, const char * source)
764 int num_connections;
765 struct monitor_connection *con;
766 u_int8_t dcini[I4B_MON_DCINI_SIZE];
768 for (num_connections = 0, con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
769 num_connections++;
771 I4B_PREP_EVNT(dcini, I4B_MON_DCINI_CODE);
772 I4B_PUT_2B(dcini, I4B_MON_DCINI_COUNT, num_connections);
774 if ((sock_write(fd, dcini, sizeof dcini)) == -1)
776 logit(LL_MER, "cmd_dump_mcons: sock_write 1 error - %s", strerror(errno));
779 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
781 #ifndef I4B_NOTCPIP_MONITOR
782 socklen_t namelen;
783 struct sockaddr_in name;
784 #endif
785 u_int8_t dc[I4B_MON_DC_SIZE];
787 I4B_PREP_EVNT(dc, I4B_MON_DC_CODE);
788 I4B_PUT_4B(dc, I4B_MON_DC_RIGHTS, con->rights);
790 #ifndef I4B_NOTCPIP_MONITOR
791 namelen = sizeof name;
793 if (getpeername(con->sock, (struct sockaddr*)&name, &namelen) == 0)
794 memcpy(dc+I4B_MON_DC_WHO, &name.sin_addr, sizeof name.sin_addr);
795 #endif
796 if ((sock_write(fd, dc, sizeof dc)) == -1)
798 logit(LL_MER, "cmd_dump_mcons: sock_write 2 error - %s", strerror(errno));
803 /*---------------------------------------------------------------------------
804 * Handle a command from the given socket. The client
805 * has rights as specified in the rights parameter.
806 * Return non-zero if connection is closed.
807 *---------------------------------------------------------------------------*/
808 static int
809 monitor_command(struct monitor_connection * con, int fd, int mcrights)
811 char cmd[I4B_MAX_MON_CLIENT_CMD];
812 u_int code;
814 /* command dispatch table */
815 typedef void (*cmd_func_t)(int fd, int rights, u_int8_t *cmd, const char *source);
817 static struct {
818 cmd_func_t call; /* function to execute */
819 u_int rights; /* necessary rights */
820 } cmd_tab[] =
822 /* 0 */ { NULL, 0 },
823 /* 1 */ { cmd_dump_rights, I4B_CA_COMMAND_FULL },
824 /* 2 */ { cmd_dump_mcons, I4B_CA_COMMAND_FULL },
825 /* 3 */ { cmd_reread_cfg, I4B_CA_COMMAND_FULL },
826 /* 4 */ { cmd_hangup, I4B_CA_COMMAND_FULL },
828 #define NUMCMD (sizeof cmd_tab / sizeof cmd_tab[0])
830 int avail, bytes, err;
832 /* Network transfer may deliver two or more packets concatenated.
833 * Peek at the header and read only one event at a time... */
835 avail = 0;
836 err = ioctl(fd, FIONREAD, &avail);
838 if (err == -1 || avail < I4B_MON_CMD_HDR)
840 if (err == -1 && errno == EINTR)
841 return 0; /* try again later */
843 if (err == -1 || avail == 0)
845 /* logit(LL_MER, "monitor read 0 bytes"); */
846 /* socket closed by peer */
847 close(fd);
848 return 1;
850 return 0; /* not enough data there yet */
853 bytes = recv(fd, cmd, I4B_MON_CMD_HDR, MSG_PEEK);
855 if (bytes < I4B_MON_CMD_HDR)
857 logit(LL_MER, "monitor read only %d bytes", bytes);
858 return 0; /* errh? something must be wrong... */
861 bytes = I4B_GET_2B(cmd, I4B_MON_CMD_LEN);
863 if (bytes >= (int)sizeof cmd)
865 close(fd);
866 logit(LL_MER, "monitor: garbage on connection");
867 return 1;
870 /* now we know the size, it fits, so lets read it! */
872 if (sock_read(fd, cmd, bytes) <= 0)
874 logit(LL_MER, "monitor: sock_read <= 0");
875 close(fd);
876 return 1;
879 /* decode command */
880 code = I4B_GET_2B(cmd, I4B_MON_CMD);
882 /* special case: may modify our connection descriptor, is
883 * beyound all rights checks */
885 if (code == I4B_MON_CCMD_SETMASK)
887 /*XXX*/
889 u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR);
890 u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR);
893 int events = I4B_GET_4B(cmd, I4B_MON_ICLIENT_EVENTS);
894 con->events = events & mcrights;
895 return 0;
898 if (code >= NUMCMD)
900 logit(LL_MER, "illegal command from client, code = %d\n",
901 code);
902 return 0;
905 if (cmd_tab[code].call == NULL)
906 return 0;
908 if ((cmd_tab[code].rights & mcrights) == cmd_tab[code].rights)
909 cmd_tab[code].call(fd, mcrights, (u_char *)cmd, con->source);
911 return 0;
914 /*---------------------------------------------------------------------------
915 * Check if somebody would receive an event with this mask.
916 * We are lazy and try to avoid assembling unneccesary packets.
917 * Return 0 if no one interested, nonzero otherwise.
918 *---------------------------------------------------------------------------*/
919 static int
920 anybody(int mask)
922 struct monitor_connection * con;
924 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
926 if ((con->events & mask) == mask)
927 return 1;
929 return 0;
932 /*---------------------------------------------------------------------------
933 * exec hangup command
934 *---------------------------------------------------------------------------*/
935 static void
936 hangup_channel(int controller, int channel, const char *source)
938 struct cfg_entry * cep = NULL;
939 struct isdn_ctrl_state * ctrl = NULL;
940 int i;
942 ctrl = find_ctrl_state(controller);
943 if (ctrl != NULL) {
944 if (ctrl->state != CTRL_UP)
945 return;
946 for (i = 0; i < ctrl->nbch; i++) {
947 if (ctrl->stateb[i] != CHAN_IDLE) {
948 cep = get_cep_by_cc(controller, i);
949 if (cep != NULL
950 && cep->isdnchannelused == channel
951 && cep->isdncontrollerused == controller)
952 goto found;
956 /* not found */
957 return;
959 found:
960 logit(LL_CHD, "%05d %s manual disconnect (remote from %s)", cep->cdid, cep->name, source);
961 cep->hangup = 1;
962 return;
965 /*---------------------------------------------------------------------------
966 * Send an event to every connection interested in this kind of
967 * event
968 *---------------------------------------------------------------------------*/
969 static void
970 monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes)
972 struct monitor_connection *con;
974 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
976 if ((con->events & mask) == mask)
978 int fd = con->sock;
980 if ((sock_write(fd, pkt, bytes)) == -1)
982 logit(LL_MER, "monitor_broadcast: sock_write error - %s", strerror(errno));
988 /*---------------------------------------------------------------------------
989 * Post a logfile event
990 *---------------------------------------------------------------------------*/
991 void
992 monitor_evnt_log(int prio, const char * what, const char * msg)
994 u_int8_t evnt[I4B_MON_LOGEVNT_SIZE];
995 time_t now;
997 if (!anybody(I4B_CA_EVNT_I4B))
998 return;
1000 time(&now);
1002 I4B_PREP_EVNT(evnt, I4B_MON_LOGEVNT_CODE);
1003 I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_TSTAMP, (long)now);
1004 I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_PRIO, prio);
1005 I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_WHAT, what);
1006 I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_MSG, msg);
1008 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1011 /*---------------------------------------------------------------------------
1012 * Post a charging event on the connection described
1013 * by the given config entry.
1014 *---------------------------------------------------------------------------*/
1015 void
1016 monitor_evnt_charge(struct cfg_entry *cep, int units, int estimate)
1018 int mask;
1019 time_t now;
1020 u_int8_t evnt[I4B_MON_CHRG_SIZE];
1022 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1024 if (!anybody(mask))
1025 return;
1027 time(&now);
1029 I4B_PREP_EVNT(evnt, I4B_MON_CHRG_CODE);
1030 I4B_PUT_4B(evnt, I4B_MON_CHRG_TSTAMP, (long)now);
1031 I4B_PUT_4B(evnt, I4B_MON_CHRG_CTRL, cep->isdncontrollerused);
1032 I4B_PUT_4B(evnt, I4B_MON_CHRG_CHANNEL, cep->isdnchannelused);
1033 I4B_PUT_4B(evnt, I4B_MON_CHRG_UNITS, units);
1034 I4B_PUT_4B(evnt, I4B_MON_CHRG_ESTIMATED, estimate ? 1 : 0);
1036 monitor_broadcast(mask, evnt, sizeof evnt);
1039 /*---------------------------------------------------------------------------
1040 * Post a connection event
1041 *---------------------------------------------------------------------------*/
1042 void
1043 monitor_evnt_connect(struct cfg_entry *cep)
1045 u_int8_t evnt[I4B_MON_CONNECT_SIZE];
1046 char devnam[I4B_MAX_MON_STRING];
1047 int mask;
1048 time_t now;
1050 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1052 if (!anybody(mask))
1053 return;
1055 time(&now);
1057 snprintf(devnam, sizeof devnam, "%s%d", cep->usrdevicename, cep->usrdeviceunit);
1059 I4B_PREP_EVNT(evnt, I4B_MON_CONNECT_CODE);
1060 I4B_PUT_4B(evnt, I4B_MON_CONNECT_TSTAMP, (long)now);
1061 I4B_PUT_4B(evnt, I4B_MON_CONNECT_DIR, cep->direction == DIR_OUT ? 1 : 0);
1062 I4B_PUT_4B(evnt, I4B_MON_CONNECT_CTRL, cep->isdncontrollerused);
1063 I4B_PUT_4B(evnt, I4B_MON_CONNECT_CHANNEL, cep->isdnchannelused);
1064 I4B_PUT_STR(evnt, I4B_MON_CONNECT_CFGNAME, cep->name);
1065 I4B_PUT_STR(evnt, I4B_MON_CONNECT_DEVNAME, devnam);
1067 if (cep->direction == DIR_OUT)
1069 I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->remote_phone_dialout);
1070 I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_dialout);
1072 else
1074 I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->real_phone_incoming);
1075 I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_incoming);
1077 monitor_broadcast(mask, evnt, sizeof evnt);
1080 /*---------------------------------------------------------------------------
1081 * Post a disconnect event
1082 *---------------------------------------------------------------------------*/
1083 void
1084 monitor_evnt_disconnect(struct cfg_entry *cep)
1086 u_int8_t evnt[I4B_MON_DISCONNECT_SIZE];
1087 int mask;
1088 time_t now;
1090 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1092 if (!anybody(mask))
1093 return;
1095 time(&now);
1097 I4B_PREP_EVNT(evnt, I4B_MON_DISCONNECT_CODE);
1098 I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_TSTAMP, (long)now);
1099 I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CTRL, cep->isdncontrollerused);
1100 I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CHANNEL, cep->isdnchannelused);
1102 monitor_broadcast(mask, evnt, sizeof evnt);
1105 /*---------------------------------------------------------------------------
1106 * Post an up/down event
1107 *---------------------------------------------------------------------------*/
1108 void
1109 monitor_evnt_updown(struct cfg_entry *cep, int up)
1111 u_int8_t evnt[I4B_MON_UPDOWN_SIZE];
1112 int mask;
1113 time_t now;
1115 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1117 if (!anybody(mask))
1118 return;
1120 time(&now);
1122 I4B_PREP_EVNT(evnt, I4B_MON_UPDOWN_CODE);
1123 I4B_PUT_4B(evnt, I4B_MON_UPDOWN_TSTAMP, (long)now);
1124 I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CTRL, cep->isdncontrollerused);
1125 I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CHANNEL, cep->isdnchannelused);
1126 I4B_PUT_4B(evnt, I4B_MON_UPDOWN_ISUP, up);
1128 monitor_broadcast(mask, evnt, sizeof evnt);
1131 /*---------------------------------------------------------------------------
1132 * Post a Layer1/2 status change event
1133 *---------------------------------------------------------------------------*/
1134 void
1135 monitor_evnt_l12stat(int controller, int layer, int state)
1137 u_int8_t evnt[I4B_MON_L12STAT_SIZE];
1138 time_t now;
1140 if (!anybody(I4B_CA_EVNT_I4B))
1141 return;
1143 time(&now);
1145 I4B_PREP_EVNT(evnt, I4B_MON_L12STAT_CODE);
1146 I4B_PUT_4B(evnt, I4B_MON_L12STAT_TSTAMP, (long)now);
1147 I4B_PUT_4B(evnt, I4B_MON_L12STAT_CTRL, controller);
1148 I4B_PUT_4B(evnt, I4B_MON_L12STAT_LAYER, layer);
1149 I4B_PUT_4B(evnt, I4B_MON_L12STAT_STATE, state);
1151 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1154 /*---------------------------------------------------------------------------
1155 * Post a TEI change event
1156 *---------------------------------------------------------------------------*/
1157 void
1158 monitor_evnt_tei(int controller, int tei)
1160 u_int8_t evnt[I4B_MON_TEI_SIZE];
1161 time_t now;
1163 if (!anybody(I4B_CA_EVNT_I4B))
1164 return;
1166 time(&now);
1168 I4B_PREP_EVNT(evnt, I4B_MON_TEI_CODE);
1169 I4B_PUT_4B(evnt, I4B_MON_TEI_TSTAMP, (long)now);
1170 I4B_PUT_4B(evnt, I4B_MON_TEI_CTRL, controller);
1171 I4B_PUT_4B(evnt, I4B_MON_TEI_TEI, tei);
1173 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1176 /*---------------------------------------------------------------------------
1177 * Post an accounting event
1178 *---------------------------------------------------------------------------*/
1179 void
1180 monitor_evnt_acct(struct cfg_entry *cep)
1182 u_int8_t evnt[I4B_MON_ACCT_SIZE];
1183 time_t now;
1185 if (!anybody(I4B_CA_EVNT_I4B))
1186 return;
1188 time(&now);
1190 I4B_PREP_EVNT(evnt, I4B_MON_ACCT_CODE);
1191 I4B_PUT_4B(evnt, I4B_MON_ACCT_TSTAMP, (long)now);
1193 I4B_PUT_4B(evnt, I4B_MON_ACCT_CTRL, cep->isdncontrollerused);
1194 I4B_PUT_4B(evnt, I4B_MON_ACCT_CHAN, cep->isdnchannelused);
1195 I4B_PUT_4B(evnt, I4B_MON_ACCT_OBYTES, cep->outbytes);
1196 I4B_PUT_4B(evnt, I4B_MON_ACCT_OBPS, cep->outbps);
1197 I4B_PUT_4B(evnt, I4B_MON_ACCT_IBYTES, cep->inbytes);
1198 I4B_PUT_4B(evnt, I4B_MON_ACCT_IBPS, cep->inbps);
1200 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1203 /*---------------------------------------------------------------------------
1204 * read from a socket
1205 *---------------------------------------------------------------------------*/
1206 static ssize_t
1207 sock_read(int fd, void *buf, size_t nbytes)
1209 size_t nleft;
1210 ssize_t nread;
1211 unsigned char *ptr;
1213 ptr = buf;
1214 nleft = nbytes;
1216 while(nleft > 0)
1218 if ((nread = read(fd, ptr, nleft)) < 0)
1220 if (errno == EINTR)
1222 nread = 0;
1224 else
1226 return(-1);
1229 else if (nread == 0)
1231 break; /* EOF */
1234 nleft -= nread;
1235 ptr += nread;
1237 return(nbytes - nleft);
1240 /*---------------------------------------------------------------------------
1241 * write to a socket
1242 *---------------------------------------------------------------------------*/
1243 static ssize_t
1244 sock_write(int fd, void *buf, size_t nbytes)
1246 size_t nleft;
1247 ssize_t nwritten;
1248 unsigned char *ptr;
1250 ptr = buf;
1251 nleft = nbytes;
1253 while(nleft > 0)
1255 if ((nwritten = write(fd, ptr, nleft)) <= 0)
1257 if (errno == EINTR)
1259 nwritten = 0;
1261 else
1263 return(-1);
1267 nleft -= nwritten;
1268 ptr += nwritten;
1270 return(nbytes);
1273 struct monitor_rights * monitor_next_rights(const struct monitor_rights *r)
1275 if (r == NULL)
1276 return TAILQ_FIRST(&rights);
1277 else
1278 return TAILQ_NEXT(r, list);
1281 #endif /* I4B_EXTERNAL_MONITOR */