summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--proxy.c269
2 files changed, 271 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index a18fb3e..269a109 100644
--- a/Makefile
+++ b/Makefile
@@ -60,6 +60,8 @@ $(BINARY): $(OBJECTS) $(HEADERS)
60 strip $@ 60 strip $@
61$(BINARY).debug: $(OBJECTS_debug) $(HEADERS) 61$(BINARY).debug: $(OBJECTS_debug) $(HEADERS)
62 $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS) 62 $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS)
63proxy: proxy.o ot_vector.o $(HEADERS)
64 $(CC) -o $@ proxy.o ot_vector.o $(LDFLAGS)
63 65
64.c.debug.o : $(HEADERS) 66.c.debug.o : $(HEADERS)
65 $(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c) 67 $(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c)
diff --git a/proxy.c b/proxy.c
new file mode 100644
index 0000000..ca5a773
--- /dev/null
+++ b/proxy.c
@@ -0,0 +1,269 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
3
4 $Id$ */
5
6/* System */
7#include <stdlib.h>
8#include <string.h>
9#include <arpa/inet.h>
10#include <sys/socket.h>
11#include <unistd.h>
12#include <errno.h>
13#include <signal.h>
14#include <stdio.h>
15#include <pwd.h>
16#include <ctype.h>
17
18/* Libowfat */
19#include "socket.h"
20#include "io.h"
21#include "iob.h"
22#include "byte.h"
23#include "scan.h"
24#include "ip6.h"
25#include "ndelay.h"
26
27/* Opentracker */
28#include "trackerlogic.h"
29#include "ot_livesync.h"
30
31uint32_t g_tracker_id;
32char groupip_1[4] = { 224,0,23,5 };
33
34#define LIVESYNC_INCOMING_BUFFSIZE (256*256)
35
36#define LIVESYNC_OUTGOING_BUFFSIZE_PEERS 1480
37#define LIVESYNC_OUTGOING_WATERMARK_PEERS (sizeof(ot_peer)+sizeof(ot_hash))
38
39enum { OT_SYNC_PEER };
40
41/* For outgoing packets */
42static int64 g_socket_in = -1;
43
44/* For incoming packets */
45static int64 g_socket_out = -1;
46static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE];
47
48void exerr( char * message ) {
49 fprintf( stderr, "%s\n", message );
50 exit( 111 );
51}
52
53void livesync_bind_mcast( ot_ip6 ip, uint16_t port) {
54 char tmpip[4] = {0,0,0,0};
55 char *v4ip;
56
57 if( !ip6_isv4mapped(ip))
58 exerr("v6 mcast support not yet available.");
59 v4ip = ip+12;
60
61 if( g_socket_in != -1 )
62 exerr("Error: Livesync listen ip specified twice.");
63
64 if( ( g_socket_in = socket_udp4( )) < 0)
65 exerr("Error: Cant create live sync incoming socket." );
66 ndelay_off(g_socket_in);
67
68 if( socket_bind4_reuse( g_socket_in, tmpip, port ) == -1 )
69 exerr("Error: Cant bind live sync incoming socket." );
70
71 if( socket_mcjoin4( g_socket_in, groupip_1, v4ip ) )
72 exerr("Error: Cant make live sync incoming socket join mcast group.");
73
74 if( ( g_socket_out = socket_udp4()) < 0)
75 exerr("Error: Cant create live sync outgoing socket." );
76 if( socket_bind4_reuse( g_socket_out, v4ip, port ) == -1 )
77 exerr("Error: Cant bind live sync outgoing socket." );
78
79 socket_mcttl4(g_socket_out, 1);
80 socket_mcloop4(g_socket_out, 1);
81}
82
83static ot_vector all_torrents[OT_BUCKET_COUNT];
84ot_vector *mutex_bucket_lock_by_hash( ot_hash hash ) {
85 return all_torrents + ( uint32_read_big( (char*)hash ) >> OT_BUCKET_COUNT_SHIFT );
86}
87ot_vector *mutex_bucket_lock( int bucket ) {
88 return all_torrents + bucket;
89}
90#define mutex_bucket_unlock_by_hash(A,B)
91#define mutex_bucket_unlock(A)
92
93size_t add_peer_to_torrent_proxy( ot_hash hash, ot_peer *peer ) {
94 int exactmatch;
95 ot_torrent *torrent;
96 ot_peer *peer_dest;
97 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
98
99 torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
100 if( !torrent )
101 return -1;
102
103 if( !exactmatch ) {
104 /* Create a new torrent entry, then */
105 memcpy( torrent->hash, hash, sizeof(ot_hash) );
106
107 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
108 vector_remove_torrent( torrents_list, torrent );
109 return -1;
110 }
111
112 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
113 }
114
115 /* Check for peer in torrent */
116 peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), peer, &exactmatch );
117 if( !peer_dest ) return -1;
118
119 /* Tell peer that it's fresh */
120 OT_PEERTIME( peer ) = 0;
121
122 /* If we hadn't had a match create peer there */
123 if( !exactmatch ) {
124 torrent->peer_list->peer_count++;
125 if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING )
126 torrent->peer_list->seed_count++;
127 }
128 memcpy( peer_dest, peer, sizeof(ot_peer) );
129 return 0;
130}
131
132size_t remove_peer_from_torrent_proxy( ot_hash hash, ot_peer *peer ) {
133 int exactmatch;
134 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
135 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
136
137 if( exactmatch ) {
138 ot_peerlist *peer_list = torrent->peer_list;
139 switch( vector_remove_peer( &peer_list->peers, peer ) ) {
140 case 2: peer_list->seed_count--; /* Fall throughs intended */
141 case 1: peer_list->peer_count--; /* Fall throughs intended */
142 default: break;
143 }
144 }
145
146 return 0;
147}
148
149void free_peerlist( ot_peerlist *peer_list ) {
150 if( peer_list->peers.data ) {
151 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
152 ot_vector *bucket_list = (ot_vector*)(peer_list->peers.data);
153
154 while( peer_list->peers.size-- )
155 free( bucket_list++->data );
156 }
157 free( peer_list->peers.data );
158 }
159 free( peer_list );
160}
161
162static void livesync_handle_peersync( ssize_t datalen ) {
163 int off = sizeof( g_tracker_id ) + sizeof( uint32_t );
164
165 /* Now basic sanity checks have been done on the live sync packet
166 We might add more testing and logging. */
167 while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= datalen ) {
168 ot_peer *peer = (ot_peer*)(g_inbuffer + off + sizeof(ot_hash));
169 ot_hash *hash = (ot_hash*)(g_inbuffer + off);
170
171 if( OT_PEERFLAG(peer) & PEER_FLAG_STOPPED )
172 remove_peer_from_torrent_proxy( *hash, peer );
173 else
174 add_peer_to_torrent_proxy( *hash, peer );
175
176 off += sizeof( ot_hash ) + sizeof( ot_peer );
177 }
178}
179
180int usage( char *self ) {
181 fprintf( stderr, "Usage: %s -i ip -p port\n", self );
182 return 0;
183}
184
185static ot_vector all_torrents[1024];
186static uint32_t peer_counts[1024];
187#ifdef WANT_SCROOOOOOOLL
188static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;}
189#endif
190
191int main( int argc, char **argv ) {
192 ot_ip6 serverip;
193 uint16_t tmpport;
194 int scanon = 1, bound = 0;
195 time_t next_dump = time(NULL)+1;
196
197 srandom( time(NULL) );
198 g_tracker_id = random();
199
200 while( scanon ) {
201 switch( getopt( argc, argv, ":i:p:vh" ) ) {
202 case -1: scanon = 0; break;
203 case 'i':
204 if( !scan_ip6( optarg, serverip )) { usage( argv[0] ); exit( 1 ); }
205 break;
206 case 'p':
207 if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
208 livesync_bind_mcast( serverip, tmpport); bound++; break;
209 default:
210 case '?': usage( argv[0] ); exit( 1 );
211 }
212 }
213
214 if( !bound ) exerr( "No port bound." );
215
216 while( 1 ) {
217 ot_ip6 in_ip; uint16_t in_port;
218 size_t datalen = socket_recv4(g_socket_in, (char*)g_inbuffer, LIVESYNC_INCOMING_BUFFSIZE, 12+(char*)in_ip, &in_port);
219
220 /* Expect at least tracker id and packet type */
221 if( datalen <= (ssize_t)(sizeof( g_tracker_id ) + sizeof( uint32_t )) )
222 continue;
223 if( !memcmp( g_inbuffer, &g_tracker_id, sizeof( g_tracker_id ) ) ) {
224 /* drop packet coming from ourselves */
225 continue;
226 }
227
228 switch( uint32_read_big( sizeof( g_tracker_id ) + (char*)g_inbuffer ) ) {
229 case OT_SYNC_PEER:
230 livesync_handle_peersync( datalen );
231 break;
232 default:
233 fprintf( stderr, "Received an unknown live sync packet type %u.\n", uint32_read_big( sizeof( g_tracker_id ) + (char*)g_inbuffer ) );
234 break;
235 }
236 if( time(NULL) > next_dump ) {
237 int bucket, i;
238 /* For each bucket... */
239 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
240 /* Get exclusive access to that bucket */
241 ot_vector *torrents_list = mutex_bucket_lock( bucket );
242 size_t tor_offset;
243
244 /* For each torrent in this bucket.. */
245 for( tor_offset=0; tor_offset<torrents_list->size; ++tor_offset ) {
246 /* Address torrents members */
247 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[tor_offset] ).peer_list;
248#ifdef WANT_SCROOOOOOOLL
249 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[tor_offset] ).hash;
250 char hash_out[41];
251 to_hex(hash_out,*hash);
252 printf( "%s %08zd\n", hash_out, peer_list->peer_count );
253#endif
254 if(peer_list->peer_count<1024) peer_counts[peer_list->peer_count]++; else peer_counts[1023]++;
255 free_peerlist(peer_list);
256 }
257 free( torrents_list->data );
258 memset( torrents_list, 0, sizeof(*torrents_list ) );
259 }
260 for( i=1023; i>=0; --i )
261 if( peer_counts[i] ) {
262 printf( "%d:%d ", i, peer_counts[i] );
263 peer_counts[i] = 0;
264 }
265 printf( "\n" );
266 next_dump = time(NULL) + 1;
267 }
268 }
269}