source: trunk/libtransmission/tr-utp.c @ 11971

Last change on this file since 11971 was 11971, checked in by jch, 11 years ago

Stub out UTP_Create in non-uTP builds.

File size: 6.0 KB
Line 
1/*
2Copyright (c) 2010 by Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21
22*/
23
24#include <assert.h>
25#include <unistd.h>
26
27#include <event2/event.h>
28#include <libutp/utp.h>
29
30#include "transmission.h"
31#include "net.h"
32#include "session.h"
33#include "crypto.h"
34#include "peer-io.h"
35#include "peer-mgr.h"
36#include "tr-utp.h"
37#include "utils.h"
38
39#define MY_NAME "UTP"
40
41#define dbgmsg( ... ) \
42    do { \
43        if( tr_deepLoggingIsActive( ) ) \
44            tr_deepLog( __FILE__, __LINE__, MY_NAME, __VA_ARGS__ ); \
45    } while( 0 )
46
47#ifndef WITH_UTP
48
49void
50UTP_Close(struct UTPSocket * socket)
51{
52    tr_nerr( MY_NAME, "UTP_Close(%p) was called.", socket );
53    dbgmsg( "UTP_Close(%p) was called.", socket );
54    assert( 0 ); /* FIXME: this is too much for the long term, but probably needed in the short term */
55}
56
57void
58UTP_RBDrained(struct UTPSocket *socket)
59{
60    tr_nerr( MY_NAME, "UTP_RBDrained(%p) was called.", socket );
61    dbgmsg( "UTP_RBDrained(%p) was called.", socket );
62    assert( 0 ); /* FIXME: this is too much for the long term, but probably needed in the short term */
63}
64
65bool
66UTP_Write(struct UTPSocket *socket, size_t count)
67{
68    tr_nerr( MY_NAME, "UTP_RBDrained(%p, %zu) was called.", socket, count );
69    dbgmsg( "UTP_RBDrained(%p, %zu) was called.", socket, count );
70    assert( 0 ); /* FIXME: this is too much for the long term, but probably needed in the short term */
71    return FALSE;
72}
73
74int tr_utpPacket(const unsigned char *buf UNUSED, size_t buflen UNUSED,
75                 const struct sockaddr *from UNUSED, socklen_t fromlen UNUSED,
76                 tr_session *ss UNUSED) { return -1; }
77
78struct UTPSocket *UTP_Create(SendToProc *send_to_proc UNUSED,
79                             void *send_to_userdata UNUSED,
80                             const struct sockaddr *addr UNUSED,
81                             socklen_t addrlen UNUSED)
82{
83    errno = ENOSYS;
84    return NULL;
85}
86
87void tr_utpClose( tr_session * ss UNUSED ) { }
88
89void tr_utpSendTo(void *closure UNUSED,
90                  const unsigned char *buf UNUSED, size_t buflen UNUSED,
91                  const struct sockaddr *to UNUSED, socklen_t tolen UNUSED) { }
92
93#else
94
95/* Greg says 50ms works for them. */
96
97#define UTP_INTERVAL_US 50000
98
99static struct event *utp_timer = NULL;
100
101static void
102incoming(void *closure, struct UTPSocket *s)
103{
104    tr_session *ss = (tr_session*)closure;
105    struct sockaddr_storage from_storage;
106    struct sockaddr *from = (struct sockaddr*)&from_storage;
107    socklen_t fromlen = sizeof(from_storage);
108    tr_address addr;
109    tr_port port;
110
111    if( !tr_sessionIsUTPEnabled(ss) ) {
112        UTP_Close(s);
113        return;
114    }
115   
116    UTP_GetPeerName(s, from, &fromlen);
117    if(from->sa_family == AF_INET) {
118        struct sockaddr_in *sin = (struct sockaddr_in*)from;
119        addr.type = TR_AF_INET;
120        addr.addr.addr4.s_addr = sin->sin_addr.s_addr;
121        port = sin->sin_port;
122    } else if(from->sa_family == AF_INET6) {
123        struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)from;
124        addr.type = TR_AF_INET6;
125        addr.addr.addr6 = sin6->sin6_addr;
126        port = sin6->sin6_port;
127    } else {
128        tr_nerr("UTP", "Unknown socket family");
129        UTP_Close(s);
130        return;
131    }
132
133    tr_peerMgrAddIncoming(ss->peerMgr, &addr, port, -1, s);
134}
135
136void
137tr_utpSendTo(void *closure, const unsigned char *buf, size_t buflen,
138             const struct sockaddr *to, socklen_t tolen)
139{
140    tr_session *ss = (tr_session*)closure;
141
142    if(to->sa_family == AF_INET && ss->udp_socket)
143        sendto(ss->udp_socket, buf, buflen, 0, to, tolen);
144    else if(to->sa_family == AF_INET6 && ss->udp_socket)
145        sendto(ss->udp6_socket, buf, buflen, 0, to, tolen);
146}
147
148static void
149reset_timer(tr_session *ss)
150{
151    int sec;
152    int usec;
153    if( tr_sessionIsUTPEnabled( ss ) ) {
154        sec = 0;
155        usec = UTP_INTERVAL_US / 2 + tr_cryptoWeakRandInt(UTP_INTERVAL_US);
156    } else {
157        /* If somebody has disabled uTP, then we still want to run
158           UTP_CheckTimeouts, in order to let closed sockets finish
159           gracefully and so on.  However, since we're not particularly
160           interested in that happening in a timely manner, we might as
161           well use a large timeout. */
162        sec = 2;
163        usec = tr_cryptoWeakRandInt( 1000000 );
164    }
165    tr_timerAdd( utp_timer, sec, usec );
166}
167
168static void
169timer_callback(int s UNUSED, short type UNUSED, void *closure)
170{
171    tr_session *ss = closure;
172    UTP_CheckTimeouts();
173    reset_timer( ss );
174}
175
176int
177tr_utpPacket(const unsigned char *buf, size_t buflen,
178             const struct sockaddr *from, socklen_t fromlen,
179             tr_session *ss)
180{
181    if(utp_timer == NULL)
182    {
183        utp_timer = evtimer_new( ss->event_base, timer_callback, ss );
184        if(utp_timer == NULL)
185            return -1;
186        reset_timer( ss );
187    }
188
189    return UTP_IsIncomingUTP(incoming, tr_utpSendTo, ss,
190                             buf, buflen, from, fromlen);
191}
192
193void
194tr_utpClose( tr_session * session UNUSED )
195{
196    if( utp_timer )
197    {
198        evtimer_del( utp_timer );
199        utp_timer = NULL;
200    }
201}
202
203#endif /* #ifndef WITH_UTP ... else */
Note: See TracBrowser for help on using the repository browser.