Root/package/wprobe/src/user/wprobe-util.c

1/*
2 * wprobe-test.c: Wireless probe user space test code
3 * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <sys/types.h>
17#include <sys/socket.h>
18#include <sys/wait.h>
19#include <arpa/inet.h>
20#include <stdio.h>
21#include <string.h>
22#include <stdlib.h>
23#include <inttypes.h>
24#include <errno.h>
25#include <stdint.h>
26#include <getopt.h>
27#include <stdbool.h>
28#include <unistd.h>
29#include <netdb.h>
30#include <fcntl.h>
31#include <signal.h>
32
33#include <linux/wprobe.h>
34#include "wprobe.h"
35
36static bool simple_mode = false;
37
38static const char *
39wprobe_dump_value(struct wprobe_attribute *attr)
40{
41    static char buf[128];
42
43#define HANDLE_TYPE(_type, _format) \
44    case WPROBE_VAL_##_type: \
45        snprintf(buf, sizeof(buf), _format, attr->val._type); \
46        break
47
48    switch(attr->type) {
49        HANDLE_TYPE(S8, "%d");
50        HANDLE_TYPE(S16, "%d");
51        HANDLE_TYPE(S32, "%d");
52        HANDLE_TYPE(S64, "%lld");
53        HANDLE_TYPE(U8, "%d");
54        HANDLE_TYPE(U16, "%d");
55        HANDLE_TYPE(U32, "%d");
56        HANDLE_TYPE(U64, "%lld");
57        case WPROBE_VAL_STRING:
58            /* FIXME: implement this */
59        default:
60            strncpy(buf, "<unknown>", sizeof(buf));
61            break;
62    }
63    if ((attr->flags & WPROBE_F_KEEPSTAT) &&
64        (attr->val.n > 0)) {
65        int len = strlen(buf);
66        if (simple_mode)
67            snprintf(buf + len, sizeof(buf) - len, ";%.02f;%.02f;%d;%lld;%lld", attr->val.avg, attr->val.stdev, attr->val.n, attr->val.s, attr->val.ss);
68        else
69            snprintf(buf + len, sizeof(buf) - len, " (avg: %.02f; stdev: %.02f, n=%d)", attr->val.avg, attr->val.stdev, attr->val.n);
70    }
71#undef HANDLE_TYPE
72
73    return buf;
74}
75
76
77static void
78wprobe_dump_data(struct wprobe_iface *dev)
79{
80    struct wprobe_attribute *attr;
81    struct wprobe_link *link;
82    bool first = true;
83
84    if (!simple_mode)
85        fprintf(stdout, "\n");
86    wprobe_request_data(dev, NULL);
87    list_for_each_entry(attr, &dev->global_attr, list) {
88        if (simple_mode) {
89            if (first)
90                fprintf(stdout, "[global]\n");
91            fprintf(stdout, "%s=%s\n", attr->name, wprobe_dump_value(attr));
92        } else {
93            fprintf(stdout, (first ?
94                "Global: %s=%s\n" :
95                " %s=%s\n"),
96                attr->name,
97                wprobe_dump_value(attr)
98            );
99        }
100        first = false;
101    }
102
103    list_for_each_entry(link, &dev->links, list) {
104        first = true;
105        wprobe_request_data(dev, link->addr);
106        list_for_each_entry(attr, &dev->link_attr, list) {
107            if (first) {
108                fprintf(stdout,
109                    (simple_mode ?
110                     "[%02x:%02x:%02x:%02x:%02x:%02x]\n%s=%s\n" :
111                     "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n"),
112                    link->addr[0], link->addr[1], link->addr[2],
113                    link->addr[3], link->addr[4], link->addr[5],
114                    attr->name,
115                    wprobe_dump_value(attr));
116                first = false;
117            } else {
118                fprintf(stdout,
119                    (simple_mode ? "%s=%s\n" :
120                     " %s=%s\n"),
121                    attr->name,
122                    wprobe_dump_value(attr));
123            }
124        }
125    }
126    fflush(stdout);
127}
128
129static const char *attr_typestr[] = {
130    [0] = "Unknown",
131    [WPROBE_VAL_STRING] = "String",
132    [WPROBE_VAL_U8] = "Unsigned 8 bit",
133    [WPROBE_VAL_U16] = "Unsigned 16 bit",
134    [WPROBE_VAL_U32] = "Unsigned 32 bit",
135    [WPROBE_VAL_U64] = "Unsigned 64 bit",
136    [WPROBE_VAL_S8] = "Signed 8 bit",
137    [WPROBE_VAL_S16] = "Signed 16 bit",
138    [WPROBE_VAL_S32] = "Signed 32 bit",
139    [WPROBE_VAL_S64] = "Signed 64 bit",
140};
141
142static int usage(const char *prog)
143{
144    fprintf(stderr,
145#ifndef NO_LOCAL_ACCESS
146        "Usage: %s <interface>|<host>:<device>|-P [options]\n"
147#else
148        "Usage: %s <host>:<device> [options]\n"
149#endif
150        "\n"
151        "Options:\n"
152        " -a: Print attributes\n"
153        " -c: Only apply configuration\n"
154        " -d: Delay between measurement dumps (in milliseconds, default: 1000)\n"
155        " A value of 0 (zero) prints once and exits; useful for scripts\n"
156        " -f: Dump contents of layer 2 filter counters during measurement\n"
157        " -F <file>: Apply layer 2 filters from <file>\n"
158        " -h: This help text\n"
159        " -i <interval>: Set measurement interval\n"
160        " -m: Run measurement loop\n"
161        " -p: Set the TCP port for server/client (default: 17990)\n"
162#ifndef NO_LOCAL_ACCESS
163        " -P: Run in proxy mode (listen on network)\n"
164#endif
165        "\n"
166        , prog);
167    exit(1);
168}
169
170static void show_attributes(struct wprobe_iface *dev)
171{
172    struct wprobe_attribute *attr;
173    if (simple_mode)
174        return;
175    list_for_each_entry(attr, &dev->global_attr, list) {
176        fprintf(stdout, "Global attribute: '%s' (%s)\n",
177            attr->name, attr_typestr[attr->type]);
178    }
179    list_for_each_entry(attr, &dev->link_attr, list) {
180        fprintf(stdout, "Link attribute: '%s' (%s)\n",
181            attr->name, attr_typestr[attr->type]);
182    }
183}
184
185static void show_filter_simple(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
186{
187    int i;
188
189    fprintf(stdout, "[filter:%s]\n", group);
190    for (i = 0; i < n_items; i++) {
191        fprintf(stdout, "%s=%lld;%lld\n",
192            items[i].name, items[i].tx, items[i].rx);
193    }
194    fflush(stdout);
195}
196
197
198static void show_filter(void *arg, const char *group, struct wprobe_filter_item *items, int n_items)
199{
200    int i;
201    fprintf(stdout, "Filter group: '%s' (tx/rx)\n", group);
202    for (i = 0; i < n_items; i++) {
203        fprintf(stdout, " - %s (%lld/%lld)\n",
204            items[i].name, items[i].tx, items[i].rx);
205    }
206}
207
208static void loop_measurement(struct wprobe_iface *dev, bool print_filters, unsigned long delay)
209{
210    do {
211        wprobe_update_links(dev);
212        wprobe_dump_data(dev);
213        if (print_filters)
214            wprobe_dump_filters(dev, simple_mode ? show_filter_simple : show_filter, NULL);
215        usleep(delay * 1000);
216    }
217    while (delay);
218}
219
220static void set_filter(struct wprobe_iface *dev, const char *filename)
221{
222    unsigned char *buf = NULL;
223    unsigned int buflen = 0;
224    unsigned int len = 0;
225    int fd;
226
227    /* clear filter */
228    if (filename[0] == 0) {
229        dev->filter_len = -1;
230        return;
231    }
232
233    fd = open(filename, O_RDONLY);
234    if (fd < 0) {
235        perror("open filter");
236        return;
237    }
238
239    do {
240        int rlen;
241
242        if (!buf) {
243            len = 0;
244            buflen = 1024;
245            buf = malloc(1024);
246        } else {
247            buflen *= 2;
248            buf = realloc(buf, buflen);
249        }
250        rlen = read(fd, buf + len, buflen - len);
251        if (rlen < 0)
252            break;
253
254        len += rlen;
255    } while (len == buflen);
256
257    dev->filter = buf;
258    dev->filter_len = len;
259    close(fd);
260}
261
262#ifndef NO_LOCAL_ACCESS
263
264static void sigchld_handler(int s)
265{
266    while (waitpid(-1, NULL, WNOHANG) > 0);
267}
268
269static int run_proxy(int port)
270{
271    struct sockaddr_in sa;
272    struct sigaction sig;
273    int v = 1;
274    int s;
275
276    s = socket(AF_INET, SOCK_STREAM, 0);
277    if (s < 0) {
278        perror("socket");
279        return 1;
280    }
281
282    sig.sa_handler = sigchld_handler; // Signal Handler fuer Zombie Prozesse
283    sigemptyset(&sig.sa_mask);
284    sig.sa_flags = SA_RESTART;
285    sigaction(SIGCHLD, &sig, NULL);
286
287    memset(&sa, 0, sizeof(sa));
288    sa.sin_family = AF_INET;
289    sa.sin_addr.s_addr = htonl(INADDR_ANY);
290    sa.sin_port = htons(wprobe_port);
291
292    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
293    if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
294        perror("bind");
295        return 1;
296    }
297    if (listen(s, 10)) {
298        perror("listen");
299        return 1;
300    }
301    while(1) {
302        unsigned int addrlen = sizeof(struct sockaddr_in);
303        int ret, c;
304
305        c = accept(s, (struct sockaddr *)&sa, &addrlen);
306        if (c < 0) {
307            if (errno == EINTR)
308                continue;
309
310            perror("accept");
311            return 1;
312        }
313        if (fork() == 0) {
314            /* close server socket, stdin, stdout, stderr */
315            close(s);
316            close(0);
317            close(1);
318            close(2);
319
320            wprobe_server_init(c);
321            do {
322                ret = wprobe_server_handle(c);
323            } while (ret >= 0);
324            wprobe_server_done();
325            close(c);
326            exit(0);
327        }
328        close(c);
329    }
330
331    return 0;
332}
333#endif
334
335int main(int argc, char **argv)
336{
337    struct wprobe_iface *dev = NULL;
338    const char *ifname;
339    const char *prog = argv[0];
340    char *err = NULL;
341    enum {
342        CMD_NONE,
343        CMD_CONFIG,
344        CMD_MEASURE,
345        CMD_PROXY,
346    } cmd = CMD_NONE;
347    const char *filter = NULL;
348    bool print_attributes = false;
349    bool print_filters = false;
350    unsigned long delay = 1000;
351    int interval = -1;
352    int ch;
353
354    if (argc < 2)
355        return usage(prog);
356
357#ifndef NO_LOCAL_ACCESS
358    if (!strcmp(argv[1], "-P")) {
359        while ((ch = getopt(argc - 1, argv + 1, "p:")) != -1) {
360            switch(ch) {
361            case 'p':
362                /* set port */
363                wprobe_port = strtoul(optarg, NULL, 0);
364                break;
365            default:
366                return usage(prog);
367            }
368        }
369        return run_proxy(wprobe_port);
370    }
371#endif
372
373    if (argv[1][0] == '-')
374        return usage(prog);
375
376    ifname = argv[1];
377    argv++;
378    argc--;
379
380    while ((ch = getopt(argc, argv, "acd:fF:hi:msp:")) != -1) {
381        switch(ch) {
382        case 'a':
383            print_attributes = true;
384            break;
385        case 'c':
386            cmd = CMD_CONFIG;
387            break;
388        case 'd':
389            delay = strtoul(optarg, NULL, 10);
390            break;
391        case 'm':
392            cmd = CMD_MEASURE;
393            break;
394        case 'i':
395            interval = strtoul(optarg, NULL, 10);
396            break;
397        case 'f':
398            print_filters = true;
399            break;
400        case 'F':
401            if (filter) {
402                fprintf(stderr, "Cannot set multiple filters\n");
403                return usage(prog);
404            }
405            filter = optarg;
406            break;
407        case 's':
408            simple_mode = true;
409            break;
410        case 'p':
411            /* set port */
412            wprobe_port = strtoul(optarg, NULL, 0);
413            break;
414        case 'h':
415        default:
416            usage(prog);
417            break;
418        }
419    }
420
421    dev = wprobe_get_auto(ifname, &err);
422    if (!dev || (list_empty(&dev->global_attr) &&
423        list_empty(&dev->link_attr))) {
424        if (err)
425            fprintf(stdout, "%s\n", err);
426        else
427            fprintf(stderr, "Interface '%s' not found\n", ifname);
428        return 1;
429    }
430
431    if (filter || interval >= 0) {
432        if (filter)
433            set_filter(dev, filter);
434        if (interval >= 0)
435            dev->interval = interval;
436
437        wprobe_apply_config(dev);
438    }
439
440    if (cmd != CMD_CONFIG) {
441        if (print_attributes)
442            show_attributes(dev);
443    }
444    if (cmd == CMD_MEASURE)
445        loop_measurement(dev, print_filters, delay);
446
447    wprobe_free_dev(dev);
448
449    return 0;
450}
451

Archive Download this file



interactive