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