linux/samples/connector/ucon.c
<<
>>
Prefs
   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 = size;
  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