]> git.ipfire.org Git - thirdparty/opentracker.git/commitdiff
Now actually seems to work for the most parts
authorerdgeist <>
Thu, 14 Dec 2006 02:44:50 +0000 (02:44 +0000)
committererdgeist <>
Thu, 14 Dec 2006 02:44:50 +0000 (02:44 +0000)
Added scraping
Added graceful disconnect

Makefile
opentracker.c
scan_urlencoded_query.c
scan_urlencoded_query.h
trackerlogic.c
trackerlogic.h

index a85ab2b3f5f027e7a278c8aba56dd9c9ae282dcd..21689e504e00d8644a8cc6a35af28a5ee350c217 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC?=gcc
-CFLAGS+=-I../libowfat -Wall -pipe -g -ggdb
-LDFLAGS+=-L../libowfat/ -lowfat 
+CFLAGS+=-I../libowfat -Wall -pipe -O2
+LDFLAGS+=-L../libowfat/ -lowfat -s
 
 SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c
 
index bd8f5ca4580cd81e77cc4f1cebba494d64980589..6858f37ce5f2cd827ff5ca826cf156b1307e220b 100644 (file)
@@ -106,13 +106,12 @@ const char* http_header(struct http_data* r,const char* h)
 
 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);
 
@@ -137,14 +136,57 @@ e400:
     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 ) {
@@ -155,19 +197,44 @@ e400:
         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:
@@ -180,9 +247,8 @@ e400:
           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:
@@ -192,20 +258,25 @@ e400:
       }
 
       /* 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 */
@@ -213,6 +284,7 @@ e404:
       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: ");
@@ -239,7 +311,6 @@ void graceful( int s ) {
 int main()
 {
     int s=socket_tcp4();
-    uint32 scope_id;
     unsigned long ip;
     uint16 port;
 
@@ -284,7 +355,6 @@ int main()
                             io_close(n);
                     } else
                         io_close(n);
-                    buffer_putnlflush(buffer_2);
                 }
                 if (errno==EAGAIN)
                     io_eagain(s);
index 3ac01cd8fe89a6deef0304346ab9d08d21349aa9..7bd5ee13d254b020c902b0cfad9c50a8ec8d8223 100644 (file)
@@ -49,3 +49,9 @@ size_t scan_urlencoded_query(char **string, char *deststring, int flags) {
   *string = (char *)s;
   return d - (unsigned char*)deststring;
 }
+
+size_t scan_fixed_int( char *data, size_t len, int *tmp ) {
+  *tmp = 0;
+  while( (len > 0) && (*data >= '0') && (*data <= '9') ) { --len; *tmp = 10**tmp + *data++-'0'; }
+  return len;
+}
index 1e597451ab93de6d1e1c490e2aac0a049598a0a2..c87dbee5197002c3e2c16f8b19208445a7fe3a08 100644 (file)
@@ -12,4 +12,9 @@
 //            or -1 for parse error
 size_t scan_urlencoded_query(char **string, char *deststring, int flags);
 
+// data       pointer to len chars of string
+// len        length of chars in data to parse
+// number     number to receive result
+size_t scan_fixed_int( char *data, size_t len, int *number );
+
 #endif
index 9b8c5410d3742f1dda75fa11bc2d0f73540f78c1..0207fad5320591389d23d9ea639fdbbfbcadd98a 100644 (file)
 //
 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;
 
@@ -51,9 +52,9 @@ char ths[1+2*20];char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+40;
 
 // 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;
@@ -72,22 +73,22 @@ void *vector_find_or_insert( ot_vector vector, void *key, size_t member_size, in
   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 )
@@ -95,10 +96,10 @@ void free_peerlist( ot_peerlist peer_list ) {
   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 );
@@ -111,11 +112,12 @@ int vector_remove_torrent( ot_vector vector, ot_hash *hash ) {
   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 )
@@ -128,39 +130,40 @@ void clean_peerlist( ot_peerlist peer_list ) {
   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 ) {
@@ -176,6 +179,8 @@ ot_torrent add_peer_to_torrent( ot_hash *hash, ot_peer peer ) {
     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;
 }
@@ -186,7 +191,7 @@ ot_torrent add_peer_to_torrent( ot_hash *hash, ot_peer peer ) {
 // * 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;
@@ -214,6 +219,48 @@ size_t return_peers_for_torrent( ot_torrent torrent, unsigned long amount, char
   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;
@@ -257,7 +304,7 @@ void deinit_logic( ) {
   // 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 );
index 3243eb7c907c0b2d302e9fb75f9e2b1d6209c245..44bd7443ba083796a82a94081a1582d9bb57dfa9 100644 (file)
@@ -32,40 +32,31 @@ typedef time_t         ot_time;
 #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
@@ -74,7 +65,10 @@ void *binary_search( const void *key, const void *base,
 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