Remove some unnecessary casts.
[dragonfly.git] / usr.sbin / i4b / isdnd / monitor.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1998,1999 Martin Husemann. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
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.
18 *
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.
30 *
31 *---------------------------------------------------------------------------
32 *
33 * i4b daemon - network monitor server module
34 * ------------------------------------------
35 *
36 * $Id: monitor.c,v 1.30 2000/10/09 12:53:29 hm Exp $
37 *
38 * $FreeBSD: src/usr.sbin/i4b/isdnd/monitor.c,v 1.6.2.2 2001/08/01 17:45:03 obrien Exp $
fe361e7d 39 * $DragonFly: src/usr.sbin/i4b/isdnd/monitor.c,v 1.4 2005/11/25 00:58:52 swildner Exp $
984263bc
MD
40 *
41 * last edit-date: [Mon Dec 13 21:47:44 1999]
42 *
43 *---------------------------------------------------------------------------*/
44
45#include "isdnd.h"
46
47#ifndef I4B_EXTERNAL_MONITOR
48
49/*
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)
53 */
54
fe361e7d
SW
55void
56monitor_clear_rights(void)
68da13b1
EN
57{
58}
984263bc 59
fe361e7d
SW
60int
61monitor_start_rights(const char *clientspec)
68da13b1
EN
62{
63 return I4BMAR_OK;
64}
984263bc 65
fe361e7d
SW
66void
67monitor_add_rights(int rights_mask)
68da13b1
EN
68{
69}
984263bc 70
fe361e7d
SW
71void
72monitor_fixup_rights(void)
68da13b1
EN
73{
74}
984263bc
MD
75
76#else
77
78#include "monitor.h"
79#include <sys/socket.h>
80#include <sys/un.h>
81#ifndef I4B_NOTCPIP_MONITOR
82#include <netinet/in.h>
83#include <arpa/inet.h>
84#include <netdb.h>
85#endif
86
87
88static TAILQ_HEAD(rights_q, monitor_rights) rights = TAILQ_HEAD_INITIALIZER(rights);
89
90static struct monitor_rights * local_rights = NULL; /* entry for local socket */
91
92/* for each active monitor connection we have one of this: */
93
94struct 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];
100};
101
102static TAILQ_HEAD(connections_tq, monitor_connection) connections = TAILQ_HEAD_INITIALIZER(connections);
103
104/* local prototypes */
105static int cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb);
106static int monitor_command(struct monitor_connection *con, int fd, int rights);
107static void cmd_dump_rights(int fd, int rights, u_int8_t *cmd, const char * source);
108static void cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source);
109static void cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source);
110static void cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source);
111static void monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes);
112static int anybody(int mask);
113static void hangup_channel(int controller, int channel, const char *source);
114static ssize_t sock_read(int fd, void *buf, size_t nbytes);
115static ssize_t sock_write(int fd, void *buf, size_t nbytes);
116
117/*
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.
124 */
125static struct monitor_rights * cur_add_entry = NULL;
126
127/*---------------------------------------------------------------------------
128 * Initialize the monitor server module. This affects only active
129 * connections, the access rights are not modified here!
130 *---------------------------------------------------------------------------*/
131void
132monitor_init(void)
133{
134 struct monitor_connection * con;
135 accepted = 0;
136 while ((con = TAILQ_FIRST(&connections)) != NULL)
137 {
138 TAILQ_REMOVE(&connections, con, connections);
139 free(con);
140 }
141}
142
143/*---------------------------------------------------------------------------
144 * Prepare for exit
145 *---------------------------------------------------------------------------*/
146void
147monitor_exit(void)
148{
149 struct monitor_connection *c;
150
151 /* Close all open connections. */
152 while((c = TAILQ_FIRST(&connections)) != NULL) {
153 close(c->sock);
154 TAILQ_REMOVE(&connections, c, connections);
155 free(c);
156 }
157}
158
159/*---------------------------------------------------------------------------
160 * Initialize access rights. No active connections are affected!
161 *---------------------------------------------------------------------------*/
162void
163monitor_clear_rights(void)
164{
165 struct monitor_rights *r;
166 while ((r = TAILQ_FIRST(&rights)) != NULL) {
167 TAILQ_REMOVE(&rights, r, list);
168 free(r);
169 }
170 cur_add_entry = NULL;
171 local_rights = NULL;
172}
173
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 *---------------------------------------------------------------------------*/
179int
180monitor_start_rights(const char *clientspec)
181{
182 struct monitor_rights r;
183
184 /* initialize the new rights entry */
185
186 memset(&r, 0, sizeof r);
187
188 /* check clientspec */
189
190 if (*clientspec == '/')
191 {
192 struct sockaddr_un sa;
193
194 /* this is a local socket spec, check if we already have one */
195
196 if (local_rights != NULL)
197 return I4BMAR_DUP;
198
199 /* does it fit in a local socket address? */
200
201 if (strlen(clientspec) > sizeof sa.sun_path)
202 return I4BMAR_LENGTH;
203
204 r.local = 1;
205 strcpy(r.name, clientspec);
206
207#ifndef I4B_NOTCPIP_MONITOR
208
209 }
210 else
211 {
212 /* remote entry, parse host/net and cidr */
213
214 struct monitor_rights * rp;
215 char hostname[FILENAME_MAX];
216 char *p;
217
218 p = strchr(clientspec, '/');
219
220 if (!p)
221 {
222 struct hostent *host;
223 u_int32_t hn;
224
225 /* must be a host spec */
226
227 r.mask = ~0;
228 host = gethostbyname(clientspec);
229
230 if (!host)
231 return I4BMAR_NOIP;
232
233 memcpy(&hn, host->h_addr_list[0], sizeof hn);
234 r.net = (u_int32_t)ntohl(hn);
235 }
236 else if(p[1])
237 {
238 /* must be net/cidr spec */
239
240 int l;
241 struct netent *net;
242 u_int32_t s = ~0U;
243 int num = strtol(p+1, NULL, 10);
244
245 if (num < 0 || num > 32)
246 return I4BMAR_CIDR;
247
248 s >>= num;
249 s ^= ~0U;
250 l = p - clientspec;
251
252 if (l >= sizeof hostname)
253 return I4BMAR_LENGTH;
254
255 strncpy(hostname, clientspec, l);
256
257 hostname[l] = '\0';
258
259 net = getnetbyname(hostname);
260
261 if (net == NULL)
262 r.net = (u_int32_t)inet_network(hostname);
263 else
264 r.net = (u_int32_t)net->n_net;
265
266 r.mask = s;
267 r.net &= s;
268 }
269 else
270 {
271 return I4BMAR_CIDR;
272 }
273
274 /* check for duplicate entry */
275
276 for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
277 {
278 if (rp->mask == r.mask &&
279 rp->net == r.net &&
280 rp->local == r.local)
281 {
282 return I4BMAR_DUP;
283 }
284 }
285#endif
286 }
287
288 r.rights = 0;
289
290 /* entry ok, add it to the collection */
291
292 cur_add_entry = malloc(sizeof(r));
293 memcpy(cur_add_entry, &r, sizeof(r));
294 TAILQ_INSERT_TAIL(&rights, cur_add_entry, list);
295
296 if(r.local)
297 local_rights = cur_add_entry;
298
299 DBGL(DL_RCCF, (log(LL_DBG, "system: monitor = %s", clientspec)));
300
301 return I4BMAR_OK;
302}
303
304/*---------------------------------------------------------------------------
305 * Add rights to the currently constructed entry - if any.
306 *---------------------------------------------------------------------------*/
307void
308monitor_add_rights(int rights_mask)
309{
310 if(cur_add_entry == NULL)
311 return; /* noone under construction */
312
313 cur_add_entry->rights |= rights_mask;
314
315 DBGL(DL_RCCF, (log(LL_DBG, "system: monitor-access = 0x%x", rights_mask)));
316}
317
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 *---------------------------------------------------------------------------*/
323void
324monitor_fixup_rights(void)
325{
326 struct monitor_rights * cur, * test, * next;
327
328 /* no more rights may be added to the current entry */
329
330 cur_add_entry = NULL;
331
332 /* sort the rights */
333 for (next = NULL, cur = TAILQ_FIRST(&rights); cur != NULL; cur = next)
334 {
335 next = TAILQ_NEXT(cur, list);
336 for (test = TAILQ_FIRST(&rights); test != NULL && test != cur; test = TAILQ_NEXT(test, list))
337 {
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);
343 else
344 TAILQ_INSERT_BEFORE(test, cur, list);
345 break;
346 }
347 }
348 }
349}
350
351/*---------------------------------------------------------------------------
352 * comparator for rights
353 *---------------------------------------------------------------------------*/
354static int
355cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb)
356{
357 u_int32_t mask;
358
359 /* local sorts first */
360
361 if (pa->local)
362 return -1;
363
364 /* which is the less specific netmask? */
365
366 mask = pa->mask;
367
368 if ((pb->mask & mask) == 0)
369 mask = pb->mask;
370
371 /* are the entries disjunct? */
372
373 if ((pa->net & mask) != (pb->net & mask))
374 {
375 /* simply compare net part of address */
376 return ((pa->net & mask) < (pb->net & mask)) ? -1 : 1;
377 }
378
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 */
381
382 return (pa->mask == mask) ? 1 : -1;
383}
384
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 *---------------------------------------------------------------------------*/
390int
391monitor_create_remote_socket(int portno)
392{
393 struct sockaddr_in sa;
394 int val;
395 int remotesockfd;
396
397 remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
398
399 if(remotesockfd == -1)
400 {
401 log(LL_MER, "could not create remote monitor socket: %s", strerror(errno));
402 return(-1);
403 }
404
405 val = 1;
406
407 if(setsockopt(remotesockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val))
408 {
409 log(LL_MER, "could not setsockopt: %s", strerror(errno));
410 return(-1);
411 }
412
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);
418
419 if(bind(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1)
420 {
421 log(LL_MER, "could not bind remote monitor socket to port %d: %s", portno, strerror(errno));
422 return(-1);
423 }
424
425 if(listen(remotesockfd, 0))
426 {
427 log(LL_MER, "could not listen on monitor socket: %s", strerror(errno));
428 return(-1);
429 }
430
431 return(remotesockfd);
432}
433#endif
434
435/*---------------------------------------------------------------------------
436 * Check if access rights for a local socket are specified and
437 * create this socket. Return -1 otherwise.
438 *---------------------------------------------------------------------------*/
439int
440monitor_create_local_socket(void)
441{
442 int s;
443 struct sockaddr_un sa;
444
445 /* check for a local entry */
446
447 if (local_rights == NULL)
448 return(-1);
449
450 /* create and setup socket */
451
452 s = socket(AF_LOCAL, SOCK_STREAM, 0);
453
454 if (s == -1)
455 {
456 log(LL_MER, "could not create local monitor socket, errno = %d", errno);
457 return(-1);
458 }
459
460 unlink(local_rights->name);
461
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);
466
467 if (bind(s, (struct sockaddr *)&sa, SUN_LEN(&sa)))
468 {
469 log(LL_MER, "could not bind local monitor socket [%s], errno = %d", local_rights->name, errno);
470 return(-1);
471 }
472
473 chmod(local_rights->name, 0500);
474
475 if (listen(s, 0))
476 {
477 log(LL_MER, "could not listen on local monitor socket, errno = %d", errno);
478 return(-1);
479 }
480
481 return(s);
482}
483
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 *---------------------------------------------------------------------------*/
488void
489monitor_prepselect(fd_set *selset, int *max_fd)
490{
491 struct monitor_connection * con;
492
493 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
494 {
495 int fd = con->sock;
496
497 if (fd > *max_fd)
498 *max_fd = fd;
499
500 FD_SET(fd, selset);
501 }
502}
503
504/*---------------------------------------------------------------------------
505 * Check if the result from a select call indicates something
506 * to do for us.
507 *---------------------------------------------------------------------------*/
508void
509monitor_handle_input(fd_set *selset)
510{
511 struct monitor_connection * con, * next;
512
513 for (next = NULL, con = TAILQ_FIRST(&connections); con != NULL; con = next)
514 {
515 int fd = con->sock;
516 next = TAILQ_NEXT(con, connections);
517
518 if (FD_ISSET(fd, selset))
519 {
520 /* handle command from this client */
521
522 if (monitor_command(con, fd, con->rights) != 0)
523 {
524 /* broken or closed connection */
525
526 char source[FILENAME_MAX];
527
528 strcpy(source, con->source);
529 TAILQ_REMOVE(&connections, con, connections);
530 free(con);
531 log(LL_DMN, "monitor closed from %s", source );
532 }
533 }
534 }
535
536 /* all connections gone? */
537
538 if (TAILQ_FIRST(&connections) == NULL)
539 accepted = 0;
540}
541
542/*---------------------------------------------------------------------------
543 * Try new incoming connection on the given socket.
544 * Setup client descriptor and send initial data.
545 *---------------------------------------------------------------------------*/
546void
547monitor_handle_connect(int sockfd, int is_local)
548{
549 struct monitor_connection *con;
550 struct monitor_rights *rp;
551
552#ifndef I4B_NOTCPIP_MONITOR
553 struct sockaddr_in ia;
554 u_int32_t ha = 0;
555#endif
556
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];
561
562 /* accept the connection */
563
564 if(is_local)
565 {
566 s = sizeof ua;
567 fd = accept(sockfd, (struct sockaddr *)&ua, &s);
568 strcpy(source, "local");
569
570#ifndef I4B_NOTCPIP_MONITOR
571 }
572 else
573 {
574 struct hostent *hp;
575
576 s = sizeof ia;
577 fd = accept(sockfd, (struct sockaddr *)&ia, &s);
578
15b85273 579 hp = gethostbyaddr(&ia.sin_addr, 4, AF_INET);
984263bc
MD
580
581 if(hp == NULL)
582 snprintf(source, sizeof source, "%s (%s)", inet_ntoa(ia.sin_addr), inet_ntoa(ia.sin_addr));
583 else
584 snprintf(source, sizeof source, "%s (%s)", hp->h_name, inet_ntoa(ia.sin_addr));
585
586 memcpy(&ha, &ia.sin_addr.s_addr, sizeof ha);
587
588 ha = ntohl(ha);
589#endif
590 }
591
592 /* check the access rights of this connection */
593
594 r_mask = 0;
595
596 for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
597 {
598 if(rp->local)
599 {
600 if(is_local)
601 {
602 r_mask = rp->rights;
603 break;
604 }
605
606#ifndef I4B_NOTCPIP_MONITOR
607 }
608 else
609 {
610 if((ha & rp->mask) == rp->net)
611 {
612 r_mask = rp->rights;
613 break;
614 }
615#endif
616 }
617 }
618
619 if(r_mask == 0)
620 {
621 /* no rights - go away */
622 log(LL_MER, "monitor access denied from %s", source);
623 close(fd);
624 return;
625 }
626
627 accepted = 1;
628
629 con = malloc(sizeof(struct monitor_connection));
630 memset(con, 0, sizeof *con);
631 TAILQ_INSERT_TAIL(&connections, con, connections);
632 con->sock = fd;
633 con->rights = r_mask;
634 strcpy(con->source, source);
635
636 log(LL_DMN, "monitor opened from %s rights 0x%x", source, r_mask);
637
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);
645
646 if((sock_write(fd, idata, sizeof idata)) == -1)
647 {
648 log(LL_MER, "monitor_handle_connect: sock_write 1 error - %s", strerror(errno));
649 }
650
651 for (i = 0; i < ncontroller; i++)
652 {
653 u_int8_t ictrl[I4B_MON_ICTRL_SIZE];
654
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);
660
661 if((sock_write(fd, ictrl, sizeof ictrl)) == -1)
662 {
663 log(LL_MER, "monitor_handle_connect: sock_write 2 error - %s", strerror(errno));
664 }
665
666 }
667
668 /* send device names from entries */
669
670 for(i=0; i < nentries; i++) /* walk thru all entries */
671 {
672 u_int8_t ictrl[I4B_MON_IDEV_SIZE];
673 cfg_entry_t *p;
674 char nbuf[64];
675 p = &cfg_entry_tab[i]; /* get ptr to enry */
676
677 snprintf(nbuf, sizeof(nbuf), "%s%d ", bdrivername(p->usrdevicename), p->usrdeviceunit);
678
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);
682
683 if((sock_write(fd, ictrl, sizeof ictrl)) == -1)
684 {
685 log(LL_MER, "monitor_handle_connect: sock_write 3 error - %s", strerror(errno));
686 }
687 }
688
689/*XXX*/ t_events = con->events;
690/*XXX*/ con->events = -1;
691
692 /* current state of controller(s) */
693
694 for(i=0; i < ncontroller; i++)
695 {
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);
699 }
700
701 /* current state of entries */
702
703 for(i=0; i < nentries; i++)
704 {
705 cfg_entry_t *cep = &cfg_entry_tab[i];
706
707 if(cep->state == ST_CONNECTED)
708 {
709 monitor_evnt_connect(cep);
710 monitor_evnt_acct(cep);
711 monitor_evnt_charge(cep, cep->charge, 1);
712 }
713 }
714
715/*XXX*/ con->events = t_events;
716
717}
718
719/*---------------------------------------------------------------------------
720 * dump all monitor rights
721 *---------------------------------------------------------------------------*/
722static void
723cmd_dump_rights(int fd, int r_mask, u_int8_t *cmd, const char *source)
724{
725 struct monitor_rights * r;
726 int num_rights;
727 u_int8_t drini[I4B_MON_DRINI_SIZE];
728 u_int8_t dr[I4B_MON_DR_SIZE];
729
730 for (num_rights = 0, r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
731 num_rights++;
732
733 I4B_PREP_EVNT(drini, I4B_MON_DRINI_CODE);
734 I4B_PUT_2B(drini, I4B_MON_DRINI_COUNT, num_rights);
735
736 if((sock_write(fd, drini, sizeof drini)) == -1)
737 {
738 log(LL_MER, "cmd_dump_rights: sock_write 1 error - %s", strerror(errno));
739 }
740
741 for (r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
742 {
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)
749 {
750 log(LL_MER, "cmd_dump_rights: sock_write 2 error - %s", strerror(errno));
751 }
752 }
753}
754
755/*---------------------------------------------------------------------------
756 * rescan config file
757 *---------------------------------------------------------------------------*/
758static void
759cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source)
760{
761 rereadconfig(42);
762}
763
764/*---------------------------------------------------------------------------
765 * drop one connection
766 *---------------------------------------------------------------------------*/
767static void
768cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source)
769{
770 int channel = I4B_GET_4B(cmd, I4B_MON_HANGUP_CHANNEL);
771 int ctrl = I4B_GET_4B(cmd, I4B_MON_HANGUP_CTRL);
772
773 hangup_channel(ctrl, channel, source);
774}
775
776/*---------------------------------------------------------------------------
777 * dump all active monitor connections
778 *---------------------------------------------------------------------------*/
779static void
780cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source)
781{
782 int num_connections;
783 struct monitor_connection *con;
784 u_int8_t dcini[I4B_MON_DCINI_SIZE];
785
786 for (num_connections = 0, con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
787 num_connections++;
788
789 I4B_PREP_EVNT(dcini, I4B_MON_DCINI_CODE);
790 I4B_PUT_2B(dcini, I4B_MON_DCINI_COUNT, num_connections);
791
792 if((sock_write(fd, dcini, sizeof dcini)) == -1)
793 {
794 log(LL_MER, "cmd_dump_mcons: sock_write 1 error - %s", strerror(errno));
795 }
796
797 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
798 {
799#ifndef I4B_NOTCPIP_MONITOR
800 int namelen;
801 struct sockaddr_in name;
802#endif
803 u_int8_t dc[I4B_MON_DC_SIZE];
804
805 I4B_PREP_EVNT(dc, I4B_MON_DC_CODE);
806 I4B_PUT_4B(dc, I4B_MON_DC_RIGHTS, con->rights);
807
808#ifndef I4B_NOTCPIP_MONITOR
809 namelen = sizeof name;
810
811 if (getpeername(con->sock, (struct sockaddr*)&name, &namelen) == 0)
812 memcpy(dc+I4B_MON_DC_WHO, &name.sin_addr, sizeof name.sin_addr);
813#endif
814 if((sock_write(fd, dc, sizeof dc)) == -1)
815 {
816 log(LL_MER, "cmd_dump_mcons: sock_write 2 error - %s", strerror(errno));
817 }
818 }
819}
820
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 *---------------------------------------------------------------------------*/
826static int
827monitor_command(struct monitor_connection * con, int fd, int rights)
828{
829 char cmd[I4B_MAX_MON_CLIENT_CMD];
830 u_int code;
831
832 /* command dispatch table */
833 typedef void (*cmd_func_t)(int fd, int rights, u_int8_t *cmd, const char *source);
834
835 static struct {
836 cmd_func_t call; /* function to execute */
837 u_int rights; /* necessary rights */
838 } cmd_tab[] =
839 {
840 /* 0 */ { NULL, 0 },
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 },
845 };
846#define NUMCMD (sizeof cmd_tab / sizeof cmd_tab[0])
847
848 u_long u;
849 int bytes;
850
851 /* Network transfer may deliver two or more packets concatenated.
852 * Peek at the header and read only one event at a time... */
853
854 ioctl(fd, FIONREAD, &u);
855
856 if (u < I4B_MON_CMD_HDR)
857 {
858 if (u == 0)
859 {
860 /* log(LL_MER, "monitor read 0 bytes"); */
861 /* socket closed by peer */
862 close(fd);
863 return 1;
864 }
865 return 0; /* not enough data there yet */
866 }
867
868 bytes = recv(fd, cmd, I4B_MON_CMD_HDR, MSG_PEEK);
869
870 if (bytes < I4B_MON_CMD_HDR)
871 {
872 log(LL_MER, "monitor read only %d bytes", bytes);
873 return 0; /* errh? something must be wrong... */
874 }
875
876 bytes = I4B_GET_2B(cmd, I4B_MON_CMD_LEN);
877
878 if (bytes >= sizeof cmd)
879 {
880 close(fd);
881 log(LL_MER, "monitor: garbage on connection");
882 return 1;
883 }
884
885 /* now we know the size, it fits, so lets read it! */
886
887 if(sock_read(fd, cmd, bytes) <= 0)
888 {
889 log(LL_MER, "monitor: sock_read <= 0");
890 close(fd);
891 return 1;
892 }
893
894 /* decode command */
895 code = I4B_GET_2B(cmd, I4B_MON_CMD);
896
897 /* special case: may modify our connection descriptor, is
898 * beyound all rights checks */
899
900 if (code == I4B_MON_CCMD_SETMASK)
901 {
902/*XXX*/
903 /*
904 u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR);
905 u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR);
906 */
907
908 int events = I4B_GET_4B(cmd, I4B_MON_ICLIENT_EVENTS);
909 con->events = events & rights;
910 return 0;
911 }
912
913 if (code < 0 || code >= NUMCMD)
914 {
915 log(LL_MER, "illegal command from client, code = %d\n",
916 code);
917 return 0;
918 }
919
920 if (cmd_tab[code].call == NULL)
921 return 0;
922
923 if ((cmd_tab[code].rights & rights) == cmd_tab[code].rights)
924 cmd_tab[code].call(fd, rights, cmd, con->source);
925
926 return 0;
927}
928
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 *---------------------------------------------------------------------------*/
934static int
935anybody(int mask)
936{
937 struct monitor_connection * con;
938
939 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
940 {
941 if ((con->events & mask) == mask)
942 return 1;
943 }
944 return 0;
945}
946
947/*---------------------------------------------------------------------------
948 * exec hangup command
949 *---------------------------------------------------------------------------*/
950static void
951hangup_channel(int controller, int channel, const char *source)
952{
953 cfg_entry_t * cep = NULL;
954 int i;
955
956 if(controller < ncontroller)
957 {
958 if(isdn_ctrl_tab[controller].state != CTRL_UP)
959 return;
960 for (i = 0; i < isdn_ctrl_tab[controller].nbch; i++)
961 {
962 if(isdn_ctrl_tab[controller].stateb[i] != CHAN_IDLE)
963 {
964 cep = get_cep_by_cc(controller, i);
965 if (cep != NULL && cep->isdnchannelused == channel &&
966 cep->isdncontrollerused == controller)
967 goto found;
968 }
969 }
970 }
971 /* not found */
972 return;
973
974found:
975 log(LL_CHD, "%05d %s manual disconnect (remote from %s)", cep->cdid, cep->name, source);
976 cep->hangup = 1;
977 return;
978}
979
980/*---------------------------------------------------------------------------
981 * Send an event to every connection interested in this kind of
982 * event
983 *---------------------------------------------------------------------------*/
984static void
985monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes)
986{
987 struct monitor_connection *con;
988
989 for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
990 {
991 if ((con->events & mask) == mask)
992 {
993 int fd = con->sock;
994
995 if((sock_write(fd, pkt, bytes)) == -1)
996 {
997 log(LL_MER, "monitor_broadcast: sock_write error - %s", strerror(errno));
998 }
999 }
1000 }
1001}
1002
1003/*---------------------------------------------------------------------------
1004 * Post a logfile event
1005 *---------------------------------------------------------------------------*/
1006void
1007monitor_evnt_log(int prio, const char * what, const char * msg)
1008{
1009 u_int8_t evnt[I4B_MON_LOGEVNT_SIZE];
1010 time_t now;
1011
1012 if (!anybody(I4B_CA_EVNT_I4B))
1013 return;
1014
1015 time(&now);
1016
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);
1022
1023 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1024}
1025
1026/*---------------------------------------------------------------------------
1027 * Post a charging event on the connection described
1028 * by the given config entry.
1029 *---------------------------------------------------------------------------*/
1030void
1031monitor_evnt_charge(cfg_entry_t *cep, int units, int estimate)
1032{
1033 int mask;
1034 time_t now;
1035 u_int8_t evnt[I4B_MON_CHRG_SIZE];
1036
1037 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1038
1039 if(!anybody(mask))
1040 return;
1041
1042 time(&now);
1043
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);
1050
1051 monitor_broadcast(mask, evnt, sizeof evnt);
1052}
1053
1054/*---------------------------------------------------------------------------
1055 * Post a connection event
1056 *---------------------------------------------------------------------------*/
1057void
1058monitor_evnt_connect(cfg_entry_t *cep)
1059{
1060 u_int8_t evnt[I4B_MON_CONNECT_SIZE];
1061 char devname[I4B_MAX_MON_STRING];
1062 int mask;
1063 time_t now;
1064
1065 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1066
1067 if (!anybody(mask))
1068 return;
1069
1070 time(&now);
1071
1072 snprintf(devname, sizeof devname, "%s%d", bdrivername(cep->usrdevicename), cep->usrdeviceunit);
1073
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);
1081
1082 if(cep->direction == DIR_OUT)
1083 {
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);
1086 }
1087 else
1088 {
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);
1091 }
1092 monitor_broadcast(mask, evnt, sizeof evnt);
1093}
1094
1095/*---------------------------------------------------------------------------
1096 * Post a disconnect event
1097 *---------------------------------------------------------------------------*/
1098void
1099monitor_evnt_disconnect(cfg_entry_t *cep)
1100{
1101 u_int8_t evnt[I4B_MON_DISCONNECT_SIZE];
1102 int mask;
1103 time_t now;
1104
1105 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1106
1107 if (!anybody(mask))
1108 return;
1109
1110 time(&now);
1111
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);
1116
1117 monitor_broadcast(mask, evnt, sizeof evnt);
1118}
1119
1120/*---------------------------------------------------------------------------
1121 * Post an up/down event
1122 *---------------------------------------------------------------------------*/
1123void
1124monitor_evnt_updown(cfg_entry_t *cep, int up)
1125{
1126 u_int8_t evnt[I4B_MON_UPDOWN_SIZE];
1127 int mask;
1128 time_t now;
1129
1130 mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1131
1132 if (!anybody(mask))
1133 return;
1134
1135 time(&now);
1136
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);
1142
1143 monitor_broadcast(mask, evnt, sizeof evnt);
1144}
1145
1146/*---------------------------------------------------------------------------
1147 * Post a Layer1/2 status change event
1148 *---------------------------------------------------------------------------*/
1149void
1150monitor_evnt_l12stat(int controller, int layer, int state)
1151{
1152 u_int8_t evnt[I4B_MON_L12STAT_SIZE];
1153 time_t now;
1154
1155 if(!anybody(I4B_CA_EVNT_I4B))
1156 return;
1157
1158 time(&now);
1159
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);
1165
1166 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1167}
1168
1169/*---------------------------------------------------------------------------
1170 * Post a TEI change event
1171 *---------------------------------------------------------------------------*/
1172void
1173monitor_evnt_tei(int controller, int tei)
1174{
1175 u_int8_t evnt[I4B_MON_TEI_SIZE];
1176 time_t now;
1177
1178 if(!anybody(I4B_CA_EVNT_I4B))
1179 return;
1180
1181 time(&now);
1182
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);
1187
1188 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1189}
1190
1191/*---------------------------------------------------------------------------
1192 * Post an accounting event
1193 *---------------------------------------------------------------------------*/
1194void
1195monitor_evnt_acct(cfg_entry_t *cep)
1196{
1197 u_int8_t evnt[I4B_MON_ACCT_SIZE];
1198 time_t now;
1199
1200 if(!anybody(I4B_CA_EVNT_I4B))
1201 return;
1202
1203 time(&now);
1204
1205 I4B_PREP_EVNT(evnt, I4B_MON_ACCT_CODE);
1206 I4B_PUT_4B(evnt, I4B_MON_ACCT_TSTAMP, (long)now);
1207
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);
1214
1215 monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1216}
1217
1218/*---------------------------------------------------------------------------
1219 * read from a socket
1220 *---------------------------------------------------------------------------*/
1221static ssize_t
1222sock_read(int fd, void *buf, size_t nbytes)
1223{
1224 size_t nleft;
1225 ssize_t nread;
1226 unsigned char *ptr;
1227
1228 ptr = buf;
1229 nleft = nbytes;
1230
1231 while(nleft > 0)
1232 {
1233 if((nread = read(fd, ptr, nleft)) < 0)
1234 {
1235 if(errno == EINTR)
1236 {
1237 nread = 0;
1238 }
1239 else
1240 {
1241 return(-1);
1242 }
1243 }
1244 else if(nread == 0)
1245 {
1246 break; /* EOF */
1247 }
1248
1249 nleft -= nread;
1250 ptr += nread;
1251 }
1252 return(nbytes - nleft);
1253}
1254
1255/*---------------------------------------------------------------------------
1256 * write to a socket
1257 *---------------------------------------------------------------------------*/
1258static ssize_t
1259sock_write(int fd, void *buf, size_t nbytes)
1260{
1261 size_t nleft;
1262 ssize_t nwritten;
1263 unsigned char *ptr;
1264
1265 ptr = buf;
1266 nleft = nbytes;
1267
1268 while(nleft > 0)
1269 {
1270 if((nwritten = write(fd, ptr, nleft)) <= 0)
1271 {
1272 if(errno == EINTR)
1273 {
1274 nwritten = 0;
1275 }
1276 else
1277 {
1278 return(-1);
1279 }
1280 }
1281
1282 nleft -= nwritten;
1283 ptr += nwritten;
1284 }
1285 return(nbytes);
1286}
1287
fe361e7d
SW
1288struct monitor_rights *
1289monitor_next_rights(const struct monitor_rights *r)
984263bc
MD
1290{
1291 if (r == NULL)
1292 return TAILQ_FIRST(&rights);
1293 else
1294 return TAILQ_NEXT(r, list);
1295}
1296
1297#endif /* I4B_EXTERNAL_MONITOR */