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