2 Copyright (c) 2010 by Juliusz Chroboczek
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
25 #include <string.h> /* memcmp (), memcpy (), memset () */
26 #include <stdlib.h> /* malloc (), free () */
28 #include <unistd.h> /* close () */
30 #include <event2/event.h>
32 #include <libutp/utp.h>
34 #include "transmission.h"
42 /* Since we use a single UDP socket in order to implement multiple
43 uTP sockets, try to set up huge buffers. */
45 #define RECV_BUFFER_SIZE (4 * 1024 * 1024)
46 #define SEND_BUFFER_SIZE (1 * 1024 * 1024)
47 #define SMALL_BUFFER_SIZE (32 * 1024)
50 set_socket_buffers (int fd
, int large
)
52 int size
, rbuf
, sbuf
, rc
;
53 socklen_t rbuf_len
= sizeof (rbuf
), sbuf_len
= sizeof (sbuf
);
55 size
= large
? RECV_BUFFER_SIZE
: SMALL_BUFFER_SIZE
;
56 rc
= setsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
, &size
, sizeof (size
));
58 tr_logAddNamedError ("UDP", "Failed to set receive buffer: %s",
61 size
= large
? SEND_BUFFER_SIZE
: SMALL_BUFFER_SIZE
;
62 rc
= setsockopt (fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof (size
));
64 tr_logAddNamedError ("UDP", "Failed to set send buffer: %s",
68 rc
= getsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
, &rbuf
, &rbuf_len
);
72 rc
= getsockopt (fd
, SOL_SOCKET
, SO_SNDBUF
, &sbuf
, &sbuf_len
);
76 if (rbuf
< RECV_BUFFER_SIZE
) {
77 tr_logAddNamedError ("UDP", "Failed to set receive buffer: requested %d, got %d",
78 RECV_BUFFER_SIZE
, rbuf
);
80 tr_logAddNamedInfo ("UDP",
81 "Please add the line "
82 "\"net.core.rmem_max = %d\" to /etc/sysctl.conf",
87 if (sbuf
< SEND_BUFFER_SIZE
) {
88 tr_logAddNamedError ("UDP", "Failed to set send buffer: requested %d, got %d",
89 SEND_BUFFER_SIZE
, sbuf
);
91 tr_logAddNamedInfo ("UDP",
92 "Please add the line "
93 "\"net.core.wmem_max = %d\" to /etc/sysctl.conf",
101 tr_udpSetSocketBuffers (tr_session
*session
)
103 bool utp
= tr_sessionIsUTPEnabled (session
);
104 if (session
->udp_socket
>= 0)
105 set_socket_buffers (session
->udp_socket
, utp
);
106 if (session
->udp6_socket
>= 0)
107 set_socket_buffers (session
->udp6_socket
, utp
);
113 /* BEP-32 has a rather nice explanation of why we need to bind to one
114 IPv6 address, if I may say so myself. */
117 rebind_ipv6 (tr_session
*ss
, bool force
)
120 const struct tr_address
* public_addr
;
121 struct sockaddr_in6 sin6
;
122 const unsigned char *ipv6
= tr_globalIPv6 ();
126 /* We currently have no way to enable or disable IPv6 after initialisation.
127 No way to fix that without some surgery to the DHT code itself. */
128 if (ipv6
== NULL
|| (!force
&& ss
->udp6_socket
< 0)) {
129 if (ss
->udp6_bound
) {
130 free (ss
->udp6_bound
);
131 ss
->udp6_bound
= NULL
;
136 if (ss
->udp6_bound
!= NULL
&& memcmp (ipv6
, ss
->udp6_bound
, 16) == 0)
139 s
= socket (PF_INET6
, SOCK_DGRAM
, 0);
144 /* Since we always open an IPv4 socket on the same port, this
145 shouldn't matter. But I'm superstitious. */
146 setsockopt (s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof (one
));
149 memset (&sin6
, 0, sizeof (sin6
));
150 sin6
.sin6_family
= AF_INET6
;
152 memcpy (&sin6
.sin6_addr
, ipv6
, 16);
153 sin6
.sin6_port
= htons (ss
->udp_port
);
154 public_addr
= tr_sessionGetPublicAddress (ss
, TR_AF_INET6
, &is_default
);
155 if (public_addr
&& !is_default
)
156 sin6
.sin6_addr
= public_addr
->addr
.addr6
;
158 rc
= bind (s
, (struct sockaddr
*)&sin6
, sizeof (sin6
));
162 if (ss
->udp6_socket
< 0) {
165 rc
= dup2 (s
, ss
->udp6_socket
);
171 if (ss
->udp6_bound
== NULL
)
172 ss
->udp6_bound
= malloc (16);
174 memcpy (ss
->udp6_bound
, ipv6
, 16);
179 /* Something went wrong. It's difficult to recover, so let's simply
180 set things up so that we try again next time. */
181 tr_logAddNamedError ("UDP", "Couldn't rebind IPv6 socket");
184 if (ss
->udp6_bound
) {
185 free (ss
->udp6_bound
);
186 ss
->udp6_bound
= NULL
;
191 event_callback (evutil_socket_t s
, short type UNUSED
, void *sv
)
195 unsigned char buf
[4096];
196 struct sockaddr_storage from
;
199 assert (tr_isSession (sv
));
200 assert (type
== EV_READ
);
202 fromlen
= sizeof (from
);
203 rc
= recvfrom (s
, buf
, 4096 - 1, 0,
204 (struct sockaddr
*)&from
, &fromlen
);
206 /* Since most packets we receive here are µTP, make quick inline
207 checks for the other protocols. The logic is as follows:
208 - all DHT packets start with 'd';
209 - all UDP tracker packets start with a 32-bit (!) "action", which
211 - the above cannot be µTP packets, since these start with a 4-bit
212 version number (1). */
215 if (tr_sessionAllowsDHT (ss
)) {
216 buf
[rc
] = '\0'; /* required by the DHT code */
217 tr_dhtCallback (buf
, rc
, (struct sockaddr
*)&from
, fromlen
, sv
);
219 } else if (rc
>= 8 &&
220 buf
[0] == 0 && buf
[1] == 0 && buf
[2] == 0 && buf
[3] <= 3) {
221 rc
= tau_handle_message (ss
, buf
, rc
);
223 tr_logAddNamedDbg ("UDP", "Couldn't parse UDP tracker packet.");
225 if (tr_sessionIsUTPEnabled (ss
)) {
226 rc
= tr_utpPacket (buf
, rc
, (struct sockaddr
*)&from
, fromlen
, ss
);
228 tr_logAddNamedDbg ("UDP", "Unexpected UDP packet");
235 tr_udpInit (tr_session
*ss
)
238 const struct tr_address
* public_addr
;
239 struct sockaddr_in sin
;
242 assert (ss
->udp_socket
< 0);
243 assert (ss
->udp6_socket
< 0);
245 ss
->udp_port
= tr_sessionGetPeerPort (ss
);
246 if (ss
->udp_port
<= 0)
249 ss
->udp_socket
= socket (PF_INET
, SOCK_DGRAM
, 0);
250 if (ss
->udp_socket
< 0) {
251 tr_logAddNamedError ("UDP", "Couldn't create IPv4 socket");
255 memset (&sin
, 0, sizeof (sin
));
256 sin
.sin_family
= AF_INET
;
257 public_addr
= tr_sessionGetPublicAddress (ss
, TR_AF_INET
, &is_default
);
258 if (public_addr
&& !is_default
)
259 memcpy (&sin
.sin_addr
, &public_addr
->addr
.addr4
, sizeof (struct in_addr
));
260 sin
.sin_port
= htons (ss
->udp_port
);
261 rc
= bind (ss
->udp_socket
, (struct sockaddr
*)&sin
, sizeof (sin
));
263 tr_logAddNamedError ("UDP", "Couldn't bind IPv4 socket");
264 close (ss
->udp_socket
);
269 event_new (ss
->event_base
, ss
->udp_socket
, EV_READ
| EV_PERSIST
,
271 if (ss
->udp_event
== NULL
)
272 tr_logAddNamedError ("UDP", "Couldn't allocate IPv4 event");
275 if (tr_globalIPv6 ())
276 rebind_ipv6 (ss
, true);
277 if (ss
->udp6_socket
>= 0) {
279 event_new (ss
->event_base
, ss
->udp6_socket
, EV_READ
| EV_PERSIST
,
281 if (ss
->udp6_event
== NULL
)
282 tr_logAddNamedError ("UDP", "Couldn't allocate IPv6 event");
285 tr_udpSetSocketBuffers (ss
);
287 if (ss
->isDHTEnabled
)
291 event_add (ss
->udp_event
, NULL
);
293 event_add (ss
->udp6_event
, NULL
);
297 tr_udpUninit (tr_session
*ss
)
301 if (ss
->udp_socket
>= 0) {
302 tr_netCloseSocket (ss
->udp_socket
);
307 event_free (ss
->udp_event
);
308 ss
->udp_event
= NULL
;
311 if (ss
->udp6_socket
>= 0) {
312 tr_netCloseSocket (ss
->udp6_socket
);
313 ss
->udp6_socket
= -1;
316 if (ss
->udp6_event
) {
317 event_free (ss
->udp6_event
);
318 ss
->udp6_event
= NULL
;
321 if (ss
->udp6_bound
) {
322 free (ss
->udp6_bound
);
323 ss
->udp6_bound
= NULL
;