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
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
31 *---------------------------------------------------------------------------
33 * i4b daemon - network monitor server module
34 * ------------------------------------------
36 * $Id: monitor.c,v 1.30 2000/10/09 12:53:29 hm Exp $
38 * $FreeBSD: src/usr.sbin/i4b/isdnd/monitor.c,v 1.6.2.2 2001/08/01 17:45:03 obrien Exp $
39 * $DragonFly: src/usr.sbin/i4b/isdnd/monitor.c,v 1.4 2005/11/25 00:58:52 swildner Exp $
41 * last edit-date: [Mon Dec 13 21:47:44 1999]
43 *---------------------------------------------------------------------------*/
47 #ifndef I4B_EXTERNAL_MONITOR
50 * dummy version of routines needed by config file parser
51 * (config files should be valid with and without external montioring
52 * support compiled into the daemon)
56 monitor_clear_rights(void)
61 monitor_start_rights(const char *clientspec
)
67 monitor_add_rights(int rights_mask
)
72 monitor_fixup_rights(void)
79 #include <sys/socket.h>
81 #ifndef I4B_NOTCPIP_MONITOR
82 #include <netinet/in.h>
83 #include <arpa/inet.h>
88 static TAILQ_HEAD(rights_q
, monitor_rights
) rights
= TAILQ_HEAD_INITIALIZER(rights
);
90 static struct monitor_rights
* local_rights
= NULL
; /* entry for local socket */
92 /* for each active monitor connection we have one of this: */
94 struct monitor_connection
{
95 TAILQ_ENTRY(monitor_connection
) connections
;
96 int sock
; /* socket for this connection */
97 int rights
; /* active rights for this connection */
98 int events
; /* bitmask of events client is interested in */
99 char source
[FILENAME_MAX
];
102 static TAILQ_HEAD(connections_tq
, monitor_connection
) connections
= TAILQ_HEAD_INITIALIZER(connections
);
104 /* local prototypes */
105 static int cmp_rights(const struct monitor_rights
*pa
, const struct monitor_rights
*pb
);
106 static int monitor_command(struct monitor_connection
*con
, int fd
, int rights
);
107 static void cmd_dump_rights(int fd
, int rights
, u_int8_t
*cmd
, const char * source
);
108 static void cmd_dump_mcons(int fd
, int rights
, u_int8_t
*cmd
, const char * source
);
109 static void cmd_reread_cfg(int fd
, int rights
, u_int8_t
*cmd
, const char * source
);
110 static void cmd_hangup(int fd
, int rights
, u_int8_t
*cmd
, const char * source
);
111 static void monitor_broadcast(int mask
, u_int8_t
*pkt
, size_t bytes
);
112 static int anybody(int mask
);
113 static void hangup_channel(int controller
, int channel
, const char *source
);
114 static ssize_t
sock_read(int fd
, void *buf
, size_t nbytes
);
115 static ssize_t
sock_write(int fd
, void *buf
, size_t nbytes
);
118 * Due to the way we structure config files, the rights for an external
119 * monitor might be stated in multiple steps. First a call to
120 * monitor_start_rights opens an entry. Further (optional) calls to
121 * montior_add_rights assemble additional rights for this "current"
122 * entry. When closing the sys-file section of the config file, the
123 * "current" entry becomes invalid.
125 static struct monitor_rights
* cur_add_entry
= NULL
;
127 /*---------------------------------------------------------------------------
128 * Initialize the monitor server module. This affects only active
129 * connections, the access rights are not modified here!
130 *---------------------------------------------------------------------------*/
134 struct monitor_connection
* con
;
136 while ((con
= TAILQ_FIRST(&connections
)) != NULL
)
138 TAILQ_REMOVE(&connections
, con
, connections
);
143 /*---------------------------------------------------------------------------
145 *---------------------------------------------------------------------------*/
149 struct monitor_connection
*c
;
151 /* Close all open connections. */
152 while((c
= TAILQ_FIRST(&connections
)) != NULL
) {
154 TAILQ_REMOVE(&connections
, c
, connections
);
159 /*---------------------------------------------------------------------------
160 * Initialize access rights. No active connections are affected!
161 *---------------------------------------------------------------------------*/
163 monitor_clear_rights(void)
165 struct monitor_rights
*r
;
166 while ((r
= TAILQ_FIRST(&rights
)) != NULL
) {
167 TAILQ_REMOVE(&rights
, r
, list
);
170 cur_add_entry
= NULL
;
174 /*---------------------------------------------------------------------------
175 * Add an entry to the access lists. The clientspec either is
176 * the name of the local socket or a host- or networkname or
177 * numeric ip/host-bit-len spec.
178 *---------------------------------------------------------------------------*/
180 monitor_start_rights(const char *clientspec
)
182 struct monitor_rights r
;
184 /* initialize the new rights entry */
186 memset(&r
, 0, sizeof r
);
188 /* check clientspec */
190 if (*clientspec
== '/')
192 struct sockaddr_un sa
;
194 /* this is a local socket spec, check if we already have one */
196 if (local_rights
!= NULL
)
199 /* does it fit in a local socket address? */
201 if (strlen(clientspec
) > sizeof sa
.sun_path
)
202 return I4BMAR_LENGTH
;
205 strcpy(r
.name
, clientspec
);
207 #ifndef I4B_NOTCPIP_MONITOR
212 /* remote entry, parse host/net and cidr */
214 struct monitor_rights
* rp
;
215 char hostname
[FILENAME_MAX
];
218 p
= strchr(clientspec
, '/');
222 struct hostent
*host
;
225 /* must be a host spec */
228 host
= gethostbyname(clientspec
);
233 memcpy(&hn
, host
->h_addr_list
[0], sizeof hn
);
234 r
.net
= (u_int32_t
)ntohl(hn
);
238 /* must be net/cidr spec */
243 int num
= strtol(p
+1, NULL
, 10);
245 if (num
< 0 || num
> 32)
252 if (l
>= sizeof hostname
)
253 return I4BMAR_LENGTH
;
255 strncpy(hostname
, clientspec
, l
);
259 net
= getnetbyname(hostname
);
262 r
.net
= (u_int32_t
)inet_network(hostname
);
264 r
.net
= (u_int32_t
)net
->n_net
;
274 /* check for duplicate entry */
276 for (rp
= TAILQ_FIRST(&rights
); rp
!= NULL
; rp
= TAILQ_NEXT(rp
, list
))
278 if (rp
->mask
== r
.mask
&&
280 rp
->local
== r
.local
)
290 /* entry ok, add it to the collection */
292 cur_add_entry
= malloc(sizeof(r
));
293 memcpy(cur_add_entry
, &r
, sizeof(r
));
294 TAILQ_INSERT_TAIL(&rights
, cur_add_entry
, list
);
297 local_rights
= cur_add_entry
;
299 DBGL(DL_RCCF
, (dolog(LL_DBG
, "system: monitor = %s", clientspec
)));
304 /*---------------------------------------------------------------------------
305 * Add rights to the currently constructed entry - if any.
306 *---------------------------------------------------------------------------*/
308 monitor_add_rights(int rights_mask
)
310 if(cur_add_entry
== NULL
)
311 return; /* noone under construction */
313 cur_add_entry
->rights
|= rights_mask
;
315 DBGL(DL_RCCF
, (dolog(LL_DBG
, "system: monitor-access = 0x%x", rights_mask
)));
318 /*---------------------------------------------------------------------------
319 * All rights have been added now. Sort the to get most specific
320 * host/net masks first, so we can travel the list and use the first
321 * match for actual rights.
322 *---------------------------------------------------------------------------*/
324 monitor_fixup_rights(void)
326 struct monitor_rights
* cur
, * test
, * next
;
328 /* no more rights may be added to the current entry */
330 cur_add_entry
= NULL
;
332 /* sort the rights */
333 for (next
= NULL
, cur
= TAILQ_FIRST(&rights
); cur
!= NULL
; cur
= next
)
335 next
= TAILQ_NEXT(cur
, list
);
336 for (test
= TAILQ_FIRST(&rights
); test
!= NULL
&& test
!= cur
; test
= TAILQ_NEXT(test
, list
))
338 if (cmp_rights(cur
, test
) > 0) {
339 /* move cur up the list and insert before test */
340 TAILQ_REMOVE(&rights
, cur
, list
);
341 if (test
== TAILQ_FIRST(&rights
))
342 TAILQ_INSERT_HEAD(&rights
, cur
, list
);
344 TAILQ_INSERT_BEFORE(test
, cur
, list
);
351 /*---------------------------------------------------------------------------
352 * comparator for rights
353 *---------------------------------------------------------------------------*/
355 cmp_rights(const struct monitor_rights
*pa
, const struct monitor_rights
*pb
)
359 /* local sorts first */
364 /* which is the less specific netmask? */
368 if ((pb
->mask
& mask
) == 0)
371 /* are the entries disjunct? */
373 if ((pa
->net
& mask
) != (pb
->net
& mask
))
375 /* simply compare net part of address */
376 return ((pa
->net
& mask
) < (pb
->net
& mask
)) ? -1 : 1;
379 /* One entry is part of the others net. We already now "mask" is
380 * the netmask of the less specific (i.e. greater) one */
382 return (pa
->mask
== mask
) ? 1 : -1;
385 #ifndef I4B_NOTCPIP_MONITOR
386 /*---------------------------------------------------------------------------
387 * Check if access rights for a remote socket are specified and
388 * create this socket. Return -1 otherwise.
389 *---------------------------------------------------------------------------*/
391 monitor_create_remote_socket(int portno
)
393 struct sockaddr_in sa
;
397 remotesockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
399 if(remotesockfd
== -1)
401 dolog(LL_MER
, "could not create remote monitor socket: %s", strerror(errno
));
407 if(setsockopt(remotesockfd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof val
))
409 dolog(LL_MER
, "could not setsockopt: %s", strerror(errno
));
413 memset(&sa
, 0, sizeof sa
);
414 sa
.sin_len
= sizeof sa
;
415 sa
.sin_family
= AF_INET
;
416 sa
.sin_port
= htons(portno
);
417 sa
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
419 if(bind(remotesockfd
, (struct sockaddr
*)&sa
, sizeof sa
) == -1)
421 dolog(LL_MER
, "could not bind remote monitor socket to port %d: %s", portno
, strerror(errno
));
425 if(listen(remotesockfd
, 0))
427 dolog(LL_MER
, "could not listen on monitor socket: %s", strerror(errno
));
431 return(remotesockfd
);
435 /*---------------------------------------------------------------------------
436 * Check if access rights for a local socket are specified and
437 * create this socket. Return -1 otherwise.
438 *---------------------------------------------------------------------------*/
440 monitor_create_local_socket(void)
443 struct sockaddr_un sa
;
445 /* check for a local entry */
447 if (local_rights
== NULL
)
450 /* create and setup socket */
452 s
= socket(AF_LOCAL
, SOCK_STREAM
, 0);
456 dolog(LL_MER
, "could not create local monitor socket, errno = %d", errno
);
460 unlink(local_rights
->name
);
462 memset(&sa
, 0, sizeof sa
);
463 sa
.sun_len
= sizeof sa
;
464 sa
.sun_family
= AF_LOCAL
;
465 strcpy(sa
.sun_path
, local_rights
->name
);
467 if (bind(s
, (struct sockaddr
*)&sa
, SUN_LEN(&sa
)))
469 dolog(LL_MER
, "could not bind local monitor socket [%s], errno = %d", local_rights
->name
, errno
);
473 chmod(local_rights
->name
, 0500);
477 dolog(LL_MER
, "could not listen on local monitor socket, errno = %d", errno
);
484 /*---------------------------------------------------------------------------
485 * Prepare a fd_set for a select call. Add all our local
486 * filedescriptors to the set, increment max_fd if appropriate.
487 *---------------------------------------------------------------------------*/
489 monitor_prepselect(fd_set
*selset
, int *max_fd
)
491 struct monitor_connection
* con
;
493 for (con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= TAILQ_NEXT(con
, connections
))
504 /*---------------------------------------------------------------------------
505 * Check if the result from a select call indicates something
507 *---------------------------------------------------------------------------*/
509 monitor_handle_input(fd_set
*selset
)
511 struct monitor_connection
* con
, * next
;
513 for (next
= NULL
, con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= next
)
516 next
= TAILQ_NEXT(con
, connections
);
518 if (FD_ISSET(fd
, selset
))
520 /* handle command from this client */
522 if (monitor_command(con
, fd
, con
->rights
) != 0)
524 /* broken or closed connection */
526 char source
[FILENAME_MAX
];
528 strcpy(source
, con
->source
);
529 TAILQ_REMOVE(&connections
, con
, connections
);
531 dolog(LL_DMN
, "monitor closed from %s", source
);
536 /* all connections gone? */
538 if (TAILQ_FIRST(&connections
) == NULL
)
542 /*---------------------------------------------------------------------------
543 * Try new incoming connection on the given socket.
544 * Setup client descriptor and send initial data.
545 *---------------------------------------------------------------------------*/
547 monitor_handle_connect(int sockfd
, int is_local
)
549 struct monitor_connection
*con
;
550 struct monitor_rights
*rp
;
552 #ifndef I4B_NOTCPIP_MONITOR
553 struct sockaddr_in ia
;
557 struct sockaddr_un ua
;
558 u_int8_t idata
[I4B_MON_IDATA_SIZE
];
559 int fd
= -1, s
, i
, r_mask
, t_events
;
560 char source
[FILENAME_MAX
];
562 /* accept the connection */
567 fd
= accept(sockfd
, (struct sockaddr
*)&ua
, &s
);
568 strcpy(source
, "local");
570 #ifndef I4B_NOTCPIP_MONITOR
577 fd
= accept(sockfd
, (struct sockaddr
*)&ia
, &s
);
579 hp
= gethostbyaddr(&ia
.sin_addr
, 4, AF_INET
);
582 snprintf(source
, sizeof source
, "%s (%s)", inet_ntoa(ia
.sin_addr
), inet_ntoa(ia
.sin_addr
));
584 snprintf(source
, sizeof source
, "%s (%s)", hp
->h_name
, inet_ntoa(ia
.sin_addr
));
586 memcpy(&ha
, &ia
.sin_addr
.s_addr
, sizeof ha
);
592 /* check the access rights of this connection */
596 for (rp
= TAILQ_FIRST(&rights
); rp
!= NULL
; rp
= TAILQ_NEXT(rp
, list
))
606 #ifndef I4B_NOTCPIP_MONITOR
610 if((ha
& rp
->mask
) == rp
->net
)
621 /* no rights - go away */
622 dolog(LL_MER
, "monitor access denied from %s", source
);
629 con
= malloc(sizeof(struct monitor_connection
));
630 memset(con
, 0, sizeof *con
);
631 TAILQ_INSERT_TAIL(&connections
, con
, connections
);
633 con
->rights
= r_mask
;
634 strcpy(con
->source
, source
);
636 dolog(LL_DMN
, "monitor opened from %s rights 0x%x", source
, r_mask
);
638 /* send initial data */
639 I4B_PREP_CMD(idata
, I4B_MON_IDATA_CODE
);
640 I4B_PUT_2B(idata
, I4B_MON_IDATA_VERSMAJOR
, MPROT_VERSION
);
641 I4B_PUT_2B(idata
, I4B_MON_IDATA_VERSMINOR
, MPROT_REL
);
642 I4B_PUT_2B(idata
, I4B_MON_IDATA_NUMCTRL
, ncontroller
);
643 I4B_PUT_2B(idata
, I4B_MON_IDATA_NUMENTR
, nentries
);
644 I4B_PUT_4B(idata
, I4B_MON_IDATA_CLACCESS
, r_mask
);
646 if((sock_write(fd
, idata
, sizeof idata
)) == -1)
648 dolog(LL_MER
, "monitor_handle_connect: sock_write 1 error - %s", strerror(errno
));
651 for (i
= 0; i
< ncontroller
; i
++)
653 u_int8_t ictrl
[I4B_MON_ICTRL_SIZE
];
655 I4B_PREP_CMD(ictrl
, I4B_MON_ICTRL_CODE
);
656 I4B_PUT_STR(ictrl
, I4B_MON_ICTRL_NAME
, name_of_controller(isdn_ctrl_tab
[i
].ctrl_type
, isdn_ctrl_tab
[i
].card_type
));
657 I4B_PUT_2B(ictrl
, I4B_MON_ICTRL_BUSID
, 0);
658 I4B_PUT_4B(ictrl
, I4B_MON_ICTRL_FLAGS
, 0);
659 I4B_PUT_4B(ictrl
, I4B_MON_ICTRL_NCHAN
, 2);
661 if((sock_write(fd
, ictrl
, sizeof ictrl
)) == -1)
663 dolog(LL_MER
, "monitor_handle_connect: sock_write 2 error - %s", strerror(errno
));
668 /* send device names from entries */
670 for(i
=0; i
< nentries
; i
++) /* walk thru all entries */
672 u_int8_t ictrl
[I4B_MON_IDEV_SIZE
];
675 p
= &cfg_entry_tab
[i
]; /* get ptr to enry */
677 snprintf(nbuf
, sizeof(nbuf
), "%s%d ", bdrivername(p
->usrdevicename
), p
->usrdeviceunit
);
679 I4B_PREP_CMD(ictrl
, I4B_MON_IDEV_CODE
);
680 /*XXX*/ I4B_PUT_2B(ictrl
, I4B_MON_IDEV_STATE
, 1);
681 I4B_PUT_STR(ictrl
, I4B_MON_IDEV_NAME
, nbuf
);
683 if((sock_write(fd
, ictrl
, sizeof ictrl
)) == -1)
685 dolog(LL_MER
, "monitor_handle_connect: sock_write 3 error - %s", strerror(errno
));
689 /*XXX*/ t_events
= con
->events
;
690 /*XXX*/ con
->events
= -1;
692 /* current state of controller(s) */
694 for(i
=0; i
< ncontroller
; i
++)
696 monitor_evnt_tei(i
, isdn_ctrl_tab
[i
].tei
);
697 monitor_evnt_l12stat(i
, LAYER_ONE
, isdn_ctrl_tab
[i
].l1stat
);
698 monitor_evnt_l12stat(i
, LAYER_TWO
, isdn_ctrl_tab
[i
].l2stat
);
701 /* current state of entries */
703 for(i
=0; i
< nentries
; i
++)
705 cfg_entry_t
*cep
= &cfg_entry_tab
[i
];
707 if(cep
->state
== ST_CONNECTED
)
709 monitor_evnt_connect(cep
);
710 monitor_evnt_acct(cep
);
711 monitor_evnt_charge(cep
, cep
->charge
, 1);
715 /*XXX*/ con
->events
= t_events
;
719 /*---------------------------------------------------------------------------
720 * dump all monitor rights
721 *---------------------------------------------------------------------------*/
723 cmd_dump_rights(int fd
, int r_mask
, u_int8_t
*cmd
, const char *source
)
725 struct monitor_rights
* r
;
727 u_int8_t drini
[I4B_MON_DRINI_SIZE
];
728 u_int8_t dr
[I4B_MON_DR_SIZE
];
730 for (num_rights
= 0, r
= TAILQ_FIRST(&rights
); r
!= NULL
; r
= TAILQ_NEXT(r
, list
))
733 I4B_PREP_EVNT(drini
, I4B_MON_DRINI_CODE
);
734 I4B_PUT_2B(drini
, I4B_MON_DRINI_COUNT
, num_rights
);
736 if((sock_write(fd
, drini
, sizeof drini
)) == -1)
738 dolog(LL_MER
, "cmd_dump_rights: sock_write 1 error - %s", strerror(errno
));
741 for (r
= TAILQ_FIRST(&rights
); r
!= NULL
; r
= TAILQ_NEXT(r
, list
))
743 I4B_PREP_EVNT(dr
, I4B_MON_DR_CODE
);
744 I4B_PUT_4B(dr
, I4B_MON_DR_RIGHTS
, r
->rights
);
745 I4B_PUT_4B(dr
, I4B_MON_DR_NET
, r
->net
);
746 I4B_PUT_4B(dr
, I4B_MON_DR_MASK
, r
->mask
);
747 I4B_PUT_1B(dr
, I4B_MON_DR_LOCAL
, r
->local
);
748 if((sock_write(fd
, dr
, sizeof dr
)) == -1)
750 dolog(LL_MER
, "cmd_dump_rights: sock_write 2 error - %s", strerror(errno
));
755 /*---------------------------------------------------------------------------
757 *---------------------------------------------------------------------------*/
759 cmd_reread_cfg(int fd
, int rights
, u_int8_t
*cmd
, const char * source
)
764 /*---------------------------------------------------------------------------
765 * drop one connection
766 *---------------------------------------------------------------------------*/
768 cmd_hangup(int fd
, int rights
, u_int8_t
*cmd
, const char * source
)
770 int channel
= I4B_GET_4B(cmd
, I4B_MON_HANGUP_CHANNEL
);
771 int ctrl
= I4B_GET_4B(cmd
, I4B_MON_HANGUP_CTRL
);
773 hangup_channel(ctrl
, channel
, source
);
776 /*---------------------------------------------------------------------------
777 * dump all active monitor connections
778 *---------------------------------------------------------------------------*/
780 cmd_dump_mcons(int fd
, int rights
, u_int8_t
*cmd
, const char * source
)
783 struct monitor_connection
*con
;
784 u_int8_t dcini
[I4B_MON_DCINI_SIZE
];
786 for (num_connections
= 0, con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= TAILQ_NEXT(con
, connections
))
789 I4B_PREP_EVNT(dcini
, I4B_MON_DCINI_CODE
);
790 I4B_PUT_2B(dcini
, I4B_MON_DCINI_COUNT
, num_connections
);
792 if((sock_write(fd
, dcini
, sizeof dcini
)) == -1)
794 dolog(LL_MER
, "cmd_dump_mcons: sock_write 1 error - %s", strerror(errno
));
797 for (con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= TAILQ_NEXT(con
, connections
))
799 #ifndef I4B_NOTCPIP_MONITOR
801 struct sockaddr_in name
;
803 u_int8_t dc
[I4B_MON_DC_SIZE
];
805 I4B_PREP_EVNT(dc
, I4B_MON_DC_CODE
);
806 I4B_PUT_4B(dc
, I4B_MON_DC_RIGHTS
, con
->rights
);
808 #ifndef I4B_NOTCPIP_MONITOR
809 namelen
= sizeof name
;
811 if (getpeername(con
->sock
, (struct sockaddr
*)&name
, &namelen
) == 0)
812 memcpy(dc
+I4B_MON_DC_WHO
, &name
.sin_addr
, sizeof name
.sin_addr
);
814 if((sock_write(fd
, dc
, sizeof dc
)) == -1)
816 dolog(LL_MER
, "cmd_dump_mcons: sock_write 2 error - %s", strerror(errno
));
821 /*---------------------------------------------------------------------------
822 * Handle a command from the given socket. The client
823 * has rights as specified in the rights parameter.
824 * Return non-zero if connection is closed.
825 *---------------------------------------------------------------------------*/
827 monitor_command(struct monitor_connection
* con
, int fd
, int rights
)
829 char cmd
[I4B_MAX_MON_CLIENT_CMD
];
832 /* command dispatch table */
833 typedef void (*cmd_func_t
)(int fd
, int rights
, u_int8_t
*cmd
, const char *source
);
836 cmd_func_t call
; /* function to execute */
837 u_int rights
; /* necessary rights */
841 /* 1 */ { cmd_dump_rights
, I4B_CA_COMMAND_FULL
},
842 /* 2 */ { cmd_dump_mcons
, I4B_CA_COMMAND_FULL
},
843 /* 3 */ { cmd_reread_cfg
, I4B_CA_COMMAND_FULL
},
844 /* 4 */ { cmd_hangup
, I4B_CA_COMMAND_FULL
},
846 #define NUMCMD (sizeof cmd_tab / sizeof cmd_tab[0])
851 /* Network transfer may deliver two or more packets concatenated.
852 * Peek at the header and read only one event at a time... */
854 ioctl(fd
, FIONREAD
, &u
);
856 if (u
< I4B_MON_CMD_HDR
)
860 /* dolog(LL_MER, "monitor read 0 bytes"); */
861 /* socket closed by peer */
865 return 0; /* not enough data there yet */
868 bytes
= recv(fd
, cmd
, I4B_MON_CMD_HDR
, MSG_PEEK
);
870 if (bytes
< I4B_MON_CMD_HDR
)
872 dolog(LL_MER
, "monitor read only %d bytes", bytes
);
873 return 0; /* errh? something must be wrong... */
876 bytes
= I4B_GET_2B(cmd
, I4B_MON_CMD_LEN
);
878 if (bytes
>= sizeof cmd
)
881 dolog(LL_MER
, "monitor: garbage on connection");
885 /* now we know the size, it fits, so lets read it! */
887 if(sock_read(fd
, cmd
, bytes
) <= 0)
889 dolog(LL_MER
, "monitor: sock_read <= 0");
895 code
= I4B_GET_2B(cmd
, I4B_MON_CMD
);
897 /* special case: may modify our connection descriptor, is
898 * beyound all rights checks */
900 if (code
== I4B_MON_CCMD_SETMASK
)
904 u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR);
905 u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR);
908 int events
= I4B_GET_4B(cmd
, I4B_MON_ICLIENT_EVENTS
);
909 con
->events
= events
& rights
;
913 if (code
< 0 || code
>= NUMCMD
)
915 dolog(LL_MER
, "illegal command from client, code = %d\n",
920 if (cmd_tab
[code
].call
== NULL
)
923 if ((cmd_tab
[code
].rights
& rights
) == cmd_tab
[code
].rights
)
924 cmd_tab
[code
].call(fd
, rights
, cmd
, con
->source
);
929 /*---------------------------------------------------------------------------
930 * Check if somebody would receive an event with this mask.
931 * We are lazy and try to avoid assembling unneccesary packets.
932 * Return 0 if no one interested, nonzero otherwise.
933 *---------------------------------------------------------------------------*/
937 struct monitor_connection
* con
;
939 for (con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= TAILQ_NEXT(con
, connections
))
941 if ((con
->events
& mask
) == mask
)
947 /*---------------------------------------------------------------------------
948 * exec hangup command
949 *---------------------------------------------------------------------------*/
951 hangup_channel(int controller
, int channel
, const char *source
)
953 cfg_entry_t
* cep
= NULL
;
956 if(controller
< ncontroller
)
958 if(isdn_ctrl_tab
[controller
].state
!= CTRL_UP
)
960 for (i
= 0; i
< isdn_ctrl_tab
[controller
].nbch
; i
++)
962 if(isdn_ctrl_tab
[controller
].stateb
[i
] != CHAN_IDLE
)
964 cep
= get_cep_by_cc(controller
, i
);
965 if (cep
!= NULL
&& cep
->isdnchannelused
== channel
&&
966 cep
->isdncontrollerused
== controller
)
975 dolog(LL_CHD
, "%05d %s manual disconnect (remote from %s)", cep
->cdid
, cep
->name
, source
);
980 /*---------------------------------------------------------------------------
981 * Send an event to every connection interested in this kind of
983 *---------------------------------------------------------------------------*/
985 monitor_broadcast(int mask
, u_int8_t
*pkt
, size_t bytes
)
987 struct monitor_connection
*con
;
989 for (con
= TAILQ_FIRST(&connections
); con
!= NULL
; con
= TAILQ_NEXT(con
, connections
))
991 if ((con
->events
& mask
) == mask
)
995 if((sock_write(fd
, pkt
, bytes
)) == -1)
997 dolog(LL_MER
, "monitor_broadcast: sock_write error - %s", strerror(errno
));
1003 /*---------------------------------------------------------------------------
1004 * Post a logfile event
1005 *---------------------------------------------------------------------------*/
1007 monitor_evnt_log(int prio
, const char * what
, const char * msg
)
1009 u_int8_t evnt
[I4B_MON_LOGEVNT_SIZE
];
1012 if (!anybody(I4B_CA_EVNT_I4B
))
1017 I4B_PREP_EVNT(evnt
, I4B_MON_LOGEVNT_CODE
);
1018 I4B_PUT_4B(evnt
, I4B_MON_LOGEVNT_TSTAMP
, (long)now
);
1019 I4B_PUT_4B(evnt
, I4B_MON_LOGEVNT_PRIO
, prio
);
1020 I4B_PUT_STR(evnt
, I4B_MON_LOGEVNT_WHAT
, what
);
1021 I4B_PUT_STR(evnt
, I4B_MON_LOGEVNT_MSG
, msg
);
1023 monitor_broadcast(I4B_CA_EVNT_I4B
, evnt
, sizeof evnt
);
1026 /*---------------------------------------------------------------------------
1027 * Post a charging event on the connection described
1028 * by the given config entry.
1029 *---------------------------------------------------------------------------*/
1031 monitor_evnt_charge(cfg_entry_t
*cep
, int units
, int estimate
)
1035 u_int8_t evnt
[I4B_MON_CHRG_SIZE
];
1037 mask
= (cep
->direction
== DIR_IN
) ? I4B_CA_EVNT_CALLIN
: I4B_CA_EVNT_CALLOUT
;
1044 I4B_PREP_EVNT(evnt
, I4B_MON_CHRG_CODE
);
1045 I4B_PUT_4B(evnt
, I4B_MON_CHRG_TSTAMP
, (long)now
);
1046 I4B_PUT_4B(evnt
, I4B_MON_CHRG_CTRL
, cep
->isdncontrollerused
);
1047 I4B_PUT_4B(evnt
, I4B_MON_CHRG_CHANNEL
, cep
->isdnchannelused
);
1048 I4B_PUT_4B(evnt
, I4B_MON_CHRG_UNITS
, units
);
1049 I4B_PUT_4B(evnt
, I4B_MON_CHRG_ESTIMATED
, estimate
? 1 : 0);
1051 monitor_broadcast(mask
, evnt
, sizeof evnt
);
1054 /*---------------------------------------------------------------------------
1055 * Post a connection event
1056 *---------------------------------------------------------------------------*/
1058 monitor_evnt_connect(cfg_entry_t
*cep
)
1060 u_int8_t evnt
[I4B_MON_CONNECT_SIZE
];
1061 char devname
[I4B_MAX_MON_STRING
];
1065 mask
= (cep
->direction
== DIR_IN
) ? I4B_CA_EVNT_CALLIN
: I4B_CA_EVNT_CALLOUT
;
1072 snprintf(devname
, sizeof devname
, "%s%d", bdrivername(cep
->usrdevicename
), cep
->usrdeviceunit
);
1074 I4B_PREP_EVNT(evnt
, I4B_MON_CONNECT_CODE
);
1075 I4B_PUT_4B(evnt
, I4B_MON_CONNECT_TSTAMP
, (long)now
);
1076 I4B_PUT_4B(evnt
, I4B_MON_CONNECT_DIR
, cep
->direction
== DIR_OUT
? 1 : 0);
1077 I4B_PUT_4B(evnt
, I4B_MON_CONNECT_CTRL
, cep
->isdncontrollerused
);
1078 I4B_PUT_4B(evnt
, I4B_MON_CONNECT_CHANNEL
, cep
->isdnchannelused
);
1079 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_CFGNAME
, cep
->name
);
1080 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_DEVNAME
, devname
);
1082 if(cep
->direction
== DIR_OUT
)
1084 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_REMPHONE
, cep
->remote_phone_dialout
);
1085 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_LOCPHONE
, cep
->local_phone_dialout
);
1089 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_REMPHONE
, cep
->real_phone_incoming
);
1090 I4B_PUT_STR(evnt
, I4B_MON_CONNECT_LOCPHONE
, cep
->local_phone_incoming
);
1092 monitor_broadcast(mask
, evnt
, sizeof evnt
);
1095 /*---------------------------------------------------------------------------
1096 * Post a disconnect event
1097 *---------------------------------------------------------------------------*/
1099 monitor_evnt_disconnect(cfg_entry_t
*cep
)
1101 u_int8_t evnt
[I4B_MON_DISCONNECT_SIZE
];
1105 mask
= (cep
->direction
== DIR_IN
) ? I4B_CA_EVNT_CALLIN
: I4B_CA_EVNT_CALLOUT
;
1112 I4B_PREP_EVNT(evnt
, I4B_MON_DISCONNECT_CODE
);
1113 I4B_PUT_4B(evnt
, I4B_MON_DISCONNECT_TSTAMP
, (long)now
);
1114 I4B_PUT_4B(evnt
, I4B_MON_DISCONNECT_CTRL
, cep
->isdncontrollerused
);
1115 I4B_PUT_4B(evnt
, I4B_MON_DISCONNECT_CHANNEL
, cep
->isdnchannelused
);
1117 monitor_broadcast(mask
, evnt
, sizeof evnt
);
1120 /*---------------------------------------------------------------------------
1121 * Post an up/down event
1122 *---------------------------------------------------------------------------*/
1124 monitor_evnt_updown(cfg_entry_t
*cep
, int up
)
1126 u_int8_t evnt
[I4B_MON_UPDOWN_SIZE
];
1130 mask
= (cep
->direction
== DIR_IN
) ? I4B_CA_EVNT_CALLIN
: I4B_CA_EVNT_CALLOUT
;
1137 I4B_PREP_EVNT(evnt
, I4B_MON_UPDOWN_CODE
);
1138 I4B_PUT_4B(evnt
, I4B_MON_UPDOWN_TSTAMP
, (long)now
);
1139 I4B_PUT_4B(evnt
, I4B_MON_UPDOWN_CTRL
, cep
->isdncontrollerused
);
1140 I4B_PUT_4B(evnt
, I4B_MON_UPDOWN_CHANNEL
, cep
->isdnchannelused
);
1141 I4B_PUT_4B(evnt
, I4B_MON_UPDOWN_ISUP
, up
);
1143 monitor_broadcast(mask
, evnt
, sizeof evnt
);
1146 /*---------------------------------------------------------------------------
1147 * Post a Layer1/2 status change event
1148 *---------------------------------------------------------------------------*/
1150 monitor_evnt_l12stat(int controller
, int layer
, int state
)
1152 u_int8_t evnt
[I4B_MON_L12STAT_SIZE
];
1155 if(!anybody(I4B_CA_EVNT_I4B
))
1160 I4B_PREP_EVNT(evnt
, I4B_MON_L12STAT_CODE
);
1161 I4B_PUT_4B(evnt
, I4B_MON_L12STAT_TSTAMP
, (long)now
);
1162 I4B_PUT_4B(evnt
, I4B_MON_L12STAT_CTRL
, controller
);
1163 I4B_PUT_4B(evnt
, I4B_MON_L12STAT_LAYER
, layer
);
1164 I4B_PUT_4B(evnt
, I4B_MON_L12STAT_STATE
, state
);
1166 monitor_broadcast(I4B_CA_EVNT_I4B
, evnt
, sizeof evnt
);
1169 /*---------------------------------------------------------------------------
1170 * Post a TEI change event
1171 *---------------------------------------------------------------------------*/
1173 monitor_evnt_tei(int controller
, int tei
)
1175 u_int8_t evnt
[I4B_MON_TEI_SIZE
];
1178 if(!anybody(I4B_CA_EVNT_I4B
))
1183 I4B_PREP_EVNT(evnt
, I4B_MON_TEI_CODE
);
1184 I4B_PUT_4B(evnt
, I4B_MON_TEI_TSTAMP
, (long)now
);
1185 I4B_PUT_4B(evnt
, I4B_MON_TEI_CTRL
, controller
);
1186 I4B_PUT_4B(evnt
, I4B_MON_TEI_TEI
, tei
);
1188 monitor_broadcast(I4B_CA_EVNT_I4B
, evnt
, sizeof evnt
);
1191 /*---------------------------------------------------------------------------
1192 * Post an accounting event
1193 *---------------------------------------------------------------------------*/
1195 monitor_evnt_acct(cfg_entry_t
*cep
)
1197 u_int8_t evnt
[I4B_MON_ACCT_SIZE
];
1200 if(!anybody(I4B_CA_EVNT_I4B
))
1205 I4B_PREP_EVNT(evnt
, I4B_MON_ACCT_CODE
);
1206 I4B_PUT_4B(evnt
, I4B_MON_ACCT_TSTAMP
, (long)now
);
1208 I4B_PUT_4B(evnt
, I4B_MON_ACCT_CTRL
, cep
->isdncontrollerused
);
1209 I4B_PUT_4B(evnt
, I4B_MON_ACCT_CHAN
, cep
->isdnchannelused
);
1210 I4B_PUT_4B(evnt
, I4B_MON_ACCT_OBYTES
, cep
->outbytes
);
1211 I4B_PUT_4B(evnt
, I4B_MON_ACCT_OBPS
, cep
->outbps
);
1212 I4B_PUT_4B(evnt
, I4B_MON_ACCT_IBYTES
, cep
->inbytes
);
1213 I4B_PUT_4B(evnt
, I4B_MON_ACCT_IBPS
, cep
->inbps
);
1215 monitor_broadcast(I4B_CA_EVNT_I4B
, evnt
, sizeof evnt
);
1218 /*---------------------------------------------------------------------------
1219 * read from a socket
1220 *---------------------------------------------------------------------------*/
1222 sock_read(int fd
, void *buf
, size_t nbytes
)
1233 if((nread
= read(fd
, ptr
, nleft
)) < 0)
1252 return(nbytes
- nleft
);
1255 /*---------------------------------------------------------------------------
1257 *---------------------------------------------------------------------------*/
1259 sock_write(int fd
, void *buf
, size_t nbytes
)
1270 if((nwritten
= write(fd
, ptr
, nleft
)) <= 0)
1288 struct monitor_rights
*
1289 monitor_next_rights(const struct monitor_rights
*r
)
1292 return TAILQ_FIRST(&rights
);
1294 return TAILQ_NEXT(r
, list
);
1297 #endif /* I4B_EXTERNAL_MONITOR */