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