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