void httpresponse(struct http_data* h,int64 s)
{
- char *c, *d, *data, *reply = NULL;
- struct ot_peer peer;
- ot_torrent torrent;
- ot_hash *hash = NULL;
- unsigned long numwant;
- int compact, scanon;
- size_t reply_size = 0;
+ char *c, *d, *data, *reply = NULL;
+ ot_peer peer;
+ ot_torrent *torrent;
+ ot_hash *hash = NULL;
+ int numwant, tmp, scanon;
+ size_t reply_size = 0;
array_cat0(&h->r);
case 6: /* scrape ? */
if (byte_diff(data,6,"scrape"))
goto e404;
+ scanon = 1;
+
+ while( scanon ) {
+ switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
+ case -2: /* terminator */
+ scanon = 0;
+ break;
+ case -1: /* error */
+ goto e404;
+ case 9:
+ if(byte_diff(data,9,"info_hash")) {
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ continue;
+ }
+ /* ignore this, when we have less than 20 bytes */
+ switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
+ case -1:
+ goto e404;
+ case 20:
+ hash = (ot_hash*)data; /* Fall through intended */
+ default:
+ continue;
+ }
+ default:
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ break;
+ }
+ }
+
+ /* Scanned whole query string, wo */
+ if( !hash ) {
+ httperror(h,"400 Invalid Request","This server only serves specific scrapes.");
+ goto bailout;
+ }
+
+ // Enough for whole scrape string
+ reply = malloc( 128 );
+ if( reply )
+ reply_size = return_scrape_for_torrent( hash, reply );
+ if( !reply || ( reply_size < 0 ) ) {
+ if( reply ) free( reply );
+ goto e500;
+ }
break;
case 8:
if( byte_diff(data,8,"announce"))
goto e404;
+
peer.ip = h->ip;
peer.port_flags = 6881 << 16;
numwant = 50;
- compact = 1;
scanon = 1;
while( scanon ) {
case -1: /* error */
goto e404;
case 4:
- if(!byte_diff(data,4,"port"))
- /* scan int */ c;
- else if(!byte_diff(data,4,"left"))
- /* scan int */ c;
- else
+ if(!byte_diff(data,4,"port")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || (tmp > 65536) ) goto e404;
+ peer.port_flags = ( tmp << 16 ) | ( peer.port_flags & 0xffff );
+ } else if(!byte_diff(data,4,"left")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e404;
+ if( !tmp ) peer.port_flags |= PEER_FLAG_SEEDING;
+ } else
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
break;
+ case 5:
+ if(byte_diff(data,5,"event"))
+ scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
+ else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
+ case -1:
+ goto e404;
+ case 7:
+ if(!byte_diff(data,7,"stopped")) peer.port_flags |= PEER_FLAG_STOPPED;
+ break;
+ case 9:
+ if(!byte_diff(data,9,"complete")) peer.port_flags |= PEER_FLAG_COMPLETED;
+ default: // Fall through intended
+ break;
+ }
+ break;
case 7:
- if(!byte_diff(data,7,"numwant"))
- /* scan int */ c;
- else if(!byte_diff(data,7,"compact"))
- /* scan flag */ c;
- else
+ if(!byte_diff(data,7,"numwant")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e404;
+ } else if(!byte_diff(data,7,"compact")) {
+ size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
+ if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e404;
+ if( !tmp ) {
+ httperror(h,"400 Invalid Request","This server only delivers compact results.");
+ goto bailout;
+ }
+ } else
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
break;
case 9:
case -1:
goto e404;
case 20:
- hash = (ot_hash*)data; /* Fall through intended */
- printf("hash: %s\n",*hash);
- default:
+ hash = (ot_hash*)data;
+ default: // Fall through intended
continue;
}
default:
}
/* Scanned whole query string */
- if( !hash || ( compact == 0 ) ) goto e404;
-
- torrent = add_peer_to_torrent( hash, &peer );
- if( !torrent ) {
+ if( !hash ) goto e404;
+
+ if( peer.port_flags & PEER_FLAG_STOPPED ) {
+ remove_peer_from_torrent( hash, &peer );
+ reply = strdup( "d15:warning message4:Okaye" ); reply_size = 26;
+ } else {
+ torrent = add_peer_to_torrent( hash, &peer );
+ if( !torrent ) {
e500:
- httperror(h,"500 Internal Server Error","A server error has occured. Please retry later.");
- goto bailout;
- }
- reply = malloc( numwant*6+24 );
- if( reply )
- reply_size = return_peers_for_torrent( torrent, numwant, reply );
- if( !reply || ( reply_size < 0 ) ) {
- if( reply ) free( reply );
- goto e500;
+ httperror(h,"500 Internal Server Error","A server error has occured. Please retry later.");
+ goto bailout;
+ }
+ reply = malloc( numwant*6+64 ); // peerlist + seeder, peers and lametta
+ if( reply )
+ reply_size = return_peers_for_torrent( torrent, numwant, reply );
+ if( !reply || ( reply_size < 0 ) ) {
+ if( reply ) free( reply );
+ goto e500;
+ }
}
break;
default: /* neither scrape nor announce */
httperror(h,"404 Not Found","No such file or directory.");
goto bailout;
}
+
c=h->hdrbuf=(char*)malloc(500);
c+=fmt_str(c,"HTTP/1.1 200 OK\r\nContent-Type: text/plain");
c+=fmt_str(c,"\r\nContent-Length: ");
int main()
{
int s=socket_tcp4();
- uint32 scope_id;
unsigned long ip;
uint16 port;
io_close(n);
} else
io_close(n);
- buffer_putnlflush(buffer_2);
}
if (errno==EAGAIN)
io_eagain(s);
//
int compare_hash( const void *hash1, const void *hash2 ) { return memcmp( hash1, hash2, sizeof( ot_hash )); }
int compare_ip_port( const void *peer1, const void *peer2 ) {
-if( ((ot_peer)peer1)->ip != ((ot_peer)peer2)->ip ) return ((ot_peer)peer1)->ip - ((ot_peer)peer2)->ip;
-return ((ot_peer)peer1)->port_flags - ((ot_peer)peer2)->port_flags; }
-
-void *binary_search( const void *key, const void *base,
- unsigned long member_count, const unsigned long member_size,
- int (*compar) (const void *, const void *),
- int *exactmatch ) {
+if( ((ot_peer*)peer1)->ip != ((ot_peer*)peer2)->ip ) return ((ot_peer*)peer1)->ip - ((ot_peer*)peer2)->ip;
+return ((ot_peer*)peer1)->port_flags - ((ot_peer*)peer2)->port_flags; }
+
+static void *binary_search( const void *key, const void *base,
+ unsigned long member_count, const unsigned long member_size,
+ int (*compar) (const void *, const void *),
+ int *exactmatch )
+{
ot_byte *lookat = ((ot_byte*)base) + member_size * (member_count >> 1);
*exactmatch = 1;
// GLOBAL VARIABLES
//
-struct ot_vector all_torrents[256];
+static ot_vector all_torrents[256];
-void *vector_find_or_insert( ot_vector vector, void *key, size_t member_size, int(*compare_func)(const void*, const void*), int *exactmatch ) {
+static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, int(*compare_func)(const void*, const void*), int *exactmatch ) {
ot_byte *match = BINARY_FIND( key, vector->data, vector->size, member_size, compare_func, exactmatch );
if( *exactmatch ) return match;
vector->size++;
return match;
}
-
-int vector_remove_peer( ot_vector vector, ot_peer peer ) {
+
+static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
int exactmatch;
- ot_peer match;
+ ot_peer *match;
if( !vector->size ) return 0;
- match = BINARY_FIND( peer, vector->data, vector->size, sizeof( struct ot_peer ), compare_ip_port, &exactmatch );
+ match = BINARY_FIND( peer, vector->data, vector->size, sizeof( ot_peer ), compare_ip_port, &exactmatch );
if( !exactmatch ) return 0;
exactmatch = match->port_flags & PEER_FLAG_SEEDING ? 2 : 1;
- MEMMOVE( match, match + 1, ((ot_peer)vector->data) + vector->size - match - 1 );
+ MEMMOVE( match, match + 1, ((ot_peer*)vector->data) + vector->size - match - 1 );
vector->size--;
return exactmatch;
}
-void free_peerlist( ot_peerlist peer_list ) {
+static void free_peerlist( ot_peerlist *peer_list ) {
int i;
for( i=0; i<OT_POOLS_COUNT; ++i )
if( peer_list->peers[i].data )
free( peer_list );
}
-int vector_remove_torrent( ot_vector vector, ot_hash *hash ) {
+static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
int exactmatch;
- ot_torrent end = ((ot_torrent)vector->data) + vector->size;
- ot_torrent match = BINARY_FIND( hash, vector->data, vector->size, sizeof( struct ot_torrent ), compare_hash, &exactmatch );
+ ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
+ ot_torrent *match = BINARY_FIND( hash, vector->data, vector->size, sizeof( ot_torrent ), compare_hash, &exactmatch );
if( !exactmatch ) return -1;
free_peerlist( match->peer_list );
return 0;
}
-void clean_peerlist( ot_peerlist peer_list ) {
+// Returns 1, if torrent is gone, 0 otherwise
+static int clean_peerlist( ot_peerlist *peer_list ) {
long timedout = NOW-peer_list->base;
int i;
- if( !timedout ) return;
+ if( !timedout ) return 0;
if( timedout > OT_POOLS_COUNT ) timedout = OT_POOLS_COUNT;
for( i=OT_POOLS_COUNT-timedout; i<OT_POOLS_COUNT; ++i )
byte_zero( peer_list->seed_count, sizeof( unsigned long ) * timedout );
peer_list->base = NOW;
+ return timedout == OT_POOLS_COUNT;
}
-ot_torrent add_peer_to_torrent( ot_hash *hash, ot_peer peer ) {
- int exactmatch;
- ot_torrent torrent;
- ot_peer peer_dest;
- ot_vector torrents_list = all_torrents + *hash[0], peer_pool;
+ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
+ int exactmatch;
+ ot_torrent *torrent;
+ ot_peer *peer_dest;
+ ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool;
- torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( struct ot_torrent ), compare_hash, &exactmatch );
+ torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), compare_hash, &exactmatch );
if( !torrent ) return NULL;
if( !exactmatch ) {
// Create a new torrent entry, then
- torrent->peer_list = malloc( sizeof (struct ot_peerlist) );
+ torrent->peer_list = malloc( sizeof (ot_peerlist) );
if( !torrent->peer_list ) {
vector_remove_torrent( torrents_list, hash );
return NULL;
}
MEMMOVE( &torrent->hash, hash, sizeof( ot_hash ) );
- byte_zero( torrent->peer_list, sizeof( struct ot_peerlist ));
+ byte_zero( torrent->peer_list, sizeof( ot_peerlist ));
torrent->peer_list->base = NOW;
} else
clean_peerlist( torrent->peer_list );
peer_pool = &torrent->peer_list->peers[0];
- peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( struct ot_peer ), compare_ip_port, &exactmatch );
+ peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), compare_ip_port, &exactmatch );
// If we hadn't had a match in current pool, create peer there and
// remove it from all older pools
if( !exactmatch ) {
int i;
- MEMMOVE( peer_dest, peer, sizeof( struct ot_peer ) );
+ MEMMOVE( peer_dest, peer, sizeof( ot_peer ) );
if( peer->port_flags & PEER_FLAG_SEEDING )
torrent->peer_list->seed_count[0]++;
for( i=1; i<OT_POOLS_COUNT; ++i ) {
if( !(peer_dest->port_flags & PEER_FLAG_SEEDING ) && (peer->port_flags & PEER_FLAG_SEEDING ) )
torrent->peer_list->seed_count[0]++;
}
+ if( peer->port_flags & PEER_FLAG_COMPLETED )
+ torrent->peer_list->downloaded++;
return torrent;
}
// * RANDOM may return huge values
// * does not yet check not to return self
//
-size_t return_peers_for_torrent( ot_torrent torrent, unsigned long amount, char *reply ) {
+size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *reply ) {
char *r = reply;
unsigned long peer_count, index;
signed long pool_offset = -1, pool_index = 0;
return r - reply;
}
+// Fetches scrape info for a specific torrent
+size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) {
+ char *r = reply;
+ int exactmatch, peers = 0, seeds = 0, i;
+ ot_vector *torrents_list = &all_torrents[*hash[0]];
+ ot_torrent *torrent = BINARY_FIND( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), compare_hash, &exactmatch );
+
+ if( !exactmatch ) return 0;
+ clean_peerlist( torrent->peer_list );
+
+ for( i=0; i<OT_POOLS_COUNT; ++i ) {
+ peers += torrent->peer_list->peers[i].size;
+ seeds += torrent->peer_list->seed_count[i];
+ }
+
+ MEMMOVE( r, "d5:filesd20:", 12 ); MEMMOVE( r+12, hash, 20 );
+ r += FORMAT_FORMAT_STRING( r+32, "d8:completei%de10:downloadedi%lde10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32;
+
+ return r - reply;
+}
+
+void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
+ int exactmatch, i;
+ ot_vector *torrents_list = &all_torrents[*hash[0]];
+ ot_torrent *torrent = BINARY_FIND( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), compare_hash, &exactmatch );
+
+ if( !exactmatch ) return;
+
+ for( i=0; i<OT_POOLS_COUNT; ++i )
+ switch( vector_remove_peer( &torrent->peer_list->peers[i], peer ) ) {
+ case 0: continue;
+ case 2: torrent->peer_list->seed_count[i]--;
+ case 1: default: return;
+ }
+
+ clean_peerlist( torrent->peer_list );
+}
+
+void cleanup_torrents( void ) {
+
+}
+
int init_logic( char *directory ) {
glob_t globber;
int i;
// Free all torrents...
for(i=0; i<256; ++i ) {
if( all_torrents[i].size ) {
- ot_torrent torrents_list = (ot_torrent)all_torrents[i].data;
+ ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data;
for( j=0; j<all_torrents[i].size; ++j )
free_peerlist( torrents_list[j].peer_list );
free( all_torrents[i].data );
#define OT_POOLS_TIMEOUT 300
#define NOW (time(NULL)/OT_POOLS_TIMEOUT)
-typedef struct ot_vector {
+typedef struct {
void *data;
size_t size;
size_t space;
-} *ot_vector;
+} ot_vector;
-typedef struct ot_peer {
+typedef struct {
ot_ip ip;
ot_dword port_flags;
-} *ot_peer;
+} ot_peer;
static const ot_byte PEER_FLAG_SEEDING = 0x80;
+static const ot_byte PEER_FLAG_COMPLETED = 0x40;
+static const ot_byte PEER_FLAG_STOPPED = 0x20;
-typedef struct ot_peerlist {
- ot_time base;
- unsigned long seed_count[ OT_POOLS_COUNT ];
- struct ot_vector peers[ OT_POOLS_COUNT ];
-} *ot_peerlist;
+typedef struct {
+ ot_time base;
+ unsigned long seed_count[ OT_POOLS_COUNT ];
+ unsigned long downloaded;
+ ot_vector peers[ OT_POOLS_COUNT ];
+} ot_peerlist;
-typedef struct ot_torrent {
- ot_hash hash;
- ot_peerlist peer_list;
-} *ot_torrent;
-
-void *map_file( char *file_name, size_t map_size );
-void unmap_file( char *file_name, void *map, size_t mapped_size, unsigned long real_size );
-
-// This behaves quite like bsearch but allows to find
-// the insertion point for inserts after unsuccessful searches
-// in this case exactmatch is 0 on exit
-//
-void *binary_search( const void *key, const void *base,
- const unsigned long member_count, const unsigned long member_size,
- int (*compar) (const void *, const void *),
- int *exactmatch );
+typedef struct {
+ ot_hash hash;
+ ot_peerlist *peer_list;
+} ot_torrent;
//
// Exported functions
int init_logic( char *chdir_directory );
void deinit_logic( );
-ot_torrent add_peer_to_torrent( ot_hash *hash, ot_peer peer );
-size_t return_peers_for_torrent( ot_torrent torrent, unsigned long amount, char *reply );
+ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer );
+size_t return_peers_for_torrent( ot_torrent *torrent, unsigned long amount, char *reply );
+size_t return_scrape_for_torrent( ot_hash *hash, char *reply );
+void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );
+void cleanup_torrents( void );
#endif