1 /*
2  * trickledu.c
3  *
4  * Copyright (c) 2003 Marius Aamodt Eriksen <marius@monkey.org>
5  * All rights reserved.
6  *
7  * $Id: trickledu.c,v 1.16 2004/02/13 06:11:21 marius Exp $
8  */
9 
10 #include <sys/types.h>
11 
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif /* HAVE_CONFIG_H */
15 
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif /* HAVE_SYS_TIME_H */
21 
22 #include <string.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #ifdef HAVE_STDINT_H
26 #include <stdint.h>
27 #endif /* HAVE_STDINT_H */
28 #if defined(HAVE_TIME_H) && defined(TIME_WITH_SYS_TIME)
29 #include <time.h>
30 #endif /* defined(HAVE_TIME_H) && defined(TIME_WITH_SYS_TIME) */
31 
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
34 #endif /* HAVE_NETINET_IN_H */
35 
36 #include "trickle.h"
37 #include "message.h"
38 #include "trickledu.h"
39 #include "util.h"
40 #include "xdr.h"
41 
42 static void _trickled_open(struct msg *, int *);
43 
44 #define DECLARE(name, ret, args) static ret (*libc_##name) args
45 
46 DECLARE(socket, int, (int, int, int));
47 DECLARE(read, ssize_t, (int, void *, size_t));
48 DECLARE(write, ssize_t, (int, const void *, size_t));
49 DECLARE(close, int, (int));
50 static char *argv0, *sockname;
51 static int trickled_sock = -1, *trickled;
52 static pid_t trickled_pid = -1;
53 
54 void
trickled_configure(char * xsockname,int (* xlibc_socket)(int,int,int),ssize_t (* xlibc_read)(int,void *,size_t),ssize_t (* xlibc_write)(int,const void *,size_t),int (* xlibc_close)(int),char * xargv0)55 trickled_configure(char *xsockname, int (*xlibc_socket)(int, int, int),
56     ssize_t (*xlibc_read)(int, void *, size_t),
57     ssize_t (*xlibc_write)(int, const void *, size_t),
58     int (*xlibc_close)(int),
59     char *xargv0)
60 {
61 	sockname = xsockname;
62 	libc_socket = xlibc_socket;
63 	libc_write = xlibc_write;
64 	libc_read = xlibc_read;
65 	libc_close = xlibc_close;
66 	argv0 = xargv0;
67 }
68 
69 void
trickled_open(int * xtrickled)70 trickled_open(int *xtrickled)
71 {
72 	struct msg msg;
73 	struct msg_conf *conf;
74 
75 	memset(&msg, 0, sizeof(msg));
76 
77 	msg.type = MSG_TYPE_CONF;
78 	conf = &msg.data.conf;
79 	/* memcpy(conf->lim, lim, sizeof(conf->lim)); */
80 	conf->pid = getpid();
81 	strlcpy(conf->argv0, argv0, sizeof(conf->argv0));
82 	conf->uid = geteuid();
83 	conf->gid = getegid();
84 
85 	_trickled_open(&msg, xtrickled);
86 }
87 
88 void
trickled_close(int * xtrickled)89 trickled_close(int *xtrickled)
90 {
91 	(*libc_close)(trickled_sock);
92 	*xtrickled = 0;
93 	trickled_sock = -1;
94 }
95 
96 void
trickled_ctl_open(int * xtrickled)97 trickled_ctl_open(int *xtrickled)
98 {
99 	struct msg msg;
100 
101 	memset(&msg, 0, sizeof(msg));
102 
103 	msg.type = MSG_TYPE_SPECTATOR;
104 
105 	_trickled_open(&msg, xtrickled);
106 }
107 
108 static void
_trickled_open(struct msg * msg,int * xtrickled)109 _trickled_open(struct msg *msg, int *xtrickled)
110 {
111 	int s;
112 	struct sockaddr_un xsun;
113 
114 	trickled = xtrickled;
115 	*trickled = 0;
116 
117 	if ((s = (*libc_socket)(AF_UNIX, SOCK_STREAM, 0)) == -1)
118 		return;
119 
120 	memset(&xsun, 0, sizeof(xsun));
121 	xsun.sun_family = AF_UNIX;
122 	strlcpy(xsun.sun_path, sockname, sizeof(xsun.sun_path));
123 
124 	if (connect(s, (struct sockaddr *)&xsun, sizeof(xsun)) == -1) {
125 		(*libc_close)(s);
126 		return;
127 	}
128 
129 	trickled_pid = getpid();
130 	trickled_sock = *trickled = s;
131 
132 	if (trickled_sendmsg(msg) == -1) {
133 		(*libc_close)(s);
134 		return;
135 	}
136 }
137 
138 int
trickled_sendmsg(struct msg * msg)139 trickled_sendmsg(struct msg *msg)
140 {
141 	u_char buf[2048];
142 	uint32_t buflen = sizeof(buf), xbuflen;
143 
144 	if (trickled_sock != -1 && trickled_pid != getpid()) {
145 		trickled_close(trickled);
146 		trickled_open(trickled);
147 	}
148 
149 	if (trickled_sock == -1)
150 		goto fail;
151 
152 	if (msg2xdr(msg, buf, &buflen) == -1)
153 		return (-1); 	/* XXX fail? */
154 
155 	xbuflen = htonl(buflen);
156 	if (atomicio(libc_write, trickled_sock, &xbuflen, sizeof(xbuflen)) !=
157 	    sizeof(xbuflen))
158 	    return (-1);
159 
160 	if (atomicio(libc_write, trickled_sock, buf, buflen) == buflen)
161 		return (0);
162 
163  fail:
164 	*trickled = 0;
165 	trickled_sock = -1;
166 
167 	return (-1);
168 }
169 
170 int
trickled_recvmsg(struct msg * msg)171 trickled_recvmsg(struct msg *msg)
172 {
173 	u_char buf[2048];
174 	uint32_t buflen, xbuflen;
175 
176 	if (trickled_sock == -1)
177 		goto fail;
178 
179 	if (atomicio(libc_read, trickled_sock, &xbuflen, sizeof(xbuflen)) !=
180 	    sizeof(xbuflen))
181 		return (-1);
182 	buflen = ntohl(xbuflen);
183 	if (buflen > sizeof(buf))
184 		return (-1);
185 
186 	if (atomicio(libc_read, trickled_sock, buf, buflen) == buflen) {
187 		if (xdr2msg(msg, buf, buflen) == -1)
188 			return (-1);
189 		return (0);
190 	}
191 
192  fail:
193 	*trickled = 0;
194 	trickled_sock = -1;
195 
196 	return (-1);
197 }
198 
199 int
trickled_update(short dir,size_t len)200 trickled_update(short dir, size_t len)
201 {
202 	struct msg msg;
203 	struct msg_update *update = &msg.data.update;
204 
205 	msg.type = MSG_TYPE_UPDATE;
206 
207 	update->len = len;
208 	update->dir = dir;
209 
210 	return (trickled_sendmsg(&msg));
211 }
212 
213 int
trickled_delay(short dir,size_t * len)214 trickled_delay(short dir, size_t *len)
215 {
216 	struct msg msg;
217 	struct msg_delay *delay = &msg.data.delay;
218 	struct msg_delayinfo *delayinfo = &msg.data.delayinfo;
219 
220 	msg.type = MSG_TYPE_DELAY;
221 
222 	delay->len = *len;
223 	delay->dir = dir;
224 
225 	if (trickled_sendmsg(&msg) == -1)
226 		return (-1);
227 
228 	/* Ignore all other messages in the meantime XXX for now. */
229 	do {
230 		if (trickled_recvmsg(&msg) == -1)
231 			return (-1);
232 	} while (msg.type != MSG_TYPE_CONT);
233 
234 	*len = delayinfo->len;
235 
236 	return (0);
237 }
238 
239 struct timeval *
trickled_getdelay(short dir,size_t * len)240 trickled_getdelay(short dir, size_t *len)
241 {
242 	struct msg msg;
243 	struct msg_delay *delay = &msg.data.delay;
244 	struct msg_delayinfo *delayinfo = &msg.data.delayinfo;
245 	static struct timeval tv;
246 
247 	msg.type = MSG_TYPE_GETDELAY;
248 
249 	delay->len = *len;
250 	delay->dir = dir;
251 
252 	if (trickled_sendmsg(&msg) == -1)
253 		return (NULL);
254 
255 	/* Ignore all other messages in the meantime XXX for now. */
256 	do {
257 		if (trickled_recvmsg(&msg) == -1)
258 			return (NULL);
259 	} while (msg.type != MSG_TYPE_DELAYINFO);
260 
261 	if (ISSET(msg.status, MSG_STATUS_FAIL))
262 		return (NULL);
263 
264 	tv = delayinfo->delaytv;
265 	*len = delayinfo->len;
266 
267 	return (&tv);
268 }
269 
270 int
trickled_getinfo(uint32_t * uplim,uint32_t * uprate,uint32_t * downlim,uint32_t * downrate)271 trickled_getinfo(uint32_t *uplim, uint32_t *uprate,
272     uint32_t *downlim, uint32_t *downrate)
273 {
274 	struct msg msg;
275 	struct msg_getinfo *getinfo = &msg.data.getinfo;
276 
277 	msg.type = MSG_TYPE_GETINFO;
278 
279 	if (trickled_sendmsg(&msg) == -1)
280 		return (-1);
281 
282 	do {
283 		if (trickled_recvmsg(&msg) == -1)
284 			return (-1);
285 	} while (msg.type != MSG_TYPE_GETINFO);
286 
287 	*uplim = getinfo->dirinfo[TRICKLE_SEND].lim;
288 	*uprate = getinfo->dirinfo[TRICKLE_SEND].rate;
289 
290 	*downlim = getinfo->dirinfo[TRICKLE_RECV].lim;
291 	*downrate = getinfo->dirinfo[TRICKLE_RECV].rate;
292 
293 	return (0);
294 }
295