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