a3395c34b44a62fa2c02631dcf0f25510d6a69d8
[can-benchmark.git] / ugw / ugw.c
1 /**************************************************************************/
2 /* CAN user space gateway for performance benchmarks                      */
3 /* Copyright (C) 2013, 2014 Michal Sojka, DCE, FEE, CTU Prague            */
4 /* License: GPLv2                                                         */
5 /**************************************************************************/
6
7 #define _GNU_SOURCE
8 #include <sys/socket.h>
9 #include <linux/can.h>
10 #include <sys/ioctl.h>
11 #include <net/if.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <time.h>
17 #include <stdbool.h>
18
19 #define STRINGIFY(val) #val
20 #define TOSTRING(val) STRINGIFY(val)
21 #define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
22
23 char *devin = "can0";
24 char *devout = "can1";
25 enum { READ, RECVMMSG } in_method = READ;
26 enum { WRITE }         out_method = WRITE;
27 bool quiet = false;
28
29 #define VERBOSE(format, ...) do { if (!quiet) fprintf(stderr, format, ##__VA_ARGS__); } while (0)
30
31 struct in_ctx {
32         int s;
33         int for_out;
34         int (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
35 };
36
37 struct out_ctx {
38         int s;
39         int from_in;
40         int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
41 };
42
43 int in_read(struct in_ctx *ctx, struct can_frame *cf)
44 {
45         int ret = read(ctx->s, cf, sizeof(*cf));
46         if (ret != sizeof(*cf)) {
47                 perror("read");
48                 exit(1);
49         }
50         return 0;
51 }
52
53 void init_read(struct in_ctx *ctx)
54 {
55         int s;
56         struct sockaddr_can addr;
57         struct ifreq ifr;
58
59         s = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW));
60
61         strcpy(ifr.ifr_name, devin);
62         if (-1 == ioctl(s, SIOCGIFINDEX, &ifr)) {
63                 perror(devin);
64                 exit(1);
65         }
66
67         addr.can_family = AF_CAN;
68         addr.can_ifindex = ifr.ifr_ifindex;
69
70         CHECK(bind(s, (struct sockaddr *)&addr, sizeof(addr)));
71
72         ctx->s = s;
73         ctx->in_fn = in_read;
74 }
75
76 int out_write(struct out_ctx *ctx, struct can_frame *cf)
77 {
78         int ret = write(ctx->s, cf, sizeof(*cf));
79         if (ret != sizeof(*cf)) {
80                 perror("write");
81                 exit(1);
82         }
83         return 0;
84 }
85
86 void init_write(struct out_ctx *ctx)
87 {
88         int s;
89         struct sockaddr_can addr;
90         struct ifreq ifr;
91
92         s = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW));
93
94         strcpy(ifr.ifr_name, devout);
95         if (-1 == ioctl(s, SIOCGIFINDEX, &ifr)) {
96                 perror(devout);
97                 exit(1);
98         }
99
100         addr.can_family = AF_CAN;
101         addr.can_ifindex = ifr.ifr_ifindex;
102
103         CHECK(bind(s, (struct sockaddr *)&addr, sizeof(addr)));
104
105         ctx->s = s;
106         ctx->out_fn = out_write;
107 }
108
109 void init_in(struct in_ctx *in)
110 {
111         switch (in_method) {
112         case READ: init_read(in); break;
113         default:
114                 fprintf(stderr, "Unknown \"in method\" %d\n", in_method);
115                 exit(1);
116         }
117 }
118
119 int in(struct in_ctx *ctx, struct can_frame *cf)
120 {
121         return ctx->in_fn(ctx, cf);
122 }
123
124 void init_out(struct out_ctx *out)
125 {
126         switch (out_method) {
127         case WRITE: init_write(out); break;
128         default:
129                 fprintf(stderr, "Unknown \"out method\" %d\n", out_method);
130                 exit(1);
131         }
132 }
133
134 int out(struct out_ctx *ctx, struct can_frame *cf)
135 {
136         return ctx->out_fn(ctx, cf);
137 }
138
139 void gw()
140 {
141         struct in_ctx    ic;
142         struct out_ctx   oc;
143         struct can_frame cf;
144
145         init_in(&ic);
146         init_out(&oc);
147
148         VERBOSE("UGW started");
149
150         while (1) {
151                 in(&ic, &cf);
152                 oc.from_in = ic.for_out;
153                 out(&oc, &cf);
154         }
155 }
156
157
158 int main(int argc, char *argv[])
159 {
160         int opt;
161
162         while ((opt = getopt(argc, argv, "q")) != -1) {
163                 switch (opt) {
164                 case 'q':
165                         quiet = true;
166                         break;
167                 default: /* '?' */
168                         fprintf(stderr, "Usage: %s [in_interface out_interface]\n",
169                                 argv[0]);
170                         exit(EXIT_FAILURE);
171                 }
172         }
173
174         if (optind < argc)
175                 devin  = argv[optind];
176         if (optind+1 < argc)
177                 devout = argv[optind+1];
178
179         gw();
180
181         return 0;
182 }