transmission 2.83
[tomato.git] / release / src / router / transmission / libtransmission / tr-udp.c
blobb0e60d64ab3397258b64a3b262f4533954f18df4
1 /*
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
20 THE SOFTWARE.
24 #include <assert.h>
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"
35 #include "log.h"
36 #include "net.h"
37 #include "session.h"
38 #include "tr-dht.h"
39 #include "tr-utp.h"
40 #include "tr-udp.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)
49 static void
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));
57 if (rc < 0)
58 tr_logAddNamedError ("UDP", "Failed to set receive buffer: %s",
59 tr_strerror (errno));
61 size = large ? SEND_BUFFER_SIZE : SMALL_BUFFER_SIZE;
62 rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size));
63 if (rc < 0)
64 tr_logAddNamedError ("UDP", "Failed to set send buffer: %s",
65 tr_strerror (errno));
67 if (large) {
68 rc = getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &rbuf_len);
69 if (rc < 0)
70 rbuf = 0;
72 rc = getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &sbuf_len);
73 if (rc < 0)
74 sbuf = 0;
76 if (rbuf < RECV_BUFFER_SIZE) {
77 tr_logAddNamedError ("UDP", "Failed to set receive buffer: requested %d, got %d",
78 RECV_BUFFER_SIZE, rbuf);
79 #ifdef __linux__
80 tr_logAddNamedInfo ("UDP",
81 "Please add the line "
82 "\"net.core.rmem_max = %d\" to /etc/sysctl.conf",
83 RECV_BUFFER_SIZE);
84 #endif
87 if (sbuf < SEND_BUFFER_SIZE) {
88 tr_logAddNamedError ("UDP", "Failed to set send buffer: requested %d, got %d",
89 SEND_BUFFER_SIZE, sbuf);
90 #ifdef __linux__
91 tr_logAddNamedInfo ("UDP",
92 "Please add the line "
93 "\"net.core.wmem_max = %d\" to /etc/sysctl.conf",
94 SEND_BUFFER_SIZE);
95 #endif
100 void
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. */
116 static void
117 rebind_ipv6 (tr_session *ss, bool force)
119 bool is_default;
120 const struct tr_address * public_addr;
121 struct sockaddr_in6 sin6;
122 const unsigned char *ipv6 = tr_globalIPv6 ();
123 int s = -1, rc;
124 int one = 1;
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;
133 return;
136 if (ss->udp6_bound != NULL && memcmp (ipv6, ss->udp6_bound, 16) == 0)
137 return;
139 s = socket (PF_INET6, SOCK_DGRAM, 0);
140 if (s < 0)
141 goto fail;
143 #ifdef IPV6_V6ONLY
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));
147 #endif
149 memset (&sin6, 0, sizeof (sin6));
150 sin6.sin6_family = AF_INET6;
151 if (ipv6)
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));
159 if (rc < 0)
160 goto fail;
162 if (ss->udp6_socket < 0) {
163 ss->udp6_socket = s;
164 } else {
165 rc = dup2 (s, ss->udp6_socket);
166 if (rc < 0)
167 goto fail;
168 close (s);
171 if (ss->udp6_bound == NULL)
172 ss->udp6_bound = malloc (16);
173 if (ss->udp6_bound)
174 memcpy (ss->udp6_bound, ipv6, 16);
176 return;
178 fail:
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");
182 if (s >= 0)
183 close (s);
184 if (ss->udp6_bound) {
185 free (ss->udp6_bound);
186 ss->udp6_bound = NULL;
190 static void
191 event_callback (evutil_socket_t s, short type UNUSED, void *sv)
193 int rc;
194 socklen_t fromlen;
195 unsigned char buf[4096];
196 struct sockaddr_storage from;
197 tr_session *ss = sv;
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
210 is between 0 and 3;
211 - the above cannot be µTP packets, since these start with a 4-bit
212 version number (1). */
213 if (rc > 0) {
214 if (buf[0] == 'd') {
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);
222 if (!rc)
223 tr_logAddNamedDbg ("UDP", "Couldn't parse UDP tracker packet.");
224 } else {
225 if (tr_sessionIsUTPEnabled (ss)) {
226 rc = tr_utpPacket (buf, rc, (struct sockaddr*)&from, fromlen, ss);
227 if (!rc)
228 tr_logAddNamedDbg ("UDP", "Unexpected UDP packet");
234 void
235 tr_udpInit (tr_session *ss)
237 bool is_default;
238 const struct tr_address * public_addr;
239 struct sockaddr_in sin;
240 int rc;
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)
247 return;
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");
252 goto ipv6;
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));
262 if (rc < 0) {
263 tr_logAddNamedError ("UDP", "Couldn't bind IPv4 socket");
264 close (ss->udp_socket);
265 ss->udp_socket = -1;
266 goto ipv6;
268 ss->udp_event =
269 event_new (ss->event_base, ss->udp_socket, EV_READ | EV_PERSIST,
270 event_callback, ss);
271 if (ss->udp_event == NULL)
272 tr_logAddNamedError ("UDP", "Couldn't allocate IPv4 event");
274 ipv6:
275 if (tr_globalIPv6 ())
276 rebind_ipv6 (ss, true);
277 if (ss->udp6_socket >= 0) {
278 ss->udp6_event =
279 event_new (ss->event_base, ss->udp6_socket, EV_READ | EV_PERSIST,
280 event_callback, ss);
281 if (ss->udp6_event == NULL)
282 tr_logAddNamedError ("UDP", "Couldn't allocate IPv6 event");
285 tr_udpSetSocketBuffers (ss);
287 if (ss->isDHTEnabled)
288 tr_dhtInit (ss);
290 if (ss->udp_event)
291 event_add (ss->udp_event, NULL);
292 if (ss->udp6_event)
293 event_add (ss->udp6_event, NULL);
296 void
297 tr_udpUninit (tr_session *ss)
299 tr_dhtUninit (ss);
301 if (ss->udp_socket >= 0) {
302 tr_netCloseSocket (ss->udp_socket);
303 ss->udp_socket = -1;
306 if (ss->udp_event) {
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;