xref: /dragonfly/test/udp/tos/udp_tos.c (revision a45b89791953e820c4b27fafe78163c88a3f5d53)
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 
4 #include <arpa/inet.h>
5 #include <netinet/in.h>
6 
7 #include <err.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 static void
usage(const char * cmd)15 usage(const char *cmd)
16 {
17           fprintf(stderr, "%s -4 ip4 -p port [-t tos [-c]]\n", cmd);
18           exit(1);
19 }
20 
21 int
main(int argc,char * argv[])22 main(int argc, char *argv[])
23 {
24           struct sockaddr_in in;
25           int s, opt, n, tos, cmsg_tos;
26           uint8_t buf[18];
27           struct msghdr msg;
28           struct iovec iov;
29           struct cmsghdr *cm;
30           union {
31                     struct cmsghdr cm;
32                     uint8_t data[CMSG_SPACE(sizeof(u_char))];
33           } ctrl;
34 
35           memset(&in, 0, sizeof(in));
36           in.sin_family = AF_INET;
37           tos = -1;
38           cmsg_tos = 0;
39 
40           while ((opt = getopt(argc, argv, "4:cp:t:")) != -1) {
41                     switch (opt) {
42                     case '4':
43                               if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0)
44                                         usage(argv[0]);
45                               break;
46 
47                     case 'c':
48                               cmsg_tos = 1;
49                               break;
50 
51                     case 'p':
52                               in.sin_port = strtol(optarg, NULL, 10);
53                               in.sin_port = htons(in.sin_port);
54                               break;
55 
56                     case 't':
57                               tos = strtol(optarg, NULL, 10);
58                               break;
59 
60                     default:
61                               usage(argv[0]);
62                     }
63           }
64 
65           if (in.sin_addr.s_addr == INADDR_ANY || in.sin_port == 0)
66                     usage(argv[0]);
67 
68           s = socket(AF_INET, SOCK_DGRAM, 0);
69           if (s < 0)
70                     err(2, "socket failed");
71 
72           if (tos >= 0) {
73                     if (!cmsg_tos) {
74                               if (setsockopt(s, IPPROTO_IP, IP_TOS,
75                                   &tos, sizeof(tos)) < 0)
76                                         err(2, "setsockopt IP_TOS %d failed", tos);
77 
78                               if (sendto(s, buf, sizeof(buf), 0,
79                                   (const struct sockaddr *)&in, sizeof(in)) < 0)
80                                         err(2, "sendto failed");
81                     } else {
82                               iov.iov_base = buf;
83                               iov.iov_len = sizeof(buf);
84 
85                               memset(&msg, 0, sizeof(msg));
86                               msg.msg_name = &in;
87                               msg.msg_namelen = sizeof(in);
88                               msg.msg_iov = &iov;
89                               msg.msg_iovlen = 1;
90                               msg.msg_control = ctrl.data;
91                               msg.msg_controllen = sizeof(ctrl.data);
92 
93                               memset(&ctrl, 0, sizeof(ctrl));
94                               cm = CMSG_FIRSTHDR(&msg);
95                               cm->cmsg_len = CMSG_LEN(sizeof(u_char));
96                               cm->cmsg_level = IPPROTO_IP;
97                               cm->cmsg_type = IP_TOS;
98                               *((u_char *)CMSG_DATA(cm)) = tos;
99 
100                               fprintf(stderr, "sendmsg tos %d\n", tos);
101                               if (sendmsg(s, &msg, MSG_SYNC) < 0)
102                                         err(2, "sendmsg failed");
103                     }
104           } else {
105                     const int on = 1;
106 
107                     if (bind(s, (const struct sockaddr *)&in, sizeof(in)) < 0)
108                               err(2, "bind failed");
109 
110                     if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) < 0)
111                               err(2, "setsockopt IP_RECVTOS failed");
112 
113                     iov.iov_base = buf;
114                     iov.iov_len = sizeof(buf);
115 
116                     memset(&msg, 0, sizeof(msg));
117                     msg.msg_iov = &iov;
118                     msg.msg_iovlen = 1;
119                     msg.msg_control = ctrl.data;
120                     msg.msg_controllen = sizeof(ctrl.data);
121 
122                     n = recvmsg(s, &msg, MSG_WAITALL);
123                     if (n < 0)
124                               err(1, "recvmsg failed");
125                     else if (n != sizeof(buf))
126                               errx(1, "recvmsg received %d", n);
127 
128                     cm = CMSG_FIRSTHDR(&msg);
129                     if (cm == NULL)
130                               errx(1, "no cmsg");
131                     if (cm->cmsg_len != CMSG_LEN(sizeof(u_char)))
132                               errx(1, "cmsg len mismatch");
133                     if (cm->cmsg_level != IPPROTO_IP)
134                               errx(1, "cmsg level mismatch");
135                     if (cm->cmsg_type != IP_RECVTOS)
136                               errx(1, "cmsg type mismatch");
137 
138                     tos = *((u_char *)CMSG_DATA(cm));
139 
140                     fprintf(stderr, "TOS: %d\n", tos);
141           }
142 
143           exit(0);
144 }
145