1 | /* |
---|
2 | * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com> |
---|
3 | * |
---|
4 | * This file is licensed by the GPL version 2. Works owned by the |
---|
5 | * Transmission project are granted a special exemption to clause 2(b) |
---|
6 | * so that the bulk of its code can remain under the MIT license. |
---|
7 | * This exemption does not extend to derived works not owned by |
---|
8 | * the Transmission project. |
---|
9 | * |
---|
10 | * $Id:$ |
---|
11 | */ |
---|
12 | |
---|
13 | #include <assert.h> |
---|
14 | #include <string.h> |
---|
15 | #include <stdio.h> |
---|
16 | #include <unistd.h> |
---|
17 | #include <arpa/inet.h> |
---|
18 | #include <event.h> |
---|
19 | #include "transmission.h" |
---|
20 | #include "encryption.h" |
---|
21 | #include "net.h" |
---|
22 | #include "peer-connection.h" |
---|
23 | #include "trevent.h" |
---|
24 | #include "utils.h" |
---|
25 | |
---|
26 | /** |
---|
27 | *** |
---|
28 | **/ |
---|
29 | |
---|
30 | struct tr_peerConnection |
---|
31 | { |
---|
32 | struct tr_handle * handle; |
---|
33 | struct tr_torrent * torrent; |
---|
34 | |
---|
35 | struct in_addr in_addr; |
---|
36 | int port; |
---|
37 | int socket; |
---|
38 | int extensions; |
---|
39 | struct bufferevent * bufev; |
---|
40 | uint8_t peerId[20]; |
---|
41 | |
---|
42 | unsigned int isEncrypted : 1; |
---|
43 | unsigned int isIncoming : 1; |
---|
44 | unsigned int peerIdIsSet : 1; |
---|
45 | |
---|
46 | tr_can_read_cb canRead; |
---|
47 | tr_did_write_cb didWrite; |
---|
48 | tr_net_error_cb gotError; |
---|
49 | void * userData; |
---|
50 | |
---|
51 | tr_encryption * encryption; |
---|
52 | }; |
---|
53 | |
---|
54 | /** |
---|
55 | *** |
---|
56 | **/ |
---|
57 | |
---|
58 | static void |
---|
59 | didWriteWrapper( struct bufferevent * e, void * userData ) |
---|
60 | { |
---|
61 | tr_peerConnection * c = (tr_peerConnection *) userData; |
---|
62 | assert( c->didWrite != NULL ); |
---|
63 | (*c->didWrite)( e, c->userData ); |
---|
64 | } |
---|
65 | |
---|
66 | static void |
---|
67 | canReadWrapper( struct bufferevent * e, void * userData ) |
---|
68 | { |
---|
69 | tr_peerConnection * c = (tr_peerConnection *) userData; |
---|
70 | |
---|
71 | assert( c->canRead != NULL ); |
---|
72 | |
---|
73 | for( ;; ) { |
---|
74 | const int ret = (*c->canRead)( e, c->userData ); |
---|
75 | switch( ret ) { |
---|
76 | case READ_DONE: return; |
---|
77 | case READ_AGAIN: continue; |
---|
78 | case READ_MORE: tr_peerConnectionSetIOMode( c, EV_READ ); return; |
---|
79 | } |
---|
80 | } |
---|
81 | } |
---|
82 | |
---|
83 | static void |
---|
84 | gotErrorWrapper( struct bufferevent * e, short what, void * userData ) |
---|
85 | { |
---|
86 | tr_peerConnection * c = (tr_peerConnection *) userData; |
---|
87 | assert( c->gotError != NULL ); |
---|
88 | (*c->gotError)( e, what, c->userData ); |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | *** |
---|
93 | **/ |
---|
94 | |
---|
95 | static tr_peerConnection* |
---|
96 | tr_peerConnectionNew( struct tr_handle * handle, |
---|
97 | struct in_addr * in_addr, |
---|
98 | struct tr_torrent * torrent, |
---|
99 | int isIncoming, |
---|
100 | int socket ) |
---|
101 | { |
---|
102 | tr_peerConnection * c; |
---|
103 | c = tr_new0( tr_peerConnection, 1 ); |
---|
104 | c->torrent = torrent; |
---|
105 | c->encryption = tr_encryptionNew( torrent ? torrent->info.hash : NULL, isIncoming ); |
---|
106 | c->handle = handle; |
---|
107 | c->in_addr = *in_addr; |
---|
108 | c->socket = socket; |
---|
109 | c->bufev = bufferevent_new( c->socket, |
---|
110 | canReadWrapper, |
---|
111 | didWriteWrapper, |
---|
112 | gotErrorWrapper, |
---|
113 | c ); |
---|
114 | return c; |
---|
115 | } |
---|
116 | |
---|
117 | tr_peerConnection* |
---|
118 | tr_peerConnectionNewIncoming( struct tr_handle * handle, |
---|
119 | struct in_addr * in_addr, |
---|
120 | int socket ) |
---|
121 | { |
---|
122 | tr_peerConnection * c = |
---|
123 | tr_peerConnectionNew( handle, in_addr, NULL, 1, socket ); |
---|
124 | c->port = -1; |
---|
125 | return c; |
---|
126 | } |
---|
127 | |
---|
128 | tr_peerConnection* |
---|
129 | tr_peerConnectionNewOutgoing( struct tr_handle * handle, |
---|
130 | struct in_addr * in_addr, |
---|
131 | int port, |
---|
132 | struct tr_torrent * torrent ) |
---|
133 | { |
---|
134 | tr_peerConnection * c; |
---|
135 | |
---|
136 | assert( handle != NULL ); |
---|
137 | assert( in_addr != NULL ); |
---|
138 | assert( port >= 0 ); |
---|
139 | assert( torrent != NULL ); |
---|
140 | |
---|
141 | c = tr_peerConnectionNew( handle, in_addr, torrent, 0, |
---|
142 | tr_netOpenTCP( in_addr, port, 0 ) ); |
---|
143 | c->port = port; |
---|
144 | return c; |
---|
145 | } |
---|
146 | |
---|
147 | void |
---|
148 | tr_peerConnectionFree( tr_peerConnection * c ) |
---|
149 | { |
---|
150 | bufferevent_free( c->bufev ); |
---|
151 | tr_netClose( c->socket ); |
---|
152 | tr_encryptionFree( c->encryption ); |
---|
153 | tr_free( c ); |
---|
154 | } |
---|
155 | |
---|
156 | void |
---|
157 | tr_peerConnectionSetIOFuncs( tr_peerConnection * connection, |
---|
158 | tr_can_read_cb readcb, |
---|
159 | tr_did_write_cb writecb, |
---|
160 | tr_net_error_cb errcb, |
---|
161 | void * userData ) |
---|
162 | { |
---|
163 | connection->canRead = readcb; |
---|
164 | connection->didWrite = writecb; |
---|
165 | connection->gotError = errcb; |
---|
166 | connection->userData = userData; |
---|
167 | } |
---|
168 | |
---|
169 | void |
---|
170 | tr_peerConnectionSetIOMode( tr_peerConnection * c, short mode ) |
---|
171 | { |
---|
172 | tr_setBufferEventMode( c->handle, c->bufev, mode ); |
---|
173 | } |
---|
174 | |
---|
175 | void |
---|
176 | tr_peerConnectionReadOrWait( tr_peerConnection * c ) |
---|
177 | { |
---|
178 | if( EVBUFFER_LENGTH( c->bufev->input ) ) |
---|
179 | canReadWrapper( c->bufev, c ); |
---|
180 | else |
---|
181 | tr_peerConnectionSetIOMode( c, EV_READ ); |
---|
182 | } |
---|
183 | |
---|
184 | int |
---|
185 | tr_peerConnectionIsIncoming( const tr_peerConnection * c ) |
---|
186 | { |
---|
187 | return c->isIncoming; |
---|
188 | } |
---|
189 | |
---|
190 | int |
---|
191 | tr_peerConnectionReconnect( tr_peerConnection * connection ) |
---|
192 | { |
---|
193 | assert( !tr_peerConnectionIsIncoming( connection ) ); |
---|
194 | |
---|
195 | if( connection->socket >= 0 ) |
---|
196 | tr_netClose( connection->socket ); |
---|
197 | |
---|
198 | connection->socket = tr_netOpenTCP( &connection->in_addr, |
---|
199 | connection->port, 0 ); |
---|
200 | |
---|
201 | return connection->socket >= 0 ? 0 : -1; |
---|
202 | } |
---|
203 | |
---|
204 | |
---|
205 | tr_encryption* |
---|
206 | tr_peerConnectionGetEncryption( tr_peerConnection * c ) |
---|
207 | { |
---|
208 | return c->encryption; |
---|
209 | } |
---|
210 | |
---|
211 | /** |
---|
212 | *** |
---|
213 | **/ |
---|
214 | |
---|
215 | void |
---|
216 | tr_peerConnectionWrite( tr_peerConnection * connection, |
---|
217 | const void * writeme, |
---|
218 | int writeme_len ) |
---|
219 | { |
---|
220 | tr_bufferevent_write( connection->handle, |
---|
221 | connection->bufev, |
---|
222 | writeme, |
---|
223 | writeme_len ); |
---|
224 | } |
---|
225 | |
---|
226 | void |
---|
227 | tr_peerConnectionWriteBuf ( tr_peerConnection * connection, |
---|
228 | struct evbuffer * buf ) |
---|
229 | { |
---|
230 | tr_peerConnectionWrite( connection, |
---|
231 | EVBUFFER_DATA(buf), |
---|
232 | EVBUFFER_LENGTH(buf) ); |
---|
233 | } |
---|
234 | |
---|
235 | /** |
---|
236 | *** |
---|
237 | **/ |
---|
238 | |
---|
239 | void |
---|
240 | tr_peerConnectionSetTorrent( tr_peerConnection * connection, |
---|
241 | struct tr_torrent * torrent ) |
---|
242 | { |
---|
243 | connection->torrent = torrent; |
---|
244 | |
---|
245 | tr_encryptionSetTorrentHash( connection->encryption, torrent->info.hash ); |
---|
246 | } |
---|
247 | |
---|
248 | struct tr_torrent* |
---|
249 | tr_peerConnectionGetTorrent( tr_peerConnection * connection ) |
---|
250 | { |
---|
251 | return connection->torrent; |
---|
252 | } |
---|
253 | |
---|
254 | /** |
---|
255 | *** |
---|
256 | **/ |
---|
257 | |
---|
258 | void |
---|
259 | tr_peerConnectionSetPeersId( tr_peerConnection * connection, |
---|
260 | const uint8_t * peer_id ) |
---|
261 | { |
---|
262 | assert( connection != NULL ); |
---|
263 | |
---|
264 | if(( connection->peerIdIsSet = peer_id != NULL )) |
---|
265 | memcpy( connection->peerId, peer_id, 20 ); |
---|
266 | else |
---|
267 | memset( connection->peerId, 0, 20 ); |
---|
268 | } |
---|
269 | |
---|
270 | const uint8_t* |
---|
271 | tr_peerConnectionGetPeersId( const tr_peerConnection * connection ) |
---|
272 | { |
---|
273 | assert( connection != NULL ); |
---|
274 | assert( connection->peerIdIsSet ); |
---|
275 | |
---|
276 | return connection->peerId; |
---|
277 | } |
---|
278 | |
---|
279 | /** |
---|
280 | *** |
---|
281 | **/ |
---|
282 | |
---|
283 | void |
---|
284 | tr_peerConnectionSetExtension( tr_peerConnection * connection, |
---|
285 | int extensions ) |
---|
286 | { |
---|
287 | assert( connection != NULL ); |
---|
288 | assert( ( extensions == LT_EXTENSIONS_NONE ) |
---|
289 | || ( extensions == LT_EXTENSIONS_LTEP ) |
---|
290 | || ( extensions == LT_EXTENSIONS_AZMP ) ); |
---|
291 | |
---|
292 | connection->extensions = extensions; |
---|
293 | } |
---|
294 | |
---|
295 | int |
---|
296 | tr_peerConnectionGetExtension( const tr_peerConnection * connection ) |
---|
297 | { |
---|
298 | assert( connection != NULL ); |
---|
299 | |
---|
300 | return connection->extensions; |
---|
301 | } |
---|