1 /*
2 Copyright (c) 2010 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 
24 #include <string.h> /* memcmp(), memcpy(), memset() */
25 #include <stdlib.h> /* malloc(), free() */
26 
27 #ifdef _WIN32
28 #include <io.h> /* dup2() */
29 #else
30 #include <unistd.h> /* dup2() */
31 #endif
32 
33 #include <event2/event.h>
34 
35 #include <libutp/utp.h>
36 
37 #include "transmission.h"
38 #include "log.h"
39 #include "net.h"
40 #include "session.h"
41 #include "tr-assert.h"
42 #include "tr-dht.h"
43 #include "tr-utp.h"
44 #include "tr-udp.h"
45 
46 /* Since we use a single UDP socket in order to implement multiple
47    uTP sockets, try to set up huge buffers. */
48 
49 #define RECV_BUFFER_SIZE (4 * 1024 * 1024)
50 #define SEND_BUFFER_SIZE (1 * 1024 * 1024)
51 #define SMALL_BUFFER_SIZE (32 * 1024)
52 
set_socket_buffers(tr_socket_t fd,bool large)53 static void set_socket_buffers(tr_socket_t fd, bool large)
54 {
55     int size;
56     int rbuf;
57     int sbuf;
58     int rc;
59     socklen_t rbuf_len = sizeof(rbuf);
60     socklen_t sbuf_len = sizeof(sbuf);
61     char err_buf[512];
62 
63     size = large ? RECV_BUFFER_SIZE : SMALL_BUFFER_SIZE;
64     rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void const*)&size, sizeof(size));
65 
66     if (rc < 0)
67     {
68         tr_logAddNamedError("UDP", "Failed to set receive buffer: %s", tr_net_strerror(err_buf, sizeof(err_buf), sockerrno));
69     }
70 
71     size = large ? SEND_BUFFER_SIZE : SMALL_BUFFER_SIZE;
72     rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void const*)&size, sizeof(size));
73 
74     if (rc < 0)
75     {
76         tr_logAddNamedError("UDP", "Failed to set send buffer: %s", tr_net_strerror(err_buf, sizeof(err_buf), sockerrno));
77     }
78 
79     if (large)
80     {
81         rc = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&rbuf, &rbuf_len);
82 
83         if (rc < 0)
84         {
85             rbuf = 0;
86         }
87 
88         rc = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&sbuf, &sbuf_len);
89 
90         if (rc < 0)
91         {
92             sbuf = 0;
93         }
94 
95         if (rbuf < RECV_BUFFER_SIZE)
96         {
97             tr_logAddNamedError("UDP", "Failed to set receive buffer: requested %d, got %d", RECV_BUFFER_SIZE, rbuf);
98 #ifdef __linux__
99             tr_logAddNamedInfo("UDP", "Please add the line \"net.core.rmem_max = %d\" to /etc/sysctl.conf", RECV_BUFFER_SIZE);
100 #endif
101         }
102 
103         if (sbuf < SEND_BUFFER_SIZE)
104         {
105             tr_logAddNamedError("UDP", "Failed to set send buffer: requested %d, got %d", SEND_BUFFER_SIZE, sbuf);
106 #ifdef __linux__
107             tr_logAddNamedInfo("UDP", "Please add the line \"net.core.wmem_max = %d\" to /etc/sysctl.conf", SEND_BUFFER_SIZE);
108 #endif
109         }
110     }
111 }
112 
tr_udpSetSocketBuffers(tr_session * session)113 void tr_udpSetSocketBuffers(tr_session* session)
114 {
115     bool utp = tr_sessionIsUTPEnabled(session);
116 
117     if (session->udp_socket != TR_BAD_SOCKET)
118     {
119         set_socket_buffers(session->udp_socket, utp);
120     }
121 
122     if (session->udp6_socket != TR_BAD_SOCKET)
123     {
124         set_socket_buffers(session->udp6_socket, utp);
125     }
126 }
127 
128 /* BEP-32 has a rather nice explanation of why we need to bind to one
129    IPv6 address, if I may say so myself. */
130 
rebind_ipv6(tr_session * ss,bool force)131 static void rebind_ipv6(tr_session* ss, bool force)
132 {
133     bool is_default;
134     struct tr_address const* public_addr;
135     struct sockaddr_in6 sin6;
136     unsigned char const* ipv6 = tr_globalIPv6();
137     tr_socket_t s = TR_BAD_SOCKET;
138     int rc;
139     int one = 1;
140 
141     /* We currently have no way to enable or disable IPv6 after initialisation.
142        No way to fix that without some surgery to the DHT code itself. */
143     if (ipv6 == NULL || (!force && ss->udp6_socket == TR_BAD_SOCKET))
144     {
145         if (ss->udp6_bound != NULL)
146         {
147             free(ss->udp6_bound);
148             ss->udp6_bound = NULL;
149         }
150 
151         return;
152     }
153 
154     if (ss->udp6_bound != NULL && memcmp(ipv6, ss->udp6_bound, 16) == 0)
155     {
156         return;
157     }
158 
159     s = socket(PF_INET6, SOCK_DGRAM, 0);
160 
161     if (s == TR_BAD_SOCKET)
162     {
163         goto fail;
164     }
165 
166 #ifdef IPV6_V6ONLY
167     /* Since we always open an IPv4 socket on the same port, this
168        shouldn't matter.  But I'm superstitious. */
169     setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void const*)&one, sizeof(one));
170 #endif
171 
172     memset(&sin6, 0, sizeof(sin6));
173     sin6.sin6_family = AF_INET6;
174 
175     if (ipv6 != NULL)
176     {
177         memcpy(&sin6.sin6_addr, ipv6, 16);
178     }
179 
180     sin6.sin6_port = htons(ss->udp_port);
181     public_addr = tr_sessionGetPublicAddress(ss, TR_AF_INET6, &is_default);
182 
183     if (public_addr != NULL && !is_default)
184     {
185         sin6.sin6_addr = public_addr->addr.addr6;
186     }
187 
188     rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
189 
190     if (rc == -1)
191     {
192         goto fail;
193     }
194 
195     if (ss->udp6_socket == TR_BAD_SOCKET)
196     {
197         ss->udp6_socket = s;
198     }
199     else
200     {
201         /* FIXME: dup2 doesn't work for sockets on Windows */
202         rc = dup2(s, ss->udp6_socket);
203 
204         if (rc == -1)
205         {
206             goto fail;
207         }
208 
209         tr_netCloseSocket(s);
210     }
211 
212     if (ss->udp6_bound == NULL)
213     {
214         ss->udp6_bound = malloc(16);
215     }
216 
217     if (ss->udp6_bound != NULL)
218     {
219         memcpy(ss->udp6_bound, ipv6, 16);
220     }
221 
222     return;
223 
224 fail:
225     /* Something went wrong.  It's difficult to recover, so let's simply
226        set things up so that we try again next time. */
227     tr_logAddNamedError("UDP", "Couldn't rebind IPv6 socket");
228 
229     if (s != TR_BAD_SOCKET)
230     {
231         tr_netCloseSocket(s);
232     }
233 
234     if (ss->udp6_bound != NULL)
235     {
236         free(ss->udp6_bound);
237         ss->udp6_bound = NULL;
238     }
239 }
240 
event_callback(evutil_socket_t s,short type UNUSED,void * sv)241 static void event_callback(evutil_socket_t s, short type UNUSED, void* sv)
242 {
243     TR_ASSERT(tr_isSession(sv));
244     TR_ASSERT(type == EV_READ);
245 
246     int rc;
247     socklen_t fromlen;
248     unsigned char buf[4096];
249     struct sockaddr_storage from;
250     tr_session* ss = sv;
251 
252     fromlen = sizeof(from);
253     rc = recvfrom(s, (void*)buf, 4096 - 1, 0, (struct sockaddr*)&from, &fromlen);
254 
255     /* Since most packets we receive here are µTP, make quick inline
256        checks for the other protocols.  The logic is as follows:
257        - all DHT packets start with 'd';
258        - all UDP tracker packets start with a 32-bit (!) "action", which
259          is between 0 and 3;
260        - the above cannot be µTP packets, since these start with a 4-bit
261          version number (1). */
262     if (rc > 0)
263     {
264         if (buf[0] == 'd')
265         {
266             if (tr_sessionAllowsDHT(ss))
267             {
268                 buf[rc] = '\0'; /* required by the DHT code */
269                 tr_dhtCallback(buf, rc, (struct sockaddr*)&from, fromlen, sv);
270             }
271         }
272         else if (rc >= 8 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] <= 3)
273         {
274             rc = tau_handle_message(ss, buf, rc);
275 
276             if (rc == 0)
277             {
278                 tr_logAddNamedDbg("UDP", "Couldn't parse UDP tracker packet.");
279             }
280         }
281         else
282         {
283             if (tr_sessionIsUTPEnabled(ss))
284             {
285                 rc = tr_utpPacket(buf, rc, (struct sockaddr*)&from, fromlen, ss);
286 
287                 if (rc == 0)
288                 {
289                     tr_logAddNamedDbg("UDP", "Unexpected UDP packet");
290                 }
291             }
292         }
293     }
294 }
295 
tr_udpInit(tr_session * ss)296 void tr_udpInit(tr_session* ss)
297 {
298     TR_ASSERT(ss->udp_socket == TR_BAD_SOCKET);
299     TR_ASSERT(ss->udp6_socket == TR_BAD_SOCKET);
300 
301     bool is_default;
302     struct tr_address const* public_addr;
303     struct sockaddr_in sin;
304     int rc;
305 
306     ss->udp_port = tr_sessionGetPeerPort(ss);
307 
308     if (ss->udp_port <= 0)
309     {
310         return;
311     }
312 
313     ss->udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
314 
315     if (ss->udp_socket == TR_BAD_SOCKET)
316     {
317         tr_logAddNamedError("UDP", "Couldn't create IPv4 socket");
318         goto ipv6;
319     }
320 
321     memset(&sin, 0, sizeof(sin));
322     sin.sin_family = AF_INET;
323     public_addr = tr_sessionGetPublicAddress(ss, TR_AF_INET, &is_default);
324 
325     if (public_addr != NULL && !is_default)
326     {
327         memcpy(&sin.sin_addr, &public_addr->addr.addr4, sizeof(struct in_addr));
328     }
329 
330     sin.sin_port = htons(ss->udp_port);
331     rc = bind(ss->udp_socket, (struct sockaddr*)&sin, sizeof(sin));
332 
333     if (rc == -1)
334     {
335         tr_logAddNamedError("UDP", "Couldn't bind IPv4 socket");
336         tr_netCloseSocket(ss->udp_socket);
337         ss->udp_socket = TR_BAD_SOCKET;
338         goto ipv6;
339     }
340 
341     ss->udp_event = event_new(ss->event_base, ss->udp_socket, EV_READ | EV_PERSIST, event_callback, ss);
342 
343     if (ss->udp_event == NULL)
344     {
345         tr_logAddNamedError("UDP", "Couldn't allocate IPv4 event");
346     }
347 
348 ipv6:
349     if (tr_globalIPv6() != NULL)
350     {
351         rebind_ipv6(ss, true);
352     }
353 
354     if (ss->udp6_socket != TR_BAD_SOCKET)
355     {
356         ss->udp6_event = event_new(ss->event_base, ss->udp6_socket, EV_READ | EV_PERSIST, event_callback, ss);
357 
358         if (ss->udp6_event == NULL)
359         {
360             tr_logAddNamedError("UDP", "Couldn't allocate IPv6 event");
361         }
362     }
363 
364     tr_udpSetSocketBuffers(ss);
365 
366     if (ss->isDHTEnabled)
367     {
368         tr_dhtInit(ss);
369     }
370 
371     if (ss->udp_event != NULL)
372     {
373         event_add(ss->udp_event, NULL);
374     }
375 
376     if (ss->udp6_event != NULL)
377     {
378         event_add(ss->udp6_event, NULL);
379     }
380 }
381 
tr_udpUninit(tr_session * ss)382 void tr_udpUninit(tr_session* ss)
383 {
384     tr_dhtUninit(ss);
385 
386     if (ss->udp_socket != TR_BAD_SOCKET)
387     {
388         tr_netCloseSocket(ss->udp_socket);
389         ss->udp_socket = TR_BAD_SOCKET;
390     }
391 
392     if (ss->udp_event != NULL)
393     {
394         event_free(ss->udp_event);
395         ss->udp_event = NULL;
396     }
397 
398     if (ss->udp6_socket != TR_BAD_SOCKET)
399     {
400         tr_netCloseSocket(ss->udp6_socket);
401         ss->udp6_socket = TR_BAD_SOCKET;
402     }
403 
404     if (ss->udp6_event != NULL)
405     {
406         event_free(ss->udp6_event);
407         ss->udp6_event = NULL;
408     }
409 
410     if (ss->udp6_bound != NULL)
411     {
412         free(ss->udp6_bound);
413         ss->udp6_bound = NULL;
414     }
415 }
416