1 /*
2 Copyright (c) 2007, 2008 by Juliusz Chroboczek
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/uio.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <arpa/inet.h>
36 #include <errno.h>
37
38 #include "babeld.h"
39 #include "util.h"
40 #include "net.h"
41
42 int
babel_socket(int port)43 babel_socket(int port)
44 {
45 struct sockaddr_in6 sin6;
46 int s, rc;
47 int saved_errno;
48 int one = 1, zero = 0;
49 const int ds = 0xc0; /* CS6 - Network Control */
50
51 s = socket(PF_INET6, SOCK_DGRAM, 0);
52 if(s < 0)
53 return -1;
54
55 rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
56 if(rc < 0)
57 goto fail;
58
59 rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
60 if(rc < 0)
61 goto fail;
62
63 rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
64 &zero, sizeof(zero));
65 if(rc < 0)
66 goto fail;
67
68 rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
69 &one, sizeof(one));
70 if(rc < 0)
71 goto fail;
72
73 rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
74 &one, sizeof(one));
75 if(rc < 0)
76 goto fail;
77
78 #ifdef IPV6_TCLASS
79 rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds));
80 #else
81 rc = -1;
82 errno = ENOSYS;
83 #endif
84 if(rc < 0)
85 perror("Couldn't set traffic class");
86
87 rc = fcntl(s, F_GETFL, 0);
88 if(rc < 0)
89 goto fail;
90
91 rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
92 if(rc < 0)
93 goto fail;
94
95 rc = fcntl(s, F_GETFD, 0);
96 if(rc < 0)
97 goto fail;
98
99 rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
100 if(rc < 0)
101 goto fail;
102
103 memset(&sin6, 0, sizeof(sin6));
104 sin6.sin6_family = AF_INET6;
105 sin6.sin6_port = htons(port);
106 rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
107 if(rc < 0)
108 goto fail;
109
110 return s;
111
112 fail:
113 saved_errno = errno;
114 close(s);
115 errno = saved_errno;
116 return -1;
117 }
118
119 int
babel_recv(int s,void * buf,int buflen,struct sockaddr * sin,int slen)120 babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen)
121 {
122 struct iovec iovec;
123 struct msghdr msg;
124 int rc;
125
126 memset(&msg, 0, sizeof(msg));
127 iovec.iov_base = buf;
128 iovec.iov_len = buflen;
129 msg.msg_name = sin;
130 msg.msg_namelen = slen;
131 msg.msg_iov = &iovec;
132 msg.msg_iovlen = 1;
133
134 rc = recvmsg(s, &msg, 0);
135 return rc;
136 }
137
138 int
babel_send(int s,const void * buf1,int buflen1,const void * buf2,int buflen2,const struct sockaddr * sin,int slen)139 babel_send(int s,
140 const void *buf1, int buflen1, const void *buf2, int buflen2,
141 const struct sockaddr *sin, int slen)
142 {
143 struct iovec iovec[2];
144 struct msghdr msg;
145 int rc, count = 0;
146
147 iovec[0].iov_base = (void*)buf1;
148 iovec[0].iov_len = buflen1;
149 iovec[1].iov_base = (void*)buf2;
150 iovec[1].iov_len = buflen2;
151 memset(&msg, 0, sizeof(msg));
152 msg.msg_name = (struct sockaddr*)sin;
153 msg.msg_namelen = slen;
154 msg.msg_iov = iovec;
155 msg.msg_iovlen = 2;
156
157 /* The Linux kernel can apparently keep returning EAGAIN indefinitely. */
158
159 again:
160 rc = sendmsg(s, &msg, 0);
161 if(rc < 0) {
162 if(errno == EINTR) {
163 count++;
164 if(count < 100)
165 goto again;
166 } else if(errno == EAGAIN) {
167 int rc2;
168 rc2 = wait_for_fd(1, s, 5);
169 if(rc2 > 0) {
170 count++;
171 if(count < 100)
172 goto again;
173 }
174 errno = EAGAIN;
175 }
176 }
177 return rc;
178 }
179
180 int
tcp_server_socket(int port,int local)181 tcp_server_socket(int port, int local)
182 {
183 struct sockaddr_in6 sin6;
184 int s, rc, saved_errno;
185 int one = 1;
186
187 s = socket(PF_INET6, SOCK_STREAM, 0);
188 if(s < 0)
189 return -1;
190
191 rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
192 if(rc < 0)
193 goto fail;
194
195 rc = fcntl(s, F_GETFL, 0);
196 if(rc < 0)
197 goto fail;
198
199 rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
200 if(rc < 0)
201 goto fail;
202
203 rc = fcntl(s, F_GETFD, 0);
204 if(rc < 0)
205 goto fail;
206
207 rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
208 if(rc < 0)
209 goto fail;
210
211 memset(&sin6, 0, sizeof(sin6));
212 sin6.sin6_family = AF_INET6;
213 sin6.sin6_port = htons(port);
214 if(local) {
215 rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr);
216 if(rc < 0)
217 goto fail;
218 }
219 rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
220 if(rc < 0)
221 goto fail;
222
223 rc = listen(s, 2);
224 if(rc < 0)
225 goto fail;
226
227 return s;
228
229 fail:
230 saved_errno = errno;
231 close(s);
232 errno = saved_errno;
233 return -1;
234 }
235
236 int
unix_server_socket(const char * path)237 unix_server_socket(const char *path)
238 {
239 struct sockaddr_un sun;
240 int s, rc, saved_errno;
241
242 if(strlen(path) >= sizeof(sun.sun_path))
243 return -1;
244
245 s = socket(PF_UNIX, SOCK_STREAM, 0);
246 if(s < 0)
247 return -1;
248
249 rc = fcntl(s, F_GETFL, 0);
250 if(rc < 0)
251 goto fail;
252
253 rc = fcntl(s, F_SETFL, rc | O_NONBLOCK);
254 if(rc < 0)
255 goto fail;
256
257 rc = fcntl(s, F_GETFD, 0);
258 if(rc < 0)
259 goto fail;
260
261 rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
262 if(rc < 0)
263 goto fail;
264
265 memset(&sun, 0, sizeof(sun));
266 sun.sun_family = AF_UNIX;
267 strncpy(sun.sun_path, path, sizeof(sun.sun_path));
268 rc = bind(s, (struct sockaddr *)&sun, sizeof(sun));
269 if(rc < 0)
270 goto fail;
271
272 rc = listen(s, 2);
273 if(rc < 0)
274 goto fail_unlink;
275
276 return s;
277
278 fail_unlink:
279 saved_errno = errno;
280 unlink(path);
281 errno = saved_errno;
282 fail:
283 saved_errno = errno;
284 close(s);
285 errno = saved_errno;
286 return -1;
287 }
288