Root/Documentation/connector/ucon.c

1/*
2 * ucon.c
3 *
4 * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <asm/types.h>
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/poll.h>
27
28#include <linux/netlink.h>
29#include <linux/rtnetlink.h>
30
31#include <arpa/inet.h>
32
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <string.h>
38#include <errno.h>
39#include <time.h>
40#include <getopt.h>
41
42#include <linux/connector.h>
43
44#define DEBUG
45#define NETLINK_CONNECTOR 11
46
47/* Hopefully your userspace connector.h matches this kernel */
48#define CN_TEST_IDX CN_NETLINK_USERS + 3
49#define CN_TEST_VAL 0x456
50
51#ifdef DEBUG
52#define ulog(f, a...) fprintf(stdout, f, ##a)
53#else
54#define ulog(f, a...) do {} while (0)
55#endif
56
57static int need_exit;
58static __u32 seq;
59
60static int netlink_send(int s, struct cn_msg *msg)
61{
62    struct nlmsghdr *nlh;
63    unsigned int size;
64    int err;
65    char buf[128];
66    struct cn_msg *m;
67
68    size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
69
70    nlh = (struct nlmsghdr *)buf;
71    nlh->nlmsg_seq = seq++;
72    nlh->nlmsg_pid = getpid();
73    nlh->nlmsg_type = NLMSG_DONE;
74    nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
75    nlh->nlmsg_flags = 0;
76
77    m = NLMSG_DATA(nlh);
78#if 0
79    ulog("%s: [%08x.%08x] len=%u, seq=%u, ack=%u.\n",
80           __func__, msg->id.idx, msg->id.val, msg->len, msg->seq, msg->ack);
81#endif
82    memcpy(m, msg, sizeof(*m) + msg->len);
83
84    err = send(s, nlh, size, 0);
85    if (err == -1)
86        ulog("Failed to send: %s [%d].\n",
87            strerror(errno), errno);
88
89    return err;
90}
91
92static void usage(void)
93{
94    printf(
95        "Usage: ucon [options] [output file]\n"
96        "\n"
97        "\t-h\tthis help screen\n"
98        "\t-s\tsend buffers to the test module\n"
99        "\n"
100        "The default behavior of ucon is to subscribe to the test module\n"
101        "and wait for state messages. Any ones received are dumped to the\n"
102        "specified output file (or stdout). The test module is assumed to\n"
103        "have an id of {%u.%u}\n"
104        "\n"
105        "If you get no output, then verify the cn_test module id matches\n"
106        "the expected id above.\n"
107        , CN_TEST_IDX, CN_TEST_VAL
108    );
109}
110
111int main(int argc, char *argv[])
112{
113    int s;
114    char buf[1024];
115    int len;
116    struct nlmsghdr *reply;
117    struct sockaddr_nl l_local;
118    struct cn_msg *data;
119    FILE *out;
120    time_t tm;
121    struct pollfd pfd;
122    bool send_msgs = false;
123
124    while ((s = getopt(argc, argv, "hs")) != -1) {
125        switch (s) {
126        case 's':
127            send_msgs = true;
128            break;
129
130        case 'h':
131            usage();
132            return 0;
133
134        default:
135            /* getopt() outputs an error for us */
136            usage();
137            return 1;
138        }
139    }
140
141    if (argc != optind) {
142        out = fopen(argv[optind], "a+");
143        if (!out) {
144            ulog("Unable to open %s for writing: %s\n",
145                argv[1], strerror(errno));
146            out = stdout;
147        }
148    } else
149        out = stdout;
150
151    memset(buf, 0, sizeof(buf));
152
153    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
154    if (s == -1) {
155        perror("socket");
156        return -1;
157    }
158
159    l_local.nl_family = AF_NETLINK;
160    l_local.nl_groups = -1; /* bitmask of requested groups */
161    l_local.nl_pid = 0;
162
163    ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
164
165    if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
166        perror("bind");
167        close(s);
168        return -1;
169    }
170
171#if 0
172    {
173        int on = 0x57; /* Additional group number */
174        setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
175    }
176#endif
177    if (send_msgs) {
178        int i, j;
179
180        memset(buf, 0, sizeof(buf));
181
182        data = (struct cn_msg *)buf;
183
184        data->id.idx = CN_TEST_IDX;
185        data->id.val = CN_TEST_VAL;
186        data->seq = seq++;
187        data->ack = 0;
188        data->len = 0;
189
190        for (j=0; j<10; ++j) {
191            for (i=0; i<1000; ++i) {
192                len = netlink_send(s, data);
193            }
194
195            ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val);
196        }
197
198        return 0;
199    }
200
201
202    pfd.fd = s;
203
204    while (!need_exit) {
205        pfd.events = POLLIN;
206        pfd.revents = 0;
207        switch (poll(&pfd, 1, -1)) {
208            case 0:
209                need_exit = 1;
210                break;
211            case -1:
212                if (errno != EINTR) {
213                    need_exit = 1;
214                    break;
215                }
216                continue;
217        }
218        if (need_exit)
219            break;
220
221        memset(buf, 0, sizeof(buf));
222        len = recv(s, buf, sizeof(buf), 0);
223        if (len == -1) {
224            perror("recv buf");
225            close(s);
226            return -1;
227        }
228        reply = (struct nlmsghdr *)buf;
229
230        switch (reply->nlmsg_type) {
231        case NLMSG_ERROR:
232            fprintf(out, "Error message received.\n");
233            fflush(out);
234            break;
235        case NLMSG_DONE:
236            data = (struct cn_msg *)NLMSG_DATA(reply);
237
238            time(&tm);
239            fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n",
240                ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack);
241            fflush(out);
242            break;
243        default:
244            break;
245        }
246    }
247
248    close(s);
249    return 0;
250}
251

Archive Download this file



interactive