1 /*	$NetBSD: link_mon.c,v 1.1.1.1 2009/12/02 00:27:10 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
5  *
6  * This copyrighted material is made available to anyone wishing to use,
7  * modify, copy, or redistribute it subject to the terms and conditions
8  * of the GNU Lesser General Public License v.2.1.
9  *
10  * You should have received a copy of the GNU Lesser General Public License
11  * along with this program; if not, write to the Free Software Foundation,
12  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
13  */
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <poll.h>
17 
18 #include "logging.h"
19 
20 struct link_callback {
21 	int fd;
22 	char *name;
23 	void *data;
24 	int (*callback)(void *data);
25 
26 	struct link_callback *next;
27 };
28 
29 static int used_pfds = 0;
30 static int free_pfds = 0;
31 static struct pollfd *pfds = NULL;
32 static struct link_callback *callbacks = NULL;
33 
34 int links_register(int fd, char *name, int (*callback)(void *data), void *data)
35 {
36 	int i;
37 	struct link_callback *lc;
38 
39 	for (i = 0; i < used_pfds; i++) {
40 		if (fd == pfds[i].fd) {
41 			LOG_ERROR("links_register: Duplicate file descriptor");
42 			return -EINVAL;
43 		}
44 	}
45 
46 	lc = malloc(sizeof(*lc));
47 	if (!lc)
48 		return -ENOMEM;
49 
50 	lc->fd = fd;
51 	lc->name = name;
52 	lc->data = data;
53 	lc->callback = callback;
54 
55 	if (!free_pfds) {
56 		struct pollfd *tmp;
57 		tmp = realloc(pfds, sizeof(struct pollfd) * ((used_pfds*2) + 1));
58 		if (!tmp) {
59 			free(lc);
60 			return -ENOMEM;
61 		}
62 
63 		pfds = tmp;
64 		free_pfds = used_pfds + 1;
65 	}
66 
67 	free_pfds--;
68 	pfds[used_pfds].fd = fd;
69 	pfds[used_pfds].events = POLLIN;
70 	pfds[used_pfds].revents = 0;
71 	used_pfds++;
72 
73 	lc->next = callbacks;
74 	callbacks = lc;
75 	LOG_DBG("Adding %s/%d", lc->name, lc->fd);
76 	LOG_DBG(" used_pfds = %d, free_pfds = %d",
77 		used_pfds, free_pfds);
78 
79 	return 0;
80 }
81 
82 int links_unregister(int fd)
83 {
84 	int i;
85 	struct link_callback *p, *c;
86 
87 	for (i = 0; i < used_pfds; i++)
88 		if (fd == pfds[i].fd) {
89 			/* entire struct is copied (overwritten) */
90 			pfds[i] = pfds[used_pfds - 1];
91 			used_pfds--;
92 			free_pfds++;
93 		}
94 
95 	for (p = NULL, c = callbacks; c; p = c, c = c->next)
96 		if (fd == c->fd) {
97 			LOG_DBG("Freeing up %s/%d", c->name, c->fd);
98 			LOG_DBG(" used_pfds = %d, free_pfds = %d",
99 				used_pfds, free_pfds);
100 			if (p)
101 				p->next = c->next;
102 			else
103 				callbacks = c->next;
104 			free(c);
105 			break;
106 		}
107 
108 	return 0;
109 }
110 
111 int links_monitor(void)
112 {
113 	int i, r;
114 
115 	for (i = 0; i < used_pfds; i++) {
116 		pfds[i].revents = 0;
117 	}
118 
119 	r = poll(pfds, used_pfds, -1);
120 	if (r <= 0)
121 		return r;
122 
123 	r = 0;
124 	/* FIXME: handle POLLHUP */
125 	for (i = 0; i < used_pfds; i++)
126 		if (pfds[i].revents & POLLIN) {
127 			LOG_DBG("Data ready on %d", pfds[i].fd);
128 
129 			/* FIXME: Add this back return 1;*/
130 			r++;
131 		}
132 
133 	return r;
134 }
135 
136 int links_issue_callbacks(void)
137 {
138 	int i;
139 	struct link_callback *lc;
140 
141 	for (i = 0; i < used_pfds; i++)
142 		if (pfds[i].revents & POLLIN)
143 			for (lc = callbacks; lc; lc = lc->next)
144 				if (pfds[i].fd == lc->fd) {
145 					LOG_DBG("Issuing callback on %s/%d",
146 						lc->name, lc->fd);
147 					lc->callback(lc->data);
148 					break;
149 				}
150 	return 0;
151 }
152