1 /*
2  * client.c
3  *
4  * Copyright (c) 2003 Marius Aamodt Eriksen <marius@monkey.org>
5  * All rights reserved.
6  *
7  * $Id: client.c,v 1.14 2003/05/09 02:16:42 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/queue.h>
17 #include <sys/tree.h>
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif /* HAVE_SYS_TIME_H */
21 
22 #include <event.h>
23 #ifdef HAVE_ERR_H
24 #include <err.h>
25 #endif /* HAVE_ERR_H */
26 #include <stdio.h>
27 #include <unistd.h>
28 #ifdef HAVE_STDINT_H
29 #include <stdint.h>
30 #endif /* HAVE_STDINT_H */
31 #if defined(HAVE_TIME_H) && defined(TIME_WITH_SYS_TIME)
32 #include <time.h>
33 #endif /* defined(HAVE_TIME_H) && defined(TIME_WITH_SYS_TIME) */
34 #include <string.h>
35 
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif /* HAVE_NETINET_IN_H */
39 
40 #include "print.h"
41 #include "trickle.h"
42 #include "message.h"
43 #include "client.h"
44 #include "bwstat.h"
45 #include "util.h"
46 #include "xdr.h"
47 
48 static int
clicmp(struct client * a,struct client * b)49 clicmp(struct client *a, struct client *b)
50 {
51 	if (a->pid == b->pid)
52 		return (0);
53 
54 	if (a->pid > b->pid)
55 		return (1);
56 
57 	return (-1);
58 }
59 
60 SPLAY_HEAD(clitree, client) clients;
61 SPLAY_PROTOTYPE(clitree, client, next, clicmp);
62 SPLAY_GENERATE(clitree, client, next, clicmp);
63 
64 static void client_delaycb(int, short, void *);
65 
66 void
client_init(uint winsz)67 client_init(uint winsz)
68 {
69 	bwstat_init(winsz);
70 
71 	SPLAY_INIT(&clients);
72 }
73 
74 int
client_register(struct client * cli)75 client_register(struct client *cli)
76 {
77 	if ((cli->stat = bwstat_new()) == NULL)
78 		return (-1);
79 
80 	SPLAY_INSERT(clitree, &clients, cli);
81 
82 	return (0);
83 }
84 
85 int
client_configure(struct client * cli)86 client_configure(struct client *cli)
87 {
88 	struct bwstat *bs = cli->stat;
89 
90 	if (cli->pri > 20)
91 		return (-1);
92 	bs->pts = 21 - cli->pri;
93 
94 	if (cli->tsmooth < 0.0)
95 		return (-1);
96 	bs->tsmooth = cli->tsmooth;
97 
98 	if (cli->lsmooth == 0)
99 		return (-1);
100 	bs->lsmooth = cli->lsmooth;
101 
102 	return (0);
103 }
104 
105 void
client_unregister(struct client * cli)106 client_unregister(struct client *cli)
107 {
108 	if (evtimer_initialized(&cli->delayev))
109 		evtimer_del(&cli->delayev);
110 
111 	bwstat_free(cli->stat);
112 
113 	SPLAY_REMOVE(clitree, &clients, cli);
114 }
115 
116 void
client_getinfo(struct client * cli,uint sendlim,uint recvlim)117 client_getinfo(struct client *cli, uint sendlim, uint recvlim)
118 {
119 	struct bwstat *bs = bwstat_gettot();
120 	struct bwstat_data *bsdrecv = &bs->data[TRICKLE_RECV],
121 	    *bsdsend = &bs->data[TRICKLE_SEND];
122 	struct msg msg;
123 	struct msg_getinfo *getinfo = &msg.data.getinfo;
124 
125 	memset(&msg, 0, sizeof(msg));
126 	msg.type = MSG_TYPE_GETINFO;
127 
128 	getinfo->dirinfo[TRICKLE_SEND].rate = bsdsend->winrate;
129 	getinfo->dirinfo[TRICKLE_SEND].lim = sendlim;
130 
131 	getinfo->dirinfo[TRICKLE_RECV].rate = bsdrecv->winrate;
132 	getinfo->dirinfo[TRICKLE_RECV].lim = recvlim;
133 
134 	client_sendmsg(cli, &msg);
135 }
136 
137 void
client_delay(struct client * cli,short which,size_t len,uint lim)138 client_delay(struct client *cli, short which, size_t len, uint lim)
139 {
140 	struct timeval *tv;
141 
142 	if ((tv = bwstat_getdelay(cli->stat, &len, lim, which)) != NULL) {
143 		warnxv(4, "Delay %d (%s/%s) by: %d bytes in %dsec%dusec START",
144 		    cli->pid, cli->argv0, cli->uname, len, tv->tv_sec,
145 		    tv->tv_usec);
146 		cli->delaytv = *tv;
147 		cli->delaylen = len;
148 		cli->delaywhich = which;
149 		evtimer_set(&cli->delayev, client_delaycb, cli);
150 		evtimer_add(&cli->delayev, &cli->delaytv);
151 	} else {
152 		struct msg msg;
153 		struct msg_delayinfo *delayinfo = &msg.data.delayinfo;
154 
155 		msg.type = MSG_TYPE_CONT;
156 		delayinfo->len = len;
157 		if (client_sendmsg(cli, &msg) == -1)
158 			;	/* XXX delete client */
159 	}
160 }
161 
162 void
client_getdelay(struct client * cli,short which,size_t len,uint lim)163 client_getdelay(struct client *cli, short which, size_t len, uint lim)
164 {
165 	struct timeval *tv;
166 	struct msg msg;
167 	struct msg_delayinfo *delayinfo = &msg.data.delayinfo;
168 
169 	memset(&msg, 0, sizeof(msg));
170 
171 	if ((tv = bwstat_getdelay(cli->stat, &len, lim, which)) != NULL)
172 		delayinfo->delaytv = *tv;
173 	else
174 		SET(msg.status, MSG_STATUS_FAIL);
175 
176 	delayinfo->len = len;
177 	tv = &delayinfo->delaytv;
178 
179 	warnxv(3, "Returning delay %d (%s/%s) info: %d bytes in %dsec%dusec",
180 	    cli->pid, cli->argv0, cli->uname, len, tv->tv_sec, tv->tv_usec);
181 
182 	msg.type = MSG_TYPE_DELAYINFO;
183 
184 	client_sendmsg(cli, &msg);
185 }
186 
187 static void
client_delaycb(int fd,short which,void * arg)188 client_delaycb(int fd, short which, void *arg)
189 {
190 	struct client *cli = arg;
191 	struct msg msg;
192 	struct msg_delayinfo *delayinfo = &msg.data.delayinfo;
193 
194 	warnxv(4, "Delay %d (%s/%s) by %dsec%dusec END", cli->pid,
195 	    cli->argv0, cli->uname, cli->delaytv.tv_sec, cli->delaytv.tv_usec);
196 
197 	delayinfo->len = cli->delaylen;
198 
199 	msg.type = MSG_TYPE_CONT;
200 
201 	/* XXX on error */
202 	client_sendmsg(cli, &msg);
203 }
204 
205 #if 0
206 static double
207 difftv(struct timeval *tv0, struct timeval *tv1)
208 {
209 	struct timeval diff_tv;
210 
211 	timersub(tv0, tv1, &diff_tv);
212         return (diff_tv.tv_sec + (diff_tv.tv_usec / 1000000.0));
213 }
214 #endif /* 0 */
215 
216 void
client_update(struct client * cli,short which,size_t len)217 client_update(struct client *cli, short which, size_t len)
218 {
219 	struct bwstat_data *bsd = &cli->stat->data[which];
220 
221 	warnxv(4, "Statistics (%s) for %d (%s/%s):",
222 	    which == TRICKLE_SEND ? "SEND" : "RECV",
223 	    cli->pid, cli->argv0, cli->uname);
224 
225 #if 0
226 	/* XXX for benchmarking. */
227 	if (which == TRICKLE_SEND) {
228 		struct timeval tv, xtv;
229 		static struct timeval begtv;
230 
231 		gettimeofday(&tv, NULL);
232 
233 		if (!timerisset(&begtv)) {
234 			begtv = tv;
235 			return;
236 		}
237 
238 		warnxv(4, "DATA %f %d.%d %d.%d",
239 		    difftv(&tv, &begtv),
240 		    bsd->rate / 1024, (bsd->rate % 1024) * 100 / 1024,
241 		    bsd->winrate / 1024, (bsd->winrate % 1024) * 100 / 1024);
242 	}
243 #endif /* 0 */
244 
245 	bwstat_update(cli->stat, len, which);
246 
247 	warnxv(4, "\tavg: %d.%d KB/s; win: %d.%d KB/s",
248 	    bsd->rate / 1024, (bsd->rate % 1024) * 100 / 1024,
249 	    bsd->winrate / 1024, (bsd->winrate % 1024) * 100 / 1024);
250 }
251 
252 void
client_force(void)253 client_force(void)
254 {
255 	struct client *cli;
256 
257 	SPLAY_FOREACH(cli, clitree, &clients) {
258 		bwstat_update(cli->stat, 0, BWSTAT_SEND);
259 		bwstat_update(cli->stat, 0, BWSTAT_RECV);
260 	}
261 
262 	bwstat_update(NULL, 0, BWSTAT_SEND);
263 	bwstat_update(NULL, 0, BWSTAT_RECV);
264 }
265 
266 void
client_printrates(void)267 client_printrates(void)
268 {
269 	struct bwstat *bs = bwstat_gettot();
270 	struct bwstat_data *bsdrecv = &bs->data[TRICKLE_RECV],
271 	    *bsdsend = &bs->data[TRICKLE_SEND], *bsd;
272 
273 	bsd = bsdsend;
274 
275 	warnxv(0, "UPLOAD total:\n"
276 	    "\tavg: %d.%d KB/s; win: %d.%d KB/s",
277 	    bsd->rate / 1024, (bsd->rate % 1024) * 100 / 1024,
278 	    bsd->winrate / 1024, (bsd->winrate % 1024) * 100 / 1024);
279 
280 	bsd = bsdrecv;
281 
282 	warnxv(0, "DOWNLOAD total:\n"
283 	    "\tavg: %d.%d KB/s; win: %d.%d KB/s",
284 	    bsd->rate / 1024, (bsd->rate % 1024) * 100 / 1024,
285 	    bsd->winrate / 1024, (bsd->winrate % 1024) * 100 / 1024);
286 }
287 
288 int
client_sendmsg(struct client * cli,struct msg * msg)289 client_sendmsg(struct client *cli, struct msg *msg)
290 {
291 	u_char buf[2048];
292 	uint32_t buflen = sizeof(buf), xbuflen;
293 
294 	if (cli->s == -1)
295 		return (-1);
296 
297 	if (msg2xdr(msg, buf, &buflen) == -1)
298 		return (-1);
299 
300 	xbuflen = htonl(buflen);
301 	if (atomicio(write, cli->s, &xbuflen, sizeof(xbuflen)) !=
302 	    sizeof(xbuflen))
303 	    return (-1);
304 
305 	if (atomicio(write, cli->s, buf, buflen) == buflen)
306 		return (0);
307 
308 	return (-1);
309 }
310 
311 int
client_recvmsg(struct client * cli,struct msg * msg)312 client_recvmsg(struct client *cli, struct msg *msg)
313 {
314 	u_char buf[2048];
315 	uint32_t buflen, xbuflen;
316 
317 	if (cli->s == -1)
318 		return (-1);
319 
320 	if (atomicio(read, cli->s, &xbuflen, sizeof(xbuflen)) !=
321 	    sizeof(xbuflen))
322 		return (-1);
323 	buflen = ntohl(xbuflen);
324 	if (buflen > sizeof(buf))
325 		return (-1);
326 
327 	if (atomicio(read, cli->s, buf, buflen) == buflen) {
328 		if (xdr2msg(msg, buf, buflen) == -1)
329 			return (-1);
330 		return (0);
331 	}
332 
333 	return (-1);
334 }
335