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