Remove outdated thridparty pacakge

This commit is contained in:
Frank 2011-03-11 10:23:23 -08:00
parent 346ca43714
commit 946413dd88
84 changed files with 0 additions and 21357 deletions

View File

@ -1,11 +0,0 @@
ALLSTATS=T
DONUMSORT=T
DOSTRINGSORT=T
DOBITFIELD=T
DOEMF=T
DOFOUR=T
DOASSIGN=T
DOIDEA=T
DOHUFF=T
DONNET=T
DOLU=T

View File

@ -1,42 +0,0 @@
This is about BYTE's beta version of the native-algorithm benchmark
December 16, 1996:
The source for DOS is obtainable at http://www.byte.com/bmark/bmark.htm
Linux adaptation written by Uwe F. Mayer <mayer@tux.org>
February 7, 1997:
added -DSOLARIS flag to support solaris
November 11, 1997:
added index split suggested by Andrew D. Balsa
re-baselined to a Linux machine
added checking of CPU-type at run-time (cpuinfo.c)
increased maximal number of loops in some tests
removed -DSOLARIS flag, works now automatically (this also removed the
compiler warnings about redefined types and leads to a 20% faster
code for "Bitfield" if compiled with -funroll-loops!)
November 13-19, 1997:
changed debugging information
changed random number generator to be always 32 bits even on 64 bit OSs
added data resets to Bitfield and Huffman
created this Changes file
added debug code for Bitfield
December 6, 1997:
got rid of cpuinfo.c
added a RESULTS file
December 7, 1997:
fixed the statistical analysis used to compute the confidence coefficient
fixed a bug in the DEBUG routine of "Assignment"
December 11, 1997
added some entries to RESULTS

View File

@ -1,153 +0,0 @@
# Makefile for nbench, December 11, 1997, Uwe F. Mayer <mayer@tux.org>
# Updated February 18, 2003
default: nbench
##########################################################################
# If you are using gcc-2.7.2.3 or earlier:
# The optimizer of gcc has a bug and in general you should not specify
# -funroll-loops together with -O (or -O2, -O3, etc.)
# This bug is supposed to be fixed with release 2.8 of gcc.
#
# This bug does NOT seem to have an effect on the correct compilation
# of this benchmark suite on my Linux box. However, it leads to
# the dreaded "internal compiler error" message on our alpha
# running DEC Unix 4.0b. The Linux-binary that was used to obtain
# the baseline results was nevertheless compiled with
# CFLAGS = -s -static -Wall -O3 -fomit-frame-pointer -funroll-loops
#
# You should leave -static in the CFLAGS so that your sysinfo can be
# compiled into the executable.
CC = gcc
# generic options for gcc
CFLAGS = -s -static -Wall -O3
# if your gcc lets you do it, then try this one
#CFLAGS = -s -static -Wall -O3 -fomit-frame-pointer -funroll-loops
# for gcc on an older Pentium type processor you can try the following
#CFLAGS = -s -static -O3 -fomit-frame-pointer -Wall -m486 \
# -fforce-addr -fforce-mem -falign-loops=2 -falign-functions=2 \
# -falign-jumps=2 -funroll-loops
# for a newer gcc on a newer Pentium type processor you can try the following
#CFLAGS = -s -static -O3 -fomit-frame-pointer -Wall -march=i686 \
# -fforce-addr -fforce-mem -falign-loops=2 -falign-functions=2 \
# -falign-jumps=2 -funroll-loops
# for a newer gcc on an Athlon XP type processor you can try the following
#CFLAGS = -s -static -O3 -fomit-frame-pointer -Wall -march=athlon-xp \
# -fforce-addr -fforce-mem -falign-loops=2 -falign-functions=2 \
# -falign-jumps=2 -funroll-loops
# For debugging using gcc
#CFLAGS = -g -O3 -Wall -DDEBUG
##########################################################################
# For Linux machines with more than one binary format.
# The default binaries, depends on your system whether it's elf or aout.
MACHINE=
# a.out code for linux on an elf machine
#MACHINE= -bi486-linuxaout
# elf code for linux on an a.out machine
#MACHINE= -bi486-linuxelf
# if you want a different compiler version and different binaries, for example
#MACHINE= -V2.7.2 -bi486-linuxaout
##########################################################################
# Read the file README.nonlinux if you are not using Linux
# for DEC Unix using cc you can try
#CC = cc
#CFLAGS = -O3
#LINKFLAGS = -s -non_shared
# for SunOS using cc
#CC = cc
#CFLAGS = -O3 -s
# for DEC Ultrix using cc
#CC = cc
#CFLAGS = -O2
#LINKFLAGS = -s
# for a Mac with OsX and the Darwin environment
#CC = cc
#CFLAGS = -O3 -DOSX
# For debugging using cc
#CC = cc
#CFLAGS = -g -DDEBUG
##########################################################################
# If your system does not understand the system command "uname -s -r"
# then comment this out
# NO_UNAME= -DNO_UNAME
##########################################################################
# For any Unix flavor you need -DLINUX
# You also need -DLINUX to get the new indices
DEFINES= -DLINUX $(NO_UNAME)
##########################################################################
# For LINUX-like systems with gcc
sysinfoc.c: Makefile
./sysinfo.sh $(CC) $(MACHINE) $(DEFINES) $(CFLAGS)
sysinfo.c: Makefile
./sysinfo.sh $(CC) $(MACHINE) $(DEFINES) $(CFLAGS)
##########################################################################
# For non-LINUX systems
# Edit the files sysinfo.c and sysinfoc.c to include your system information
# and take sysinfo.c and sysinfoc.c out of the dependencies for nbench0.o
hardware.o: hardware.c hardware.h Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c hardware.c
nbench0.o: nbench0.h nbench0.c nmglobal.h pointer.h hardware.h\
Makefile sysinfo.c sysinfoc.c
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c nbench0.c
emfloat.o: emfloat.h emfloat.c nmglobal.h pointer.h Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c emfloat.c
pointer.h: pointer Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-o pointer pointer.c
rm -f pointer.h
if [ "4" = `./pointer` ] ; then touch pointer.h ;\
else echo "#define LONG64" >pointer.h ; fi
misc.o: misc.h misc.c Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c misc.c
nbench1.o: nbench1.h nbench1.c wordcat.h nmglobal.h pointer.h Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c nbench1.c
sysspec.o: sysspec.h sysspec.c nmglobal.h pointer.h Makefile
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS)\
-c sysspec.c
nbench: emfloat.o misc.o nbench0.o nbench1.o sysspec.o hardware.o
$(CC) $(MACHINE) $(DEFINES) $(CFLAGS) $(LINKFLAGS)\
emfloat.o misc.o nbench0.o nbench1.o sysspec.o hardware.o\
-o nbench -lm
##########################################################################
clean:
- /bin/rm -f *.o *~ \#* core a.out hello sysinfo.c sysinfoc.c \
bug pointer pointer.h debugbit.dat
mrproper: clean
- /bin/rm -f nbench

View File

@ -1,210 +0,0 @@
5 7 8
26
0 0 1 0 0
0 1 0 1 0
1 0 0 0 1
1 0 0 0 1
1 1 1 1 1
1 0 0 0 1
1 0 0 0 1
0 1 0 0 0 0 0 1
1 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 1 1 1 0
0 1 0 0 0 0 1 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 1
0 1 1 1 0
0 1 0 0 0 0 1 1
1 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 1 1 0
0 1 0 0 0 1 0 0
1 1 1 1 1
1 0 0 0 0
1 0 0 0 0
1 1 1 0 0
1 0 0 0 0
1 0 0 0 0
1 1 1 1 1
0 1 0 0 0 1 0 1
1 1 1 1 1
1 0 0 0 0
1 0 0 0 0
1 1 1 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0 1 1 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 0
1 0 0 0 0
1 0 0 1 1
1 0 0 0 1
0 1 1 1 0
0 1 0 0 0 1 1 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 1 1 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
0 1 0 0 1 0 0 0
0 1 1 1 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 1 1 1 0
0 1 0 0 1 0 0 1
0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
1 0 0 0 1
1 0 0 0 1
0 1 1 1 0
0 1 0 0 1 0 1 0
1 0 0 0 1
1 0 0 1 0
1 0 1 0 0
1 1 0 0 0
1 0 1 0 0
1 0 0 1 0
1 0 0 0 1
0 1 0 0 1 0 1 1
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 1 1 1 1
0 1 0 0 1 1 0 0
1 0 0 0 1
1 1 0 1 1
1 0 1 0 1
1 0 1 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
0 1 0 0 1 1 0 1
1 0 0 0 1
1 1 0 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 0 1
1 0 0 1 1
1 0 0 0 1
0 1 0 0 1 1 1 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
0 1 1 1 0
0 1 0 0 1 1 1 1
1 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 1 1 1 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
0 1 0 1 0 0 0 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 1 0 1
1 0 0 1 1
0 1 1 1 1
0 1 0 1 0 0 0 1
1 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 1 1 1 0
1 0 1 0 0
1 0 0 1 0
1 0 0 0 1
0 1 0 1 0 0 1 0
0 1 1 1 1
1 0 0 0 0
1 0 0 0 0
0 1 1 1 0
0 0 0 0 1
0 0 0 0 1
1 1 1 1 0
0 1 0 1 0 0 1 1
1 1 1 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 1 0 1 0 1 0 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
0 1 1 1 0
0 1 0 1 0 1 0 1
1 0 0 0 1
1 0 0 0 1
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
0 0 1 0 0
0 1 0 1 0 1 1 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 0 1
0 1 0 1 0
0 1 0 1 0 1 1 1
1 0 0 0 1
0 1 0 1 0
0 1 0 1 0
0 0 1 0 0
0 1 0 1 0
0 1 0 1 0
1 0 0 0 1
0 1 0 1 1 0 0 0
1 0 0 0 1
0 1 0 1 0
0 1 0 1 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 1 0 1 1 0 0 1
1 1 1 1 1
0 0 0 1 0
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
0 1 0 0 0
1 1 1 1 1
0 1 0 1 1 0 1 0

View File

@ -1,66 +0,0 @@
February 18, 2003
-----------------
Bug-fix release.
December 9, 1997
----------------
This release is based on beta release 2 of BYTE Magazine's BYTEmark
benchmark program (previously known as BYTE's Native Mode
Benchmarks). This document covers the Native Mode (a.k.a. Algorithm
Level) tests; benchmarks designed to expose the capabilities of a
system's CPU, FPU, and memory system.
Running a "make" will create the binary if all goes well. It is called
"nbench" and performs a suite of 10 tests and compares the results to
a Dell Pentium 90 with 16 MB RAM and 256 KB L2 cache running MSDOS and
compiling with the Watcom 10.0 C/C++ compiler. If you define -DLINUX
during compilation (the default) then you also get a comparison to an
AMD K6/233 with 32 MB RAM and 512 KB L2-cache running Linux 2.0.32 and
using a binary which was compiled with GNU gcc version 2.7.2.3 and GNU
libc-5.4.38.
For more verbose output specify -v as an argument.
The primary web site is: http://www.tux.org/~mayer/linux/bmark.html
The port to Linux/Unix was done by Uwe F. Mayer <mayer@tux.org>.
The index-split was done by Andrew D. Balsa, and reflects the
realization that memory management is important in CPU design. The
original tests have been left alone, however, the tests NUMERIC SORT,
FP EMULATION, IDEA, and HUFFMAN now constitute the integer-arithmetic
focused benchmark index, while the tests STRING SORT, BITFIELD, and
ASSIGNMENT make up the new memory index.
The algorithms were not changed from the source which was obtained
from the BYTE web site at http://www.byte.com/bmark/bmark.htm on
December 14, 1996. However, the source was modified to better work
with 64-bit machines (in particular the random number generator was
modified to always work with 32 bit, no matter what kind of hardware
you run it on). Furthermore, for some of the algorithms additional
resettings of the data was added to increase the consistency across
different hardware. Some extra debugging code was added, which has no
impact on normal runs.
In case there is uneven system load due to other processes while this
benchmark suite executes, it might take longer to run than on an
unloaded system. This is because the benchmark does some statistical
analysis to make sure that the reported results are statistically
significant, and an increased variation in individual runs requires
more runs to achieve the required statistical confidence.
This is a single-threaded benchmark and is not designed to measure the
performance gain on multi-processor machines.
For details and customization read bdoc.txt.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,29 +0,0 @@
The information in this file is old and no longer valid. It seems that
the GNU C library has caught up with Motorola's libmoto, and now
performance is just as good (or better) without libmoto. I'll include
the old notice out of historical reasons only. Currently libmoto is
available at ftp://ftp.mcg.mot.com/pub/SPS/PowerPC/software/mklinux/libmoto/,
but this is subject to change and not under my control.
February 18, 2003
Uwe F. Mayer
---------------------------------------------------------------------------
If you have a Motorola CPU or equivalent:
When linked with the 'libmoto' (floating point library from Motorola)
the results you obtain are much better. (FPU index of 0.896 versus
1.910 in one example.)
The Motorola math library is currently available at:
http://www.mot.com/SPS/PowerPC/support/rsw_customer_support/mklinux/libmoto/libmoto_reg_mkdev.html
If you have a Motorola CPU and you submit a result then please let me
know whether you used libmoto or not. Please read the file README.submit.
I do not have a Motorola CPU, and I can't help you with installing the
library either.
December 3, 1997
Uwe F. Mayer

View File

@ -1,50 +0,0 @@
December 3, 1993
================
DEC Unix 4.0 or DEC OSF1 and gcc
--------------------------------
Compiles cleanly if you don't use -funroll-loops with gcc-2.7.2.3 or earlier
DEC UNIX 4.0 or DEC OSF1 and cc
-------------------------------
CC = cc
CFLAGS = -O3
LINKFLAGS = -s -non_shared
Compiles cleanly.
SunOS and gcc
-------------
Compiles cleanly
SunOS and cc
------------
CC = cc
CFLAGS = -O3 -s
Compiles with one warning during compilation of nbench1.c
"/usr/ucbinclude/strings.h", line 48: warning: identifier redeclared: strlen
current : function() returning int
previous: function() returning uint : "/usr/include/string.h", line 98
HP-UX and gcc
-------------
Compiles with one warning during compilation of sysspec.c
In file included from /usr/local/lib/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1/include/malloc.h:9,
from sysspec.h:37,
from sysspec.c:37:
/usr/local/lib/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1/include/sys/types.h:117: warning: empty declaration
/usr/local/lib/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1/include/sys/types.h:118: warning: empty declaration
DEC Ultrix and cc
-----------------
CC = cc
CFLAGS = -O2
LINKFLAGS = -s
Compiles with a warning about the correct usage of cut when running sysinfo.sh
cut: Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ...
cut: Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ...

View File

@ -1,33 +0,0 @@
I plan on posting a digest of results in case people mail me any.
The URL will be linked to
http://www.tux.org/~mayer/linux/bmark.html
If you want to submit, then run the benchmark (use your own
compilation, I don't care with what flags or compiler, but I want all
numbers from a single benchmark run) and fill in the template as given
in the example below:
CPU : AMD 5x86P75 (486DX4/133MHz)
L2 CACHE : 256 KB
OS : Linux 2.0.32
C COMPILER : gcc 2.7.2.3
LIBC : libc-5.4.38
Pentium 90 INTEGER INDEX : 1.051
Pentium 90 FLOATING-POINT INDEX : 0.450
AMD K6/233 MEMORY INDEX : 0.337
AMD K6/233 INTEGER INDEX : 0.238
AMD K6/233 FLOATING-POINT INDEX : 0.230
Any other format is fine as long as it contains the same info (write
"unknown" or "?" for data you don't know). For example, you could just
cut the summary from the output of nbench and mail it together with
cache, CPU, and OS info in case it is not already present. Please do
not email me the complete output of nbench, or any other unnecessarily
long email, as this just eats up my hard-disk space. However, long
collections of results are of course welcome.
Send your result to mayer@tux.org
Uwe F. Mayer
February 18, 2003

View File

@ -1,138 +0,0 @@
December 7, 1997
This file contains a few results so you may compare your machine.
If you read this much after December 1997 then the results herein
are probably obsolete.
For a longer and hopefully more up-to-date list of results consult
http://www.tux.org/~mayer/linux/bmark.html
This web site, however, currently lists the old Pentium 90 indices!
The indices below are with respect to the new AMD K6/233 baseline.
OS : DEC Ultrix 4.4
C compiler : cc
libc : unknown version
CPU : mips R6000
L2 cache : ?
MEMORY INDEX : 0.029
INTEGER INDEX : 0.046
FLOATING-POINT INDEX: 0.077
OS : LINUX 2.0.31
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Intel 486DX2/66 MHz
L2 cache : 256 KB
MEMORY INDEX : 0.098
INTEGER INDEX : 0.141
FLOATING-POINT INDEX: 0.116
OS : LINUX 2.0.32
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : AMD 5x86P75 (486DX4/133MHz)
L2 cache : 256 KB
MEMORY INDEX : 0.234
INTEGER INDEX : 0.286
FLOATING-POINT INDEX: 0.249
OS : OSF1 V3.2 214
C compiler : cc
libc : unknown version
CPU : 21064 alpha (DEC 3000 MODEL 300, year 1993)
L2 cache : 256 KB
MEMORY INDEX : 0.358
INTEGER INDEX : 0.362
FLOATING-POINT INDEX: 0.656
OS : HP-UX A.09.05
C compiler : gcc version 2.7.2.1
libc : unknown version
CPU : 9000/715
L2 cache : ?
MEMORY INDEX : 0.208
INTEGER INDEX : 0.369
FLOATING-POINT INDEX: 0.516
OS : LINUX 2.0.31
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Intel Pentium 133 MHz
L2 cache : 512 KB
MEMORY INDEX : 0.383
INTEGER INDEX : 0.444
FLOATING-POINT INDEX: 0.632
OS : SunOS 5.5.1
C compiler : cc
libc : unknown version
CPU : SUN-Ultra-Enterprise-2 sparc
L2 cache : ?
MEMORY INDEX : 0.417
INTEGER INDEX : 0.546
FLOATING-POINT INDEX: 1.028
OS : LINUX 2.0.29
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Cyrix 6x86L PR200+ (at 2 x 75 = 150 MHz)
L2 cache : 256 KB
MEMORY INDEX : 0.666
INTEGER INDEX : 0.599
FLOATING-POINT INDEX: 0.508
OS : LINUX 2.0.31
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Intel Pentium MMX 200 MHz
L2 cache : 512 KB
MEMORY INDEX : 0.601
INTEGER INDEX : 0.636
FLOATING-POINT INDEX: 0.970
OS : LINUX 2.0.31
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Intel 686 PentiumPro 200 MHz
L2 cache : 256 KB (internal)
MEMORY INDEX : 0.699
INTEGER INDEX : 0.732
FLOATING-POINT INDEX: 1.140
OS : LINUX 2.0.29
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Cyrix 6x86MX PR233 (at 2.5 x 75 = 187.5 MHz)
L2 cache : 512 KB
MEMORY INDEX : 0.861
INTEGER INDEX : 0.773
FLOATING-POINT INDEX: 0.730
OS : LINUX 2.0.32
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : AMD K6/233
L2 cache : 512 KB
MEMORY INDEX : 1.000
INTEGER INDEX : 1.000
FLOATING-POINT INDEX: 1.000
OS : LINUX 2.0.31
C compiler : gcc version 2.7.2.3
libc : libc.so.5.4.38
CPU : Intel 686 Pentium II 300 MHz
L2 cache : 512 KB
MEMORY INDEX : 1.255
INTEGER INDEX : 1.093
FLOATING-POINT INDEX: 1.842
OS : DEC UNIX 4.0b 564
C compiler : cc
libc : unknown version
CPU : 21164 Alpha 300 MHz (dual CPU)
L2 cache : 96 KB
L3 cache : 4 MB per CPU
MEMORY INDEX : 0.973
INTEGER INDEX : 1.124
FLOATING-POINT INDEX: 3.237

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,154 +0,0 @@
/*
** emfloat.h
** Header for emfloat.c
**
** BYTEmark (tm)
** BYTE Magazine's Native Mode benchmarks
** Rick Grehan, BYTE Magazine
**
** Create:
** Revision: 3/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
#include <stdio.h>
/* Is this a 64 bit architecture? If so, this will define LONG64 */
/* Uwe F. Mayer 15 November 1997 */
#include "pointer.h"
/*
** DEFINES
*/
#define u8 unsigned char
#define u16 unsigned short
#ifdef LONG64
#define u32 unsigned int
#else
#define u32 unsigned long
#endif
#define uchar unsigned char
#define ulong unsigned long
#define MAX_EXP 32767L
#define MIN_EXP (-32767L)
#define IFPF_IS_ZERO 0
#define IFPF_IS_SUBNORMAL 1
#define IFPF_IS_NORMAL 2
#define IFPF_IS_INFINITY 3
#define IFPF_IS_NAN 4
#define IFPF_TYPE_COUNT 5
#define ZERO_ZERO 0
#define ZERO_SUBNORMAL 1
#define ZERO_NORMAL 2
#define ZERO_INFINITY 3
#define ZERO_NAN 4
#define SUBNORMAL_ZERO 5
#define SUBNORMAL_SUBNORMAL 6
#define SUBNORMAL_NORMAL 7
#define SUBNORMAL_INFINITY 8
#define SUBNORMAL_NAN 9
#define NORMAL_ZERO 10
#define NORMAL_SUBNORMAL 11
#define NORMAL_NORMAL 12
#define NORMAL_INFINITY 13
#define NORMAL_NAN 14
#define INFINITY_ZERO 15
#define INFINITY_SUBNORMAL 16
#define INFINITY_NORMAL 17
#define INFINITY_INFINITY 18
#define INFINITY_NAN 19
#define NAN_ZERO 20
#define NAN_SUBNORMAL 21
#define NAN_NORMAL 22
#define NAN_INFINITY 23
#define NAN_NAN 24
#define OPERAND_ZERO 0
#define OPERAND_SUBNORMAL 1
#define OPERAND_NORMAL 2
#define OPERAND_INFINITY 3
#define OPERAND_NAN 4
/*
** Following already defined in NMGLOBAL.H
**
#define INTERNAL_FPF_PRECISION 4
*/
/*
** TYPEDEFS
*/
typedef struct
{
u8 type; /* Indicates, NORMAL, SUBNORMAL, etc. */
u8 sign; /* Mantissa sign */
short exp; /* Signed exponent...no bias */
u16 mantissa[INTERNAL_FPF_PRECISION];
} InternalFPF;
/*
** PROTOTYPES
*/
void SetupCPUEmFloatArrays(InternalFPF *abase,
InternalFPF *bbase, InternalFPF *cbase, ulong arraysize);
ulong DoEmFloatIteration(InternalFPF *abase,
InternalFPF *bbase, InternalFPF *cbase,
ulong arraysize, ulong loops);
static void SetInternalFPFZero(InternalFPF *dest,
uchar sign);
static void SetInternalFPFInfinity(InternalFPF *dest,
uchar sign);
static void SetInternalFPFNaN(InternalFPF *dest);
static int IsMantissaZero(u16 *mant);
static void Add16Bits(u16 *carry,u16 *a,u16 b,u16 c);
static void Sub16Bits(u16 *borrow,u16 *a,u16 b,u16 c);
static void ShiftMantLeft1(u16 *carry,u16 *mantissa);
static void ShiftMantRight1(u16 *carry,u16 *mantissa);
static void StickyShiftRightMant(InternalFPF *ptr,int amount);
static void normalize(InternalFPF *ptr);
static void denormalize(InternalFPF *ptr,int minimum_exponent);
void RoundInternalFPF(InternalFPF *ptr);
static void choose_nan(InternalFPF *x,InternalFPF *y,InternalFPF *z,
int intel_flag);
static void AddSubInternalFPF(uchar operation,InternalFPF *x,
InternalFPF *y,InternalFPF *z);
static void MultiplyInternalFPF(InternalFPF *x,InternalFPF *y,
InternalFPF *z);
static void DivideInternalFPF(InternalFPF *x,InternalFPF *y,
InternalFPF *z);
/* static void LongToInternalFPF(long mylong, */
static void Int32ToInternalFPF(int32 mylong,
InternalFPF *dest);
#ifdef DEBUG
static int InternalFPFToString(char *dest,
InternalFPF *src);
#endif
/*
** EXTERNALS
*/
extern ulong StartStopwatch();
extern ulong StopStopwatch(ulong elapsed);
/* extern long randwc(long num); */
extern int32 randwc(int32 num);

Binary file not shown.

View File

@ -1,202 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZ 1024
/******************
** output_string **
*******************
** Displays a string on the screen. Also, if the flag
** write_to_file is set, outputs the string to the output file.
** Note, this routine presumes that you've included a carriage
** return at the end of the buffer.
*/
static void output_string(const char *buffer, const int write_to_file,
FILE *global_ofile){
printf("%s",buffer);
if(write_to_file!=0)
fprintf(global_ofile,"%s",buffer);
return;
}
/******************
** removeNewLine **
*******************
** Removes a trailing newline character if present
*/
static void removeNewLine(char * s) {
if(strlen(s)>0 && s[strlen(s)-1] == '\n') {
s[strlen(s)-1] = '\0';
}
}
/***************
** runCommand **
****************
** Run the system command through a pipe
** The pointer result must point to a pre-allocated array of at least BUF_SIZ
*/
static void runCommand (const char *command, char *result) {
FILE * pipe;
pipe = popen(command, "r");
if(pipe == NULL) {
/* command failed */
result[0] = '\0';
} else {
if(NULL == fgets(result, BUF_SIZ, pipe)){
/* command failed */
result[0] = '\0';
}
pclose(pipe);
}
removeNewLine(result);
}
/********************
** readProcCpuInfo **
*********************
** Reads and parses /proc/cpuinfo on a Linux system
** The pointers must point to pre-allocated arrays of at least BUF_SIZ
*/
static void readProcCpuInfo (char *model, char *cache) {
FILE * info;
char * cp;
int cpus = 0;
char * buffer_end;
char buffer[BUF_SIZ];
char vendor_id[BUF_SIZ];
char model_name[BUF_SIZ];
char cpu_MHz[BUF_SIZ];
int i;
float f;
vendor_id[0] = model_name[0] = cpu_MHz[0] = model[0] = cache[0] = '\0';
info = fopen("/proc/cpuinfo", "r");
if(info != NULL) {
/* command did not fail */
while(NULL != fgets(buffer, BUF_SIZ, info)){
buffer_end = buffer + strlen(buffer);
cp = buffer;
if(! strncmp(buffer, "processor", 9)) {
cpus++;
} else if(! strncmp(buffer, "vendor_id", 9)) {
cp+=strlen("vendor_id");
while(cp < buffer_end && ( *cp == ' ' || *cp == ':'|| *cp == '\t'))
cp++;
if(cp<buffer_end) {
strcpy(vendor_id, cp);
}
removeNewLine(vendor_id);
} else if(! strncmp(buffer, "model name", 10)) {
cp+=strlen("model name");
while(cp < buffer_end && ( *cp == ' ' || *cp == ':'|| *cp == '\t'))
cp++;
if(cp<buffer_end) {
strcpy(model_name, cp);
}
removeNewLine(model_name);
} else if(! strncmp(buffer, "cpu MHz", 7)) {
cp+=strlen("cpu MHz");
while(cp < buffer_end && ( *cp == ' ' || *cp == ':'|| *cp == '\t'))
cp++;
if(cp<buffer_end) {
strcpy(cpu_MHz, cp);
}
removeNewLine(cpu_MHz);
} else if(! strncmp(buffer, "cache size", 10)) {
cp+=strlen("cache size");
while(cp < buffer_end && ( *cp == ' ' || *cp == ':'|| *cp == '\t'))
cp++;
if(cp<buffer_end) {
strcpy(cache, cp);
}
removeNewLine(cache);
}
}
if(cpus>1) {
if (cpus==2) {
strcpy(model, "Dual");
} else {
sprintf(model, "%d CPU", cpus);
}
}
cp = model + strlen(model);
if(vendor_id[0] != '\0'){
if(cp != model){
*cp++ = ' ';
}
strcpy(cp, vendor_id);
cp += strlen(vendor_id);
}
if(model_name[0] != '\0'){
if(cp != model){
*cp++ = ' ';
}
strcpy(cp, model_name);
cp += strlen(model_name);
}
if(cpu_MHz[0] != '\0'){
if(cp != model){
*cp++ = ' ';
}
f = atof(cpu_MHz);
i = (int)(f+0.5f);
sprintf(cpu_MHz, "%dMHz", i);
strcpy(cp, cpu_MHz);
cp += strlen(cpu_MHz);
}
fclose(info);
}
}
/*************
** hardware **
**************
** Runs the system command "uname -s -r"
** Reads /proc/cpuinfo if on a linux system
** Writes output
*/
void hardware(const int write_to_file, FILE *global_ofile) {
char buffer[BUF_SIZ];
char os[BUF_SIZ];
char model[BUF_SIZ];
char cache[BUF_SIZ];
char os_command[] = "uname -s -r";
#ifdef NO_UNAME
os[0] = '\0';
#else
runCommand(os_command, os);
#endif
if(NULL != strstr(os, "Linux")) {
readProcCpuInfo (model, cache);
} else {
model[0] = '\0';
cache[0] = '\0';
}
sprintf(buffer, "CPU : %s\n", model);
output_string(buffer, write_to_file, global_ofile);
sprintf(buffer, "L2 Cache : %s\n", cache);
output_string(buffer, write_to_file, global_ofile);
sprintf(buffer, "OS : %s\n", os);
output_string(buffer, write_to_file, global_ofile);
}
/************************
** main for hardware.c **
*************************
** For testing of code only
** Should be commented out
*/
/*
int main(int argc, char * argv[]) {
hardware(0, NULL);
return 0;
}
*/

View File

@ -1,2 +0,0 @@
extern
void hardware(const int write_to_file, FILE *global_ofile);

View File

@ -1,2 +0,0 @@
#include <stdio.h>
int main () {printf("hello.\n");return(0);}

View File

@ -1,120 +0,0 @@
/*
** misc.c
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
#include <stdio.h>
#include "misc.h"
/***********************************************************
** MISCELLANEOUS BUT OTHERWISE NECESSARY ROUTINES **
***********************************************************/
/****************************
** RANDOM NUMBER GENERATOR **
*****************************
** This is a second-order linear congruential random number
** generator. Its advantage is (of course) that it can be
** seeded and will thus produce repeatable sequences of
** random numbers.
*/
/****************************
* randwc() *
*****************************
** Returns signed long random modulo num.
*/
/*
long randwc(long num)
{
return(randnum(0L)%num);
}
*/
/*
** Returns signed 32-bit random modulo num.
*/
int32 randwc(int32 num)
{
return(randnum((int32)0)%num);
}
/***************************
** abs_randwc() **
****************************
** Same as randwc(), only this routine returns only
** positive numbers.
*/
/*
unsigned long abs_randwc(unsigned long num)
{
long temp;
temp=randwc(num);
if(temp<0) temp=0L-temp;
return((unsigned long)temp);
}
*/
u32 abs_randwc(u32 num)
{
int32 temp; /* Temporary storage */
temp=randwc(num);
if(temp<0) temp=(int32)0-temp;
return((u32)temp);
}
/****************************
* randnum() *
*****************************
** Second order linear congruential generator.
** Constants suggested by J. G. Skellam.
** If val==0, returns next member of sequence.
** val!=0, restart generator.
*/
/*
long randnum(long lngval)
{
register long interm;
static long randw[2] = { 13L , 117L };
if (lngval!=0L)
{ randw[0]=13L; randw[1]=117L; }
interm=(randw[0]*254754L+randw[1]*529562L)%999563L;
randw[1]=randw[0];
randw[0]=interm;
return(interm);
}
*/
int32 randnum(int32 lngval)
{
register int32 interm;
static int32 randw[2] = { (int32)13 , (int32)117 };
if (lngval!=(int32)0)
{ randw[0]=(int32)13; randw[1]=(int32)117; }
interm=(randw[0]*(int32)254754+randw[1]*(int32)529562)%(int32)999563;
randw[1]=randw[0];
randw[0]=interm;
return(interm);
}

View File

@ -1,41 +0,0 @@
/*
** misc.h
** Header for misc.c
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/************************
** FUNCTION PROTOTYPES **
************************/
/*
long randwc(long num);
unsigned long abs_randwc(unsigned long num);
long randnum(long lngval);
*/
#include "nmglobal.h"
int32 randwc(int32 num);
u32 abs_randwc(u32 num);
int32 randnum(int32 lngval);

File diff suppressed because it is too large Load Diff

View File

@ -1,356 +0,0 @@
/*
** nbench0.h
** Header for nbench0.c
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95;10/95
** 10/95 - Added memory array & alignment -- RG
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/*
** Following should be modified accordingly per each
** compilation.
*/
char *sysname="You can enter your system description in nbench0.h";
char *compilername="It then will be printed here after you recompile";
char *compilerversion="Have a nice day";
/* Parameter flags. Must coincide with parameter names array
** which appears below. */
#define PF_GMTICKS 0 /* GLOBALMINTICKS */
#define PF_MINSECONDS 1 /* MINSECONDS */
#define PF_ALLSTATS 2 /* ALLSTATS */
#define PF_OUTFILE 3 /* OUTFILE */
#define PF_CUSTOMRUN 4 /* CUSTOMRUN */
#define PF_DONUM 5 /* DONUMSORT */
#define PF_NUMNUMA 6 /* NUMNUMARRAYS */
#define PF_NUMASIZE 7 /* NUMARRAYSIZE */
#define PF_NUMMINS 8 /* NUMMINSECONDS */
#define PF_DOSTR 9 /* DOSTRINGSORT */
#define PF_STRASIZE 10 /* STRARRAYSIZE */
#define PF_NUMSTRA 11 /* NUMSTRARRAYS */
#define PF_STRMINS 12 /* STRMINSECONDS */
#define PF_DOBITF 13 /* DOBITFIELD */
#define PF_NUMBITOPS 14 /* NUMBITOPS */
#define PF_BITFSIZE 15 /* BITFIELDSIZE */
#define PF_BITMINS 16 /* BITMINSECONDS */
#define PF_DOEMF 17 /* DOEMF */
#define PF_EMFASIZE 18 /* EMFARRAYSIZE */
#define PF_EMFLOOPS 19 /* EMFLOOPS */
#define PF_EMFMINS 20 /* EMFMINSECOND */
#define PF_DOFOUR 21 /* DOFOUR */
#define PF_FOURASIZE 22 /* FOURASIZE */
#define PF_FOURMINS 23 /* FOURMINSECONDS */
#define PF_DOASSIGN 24 /* DOASSIGN */
#define PF_AARRAYS 25 /* ASSIGNARRAYS */
#define PF_ASSIGNMINS 26 /* ASSIGNMINSECONDS */
#define PF_DOIDEA 27 /* DOIDEA */
#define PF_IDEAASIZE 28 /* IDEAARRAYSIZE */
#define PF_IDEALOOPS 29 /* IDEALOOPS */
#define PF_IDEAMINS 30 /* IDEAMINSECONDS */
#define PF_DOHUFF 31 /* DOHUFF */
#define PF_HUFFASIZE 32 /* HUFFARRAYSIZE */
#define PF_HUFFLOOPS 33 /* HUFFLOOPS */
#define PF_HUFFMINS 34 /* HUFFMINSECONDS */
#define PF_DONNET 35 /* DONNET */
#define PF_NNETLOOPS 36 /* NNETLOOPS */
#define PF_NNETMINS 37 /* NNETMINSECONDS */
#define PF_DOLU 38 /* DOLU */
#define PF_LUNARRAYS 39 /* LUNUMARRAYS */
#define PF_LUMINS 40 /* LUMINSECONDS */
#define PF_ALIGN 41 /* ALIGN */
#define MAXPARAM 41
/* Tests-to-do flags...must coincide with test. */
#define TF_NUMSORT 0
#define TF_SSORT 1
#define TF_BITOP 2
#define TF_FPEMU 3
#define TF_FFPU 4
#define TF_ASSIGN 5
#define TF_IDEA 6
#define TF_HUFF 7
#define TF_NNET 8
#define TF_LU 9
#define NUMTESTS 10
/*
** GLOBALS
*/
#define BUF_SIZ 1024
/*
** Test names
*/
char *ftestnames[] = {
"NUMERIC SORT ",
"STRING SORT ",
"BITFIELD ",
"FP EMULATION ",
"FOURIER ",
"ASSIGNMENT ",
"IDEA ",
"HUFFMAN ",
"NEURAL NET ",
"LU DECOMPOSITION" };
/*
** Indexes -- Baseline is DELL Pentium XP90
** 11/28/94
*/
double bindex[] = {
38.993, /* Numeric sort */
2.238, /* String sort */
5829704, /* Bitfield */
2.084, /* FP Emulation */
879.278, /* Fourier */
.2628, /* Assignment */
65.382, /* IDEA */
36.062, /* Huffman */
.6225, /* Neural Net */
19.3031 }; /* LU Decomposition */
/*
** Indices -- Baseline is a AMD K6-233, 32MB RAM (60ns SDRAM),512k L2 cache,
** Linux kernel 2.0.32, libc-5.4.38, gcc-2.7.2.3)
** Nov/30/97
*/
double lx_bindex[] = {
118.73, /* Numeric sort */
14.459, /* String sort */
27910000, /* Bitfield */
9.0314, /* FP Emulation */
1565.5, /* Fourier */
1.0132, /* Assignment */
220.21, /* IDEA */
112.93, /* Huffman */
1.4799, /* Neural Net */
26.732}; /* LU Decomposition */
/* Parameter names */
char *paramnames[]= {
"GLOBALMINTICKS",
"MINSECONDS",
"ALLSTATS",
"OUTFILE",
"CUSTOMRUN",
"DONUMSORT",
"NUMNUMARRAYS",
"NUMARRAYSIZE",
"NUMMINSECONDS",
"DOSTRINGSORT",
"STRARRAYSIZE",
"NUMSTRARRAYS",
"STRMINSECONDS",
"DOBITFIELD",
"NUMBITOPS",
"BITFIELDSIZE",
"BITMINSECONDS",
"DOEMF",
"EMFARRAYSIZE",
"EMFLOOPS",
"EMFMINSECONDS",
"DOFOUR",
"FOURSIZE",
"FOURMINSECONDS",
"DOASSIGN",
"ASSIGNARRAYS",
"ASSIGNMINSECONDS",
"DOIDEA",
"IDEARRAYSIZE",
"IDEALOOPS",
"IDEAMINSECONDS",
"DOHUFF",
"HUFARRAYSIZE",
"HUFFLOOPS",
"HUFFMINSECONDS",
"DONNET",
"NNETLOOPS",
"NNETMINSECONDS",
"DOLU",
"LUNUMARRAYS",
"LUMINSECONDS",
"ALIGN" };
/*
** Following array is a collection of flags indicating which
** tests to perform.
*/
int tests_to_do[NUMTESTS];
/*
** Buffer for holding output text.
*/
char buffer[BUF_SIZ];
/*
** Global parameters.
*/
ulong global_min_ticks; /* Minimum ticks */
ulong global_min_seconds; /* Minimum seconds tests run */
int global_allstats; /* Statistics dump flag */
char global_ofile_name[BUF_SIZ];/* Output file name */
FILE *global_ofile; /* Output file */
int global_custrun; /* Custom run flag */
int write_to_file; /* Write output to file */
int global_align; /* Memory alignment */
/*
** Following global is the memory array. This is used to store
** original and aligned (modified) memory addresses.
*/
ulong mem_array[2][MEM_ARRAY_SIZE];
int mem_array_ents; /* # of active entries */
/*
** Following are global structures, one built for
** each of the tests.
*/
SortStruct global_numsortstruct; /* For numeric sort */
SortStruct global_strsortstruct; /* For string sort */
BitOpStruct global_bitopstruct; /* For bitfield operations */
EmFloatStruct global_emfloatstruct; /* For emul. float. point */
FourierStruct global_fourierstruct; /* For fourier test */
AssignStruct global_assignstruct; /* For assignment algorithm */
IDEAStruct global_ideastruct; /* For IDEA encryption */
HuffStruct global_huffstruct; /* For Huffman compression */
NNetStruct global_nnetstruct; /* For Neural Net */
LUStruct global_lustruct; /* For LU decomposition */
/*
** The following array of function struct pointers lets
** us very rapidly map a function to its controlling
** data structure. NOTE: These must match the "TF_xxx"
** constants above.
*/
void *global_fstruct[] =
{ (void *)&global_numsortstruct,
(void *)&global_strsortstruct,
(void *)&global_bitopstruct,
(void *)&global_emfloatstruct,
(void *)&global_fourierstruct,
(void *)&global_assignstruct,
(void *)&global_ideastruct,
(void *)&global_huffstruct,
(void *)&global_nnetstruct,
(void *)&global_lustruct };
/*
** Following globals added to support command line emulation on
** the Macintosh....which doesn't have command lines.
*/
#ifdef MAC
int argc; /* Argument count */
char *argv[20]; /* Argument vectors */
unsigned char Uargbuff[129]; /* Buffer holding arguments string */
unsigned char Udummy[2]; /* Dummy buffer for first arg */
#endif
#ifdef MACTIMEMGR
#include <Types.h>
#include <Timer.h>
/*
** Timer globals for Mac
*/
struct TMTask myTMTask;
long MacHSTdelay,MacHSTohead;
#endif
/*
** Following globals used by Win 31 timing routines.
** NOTE: This requires the includes of the w31timer.asm
** file in your project!!
*/
#ifdef WIN31TIMER
#include <windows.h>
#include <toolhelp.h>
extern TIMERINFO win31tinfo;
extern HANDLE hThlp;
extern FARPROC lpfn;
#endif
/*
** PROTOTYPES
*/
static int parse_arg(char *argptr);
static void display_help(char *progname);
static void read_comfile(FILE *cfile);
static int getflag(char *cptr);
static void strtoupper(char *s);
static void set_request_secs(void);
static int bench_with_confidence(int fid,
double *mean, double *stdev, ulong *numtries);
/*
static int seek_confidence(double scores[5],
double *newscore, double *c_half_interval,
double *smean,double *sdev);
*/
static int calc_confidence(double scores[],
int num_scores,
double *c_half_interval,double *smean,
double *sdev);
static double getscore(int fid);
static void output_string(char *buffer);
static void show_stats(int bid);
#ifdef MAC
void UCommandLine(void);
void UParse(void);
unsigned char *UField(unsigned char *ptr);
#endif
/*
** EXTERNAL PROTOTYPES
*/
extern void DoNumSort(void); /* From NBENCH1 */
extern void DoStringSort(void);
extern void DoBitops(void);
extern void DoEmFloat(void);
extern void DoFourier(void);
extern void DoAssign(void);
extern void DoIDEA(void);
extern void DoHuffman(void);
extern void DoNNET(void);
extern void DoLU(void);
extern void ErrorExit(void); /* From SYSSPEC */
/*
** Array of pointers to the benchmark functions.
*/
void (*funcpointer[])(void) =
{ DoNumSort,
DoStringSort,
DoBitops,
DoEmFloat,
DoFourier,
DoAssign,
DoIDEA,
DoHuffman,
DoNNET,
DoLU };

File diff suppressed because it is too large Load Diff

View File

@ -1,428 +0,0 @@
/*
** nbench1.h
** Header for nbench1.c
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95;10/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/*
** DEFINES
*/
/* #define DEBUG */
/*
** EXTERNALS
*/
extern ulong global_min_ticks;
extern SortStruct global_numsortstruct;
extern SortStruct global_strsortstruct;
extern BitOpStruct global_bitopstruct;
extern EmFloatStruct global_emfloatstruct;
extern FourierStruct global_fourierstruct;
extern AssignStruct global_assignstruct;
extern IDEAStruct global_ideastruct;
extern HuffStruct global_huffstruct;
extern NNetStruct global_nnetstruct;
extern LUStruct global_lustruct;
/* External PROTOTYPES */
/*extern unsigned long abs_randwc(unsigned long num);*/ /* From MISC */
/*extern long randnum(long lngval);*/
extern int32 randwc(int32 num);
extern u32 abs_randwc(u32 num);
extern int32 randnum(int32 lngval);
extern farvoid *AllocateMemory(unsigned long nbytes, /* From SYSSPEC */
int *errorcode);
extern void FreeMemory(farvoid *mempointer,
int *errorcode);
extern void MoveMemory(farvoid *destination,
farvoid *source, unsigned long nbytes);
extern void ReportError(char *context, int errorcode);
extern void ErrorExit();
extern unsigned long StartStopwatch();
extern unsigned long StopStopwatch(unsigned long startticks);
extern unsigned long TicksToSecs(unsigned long tickamount);
extern double TicksToFracSecs(unsigned long tickamount);
/*****************
** NUMERIC SORT **
*****************/
/*
** PROTOTYPES
*/
void DoNumSort(void);
static ulong DoNumSortIteration(farlong *arraybase,
ulong arraysize,
uint numarrays);
static void LoadNumArrayWithRand(farlong *array,
ulong arraysize,
uint numarrays);
static void NumHeapSort(farlong *array,
ulong bottom,
ulong top);
static void NumSift(farlong *array,
ulong i,
ulong j);
/****************
** STRING SORT **
*****************
*/
/*
** PROTOTYPES
*/
void DoStringSort(void);
static ulong DoStringSortIteration(faruchar *arraybase,
uint numarrays,
ulong arraysize);
static farulong *LoadStringArray(faruchar *strarray,
uint numarrays,
ulong *strings,
ulong arraysize);
static void stradjust(farulong *optrarray,
faruchar *strarray,
ulong nstrings,
ulong i,
uchar l);
static void StrHeapSort(farulong *optrarray,
faruchar *strarray,
ulong numstrings,
ulong bottom,
ulong top);
static int str_is_less(farulong *optrarray,
faruchar *strarray,
ulong numstrings,
ulong a,
ulong b);
static void strsift(farulong *optrarray,
faruchar *strarray,
ulong numstrings,
ulong i,
ulong j);
/************************
** BITFIELD OPERATIONS **
*************************
*/
/*
** PROTOTYPES
*/
void DoBitops(void);
static ulong DoBitfieldIteration(farulong *bitarraybase,
farulong *bitoparraybase,
long bitoparraysize,
ulong *nbitops);
static void ToggleBitRun(farulong *bitmap,
ulong bit_addr,
ulong nbits,
uint val);
static void FlipBitRun(farulong *bitmap,
ulong bit_addr,
ulong nbits);
/****************************
** EMULATED FLOATING POINT **
****************************/
typedef struct
{
u8 type; /* Indicates, NORMAL, SUBNORMAL, etc. */
u8 sign; /* Mantissa sign */
short exp; /* Signed exponent...no bias */
u16 mantissa[INTERNAL_FPF_PRECISION];
} InternalFPF;
/*
** PROTOTYPES
*/
void DoEmFloat(void);
/*
** EXTERNALS
*/
extern void SetupCPUEmFloatArrays(InternalFPF *abase,
InternalFPF *bbase, InternalFPF *cbase,
ulong arraysize);
extern ulong DoEmFloatIteration(InternalFPF *abase,
InternalFPF *bbase, InternalFPF *cbase,
ulong arraysize, ulong loops);
/*************************
** FOURIER COEFFICIENTS **
*************************/
/*
** PROTOTYPES
*/
void DoFourier(void);
static ulong DoFPUTransIteration(fardouble *abase,
fardouble *bbase,
ulong arraysize);
static double TrapezoidIntegrate(double x0,
double x1,
int nsteps,
double omegan,
int select);
static double thefunction(double x,
double omegan,
int select);
/*************************
** ASSIGNMENT ALGORITHM **
*************************/
/*
** DEFINES
*/
#define ASSIGNROWS 101L
#define ASSIGNCOLS 101L
/*
** TYPEDEFS
*/
typedef struct {
union {
long *p;
long (*ap)[ASSIGNROWS][ASSIGNCOLS];
} ptrs;
} longptr;
/*
** PROTOTYPES
*/
void DoAssign(void);
static ulong DoAssignIteration(farlong *arraybase,
ulong numarrays);
static void LoadAssignArrayWithRand(farlong *arraybase,
ulong numarrays);
static void LoadAssign(farlong arraybase[][ASSIGNCOLS]);
static void CopyToAssign(farlong arrayfrom[][ASSIGNCOLS],
long arrayto[][ASSIGNCOLS]);
static void Assignment(farlong arraybase[][ASSIGNCOLS]);
static void calc_minimum_costs(long tableau[][ASSIGNCOLS]);
static int first_assignments(long tableau[][ASSIGNCOLS],
short assignedtableau[][ASSIGNCOLS]);
static void second_assignments(long tableau[][ASSIGNCOLS],
short assignedtableau[][ASSIGNCOLS]);
/********************
** IDEA ENCRYPTION **
********************/
/*
** DEFINES
*/
#define IDEAKEYSIZE 16
#define IDEABLOCKSIZE 8
#define ROUNDS 8
#define KEYLEN (6*ROUNDS+4)
/*
** MACROS
*/
#define low16(x) ((x) & 0x0FFFF)
#define MUL(x,y) (x=mul(low16(x),y))
typedef u16 IDEAkey[KEYLEN];
/*
** PROTOTYPES
*/
void DoIDEA(void);
static ulong DoIDEAIteration(faruchar *plain1,
faruchar *crypt1, faruchar *plain2,
ulong arraysize, ulong nloops,
IDEAkey Z, IDEAkey DK);
static u16 mul(register u16 a, register u16 b);
static u16 inv(u16 x);
static void en_key_idea(u16 userkey[8], IDEAkey Z);
static void de_key_idea(IDEAkey Z, IDEAkey DK);
static void cipher_idea(u16 in[4], u16 out[4], IDEAkey Z);
/************************
** HUFFMAN COMPRESSION **
************************/
/*
** DEFINES
*/
#define EXCLUDED 32000L /* Big positive value */
/*
** TYPEDEFS
*/
typedef struct {
uchar c; /* Byte value */
float freq; /* Frequency */
int parent; /* Parent node */
int left; /* Left pointer = 0 */
int right; /* Right pointer = 1 */
} huff_node;
/*
** GLOBALS
*/
static huff_node *hufftree; /* The huffman tree */
static long plaintextlen; /* Length of plaintext */
/*
** PROTOTYPES
*/
void DoHuffman();
static void create_text_line(farchar *dt,long nchars);
static void create_text_block(farchar *tb, ulong tblen,
ushort maxlinlen);
static ulong DoHuffIteration(farchar *plaintext,
farchar *comparray, farchar *decomparray,
ulong arraysize, ulong nloops, huff_node *hufftree);
static void SetCompBit(u8 *comparray, u32 bitoffset, char bitchar);
static int GetCompBit(u8 *comparray, u32 bitoffset);
/********************************
** BACK PROPAGATION NEURAL NET **
********************************/
/*
** DEFINES
*/
#define T 1 /* TRUE */
#define F 0 /* FALSE */
#define ERR -1
#define MAXPATS 10 /* max number of patterns in data file */
#define IN_X_SIZE 5 /* number of neurodes/row of input layer */
#define IN_Y_SIZE 7 /* number of neurodes/col of input layer */
#define IN_SIZE 35 /* equals IN_X_SIZE*IN_Y_SIZE */
#define MID_SIZE 8 /* number of neurodes in middle layer */
#define OUT_SIZE 8 /* number of neurodes in output layer */
#define MARGIN 0.1 /* how near to 1,0 do we have to come to stop? */
#define BETA 0.09 /* beta learning constant */
#define ALPHA 0.09 /* momentum term constant */
#define STOP 0.1 /* when worst_error less than STOP, training is done */
/*
** GLOBALS
*/
double mid_wts[MID_SIZE][IN_SIZE]; /* middle layer weights */
double out_wts[OUT_SIZE][MID_SIZE]; /* output layer weights */
double mid_out[MID_SIZE]; /* middle layer output */
double out_out[OUT_SIZE]; /* output layer output */
double mid_error[MID_SIZE]; /* middle layer errors */
double out_error[OUT_SIZE]; /* output layer errors */
double mid_wt_change[MID_SIZE][IN_SIZE]; /* storage for last wt change */
double out_wt_change[OUT_SIZE][MID_SIZE]; /* storage for last wt change */
double in_pats[MAXPATS][IN_SIZE]; /* input patterns */
double out_pats[MAXPATS][OUT_SIZE]; /* desired output patterns */
double tot_out_error[MAXPATS]; /* measure of whether net is done */
double out_wt_cum_change[OUT_SIZE][MID_SIZE]; /* accumulated wt changes */
double mid_wt_cum_change[MID_SIZE][IN_SIZE]; /* accumulated wt changes */
double worst_error; /* worst error each pass through the data */
double average_error; /* average error each pass through the data */
double avg_out_error[MAXPATS]; /* average error each pattern */
int iteration_count; /* number of passes thru network so far */
int numpats; /* number of patterns in data file */
int numpasses; /* number of training passes through data file */
int learned; /* flag--if TRUE, network has learned all patterns */
/*
** The Neural Net test requires an input data file.
** The name is specified here.
*/
char *inpath="NNET.DAT";
/*
** PROTOTYPES
*/
void DoNNET(void);
static ulong DoNNetIteration(ulong nloops);
static void do_mid_forward(int patt);
static void do_out_forward();
void display_output(int patt);
static void do_forward_pass(int patt);
static void do_out_error(int patt);
static void worst_pass_error();
static void do_mid_error();
static void adjust_out_wts();
static void adjust_mid_wts();
static void do_back_pass(int patt);
static void move_wt_changes();
static int check_out_error();
static void zero_changes();
static void randomize_wts();
static int read_data_file();
/* static int initialize_net(); */
/***********************
** LU DECOMPOSITION **
** (Linear Equations) **
***********************/
/*
** DEFINES
*/
#define LUARRAYROWS 101L
#define LUARRAYCOLS 101L
/*
** TYPEDEFS
*/
typedef struct
{ union
{ fardouble *p;
fardouble (*ap)[][LUARRAYCOLS];
} ptrs;
} LUdblptr;
/*
** GLOBALS
*/
fardouble *LUtempvv;
/*
** PROTOTYPES
*/
void DoLU(void);
static void LUFreeMem(fardouble *a, fardouble *b,
fardouble *abase, fardouble *bbase);
static ulong DoLUIteration(fardouble *a, fardouble *b,
fardouble *abase, fardouble *bbase,
ulong numarrays);
static void build_problem( double a[][LUARRAYCOLS],
int n, double b[LUARRAYROWS]);
static int ludcmp(double a[][LUARRAYCOLS],
int n, int indx[], int *d);
static void lubksb(double a[][LUARRAYCOLS],
int n, int indx[LUARRAYROWS],
double b[LUARRAYROWS]);
static int lusolve(double a[][LUARRAYCOLS],
int n, double b[LUARRAYROWS]);

View File

@ -1,519 +0,0 @@
/*
** nmglobal.h
** Global definitions for native mode benchmarks.
**
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95;10/95
** 10/95 - Added memory array & alignment -- RG
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/* is this a 64 bit architecture? If so, this will define LONG64 */
#include "pointer.h"
/*
** SYSTEM DEFINES
*/
/* +++ MEMORY +++ */
/*
** You must define ONLY ONE of the following identifiers
** to specify the mechanism for allocating memory:
** MALLOCMEM
** DOS16MEM
** MACMEM
*/
/*
** Define MALLOCMEM to use the standard malloc() call for
** memory. This is the default for most systems.
*/
#define MALLOCMEM
/*
** Define DOS16MEM if you're running in the old 16-bit segmented
** model. This enables some fruity memory management routines
** required for that model. NOT defining this assumes that
** you're running in an environment that allows malloc() to
** get > 64K chunks of memory.
*/
/* #define DOS16MEM */
/* Define MACMEM to use the Mac's GetPtr call to allocate
** memory (instead of malloc()).
*/
/* #define MACMEM */
/* +++ TIMING +++ */
/*
** You must define ONLY ONE of the following identifiers to pick
** the timing routine used.
** CLOCKWCPS
** CLOCKWCT
** MACTIMEMGR
** WIN31TIMER
*/
/*
** Define CLOCKWCPS if you are using the clock() routine and the
** constant used as the divisor to determine seconds is
** CLOCKS_PER_SEC. This is the default in most cases.
*/
#define CLOCKWCPS
/*
** Define CLOCKWCT if you are using the clock() routine and the
** constant used as the divisor to determine seconds is CLK_TCK
*/
/* #define CLOCKWCT */
/*
** Define MACTIMEMGR to use the Mac Time manager routines.
** You'll need to be running at least system 6.0.3 or
** better...extended time manager is recommended (system 7 or
** better).
*/
/* #define MACTIMEMGR */
/*
** Define WIN31TIMER to user the timing routines in TOOLHELP.DLL.
** Gets accuracy down to the millisecond.
*/
/* #define WIN31TIMER */
/* +++ MISCELLANEOUS +++ */
/*
** Define DOS16 if you'll be compiling under DOS in 16-bit
** (non DOS-extended) mode. This will enable proper definitions
** for the far*** typedefs
*/
/* #define DOS16 */
/*
** Define MAC if you're compiling on a Macintosh. This
** does a number of things:
** includes unix.h
** Incorporates code to mimic the command line via either
** the console library (Symantec/Think) or the SIOUX
** library (Code Warrior).
*/
/* #define MAC */
/*
** Define LONG64 if your compiler emits 64-bit longs.
** This is typically true of Alpha compilers on Unix
** systems...though, who knows, this may change in the
** future. I MOVED THIS DEFINTION INTO THE FILE pointer.h. DO NOT
** DEFINE IT HERE. IT WILL AUTOMATICALLY BE DEFINED IF NECESSARY.
** Uwe F. Mayer, Dec 15, 1996, Nov 15, 1997
*/
/* #define LONG64 */
/*
** Define MACCWPROF if you are profiling on the Mac using
** Code Warrior. This enables code that turns off the
** profiler in an evern of an error exit.
*/
/* #define MACCWPROF */
#ifdef MAC
#include <unix.h>
#endif
/*
** ERROR CODES
*/
#define ERROR_MEMORY 1
#define ERROR_MEMARRAY_FULL 2
#define ERROR_MEMARRAY_NFOUND 3
#define ERROR_FILECREATE 10
#define ERROR_FILEREAD 11
#define ERROR_FILEWRITE 12
#define ERROR_FILEOPEN 13
#define ERROR_FILESEEK 14
/*
** MINIMUM_TICKS
**
** This sets the default number of minimum ticks.
** It can, of course, be overridden by the input
** command file.
** This ultimately gets loaded into the variable
** global_min_ticks, which specifies the minimum
** number of ticks that must take place between
** a StartStopwatch() and StopStopwatch() call.
** The idea is to reduce error buildup.
*/
#define MINIMUM_TICKS 1
/*
** MINIMUM_SECONDS
**
** Minimum number of seconds to run each test.
*/
#define MINIMUM_SECONDS 1
/*
** MAXPOSLONG
**
** This is the maximum positive long.
*/
#ifdef LONG64
#define MAXPOSLONG 0x7FFFFFFFFFFFFFFFL
#else
#define MAXPOSLONG 0x7FFFFFFFL
#endif
/*
** OTHER DEFINES
*/
#ifndef MAC
#define TRUE 1
#define FALSE 0
#endif
/*
** Memory array size. Used in SYSSPEC for keeping track
** of re-aligned memory.
*/
#define MEM_ARRAY_SIZE 20
/*
** TYPEDEFS
*/
#define ulong unsigned long
#define uchar unsigned char
#define uint unsigned int
#define ushort unsigned short
/*
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned long ulong;
*/
/*
** The 'farxxx' typedefs were added in deference to DOS, which
** requires far pointers to handle some of the bigger
** memory structures. Other systems will simply
** map 'farxxx' to 'xxx'
*/
#ifdef DOS16
typedef void huge farvoid;
typedef double huge fardouble;
typedef long huge farlong;
typedef unsigned long huge farulong;
typedef char huge farchar;
typedef unsigned char huge faruchar;
#else
typedef void farvoid;
typedef double fardouble;
typedef long farlong;
typedef unsigned long farulong;
typedef char farchar;
typedef unsigned char faruchar;
#endif
/*
** The following typedefs are used when element size
** is critical. You'll have to alter these for
** your specifical platform/compiler.
*/
typedef unsigned char u8; /* Unsigned 8-bits */
typedef unsigned short u16; /* Unsigned 16 bits */
#ifdef LONG64
typedef unsigned int u32; /* Unsigned 32 bits */
typedef int int32; /* Signed 32 bit integer */
#else
typedef unsigned long u32; /* Unsigned 32 bits */
typedef long int32; /* Signed 32 bit integer */
#endif
/*****************
** NUMERIC SORT **
*****************/
/*
** DEFINES
*/
/*
** The following constant, NUMNUMARRAYS (no, it is not a
** Peter Sellers joke) is the maximum number of arrays
** that can be built by the numeric sorting benchmark
** before it gives up. This maximum is dependent on the
** amount of memory in the system.
*/
/*#define NUMNUMARRAYS 1000*/
#define NUMNUMARRAYS 10000
/*
** The following constant NUMARRAYSIZE determines the
** default # of elements in each numeric array. Ordinarily
** this is something you shouldn't fool with, though as
** with most of the constants here, it is adjustable.
*/
#define NUMARRAYSIZE 8111L
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* # of seconds requested */
double sortspersec; /* # of sort iterations per sec */
ushort numarrays; /* # of arrays */
ulong arraysize; /* # of elements in array */
} SortStruct;
/****************
** STRING SORT **
*****************
** Note: The string sort benchmark uses the same structure to
** communicate parameters as does the numeric sort benchmark.
** (i.e., SortStruct...see above.
*/
/*
** DEFINES
*/
/*
** The following constant STRINGARRAYSIZE determines
** the default # of bytes allocated to each string array.
** Though the actual size can be pre-set from the command
** file, this constant should be left unchanged.
*/
#define STRINGARRAYSIZE 8111L
/************************
** BITFIELD OPERATIONS **
*************************
*/
/*
** DEFINES
*/
/*
** Following field sets the size of the bitfield array (in longs).
*/
#ifdef LONG64
#define BITFARRAYSIZE 16384L
#else
#define BITFARRAYSIZE 32768L
#endif
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* # of seconds requested */
double bitopspersec; /* # of bitfield ops per sec */
ulong bitoparraysize; /* Total # of bitfield ops */
ulong bitfieldarraysize; /* Bit field array size */
} BitOpStruct;
/****************************
** EMULATED FLOATING POINT **
****************************/
/*
** DEFINES
*/
#define INTERNAL_FPF_PRECISION 4
/*
** The following constant is the maximum number of loops
** of the emulated floating point test that the system
** will allow before flagging an error. This is not a
** critical constant, and can be altered if your system is
** a real barn-burner.
*/
/*#define CPUEMFLOATLOOPMAX 50000L*/
#define CPUEMFLOATLOOPMAX 500000L
/*
** Set size of array
*/
#define EMFARRAYSIZE 3000L
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* # of seconds requested */
ulong arraysize; /* Size of array */
ulong loops; /* Loops per iterations */
double emflops; /* Results */
} EmFloatStruct;
/*************************
** FOURIER COEFFICIENTS **
*************************/
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* # of requested seconds */
ulong arraysize; /* Size of coeff. arrays */
double fflops; /* Results */
} FourierStruct;
/*************************
** ASSIGNMENT ALGORITHM **
*************************/
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* Requested # of seconds */
ulong numarrays; /* # of arrays */
double iterspersec; /* Results */
} AssignStruct;
/********************
** IDEA ENCRYPTION **
********************/
/*
** DEFINES
*/
/* Following constant defines the max number of loops the
** system will attempt. Keeps things from going off into the
** weeds. */
/*#define MAXIDEALOOPS 50000L*/
#define MAXIDEALOOPS 500000L
/*
** Following constant sets the size of the arrays.
** NOTE: For the IDEA algorithm to work properly, this
** number MUST be some multiple of 8.
*/
#define IDEAARRAYSIZE 4000L
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* Requested # of seconds */
ulong arraysize; /* Size of array */
ulong loops; /* # of times to convert */
double iterspersec; /* Results */
} IDEAStruct;
/************************
** HUFFMAN COMPRESSION **
************************/
/*
** DEFINES
*/
/*
** MAXHUFFLOOPS
**
** This constant specifies the maximum number of Huffman
** compression loops the system will try for. This keeps
** the test from going off into the weeds. This is not
** a critical constant, and can be increased if your
** system is a real barn-burner.
*/
/*#define MAXHUFFLOOPS 50000L*/
#define MAXHUFFLOOPS 500000L
/*
** Following constant sets the size of the arrays to
** be compressed/uncompressed.
*/
#define HUFFARRAYSIZE 5000L
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* Requested # of seconds */
ulong arraysize; /* Size of array */
ulong loops; /* # of times to compress/decompress */
double iterspersec; /* Results */
} HuffStruct;
/********************************
** BACK PROPAGATION NEURAL NET **
********************************/
/*
** MAXNNETLOOPS
**
** This constant sets the max number of loops through the neural
** net that the system will attempt before giving up. This
** is not a critical constant. You can alter it if your system
** has sufficient horsepower.
*/
/*#define MAXNNETLOOPS 50000L*/
#define MAXNNETLOOPS 500000L
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* Requested # of seconds */
ulong loops; /* # of times to learn */
double iterspersec; /* Results */
} NNetStruct;
/***********************
** LU DECOMPOSITION **
** (Linear Equations) **
***********************/
/*
** MAXLUARRAYS
**
** This sets the upper limit on the number of arrays
** that the benchmark will attempt to build before
** flagging an error. It is not a critical constant, and
** may be increased if your system has the horsepower.
*/
/*#define MAXLUARRAYS 1000*/
#define MAXLUARRAYS 10000
/*
** TYPEDEFS
*/
typedef struct {
int adjust; /* Set adjust code */
ulong request_secs; /* Requested # of seconds */
ulong numarrays; /* # of arrays */
double iterspersec; /* Results */
} LUStruct;

View File

@ -1,6 +0,0 @@
#include <stdio.h>
int main(){
printf("%d",(int)sizeof(long));
return(0);
}

View File

@ -1,10 +0,0 @@
sprintf(buffer,"**System used for compilation:\n");
output_string(buffer);
sprintf(buffer,"**Linux mimi 2.0.31 #5 Thu Oct 23 10:02:08 CDT 1997 i486\n");
output_string(buffer);
sprintf(buffer,"**C compiler: gcc version 2.7.2.3\n");
output_string(buffer);
sprintf(buffer,"**libc: libc.so.5.4.38\n");
output_string(buffer);
sprintf(buffer,"**Date of compilation: Thu Nov 20 10:04:43 CST 1997\n");
output_string(buffer);

View File

@ -1,10 +0,0 @@
sprintf(buffer,"**System used for compilation:\n");
output_string(buffer);
sprintf(buffer,"**%SYSTEM%\n");
output_string(buffer);
sprintf(buffer,"**C compiler: %CCVERSION%\n");
output_string(buffer);
sprintf(buffer,"**libc: %LIBCVERSION%\n");
output_string(buffer);
sprintf(buffer,"**Date of compilation: %DATE%\n");
output_string(buffer);

View File

@ -1,78 +0,0 @@
#!/bin/sh
# the arguments of this script are the compiler name and flags
# try to solve a chicken-and-egg problem on SunOS
# ucb's test program does not handle -L like the other test programs
# let's try to find another implementation
if test -x /bin/test; then
TEST=/bin/test;
else
if test -x /usr/bin/test; then
TEST=/usr/bin/test;
else
# cross your fingers that it's not like ucb test
TEST=test;
fi
fi
compiler=`echo $* | sed -e 's/-static//g' -e 's/-Bstatic//g'`
if $TEST `basename $1` = "gcc" && ($compiler -v) >/dev/null 2>&1 ; then
# Cygwin writes more than one line with "version" in it
gccversion=`$compiler -v 2>&1 | sed -e "/version/!d" | tail -n 1`
else
gccversion="$1"
fi
libcversion=""
if ($* hello.c -o hello) >/dev/null 2>&1; then
ldd_output=`(ldd hello) 2>&1`
libcversion=`echo $ldd_output | sed -e 's/.*static.*/static/' \
-e 's/.*not a dynamic.*/static/'`
if $TEST "$libcversion" = "static" ; then
if ($compiler hello.c -o hello) >/dev/null 2>&1; then
if (ldd hello) >/dev/null 2>/dev/null; then
libcversion=`(ldd hello) 2>&1`
libcversion=`echo $libcversion | sed -e '/libc/!d'\
-e 's/^[ ]*//' \
-e 's/.*=>[ ][ ]*\([^ ]*\).*/\1/'`
# remember the current directory
current=`pwd`
while $TEST -L "$libcversion" && ! $TEST "$libcversion" = "" ; do
libcitself=`basename $libcversion`
libpath=`echo $libcversion | sed -e "s/$libcitself$//"`
if $TEST -d "$libpath" ; then
cd $libpath
fi
if ls $libcitself >/dev/null 2>/dev/null ; then
libcversion=`ls -l $libcitself | \
sed -e 's/.*->[ ][ ]*\(.*\)$/\1/'`
else
# something must have gone wrong, let's bail out
libcversion=""
fi
done
# return to the current directory
cd $current
fi
fi
else
libcversion=""
fi
fi
rm -f sysinfo.crm sysinfoc.c hello
# this bombs out on Ultrix which expect "cut -d"
compsystem=`uname -a | cut -b 1-78`
compdate=`date|cut -b1-55`
# let's hope that ctrl-c is not part of any string here
# this also will barf later if " is in any of the strings
for i in sysinfo.c sysinfoc.c ; do
sed -e "s%CCVERSION%$gccversion" -e "s%LIBCVERSION%$libcversion"\
-e "s%SYSTEM%$compsystem" -e "s%DATE%$compdate"\
${i}.template > $i
done

View File

@ -1,4 +0,0 @@
sprintf(buffer,"C compiler : gcc version 2.7.2.3\n");
output_string(buffer);
sprintf(buffer,"libc : libc.so.5.4.38\n");
output_string(buffer);

View File

@ -1,4 +0,0 @@
sprintf(buffer,"C compiler : %CCVERSION%\n");
output_string(buffer);
sprintf(buffer,"libc : %LIBCVERSION%\n");
output_string(buffer);

View File

@ -1,884 +0,0 @@
/*
** sysspec.c
** System-specific routines.
**
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95;10/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/***********************************
** SYSTEM-SPECIFIC ROUTINES **
************************************
**
** These are the routines that provide functions that are
** system-specific. If the benchmarks are to be ported
** to new hardware/new O.S., this is the first place to
** start.
*/
#include "sysspec.h"
#ifdef DOS16
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#endif
/*********************************
** MEMORY MANAGEMENT ROUTINES **
*********************************/
/****************************
** AllocateMemory
** This routine returns a void pointer to a memory
** block. The size of the memory block is given in bytes
** as the first argument. This routine also returns an
** error code in the second argument.
** 10/95 Update:
** Added an associative array for memory alignment reasons.
** mem_array[2][MEM_ARRAY_SIZE]
** mem_array[0][n] = Actual address (from malloc)
** mem_array[1][n] = Aligned address
** Currently, mem_array[][] is only used if you use malloc;
** it is not used for the 16-bit DOS and MAC versions.
*/
farvoid *AllocateMemory(unsigned long nbytes, /* # of bytes to alloc */
int *errorcode) /* Returned error code */
{
#ifdef DOS16MEM
union REGS registers;
unsigned short nparas; /* # of paragraphs */
/*
** Set # of paragraphs to nbytes/16 +1. The +1 is a
** slop factor.
*/
nparas=(unsigned short)(nbytes/16L) + 1;
/*
** Set incoming registers.
*/
registers.h.ah=0x48; /* Allocate memory */
registers.x.bx=nparas; /* # of paragraphs */
intdos(&registers,&registers); /* Call DOS */
/*
** See if things succeeded.
*/
if(registers.x.cflag)
{ printf("error: %d Lgst: %d\n",registers.x.ax,registers.x.bx);
*errorcode=ERROR_MEMORY;
return((farvoid *)NULL);
}
/*
** Create a farvoid pointer to return.
*/
*errorcode=0;
return((farvoid *)MK_FP(registers.x.ax,0));
#endif
#ifdef MACMEM
/*
** For MAC CodeWarrior, we'll use the MacOS NewPtr call
*/
farvoid *returnval;
returnval=(farvoid *)NewPtr((Size)nbytes);
if(returnval==(farvoid *)NULL)
*errorcode=ERROR_MEMORY;
else
*errorcode=0;
return(returnval);
#endif
#ifdef MALLOCMEM
/*
** Everyone else, its pretty straightforward, given
** that you use a 32-bit compiler which treats size_t as
** a 4-byte entity.
*/
farvoid *returnval; /* Return value */
ulong true_addr; /* True address */
ulong adj_addr; /* Adjusted address */
returnval=(farvoid *)malloc((size_t)(nbytes+2L*(long)global_align));
if(returnval==(farvoid *)NULL)
*errorcode=ERROR_MEMORY;
else
*errorcode=0;
/*
** Check for alignment
*/
adj_addr=true_addr=(ulong)returnval;
if(global_align==0)
{
if(AddMemArray(true_addr, adj_addr))
*errorcode=ERROR_MEMARRAY_FULL;
return(returnval);
}
if(global_align==1)
{
if(true_addr%2==0) adj_addr++;
}
else
{
while(adj_addr%global_align!=0) ++adj_addr;
if(adj_addr%(global_align*2)==0) adj_addr+=global_align;
}
returnval=(void *)adj_addr;
if(AddMemArray(true_addr,adj_addr))
*errorcode=ERROR_MEMARRAY_FULL;
return(returnval);
#endif
}
/****************************
** FreeMemory
** This is the reverse of AllocateMemory. The memory
** block passed in is freed. Should an error occur,
** that error is returned in errorcode.
*/
void FreeMemory(farvoid *mempointer, /* Pointer to memory block */
int *errorcode)
{
#ifdef DOS16MEM
/*
** 16-bit DOS VERSION!!
*/
unsigned int segment;
unsigned int offset;
union REGS registers;
struct SREGS sregisters;
/*
** First get the segment/offset of the farvoid pointer.
*/
segment=FP_SEG(mempointer);
offset=FP_OFF(mempointer);
/*
** Align the segment properly. For as long as offset > 16,
** subtract 16 from offset and add 1 to segment.
*/
while(offset>=16)
{ offset-=16;
segment++;
}
/*
** Build the call to DOS
*/
registers.h.ah=0x49; /* Free memory */
sregisters.es=segment;
intdosx(&registers,&registers,&sregisters);
/*
** Check for error
*/
if(registers.x.cflag)
{ *errorcode=ERROR_MEMORY;
return;
}
*errorcode=0;
return;
#endif
#ifdef MACMEM
DisposPtr((Ptr)mempointer);
*errorcode=0;
return;
#endif
#ifdef MALLOCMEM
ulong adj_addr, true_addr;
/* Locate item in memory array */
adj_addr=(ulong)mempointer;
if(RemoveMemArray(adj_addr, &true_addr))
{ *errorcode=ERROR_MEMARRAY_NFOUND;
return;
}
mempointer=(void *)true_addr;
free(mempointer);
*errorcode=0;
return;
#endif
}
/****************************
** MoveMemory
** Moves n bytes from a to b. Handles overlap.
** In most cases, this is just a memmove operation.
** But, not in DOS....noooo....
*/
void MoveMemory( farvoid *destination, /* Destination address */
farvoid *source, /* Source address */
unsigned long nbytes)
{
/* +++16-bit DOS VERSION+++ */
#ifdef DOS16MEM
FarDOSmemmove( destination, source, nbytes);
#else
memmove(destination, source, nbytes);
#endif
}
#ifdef DOS16MEM
/****************************
** FarDOSmemmove
** Performs the same function as memmove for DOS when
** the arrays are defined with far pointers.
*/
void FarDOSmemmove(farvoid *destination, /* Destination pointer */
farvoid *source, /* Source pointer */
unsigned long nbytes) /* # of bytes to move */
{
unsigned char huge *uchsource; /* Temp source */
unsigned char huge *uchdest; /* Temp destination */
unsigned long saddr; /* Source "true" address */
unsigned long daddr; /* Destination "true" address */
/*
** Get unsigned char pointer equivalents
*/
uchsource=(unsigned char huge *)source;
uchdest=(unsigned char huge *)destination;
/*
** Calculate true address of source and destination and
** compare.
*/
saddr=(unsigned long)(FP_SEG(source)*16 + FP_OFF(source));
daddr=(unsigned long)(FP_SEG(destination)*16 + FP_OFF(destination));
if(saddr > daddr)
{
/*
** Source is greater than destination.
** Use a series of standard move operations.
** We'll move 65535 bytes at a time.
*/
while(nbytes>=65535L)
{ _fmemmove((farvoid *)uchdest,
(farvoid *)uchsource,
(size_t) 65535);
uchsource+=65535; /* Advance pointers */
uchdest+=65535;
nbytes-=65535;
}
/*
** Move remaining bytes
*/
if(nbytes!=0L)
_fmemmove((farvoid *)uchdest,
(farvoid *)uchsource,
(size_t)(nbytes & 0xFFFF));
}
else
{
/*
** Destination is greater than source.
** Advance pointers to the end of their
** respective blocks.
*/
uchsource+=nbytes;
uchdest+=nbytes;
/*
** Again, move 65535 bytes at a time. However,
** "back" the pointers up before doing the
** move.
*/
while(nbytes>=65535L)
{
uchsource-=65535;
uchdest-=65535;
_fmemmove((farvoid *)uchdest,
(farvoid *)uchsource,
(size_t) 65535);
nbytes-=65535;
}
/*
** Move remaining bytes.
*/
if(nbytes!=0L)
{ uchsource-=nbytes;
uchdest-=nbytes;
_fmemmove((farvoid *)uchdest,
(farvoid *)uchsource,
(size_t)(nbytes & 0xFFFF));
}
}
return;
}
#endif
/***********************************
** MEMORY ARRAY HANDLING ROUTINES **
***********************************/
/****************************
** InitMemArray
** Initialize the memory array. This simply amounts to
** setting mem_array_ents to zero, indicating that there
** isn't anything in the memory array.
*/
void InitMemArray(void)
{
mem_array_ents=0;
return;
}
/***************************
** AddMemArray
** Add a pair of items to the memory array.
** true_addr is the true address (mem_array[0][n])
** adj_addr is the adjusted address (mem_array[0][n])
** Returns 0 if ok
** -1 if not enough room
*/
int AddMemArray(ulong true_addr,
ulong adj_addr)
{
if(mem_array_ents>=MEM_ARRAY_SIZE)
return(-1);
mem_array[0][mem_array_ents]=true_addr;
mem_array[1][mem_array_ents]=adj_addr;
mem_array_ents++;
return(0);
}
/*************************
** RemoveMemArray
** Given an adjusted address value (mem_array[1][n]), locate
** the entry and remove it from the mem_array.
** Also returns the associated true address.
** Returns 0 if ok
** -1 if not found.
*/
int RemoveMemArray(ulong adj_addr,ulong *true_addr)
{
int i,j;
/* Locate the item in the array. */
for(i=0;i<mem_array_ents;i++)
if(mem_array[1][i]==adj_addr)
{ /* Found it..bubble stuff down */
*true_addr=mem_array[0][i];
j=i;
while(j+1<mem_array_ents)
{ mem_array[0][j]=mem_array[0][j+1];
mem_array[1][j]=mem_array[1][j+1];
j++;
}
mem_array_ents--;
return(0); /* Return if found */
}
/* If we made it here...something's wrong...show error */
return(-1);
}
/**********************************
** FILE HANDLING ROUTINES **
**********************************/
/****************************
** CreateFile
** This routine accepts a filename for an argument and
** creates that file in the current directory (unless the
** name contains a path that overrides the current directory).
** Note that the routine does not OPEN the file.
** If the file exists, it is truncated to length 0.
*/
void CreateFile(char *filename,
int *errorcode)
{
#ifdef DOS16
/*
** DOS VERSION!!
*/
int fhandle; /* File handle used internally */
fhandle=open(filename,O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
if(fhandle==-1)
*errorcode=ERROR_FILECREATE;
else
*errorcode=0;
/*
** Since all we're doing here is creating the file,
** go ahead and close it.
*/
close(fhandle);
return;
#endif
#ifdef LINUX
FILE *fhandle; /* File handle used internally */
fhandle=fopen(filename,"w");
if(fhandle==NULL)
*errorcode=ERROR_FILECREATE;
else
*errorcode=0;
/*
** Since all we're doing here is creating the file,
** go ahead and close it.
*/
fclose(fhandle);
return;
#endif
}
/****************************
** bmOpenFile
** Opens the file given by fname, returning its handle.
** If an error occurs, returns its code in errorcode.
** The file is opened in read-write exclusive mode.
*/
#ifdef DOS16
/*
** DOS VERSION!!
*/
int bmOpenFile(char *fname, /* File name */
int *errorcode) /* Error code returned */
{
int fhandle; /* Returned file handle */
fhandle=open(fname,O_BINARY | O_RDWR, S_IREAD | S_IWRITE);
if(fhandle==-1)
*errorcode=ERROR_FILEOPEN;
else
*errorcode=0;
return(fhandle);
}
#endif
#ifdef LINUX
FILE *bmOpenFile(char *fname, /* File name */
int *errorcode) /* Error code returned */
{
FILE *fhandle; /* Returned file handle */
fhandle=fopen(fname,"w+");
if(fhandle==NULL)
*errorcode=ERROR_FILEOPEN;
else
*errorcode=0;
return(fhandle);
}
#endif
/****************************
** CloseFile
** Closes the file identified by fhandle.
** A more inocuous routine there never was.
*/
#ifdef DOS16
/*
** DOS VERSION!!!
*/
void CloseFile(int fhandle, /* File handle */
int *errorcode) /* Returned error code */
{
close(fhandle);
*errorcode=0;
return;
}
#endif
#ifdef LINUX
void CloseFile(FILE *fhandle, /* File handle */
int *errorcode) /* Returned error code */
{
fclose(fhandle);
*errorcode=0;
return;
}
#endif
/****************************
** readfile
** Read bytes from an opened file. This routine
** is a combination seek-and-read.
** Note that this routine expects the offset to be from
** the beginning of the file.
*/
#ifdef DOS16
/*
** DOS VERSION!!
*/
void readfile(int fhandle, /* File handle */
unsigned long offset, /* Offset into file */
unsigned long nbytes, /* # of bytes to read */
void *buffer, /* Buffer to read into */
int *errorcode) /* Returned error code */
{
long newoffset; /* New offset by lseek */
int readcode; /* Return code from read */
/*
** Presume success.
*/
*errorcode=0;
/*
** Seek to the proper offset.
*/
newoffset=lseek(fhandle,(long)offset,SEEK_SET);
if(newoffset==-1L)
{ *errorcode=ERROR_FILESEEK;
return;
}
/*
** Do the read.
*/
readcode=read(fhandle,buffer,(unsigned)(nbytes & 0xFFFF));
if(readcode==-1)
*errorcode=ERROR_FILEREAD;
return;
}
#endif
#ifdef LINUX
void readfile(FILE *fhandle, /* File handle */
unsigned long offset, /* Offset into file */
unsigned long nbytes, /* # of bytes to read */
void *buffer, /* Buffer to read into */
int *errorcode) /* Returned error code */
{
long newoffset; /* New offset by fseek */
size_t nelems; /* Expected return code from read */
size_t readcode; /* Actual return code from read */
/*
** Presume success.
*/
*errorcode=0;
/*
** Seek to the proper offset.
*/
newoffset=fseek(fhandle,(long)offset,SEEK_SET);
if(newoffset==-1L)
{ *errorcode=ERROR_FILESEEK;
return;
}
/*
** Do the read.
*/
nelems=(size_t)(nbytes & 0xFFFF);
readcode=fread(buffer,(size_t)1,nelems,fhandle);
if(readcode!=nelems)
*errorcode=ERROR_FILEREAD;
return;
}
#endif
/****************************
** writefile
** writes bytes to an opened file. This routine is
** a combination seek-and-write.
** Note that this routine expects the offset to be from
** the beinning of the file.
*/
#ifdef DOS16
/*
** DOS VERSION!!
*/
void writefile(int fhandle, /* File handle */
unsigned long offset, /* Offset into file */
unsigned long nbytes, /* # of bytes to read */
void *buffer, /* Buffer to read into */
int *errorcode) /* Returned error code */
{
long newoffset; /* New offset by lseek */
int writecode; /* Return code from write */
/*
** Presume success.
*/
*errorcode=0;
/*
** Seek to the proper offset.
*/
newoffset=lseek(fhandle,(long)offset,SEEK_SET);
if(newoffset==-1L)
{ *errorcode=ERROR_FILESEEK;
return;
}
/*
** Do the write.
*/
writecode=write(fhandle,buffer,(unsigned)(nbytes & 0xFFFF));
if(writecode==-1)
*errorcode=ERROR_FILEWRITE;
return;
}
#endif
#ifdef LINUX
void writefile(FILE *fhandle, /* File handle */
unsigned long offset, /* Offset into file */
unsigned long nbytes, /* # of bytes to read */
void *buffer, /* Buffer to read into */
int *errorcode) /* Returned error code */
{
long newoffset; /* New offset by lseek */
size_t nelems; /* Expected return code from write */
size_t writecode; /* Actual return code from write */
/*
** Presume success.
*/
*errorcode=0;
/*
** Seek to the proper offset.
*/
newoffset=fseek(fhandle,(long)offset,SEEK_SET);
if(newoffset==-1L)
{ *errorcode=ERROR_FILESEEK;
return;
}
/*
** Do the write.
*/
nelems=(size_t)(nbytes & 0xFFFF);
writecode=fwrite(buffer,(size_t)1,nelems,fhandle);
if(writecode==nelems)
*errorcode=ERROR_FILEWRITE;
return;
}
#endif
/********************************
** ERROR HANDLING ROUTINES **
********************************/
/****************************
** ReportError
** Report error message condition.
*/
void ReportError(char *errorcontext, /* Error context string */
int errorcode) /* Error code number */
{
/*
** Display error context
*/
printf("ERROR CONDITION\nContext: %s\n",errorcontext);
/*
** Display code
*/
printf("Code: %d",errorcode);
return;
}
/****************************
** ErrorExit
** Peforms an exit from an error condition.
*/
void ErrorExit()
{
/*
** For profiling on the Mac with MetroWerks -- 11/17/94 RG
** Have to do this to turn off profiler.
*/
#ifdef MACCWPROF
#if __profile__
ProfilerTerm();
#endif
#endif
/*
** FOR NOW...SIMPLE EXIT
*/
exit(1);
}
/*****************************
** STOPWATCH ROUTINES **
*****************************/
/****************************
** StartStopwatch
** Starts a software stopwatch. Returns the first value of
** the stopwatch in ticks.
*/
unsigned long StartStopwatch()
{
#ifdef MACTIMEMGR
/*
** For Mac code warrior, use timer. In this case, what we return is really
** a dummy value.
*/
InsTime((QElemPtr)&myTMTask);
PrimeTime((QElemPtr)&myTMTask,-MacHSTdelay);
return((unsigned long)1);
#else
#ifdef WIN31TIMER
/*
** Win 3.x timer returns a DWORD, which we coax into a long.
*/
_Call16(lpfn,"p",&win31tinfo);
return((unsigned long)win31tinfo.dwmsSinceStart);
#else
return((unsigned long)clock());
#endif
#endif
}
/****************************
** StopStopwatch
** Stops the software stopwatch. Expects as an input argument
** the stopwatch start time.
*/
unsigned long StopStopwatch(unsigned long startticks)
{
#ifdef MACTIMEMGR
/*
** For Mac code warrior...ignore startticks. Return val. in microseconds
*/
RmvTime((QElemPtr)&myTMTask);
return((unsigned long)(MacHSTdelay+myTMTask.tmCount-MacHSTohead));
#else
#ifdef WIN31TIMER
_Call16(lpfn,"p",&win31tinfo);
return((unsigned long)win31tinfo.dwmsSinceStart-startticks);
#else
return((unsigned long)clock()-startticks);
#endif
#endif
}
/****************************
** TicksToSecs
** Converts ticks to seconds. Converts ticks to integer
** seconds, discarding any fractional amount.
*/
unsigned long TicksToSecs(unsigned long tickamount)
{
#ifdef CLOCKWCT
return((unsigned long)(tickamount/CLK_TCK));
#endif
#ifdef MACTIMEMGR
/* +++ MAC time manager version (using timer in microseconds) +++ */
return((unsigned long)(tickamount/1000000));
#endif
#ifdef CLOCKWCPS
/* Everybody else */
return((unsigned long)(tickamount/CLOCKS_PER_SEC));
#endif
#ifdef WIN31TIMER
/* Each tick is 840 nanoseconds */
return((unsigned long)(tickamount/1000L));
#endif
}
/****************************
** TicksToFracSecs
** Converts ticks to fractional seconds. In other words,
** this returns the exact conversion from ticks to
** seconds.
*/
double TicksToFracSecs(unsigned long tickamount)
{
#ifdef CLOCKWCT
return((double)tickamount/(double)CLK_TCK);
#endif
#ifdef MACTIMEMGR
/* +++ MAC time manager version +++ */
return((double)tickamount/(double)1000000);
#endif
#ifdef CLOCKWCPS
/* Everybody else */
return((double)tickamount/(double)CLOCKS_PER_SEC);
#endif
#ifdef WIN31TIMER
/* Using 840 nanosecond ticks */
return((double)tickamount/(double)1000);
#endif
}

View File

@ -1,168 +0,0 @@
/*
** sysspec.h
** Header file for sysspec.c
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/*
** Standard includes
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "nmglobal.h"
#if !defined(MAC) && !defined(OSX)
#include <malloc.h>
#endif
/*
** System-specific includes
*/
#ifdef DOS16MEM
#include "dos.h"
#endif
/* #include "time.h"
#include "io.h"
#include "fcntl.h"
#include "sys\stat.h" */
/* Removed for MSVC++
#include "alloc.h"
*/
/*
** MAC Time Manager routines (from Code Warrior)
*/
#ifdef MACTIMEMGR
#include <memory.h>
#include <lowmem.h>
#include <Types.h>
#include <Timer.h>
extern struct TMTask myTMTask;
extern long MacHSTdelay,MacHSTohead;
#endif
/*
** Windows 3.1 timer defines
*/
#ifdef WIN31TIMER
#include <windows.h>
#include <toolhelp.h>
TIMERINFO win31tinfo;
HANDLE hThlp;
FARPROC lpfn;
#endif
/**************
** EXTERNALS **
**************/
extern ulong mem_array[2][MEM_ARRAY_SIZE];
extern int mem_array_ents;
extern int global_align;
/****************************
** FUNCTION PROTOTYPES **
****************************/
farvoid *AllocateMemory(unsigned long nbytes,
int *errorcode);
void FreeMemory(farvoid *mempointer,
int *errorcode);
void MoveMemory( farvoid *destination,
farvoid *source,
unsigned long nbytes);
#ifdef DOS16MEM
void FarDOSmemmove(farvoid *destination,
farvoid *source,
unsigned long nbytes);
#endif
void InitMemArray(void);
int AddMemArray(ulong true_addr, ulong adj_addr);
int RemoveMemArray(ulong adj_addr,ulong *true_addr);
void ReportError(char *context, int errorcode);
void ErrorExit();
void CreateFile(char *filename,
int *errorcode);
#ifdef DOS16
int bmOpenFile(char *fname,
int *errorcode);
void CloseFile(int fhandle,
int *errorcode);
void readfile(int fhandle,
unsigned long offset,
unsigned long nbytes,
void *buffer,
int *errorcode);
void writefile(int fhandle,
unsigned long offset,
unsigned long nbytes,
void *buffer,
int *errorcode);
#endif
#ifdef LINUX
FILE *bmOpenFile(char *fname,
int *errorcode);
void CloseFile(FILE *fhandle,
int *errorcode);
void readfile(FILE *fhandle,
unsigned long offset,
unsigned long nbytes,
void *buffer,
int *errorcode);
void writefile(FILE *fhandle,
unsigned long offset,
unsigned long nbytes,
void *buffer,
int *errorcode);
#endif
unsigned long StartStopwatch();
unsigned long StopStopwatch(unsigned long startticks);
unsigned long TicksToSecs(unsigned long tickamount);
double TicksToFracSecs(unsigned long tickamount);

View File

@ -1,81 +0,0 @@
/*
** wordcat.h
** Word catalog
** BYTEmark (tm)
** BYTE's Native Mode Benchmarks
** Rick Grehan, BYTE Magazine
**
** Creation:
** Revision: 3/95
**
** DISCLAIMER
** The source, executable, and documentation files that comprise
** the BYTEmark benchmarks are made available on an "as is" basis.
** This means that we at BYTE Magazine have made every reasonable
** effort to verify that the there are no errors in the source and
** executable code. We cannot, however, guarantee that the programs
** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
** no claims in regard to the fitness of the source code, executable
** code, and documentation of the BYTEmark.
** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
** of McGraw-Hill cannot be held responsible for any damages resulting
** from the use of this code or the results obtained from using
** this code.
*/
/*
** Word catalog
*/
#define WORDCATSIZE 50
char *wordcatarray[WORDCATSIZE] =
{ "Hello",
"He",
"Him",
"the",
"this",
"that",
"though",
"rough",
"cough",
"obviously",
"But",
"but",
"bye",
"begin",
"beginning",
"beginnings",
"of",
"our",
"ourselves",
"yourselves",
"to",
"together",
"togetherness",
"from",
"either",
"I",
"A",
"return",
"However",
"that",
"example",
"yet",
"quickly",
"all",
"if",
"were",
"includes",
"always",
"never",
"not",
"small",
"returns",
"set",
"basic",
"Entered",
"with",
"used",
"shown",
"you",
"know" };

View File

@ -1,2 +0,0 @@
Mark Wielaard <mark@klomp.org>
Elizabeth Fong <elizabeth@threerings.net>

View File

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,487 +0,0 @@
2003-06-27 14:24 Mark Wielaard <mark@klomp.org>
* README: Update version number and explain new features.
2003-06-27 13:51 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/GnomeInfoWindow.java,
org/klomp/snark/GnomePeerList.java,
org/klomp/snark/PeerCoordinator.java,
org/klomp/snark/SnarkGnome.java: Add GnomeInfoWindow.
2003-06-27 00:37 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Implement 'info' and 'list' commands.
2003-06-27 00:05 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/GnomePeerList.java,
org/klomp/snark/SnarkGnome.java: Add GnomePeerList to show state of
connected peers.
2003-06-27 00:04 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Peer.java, PeerID.java: Make Comparable.
2003-06-23 23:32 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerMonitorTask.java: Correctly update
lastDownloaded and lastUploaded.
2003-06-23 23:20 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: When checking storage use the
MetaInfo from the storage.
2003-06-23 21:47 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Storage.java: Fill piece hashes, not info hashes.
2003-06-23 21:42 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/MetaInfo.java: New package private
getPieceHashes() method.
2003-06-22 19:49 Mark Wielaard <mark@klomp.org>
* README, TODO, org/klomp/snark/Snark.java: Add new command line
switch --no-commands. Don't read interactive commands or show
usage info.
2003-06-22 19:26 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/PeerCheckerTask.java,
org/klomp/snark/PeerMonitorTask.java, org/klomp/snark/Snark.java:
Split peer statistic reporting from PeerCheckerTask into
PeerMonitorTask. Use new task in Snark text ui.
2003-06-22 18:32 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Only print peer id when debug level
is INFO or higher.
2003-06-22 18:00 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/ShutdownListener.java: Add new ShutdownListener
interface.
2003-06-22 17:18 Mark Wielaard <mark@klomp.org>
* TODO: Text UI item to not read from stdin.
2003-06-22 17:18 Mark Wielaard <mark@klomp.org>
* snark-gnome.sh: kaffe java-gnome support (but crashes hard at the
moment).
2003-06-22 14:04 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/CoordinatorListener.java,
org/klomp/snark/PeerCoordinator.java,
org/klomp/snark/ProgressListener.java, org/klomp/snark/Snark.java,
org/klomp/snark/SnarkGnome.java,
org/klomp/snark/SnarkShutdown.java, org/klomp/snark/Storage.java,
org/klomp/snark/StorageListener.java: Split ProgressListener into
Storage, Coordinator and Shutdown listener.
2003-06-20 19:06 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerCoordinator.java, Snark.java,
SnarkGnome.java, Storage.java: Progress listeners for both Storage
and PeerCoordinator.
2003-06-20 14:50 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/PeerCoordinator.java,
org/klomp/snark/ProgressListener.java,
org/klomp/snark/SnarkGnome.java: Add ProgressListener.
2003-06-20 13:22 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/SnarkGnome.java: Add Pieces collected field.
2003-06-20 12:26 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerCoordinator.java, PeerListener.java,
PeerState.java: Add PeerListener.downloaded() which gets called on
chunk updates. Keep PeerCoordinator.downloaded up to date using
this remove adjusting in gotPiece() except when we receive a bad
piece.
2003-06-16 00:27 Mark Wielaard <mark@klomp.org>
* Makefile, snark-gnome.sh, org/klomp/snark/Snark.java,
org/klomp/snark/SnarkGnome.java: Start of a Gnome GUI.
2003-06-05 13:19 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerCoordinator.java: Don't remove a BAD piece
from the wantedPieces list. Revert to synchronizing on
wantedPieces for all relevant sections.
2003-06-03 21:09 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Only call readLine() when !quit.
Always print exception when fatal() is called.
2003-06-01 23:12 Mark Wielaard <mark@klomp.org>
* README: Set release version to 0.4.
2003-06-01 22:59 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionIn.java: Handle negative length
prefixes (terminates connection).
2003-06-01 21:34 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Snark.java, SnarkShutdown.java: Implement
correct shutdown and read commands from stdin.
2003-06-01 21:34 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/TrackerInfo.java: Check that interval and peers
list actually exist.
2003-06-01 21:33 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Storage.java: Implement close().
2003-06-01 21:05 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Fix debug logging.
2003-06-01 20:55 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerCoordinator.java: Implement halt().
2003-06-01 20:55 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/ConnectionAcceptor.java: Rename stop() to halt().
2003-06-01 17:35 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Drop lock on this when calling
addRequest() from havePiece().
2003-06-01 14:46 Mark Wielaard <mark@klomp.org>
* README, org/klomp/snark/ConnectionAcceptor.java,
org/klomp/snark/HttpAcceptor.java, org/klomp/snark/Peer.java,
org/klomp/snark/PeerCheckerTask.java,
org/klomp/snark/PeerConnectionIn.java,
org/klomp/snark/PeerConnectionOut.java,
org/klomp/snark/PeerCoordinator.java,
org/klomp/snark/PeerState.java, org/klomp/snark/Snark.java,
org/klomp/snark/SnarkShutdown.java, org/klomp/snark/Storage.java,
org/klomp/snark/Tracker.java, org/klomp/snark/TrackerClient.java:
Add debug/log level.
2003-05-31 23:04 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerCheckerTask.java, PeerCoordinator.java: Use
just one lock (peers) for all synchronization (even for
wantedPieces). Let PeerChecker handle real disconnect and keep
count of uploaders.
2003-05-31 22:29 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Peer.java, PeerConnectionIn.java: Set state to
null on first disconnect() call. So always check whether it might
already be null. Helps disconnect check.
2003-05-31 22:27 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Don't explicitly close
the DataOutputStream (if another thread is using it libgcj seems to
not like it very much).
2003-05-30 21:33 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Cancel
(un)interested/(un)choke when (inverse) is still in send queue.
Remove pieces from send queue when choke message is actaully send.
2003-05-30 19:32 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Make sure listener.wantPiece(int)
is never called while lock on this is held.
2003-05-30 19:00 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Indentation cleanup.
2003-05-30 17:50 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Storage.java: Only synchronize on bitfield as
long as necessary.
2003-05-30 17:43 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Tracker.java: Identing cleanup.
2003-05-30 16:32 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Better error message.
2003-05-30 15:11 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Make sure not to hold the lock on
this when calling the listener to prevent deadlocks. Implement
handling and sending of cancel messages.
2003-05-30 14:50 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerCoordinator.java: First check if we still
want a piece before trying to add it to the Storage.
2003-05-30 14:49 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Implement
sendCancel(Request). Add cancelRequest(int, int, int).
2003-05-30 14:46 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Request.java: Add hashCode() and equals(Object)
methods.
2003-05-30 14:45 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Peer.java: Fix wheter -> whether javadoc
comments. Mark state null immediatly after calling
listener.disconnected(). Call PeerState.havePiece() not
PeerConnectionOut.sendHave() directly.
2003-05-25 19:23 Mark Wielaard <mark@klomp.org>
* TODO: Add PeerCoordinator TODO for connecting to seeds.
2003-05-23 12:12 Mark Wielaard <mark@klomp.org>
* Makefile: Create class files with jikes again.
2003-05-18 22:01 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerCheckerTask.java, PeerCoordinator.java:
Prefer to (optimistically) unchoke first those peers that unchoked
us. And make sure to not unchoke a peer that we just choked.
2003-05-18 21:48 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Peer.java: Fix isChoked() to not always return
true.
2003-05-18 14:46 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Peer.java, PeerCheckerTask.java,
PeerCoordinator.java, PeerState.java: Remove separate Peer
downloading/uploading states. Keep choke and interest always up to
date. Uploading is now just when we are not choking the peer.
Downloading is now defined as being unchoked and interesting.
CHECK_PERIOD is now 20 seconds. MAX_CONNECTIONS is now 24.
MAX_DOWNLOADERS doesn't exists anymore. We download whenever we can
from peers.
2003-05-18 13:57 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Remove piece messages
from queue when we are choking. (They will have to be rerequested
when we unchoke the peer again.)
2003-05-15 00:08 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Ignore missed chunk requests,
don't requeue them.
2003-05-15 00:06 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Request.java: Add sanity check
2003-05-10 15:47 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Add extra '(' to usage message.
2003-05-10 15:22 Mark Wielaard <mark@klomp.org>
* README: Set version to 0.3 (The Bakers Tale).
2003-05-10 15:17 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Mention received piece in warning
message.
2003-05-10 03:20 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerConnectionIn.java, PeerState.java,
Request.java: Remove currentRequest and handle all piece messages
from the lastRequested list.
2003-05-09 20:02 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Fix nothing requested warning
message.
2003-05-09 19:59 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionOut.java: Piece messages are big.
So if there are other (control) messages make sure they are send
first. Also remove request messages from the queue if we are
currently being choked to prevent them from being send even if we
get unchoked a little later. (Since we will resent them anyway in
that case.)
2003-05-09 18:33 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Peer.java, PeerCheckerTask.java,
PeerCoordinator.java, PeerID.java: New definition of PeerID.equals
(port + address + id) and new method PeerID.sameID (only id). These
are used to really see if we already have a connection to a certain
peer (active setup vs passive setup).
2003-05-08 03:05 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Use Snark.debug() not
System.out.println().
2003-05-06 20:29 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: s/noting/nothing/
2003-05-06 20:28 Mark Wielaard <mark@klomp.org>
* Makefile: s/lagacy/legacy/
2003-05-05 23:17 Mark Wielaard <mark@klomp.org>
* README: Set version to 0.2, explain new functionality and add
examples.
2003-05-05 22:42 Mark Wielaard <mark@klomp.org>
* .cvsignore, Makefile, org/klomp/snark/StaticSnark.java: Enable
-static binary creation.
2003-05-05 22:42 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Tracker.java: Disable --ip support.
2003-05-05 21:02 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: HttpAcceptor.java, PeerCheckerTask.java,
PeerCoordinator.java, TrackerClient.java: Use Snark.debug() not
System.out.println().
2003-05-05 21:01 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerConnectionIn.java: Be prepared to handle the
case where currentRequest is null.
2003-05-05 21:00 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Improve argument parsing errors.
2003-05-05 21:00 Mark Wielaard <mark@klomp.org>
* Makefile: Use gcj -C again for creating the class files.
2003-05-05 09:24 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Just clear outstandingRequests,
never make it null.
2003-05-05 02:55 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/TrackerClient.java: Always retry both first
started event and every other event as long the TrackerClient is
not stopped.
2003-05-05 02:54 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Remove double assignment port.
2003-05-05 02:54 Mark Wielaard <mark@klomp.org>
* TODO: Add Tracker TODO item.
2003-05-04 23:38 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: ConnectionAcceptor.java, MetaInfo.java,
Snark.java, Storage.java, Tracker.java: Add info hash calcultation
to MetaInfo. Add torrent creation to Storage. Add ip parameter
handling to Tracker. Make ConnectionAcceptor handle
null/non-existing HttpAcceptors. Add debug output, --ip handling
and all the above to Snark.
2003-05-04 23:36 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/TrackerClient.java: Handle all failing requests
the same (print a warning).
2003-05-03 15:46 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: Peer.java, PeerID.java, TrackerInfo.java: Split
Peer and PeerID a little more.
2003-05-03 15:44 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/MetaInfo.java: Add reannounce() and
getTorrentData().
2003-05-03 15:38 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/: PeerCheckerTask.java, PeerCoordinator.java:
More concise verbose/debug output. Always use addUpDownloader() to
set peers upload or download state to true.
2003-05-03 13:38 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/TrackerClient.java: Compile fixes.
2003-05-03 13:32 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/TrackerClient.java: Only generate fatal() call on
first Tracker access. Otherwise just print a warning error message.
2003-05-03 03:10 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerState.java: Better handle resending
outstanding pieces and try to recover better from unrequested
pieces.
2003-05-02 21:33 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/HttpAcceptor.java,
org/klomp/snark/MetaInfo.java, org/klomp/snark/PeerID.java,
org/klomp/snark/Snark.java, org/klomp/snark/Tracker.java,
org/klomp/snark/TrackerClient.java,
org/klomp/snark/bencode/BEncoder.java: Add Tracker, PeerID and
BEncoder.
2003-05-01 20:17 Mark Wielaard <mark@klomp.org>
* Makefile, org/klomp/snark/ConnectionAcceptor.java,
org/klomp/snark/HttpAcceptor.java, org/klomp/snark/Peer.java,
org/klomp/snark/PeerAcceptor.java, org/klomp/snark/Snark.java: Add
ConnectionAcceptor that handles both PeerAcceptor and HttpAcceptor.
2003-05-01 18:39 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/PeerCoordinator.java: connected() synchronize on
peers.
2003-04-28 02:56 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/SnarkShutdown.java: Wait some time before
returning...
2003-04-28 02:56 Mark Wielaard <mark@klomp.org>
* TODO: More items.
2003-04-28 02:56 Mark Wielaard <mark@klomp.org>
* org/klomp/snark/Snark.java: Calculate real random ID.
2003-04-27 Mark Wielaard <mark@klomp.org>
* snark: Initial (0.1) version.

View File

@ -1,85 +0,0 @@
# Simple Makefile for creating a native binary and a legacy jar file with gcj.
GCJ=gcj
GCJ_FLAGS=-g -O2
#JAVAC=$(GCJ) -C
#JAVAC_FLAGS=$(GCJ_FLAGS)
JAVAC=jikes-classpath
JAVAC_FLAGS=-g -O -source 1.5
JAR=fastjar
PROGRAM=snark
MAINCLASS=org.klomp.snark.Snark
SOURCES= \
org/klomp/snark/BitField.java \
org/klomp/snark/ConnectionAcceptor.java \
org/klomp/snark/CoordinatorListener.java \
org/klomp/snark/HttpAcceptor.java \
org/klomp/snark/MetaInfo.java \
org/klomp/snark/Message.java \
org/klomp/snark/Peer.java \
org/klomp/snark/PeerID.java \
org/klomp/snark/PeerAcceptor.java \
org/klomp/snark/PeerCheckerTask.java \
org/klomp/snark/PeerConnectionIn.java \
org/klomp/snark/PeerConnectionOut.java \
org/klomp/snark/PeerListener.java \
org/klomp/snark/PeerMonitorTask.java \
org/klomp/snark/PeerCoordinator.java \
org/klomp/snark/PeerState.java \
org/klomp/snark/Request.java \
org/klomp/snark/Snark.java \
org/klomp/snark/SnarkShutdown.java \
org/klomp/snark/ShutdownListener.java \
org/klomp/snark/Storage.java \
org/klomp/snark/StorageListener.java \
org/klomp/snark/Tracker.java \
org/klomp/snark/TrackerClient.java \
org/klomp/snark/TrackerInfo.java \
org/klomp/snark/bencode/BEValue.java \
org/klomp/snark/bencode/BEncoder.java \
org/klomp/snark/bencode/BDecoder.java \
org/klomp/snark/bencode/InvalidBEncodingException.java
STATIC_SOURCES=$(SOURCES) org/klomp/snark/StaticSnark.java
STATIC_MAINCLASS=org.klomp.snark.StaticSnark
GNOME_SOURCES=$(SOURCES) org/klomp/snark/SnarkGnome.java \
org/klomp/snark/GnomeInfoWindow.java \
org/klomp/snark/GnomePeerList.java
GNOME_MAINCLASS=org.klomp.snark.SnarkGnome
$(PROGRAM): $(SOURCES)
$(GCJ) $(GCJ_FLAGS) --main=$(MAINCLASS) -o $(PROGRAM) $(SOURCES)
$(PROGRAM)-static: $(STATIC_SOURCES)
$(GCJ) $(GCJ_FLAGS) -static --main=$(STATIC_MAINCLASS) \
-o $(PROGRAM)-static $(STATIC_SOURCES)
$(PROGRAM)-gnome: $(GNOME-SOURCES)
$(JAVAC) $(JAVAC_FLAGS) \
-classpath /usr/share/java/gtk2.8.jar:/usr/share/java/gnome2.12.jar \
-d dist/classes $(GNOME_SOURCES)
$(PROGRAM).jar: $(PROGRAM)-classes Manifest
$(JAR) cfm $(PROGRAM).jar Manifest -C dist/classes/ .
Manifest:
echo "Main-Class: $(MAINCLASS)" > Manifest
classes:
mkdir dist
mkdir dist/classes
$(PROGRAM)-classes: classes $(SOURCES)
$(JAVAC) $(JAVAC_FLAGS) -d dist/classes $(SOURCES)
all: $(PROGRAM) $(PROGRAM)-static $(PROGRAM).jar
clean:
rm -rf dist Manifest $(PROGRAM) $(PROGRAM)-static $(PROGRAM).jar
.PHONY : all clean $(PROGRAM)-classes

View File

@ -1,141 +0,0 @@
The Hunting of the Snark Project - BitTorrent Application Suite
0.5 - The Beaver's Lesson (27 June 2003)
"It's a Snark!" was the sound that first came to their ears,
And seemed almost too good to be true.
Then followed a torrent of laughter and cheers:
Then the ominous words "It's a Boo-"
-- from The Hunting Of The Snark by Lewis Carroll
Snark is a client for downloading and sharing files distributed with
the BitTorrent protocol. It is mainly used for exploring the BitTorrent
protocol and experimenting with the the GNU Compiler for Java (gcj).
But it can also be used as a regular BitTorrent Client.
Snark can also act as a torrent creator, micro http server for delivering
metainfo.torrent files and has an integrated Tracker for making sharing of
files as easy as possible.
When you give the option --share Snark will automatically
create a .torrent file, start a very simple webserver to distribute
the metainfo.torrent file and a local tracker that other BitTorrent
clients can connect to.
Distribution
------------
Copyright (C) 2003 Mark J. Wielaard
Snark is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Requirements/Installation
-------------------------
The GNU Compiler for java (gcj) version 3.3 or later.
(Earlier versions have a faulty SHA message digest implementation.)
On Debian GNU/Linux based distributions just install the gcj-3.3 package.
Edit the GCJ variable in the Makefile if your gcj binary is not gcj-3.3.
Typing 'make' will create the native snark binary and a snark.jar file
for use with traditional java byte code interpreters.
It is possible to compile the sources with other java compilers
like jikes or kjc to produce the snark.jar file. Edit the JAVAC and
JAVAC_FLAGS variables on top of the Makefile for this. And type
'make snark.jar' to create a jar file that can be used by traditional
java bytecode interpreters like kaffe: 'kaffe -jar snark.jar'.
You will need at least version 1.1 of kaffe for all functionality to work
correctly ('--share' does not work with older versions).
When trying out the experimental Gnome frontend you also need the java-gnome
bindings. On Debian GNU/Linux systems install the package libgnome0-java.
You can try it out by typing 'make snark-gnome' and then run 'snark-gnome.sh'
like you would with the normal command line client.
Running
-------
To use the program start it with:
snark [--debug [level]] [--no-commands] [--port <port>]
[--share (<ip>|<host>)] (<url>|<file>|<dir>)
--debug Shows some extra info and stacktraces.
level How much debug details to show
(defaults to 3, with --debug to 4, highest level is 6).
--no-commands Don't read interactive commands or show usage info.
--port The port to listen on for incomming connections
(if not given defaults to first free port between 6881-6889).
--share Start torrent tracker on <ip> address or <host> name.
<url> URL pointing to .torrent metainfo file to download/share.
<file> Either a local .torrent metainfo file to download
or (with --share) a file to share.
<dir> A directory with files to share (needs --share).
Since this is an early beta release there are probably still some bugs
in the program. To help find them run the program with the --debug
option which shows more information on what it going on. You can also give
the level of debug output you want. Zero will give (almost) no output at all.
Everything above debug level 4 is probably to much (only really useful to
see what goes on on the protocol/network level).
Examples
- To simple start downloading/sharing a file.
Either download the .torrent file to disk and start snark with:
./snark somefile.torrent
Or give it the complete URL:
./snark http://somehost.example.com/cd-images/bbc-lnx.iso.torrent
- To start seeding/sharing a local file:
./snark --share my-host.example.com some-file
Snark will respond with:
Listening on port: 6881
Trying to create metainfo torrent for 'some-file'
Creating torrent piece hashes: ++++++++++
Torrent available on http://my-host.example.com:6881/metainfo.torrent
You can now point other people to the above URL so they can share
the file with their own BitTorrent client.
Commands
While the program is running in text mode you can currently give the
following commands: 'info', 'list' and 'quit'.
Interactive commands are disabled when the '--no-commands' flag is given.
This is sometimes desireable for running snark in the background.
More information
----------------
- The Evolution of Cooperation - Robert Axelrod
ISBN 0-465-02121-2
- The BitTorrent protocol description:
<http://bitconjurer.org/BitTorrent/protocol.html>
- The GNU Compiler for Java (gcj):
<http://gcc.gnu.org/java/>
- java-gnome bindings : <http://java-gnome.sourceforge.net/>
- The Hunting of the Snark - Lewis Carroll
Comments welcome
- Mark Wielaard <mark@klomp.org>

22
thirdparty/snark/TODO vendored
View File

@ -1,22 +0,0 @@
- BEncode
- Byte array length indicator can overflow.
- Support really big BigNums (only 256 chars allowed now)
- Better BEValue toString(). Uses stupid heuristic now for debugging.
- Implemented bencoding.
- Remove application level hack to calculate sha1 hash for metainfo
(But can it be done as efficiently?)
- Storage
- Check file name filter.
- TrackerClient
- Support undocumented &numwant= request.
- Tracker
- Dispose of peers after some time.
- PeerCoordinator
- Disconnect from other seeds as soon as you are a seed yourself.
- Text UI
- Make it completely silent.

View File

@ -1,214 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<!-- build configuration -->
<project name="snark" default="compile" basedir=".">
<!-- import overriding properties -->
<property file="build.properties"/>
<!-- configuration parameters -->
<property name="app.name" value="snark"/>
<property name="deploy.dir" value="dist"/>
<property name="savedoc.dir" value="docs"/>
<property name="lib.version" value="0.6"/>
<!-- derived properties -->
<property name="javadoc.home" value="${deploy.dir}/docs"/>
<property name="classes.dir" value="${deploy.dir}/classes"/>
<!-- import the library dependencies -->
<property name="libs.dir" value="../../dist/lib"/>
<import file="libs-incl.xml"/>
<!-- declare our classpath business -->
<path id="classpath">
<pathelement location="${classes.dir}"/>
<fileset dir="${deploy.dir}/lib" includes="*.jar"/>
</path>
<!-- checks to see which packages are available -->
<target name="check-available">
<echo level="info" message="The packages required for building are listed below."/>
<echo level="info" message="A package followed by 'true' indicates that the package"/>
<echo level="info" message="is present. One followed by '${package.present}' indicates"/>
<echo level="info" message="that it was not found. Jar files can be placed into the"/>
<echo level="info" message="lib/ directory or placed in the directory referenced"/>
<echo level="info" message="by your JAVA_LIBS environment variable."/>
<echo level="info" message=""/>
<echo level="info" message="------------------------------------------"/>
<echo level="info" message="GTK+ libraries - http://java-gnome.sourceforge.net/"/>
<echo level="info" message="------------------------------------------"/>
<available property="glib.present"
classname="org.gnu.glib.GObject" classpathref="classpath"/>
<echo level="info" message="GLib: ${glib.present}"/>
<available property="gtk+.present"
classname="org.gnu.gtk.Gtk" classpathref="classpath"/>
<echo level="info" message="GTK+: ${gtk+.present}"/>
<available property="gnome.present"
classname="org.gnu.gnome.App" classpathref="classpath"/>
<echo level="info" message="GNOME: ${gnome.present}"/>
</target>
<!-- combines package availability into build controls -->
<target name="compute-builds" depends="check-available">
<echo level="info" message="The packages that will be built are listed below. One"/>
<echo level="info" message="followed by 'true' indicates that it will be built. One"/>
<echo level="info" message="followed by '${build.package}' indicates that it will"/>
<echo level="info" message="not be built. If a package is not being built, one or"/>
<echo level="info" message="more of its dependencies could not be located."/>
<condition property="build.interface.gtk">
<and>
<isset property="glib.present"/>
<isset property="gtk+.present"/>
<isset property="gnome.present"/>
</and>
</condition>
<echo level="info" message="org.klomp.snark.gtk: ${build.interface.gtk}"/>
</target>
<!-- prepares the application directories -->
<target name="prepare">
<mkdir dir="${deploy.dir}"/>
<mkdir dir="${deploy.dir}/lib"/>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${javadoc.home}"/>
<copy todir="${classes.dir}">
<fileset dir="src/java" includes="**/*.properties"/>
<fileset dir="src/java" includes="**/*.tmpl"/>
</copy>
<copy todir="${deploy.dir}/lib">
<fileset dir="lib" includes="**/*.jar"/>
</copy>
<copy todir="${deploy.dir}/lib" flatten="true">
<fileset refid="${app.name}.libs"/>
</copy>
</target>
<!-- cleans out the intermediate build files -->
<target name="clean">
<delete dir="${deploy.dir}/classes"/>
<delete dir="${deploy.dir}/docs"/>
</target>
<!-- wipes the entire build directory clean -->
<target name="distclean" depends="clean">
<delete dir="${deploy.dir}"/>
</target>
<!-- build the java class files -->
<target name="compile" depends="prepare,compute-builds">
<javac srcdir="src/java" destdir="${classes.dir}"
debug="on" optimize="{$build.optimize}" deprecation="on"
source="1.5" target="1.5">
<classpath refid="classpath"/>
<exclude name="org/klomp/snark/gtk/**" unless="build.interface.gtk"/>
<compilerarg value="-Xlint:unchecked"/>
</javac>
</target>
<!-- build the javadoc documentation -->
<target name="javadoc" depends="prepare,compute-builds">
<javadoc sourcepath="src/java" packagenames="org.klomp.*"
destdir="${javadoc.home}" stylesheetfile="docs/stylesheet.css"
additionalparam="-breakiterator"
link="http://www.threerings.net/code/snark/snark/docs/api">
<classpath refid="classpath"/>
<link href="http://java.sun.com/j2se/1.5/docs/api/"/>
</javadoc>
</target>
<!-- builds the javadocs and stuffs them in a directory where they -->
<!-- won't be blown away when we do "clean" next time -->
<target name="savedoc" depends="javadoc">
<delete dir="${savedoc.dir}/api"/>
<copy todir="${savedoc.dir}/api">
<fileset dir="${javadoc.home}" includes="**/*"/>
</copy>
</target>
<!-- a target for rebuilding everything -->
<target name="all"
depends="clean,prepare,compile,javadoc,dist"/>
<!-- builds our distribution files (war and jar) -->
<target name="dist" depends="prepare,compile">
<!-- build our various jar files -->
<jar destfile="${deploy.dir}/${app.name}.jar" manifest="lib/manifest.mf">
<fileset dir="${classes.dir}" includes="org/klomp/**"
excludes="org/klomp/snark/gtk/**"/>
</jar>
<jar destfile="${deploy.dir}/${app.name}-gtk.jar"
manifest="lib/manifest-gtk.mf">
<fileset dir="${classes.dir}" includes="org/klomp/**"/>
</jar>
</target>
<!-- Uses gcj to prepare a native binary -->
<target name="ndist" depends="dist">
<exec dir="${deploy.dir}" executable="gcj">
<arg line="-classpath" />
<arg pathref="classpath" />
<arg line="-o snark" />
<arg line="--main=org.klomp.snark.cmd.SnarkApplication" />
<arg line="snark.jar"/>
</exec>
</target>
<!-- a helper task for 'retro' -->
<target name="vweave">
<!-- various bits used by the retroweaver tasks -->
<taskdef name="weave" classpathref="classpath"
classname="com.rc.retroweaver.ant.RetroWeaverTask"/>
<property name="inpre" value="${deploy.dir}/${app.name}"/>
<property name="outpre" value="${deploy.dir}/retro/${app.name}"/>
<path id="retrocp">
<pathelement location="/usr/local/jdk1.4/jre/lib/rt.jar"/>
<fileset dir="lib" includes="**/*.jar"/>
<fileset dir="${deploy.dir}/retro" includes="*.jar"/>
</path>
<weave inputjar="${inpre}-${which}.jar" outputjar="${outpre}-${which}.jar"
failonerror="true">
<classpath refid="retrocp"/>
</weave>
</target>
<!-- converts our 1.5 code to a 1.4 compatible format -->
<target name="retro" depends="dist">
<mkdir dir="${deploy.dir}/retro"/>
<!-- we weave everything a first time without verification so that -->
<!-- interdependencies will resolve the second time -->
<weave inputjar="${inpre}-base.jar" outputjar="${outpre}-base.jar"/>
<weave inputjar="${inpre}-distrib.jar" outputjar="${outpre}-distrib.jar"/>
<!-- now weave again with the verifier to check for unweavable 1.5isms -->
<antcall target="vweave"><param name="which" value="base"/></antcall>
<antcall target="vweave"><param name="which" value="distrib"/></antcall>
</target>
<!-- creates a tarball and zipfile for source distribution -->
<target name="distrib">
<echo level="info" message="You may want to stop and run 'ant savedoc' first."/>
<echo level="info" message="Building ${lib.version} tar.gz distribution..."/>
<tar destfile="snark-${lib.version}.tar.gz" compression="gzip">
<tarfileset dir=".." mode="0664" dirmode="0775">
<include name="snark/**"/>
<exclude name="snark/dist/**"/>
<exclude name="snark/code/**"/>
<exclude name="snark/snark-*.*"/>
</tarfileset>
</tar>
<echo level="info" message="Building ${lib.version} zip distribution..."/>
<zip destfile="narya-${lib.version}.zip">
<fileset dir="..">
<include name="snark/**"/>
<exclude name="snark/dist/**"/>
<exclude name="snark/code/**"/>
<exclude name="snark/snark-*.*"/>
</fileset>
</zip>
</target>
</project>

View File

@ -1,4 +0,0 @@
gtk2.8.jar
gnome2.12.jar
glib0.2.jar
retroweaver-all-1.2.2.jar

View File

@ -1 +0,0 @@
Main-Class: org.klomp.snark.gtk.SnarkGnome

View File

@ -1 +0,0 @@
Main-Class: org.klomp.snark.cmd.SnarkApplication

View File

@ -1,7 +0,0 @@
<?xml version="1.0"?>
<!-- declare the libraries needed to build the snark project -->
<project name="library-dependencies">
<fileset dir="${libs.dir}" id="snark.libs">
<include name="retroweaver-all-1.2.2.jar"/>
</fileset>
</project>

View File

@ -1,8 +0,0 @@
#/bin/sh
#JAVA=kaffe
JAVA=gij
CLASSPATH=classes:/usr/share/java/gtk.jar:/usr/share/java/gnome.jar
MAINCLASS=org.klomp.snark.SnarkGnome
${JAVA} -classpath ${CLASSPATH} ${MAINCLASS} $*

View File

@ -1,143 +0,0 @@
/*
* BitField - Container of a byte array representing set and unset bits.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Container of a byte array representing set and unset bits.
*/
public class BitField
{
private final byte[] bitfield;
private final int size;
/**
* Creates a new BitField that represents <code>size</code> unset bits.
*/
public BitField (int size)
{
this.size = size;
int arraysize = ((size - 1) / 8) + 1;
bitfield = new byte[arraysize];
}
/**
* Creates a new BitField that represents <code>size</code> bits as set by
* the given byte array. This will make a copy of the array. Extra bytes
* will be ignored.
*
* @exception ArrayOutOfBoundsException
* if give byte array is not large enough.
*/
public BitField (byte[] bitfield, int size)
{
this.size = size;
int arraysize = ((size - 1) / 8) + 1;
this.bitfield = new byte[arraysize];
// XXX - More correct would be to check that unused bits are
// cleared or clear them explicitly ourselves.
System.arraycopy(bitfield, 0, this.bitfield, 0, arraysize);
}
/**
* This returns the actual byte array used. Changes to this array effect
* this BitField. Note that some bits at the end of the byte array are
* supposed to be always unset if they represent bits bigger then the size
* of the bitfield.
*/
public byte[] getFieldBytes ()
{
return bitfield;
}
/**
* Return the size of the BitField. The returned value is one bigger then
* the last valid bit number (since bit numbers are counted from zero).
*/
public int size ()
{
return size;
}
/**
* Sets the given bit to true.
*
* @exception IndexOutOfBoundsException
* if bit is smaller then zero bigger then size (inclusive).
*/
public void set (int bit)
{
if (bit < 0 || bit >= size) {
throw new IndexOutOfBoundsException(Integer.toString(bit));
}
int index = bit / 8;
int mask = 128 >> (bit % 8);
bitfield[index] |= mask;
}
/**
* Return true if the bit is set or false if it is not.
*
* @exception IndexOutOfBoundsException
* if bit is smaller then zero bigger then size (inclusive).
*/
public boolean get (int bit)
{
if (bit < 0 || bit >= size) {
throw new IndexOutOfBoundsException(Integer.toString(bit));
}
int index = bit / 8;
int mask = 128 >> (bit % 8);
return (bitfield[index] & mask) != 0;
}
@Override
public String toString ()
{
// Not very efficient
StringBuffer sb = new StringBuffer("BitField[");
for (int i = 0; i < size; i++) {
if (get(i)) {
sb.append(' ');
sb.append(i);
}
}
sb.append(" ]");
return sb.toString();
}
public String getHumanReadable()
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < size; i++) {
if (get(i)) {
sb.append('+');
} else {
sb.append('-');
}
}
return sb.toString();
}
}

View File

@ -1,146 +0,0 @@
/*
* ConnectionAcceptor - Accepts connections and routes them to sub-acceptors.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Accepts connections on a TCP port and routes them to sub-acceptors.
*/
public class ConnectionAcceptor implements Runnable
{
private final ServerSocket serverSocket;
private final HttpAcceptor httpacceptor;
private final PeerAcceptor peeracceptor;
private Thread thread;
private boolean stop;
public ConnectionAcceptor (ServerSocket serverSocket,
HttpAcceptor httpacceptor, PeerAcceptor peeracceptor)
{
this.serverSocket = serverSocket;
this.httpacceptor = httpacceptor;
this.peeracceptor = peeracceptor;
stop = false;
}
public void start ()
{
thread = new Thread(this);
thread.start();
}
public void halt ()
{
stop = true;
ServerSocket ss = serverSocket;
if (ss != null) {
try {
ss.close();
} catch (IOException ioe) {
}
}
Thread t = thread;
if (t != null) {
t.interrupt();
}
}
public int getPort ()
{
return serverSocket.getLocalPort();
}
public void run ()
{
while (!stop) {
try {
final Socket socket = serverSocket.accept();
Thread t = new Thread("Connection-" + socket) {
@Override
public void run ()
{
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(
in);
BufferedOutputStream bos = new BufferedOutputStream(
out);
// See what kind of connection it is.
if (httpacceptor != null) {
byte[] scratch = new byte[4];
bis.mark(4);
for (int len = 0; len < 4; len++) {
scratch[len++] = (byte)bis.read();
}
bis.reset();
if (scratch[0] == 19 && scratch[1] == 'B'
&& scratch[2] == 'i' && scratch[3] == 't') {
peeracceptor.connection(socket, bis, bos);
} else if (scratch[0] == 'G'
&& scratch[1] == 'E' && scratch[2] == 'T'
&& scratch[3] == ' ') {
httpacceptor.connection(socket, bis, bos);
}
} else {
peeracceptor.connection(socket, bis, bos);
}
} catch (IOException ioe) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
};
t.start();
} catch (IOException ioe) {
log.log(Level.SEVERE, "Error while accepting", ioe);
stop = true;
}
}
try {
serverSocket.close();
} catch (IOException ignored) {
}
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.server");
}

View File

@ -1,33 +0,0 @@
/*
* CoordinatorListener.java - Callback when a peer changes state
*
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Callback used when some peer changes state.
*/
public interface CoordinatorListener
{
/**
* Called when the PeerCoordinator notices a change in the state of a peer.
*/
void peerChange (PeerCoordinator coordinator, Peer peer);
}

View File

@ -1,245 +0,0 @@
/*
* HttpAcceptor - Accepts incomming http connections. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HttpAcceptor
{
private static final String SNARKHTML = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\""
+ "\"http://www.w3.org/TR/html4/loose.dtd\">"
+ "<html>"
+ "<head><title>Snark Client</title></head>"
+ "<body>"
+ "<h1>Snark Client</h1>"
+ "<p>Snark is a client for downloading and sharing files distributed with the BitTorrent protocol. It is not a normal webserver.</p>"
+ "<p><a href=\"announce\">Tracker</a></p>"
+ "<hr><p>For more info see <a href=\"http://www.klomp.org/snark/\">The Hunting of the Snark Project</a></p>"
+ "</body>" + "</html>";
private static final byte[] SNARKPAGE;
private static final String ASCII = "US-ASCII";
private static final byte[] CRLF = new byte[] { '\r', '\n' };
private static final byte[] HTTP_STATUS;
private static final byte[] CONTENT_LENGTH;
private static final byte[] CONTENT_TYPE;
static {
try {
SNARKPAGE = SNARKHTML.getBytes(ASCII);
String STATUS = "HTTP/1.0 ";
HTTP_STATUS = STATUS.getBytes(ASCII);
CONTENT_LENGTH = "Content-Length: ".getBytes(ASCII);
CONTENT_TYPE = "Content-Type: ".getBytes(ASCII);
} catch (UnsupportedEncodingException uee) {
// Cannot happen, US-ASCII unknown?
throw new InternalError(uee.toString());
}
}
private final Tracker tracker;
/**
* Creates a HttpAcceptor that can handle torrent metadata of the given
* Tracker.
*/
public HttpAcceptor (Tracker tracker)
{
this.tracker = tracker;
}
public void connection (Socket sock, BufferedInputStream bis,
BufferedOutputStream bos) throws IOException
{
BufferedReader br = new BufferedReader(
new InputStreamReader(bis, ASCII));
String resource = readRequest(br);
log.log(Level.FINE, "HTTP request for: " + resource);
if (resource != null) {
Map headers = readHeaders(br);
log.log(Level.FINER, headers.toString());
if (resource.equals("/")) {
sendData(bos, SNARKPAGE, "text/html");
} else if (resource.startsWith("/announce")) {
Map params = parseParams(resource);
byte[] response = tracker.handleRequest(sock.getInetAddress(),
sock.getPort(), params);
sendData(bos, response, "application/octet-stream");
} else if (resource.endsWith(".torrent")) {
MetaInfo info = tracker.getMetaInfo(
resource.substring(1, resource.length() - 8));
if (info != null) {
byte[] torrent = info.getTorrentData();
sendData(bos, torrent, "application/x-bittorrent");
} else {
sendError(bos, 404, "Unable to locate that hash.");
}
} else {
sendError(bos, 404, "Snark Client. Not a real webserver.");
}
} else {
sendError(bos, 500, "Snark Client. Not a real webserver.");
}
sock.close();
}
/**
* Processes an incoming HTTP request. Only handles the most basic GET
* requests. Returns the (URLEncoded) requested resource or null if the
* request wasn't a valid GET request.
*/
private static String readRequest (BufferedReader br) throws IOException
{
String request = br.readLine();
if (request != null && request.startsWith("GET ")) {
String resource;
int index = request.indexOf(' ', 4);
if (index == -1) {
resource = request.substring(4);
} else {
resource = request.substring(4, index);
}
return resource;
} else {
return null;
}
}
/**
* Consumes all headers and puts them into a Map mapping header value to
* header key Strings.
*/
private static Map<String, String> readHeaders (BufferedReader br)
throws IOException
{
Map<String, String> m = new HashMap<String, String>();
String header = br.readLine();
while (header != null && header.length() != 0) {
header = br.readLine();
if (header != null && header.length() != 0) {
int index = header.indexOf(": ");
if (index != -1) {
String key = header.substring(0, index);
String value = header.substring(index + 2);
m.put(key, value);
}
}
}
return m;
}
/**
* Sends a HTTP OK, the necessary headers and the data.
*/
private static void sendData (OutputStream out, byte[] data,
String content_type) throws IOException
{
sendData(out, 200, "OK", data, content_type);
}
private static void sendData (OutputStream out, int responseCode,
String reason, byte[] data, String content_type) throws IOException
{
log.log(Level.FINER, "HTTP/1.0 " + responseCode + " " + reason + " "
+ content_type + " (" + data.length + " bytes)");
byte[] type = content_type.getBytes(ASCII);
// Status line
out.write(HTTP_STATUS);
out.write(Integer.toString(responseCode).getBytes(ASCII));
out.write(' ');
out.write(reason.getBytes(ASCII));
out.write(CRLF);
// Entity headers
out.write(CONTENT_LENGTH);
out.write(Integer.toString(data.length).getBytes(ASCII));
out.write(CRLF);
out.write(CONTENT_TYPE);
out.write(type);
out.write(CRLF);
// Start of data
out.write(CRLF);
out.write(data);
out.flush();
}
private static void sendError (OutputStream out, int responseCode,
String reason) throws IOException
{
sendData(out, responseCode, reason, reason.getBytes(ASCII),
"text/plain");
}
/**
* Returns a key to value map of the GET request query string parameters. It
* expects a '?' and the urlencoded key=value pairs. Note that the key and
* value are NOT url decoded before putting in the paramaters map.
*/
private static Map<String, String> parseParams (String request)
{
Map<String, String> m = new HashMap<String, String>();
int index = request.indexOf('?');
if (index != -1) {
String params = request.substring(index + 1);
StringTokenizer st = new StringTokenizer(params, "&");
while (st.hasMoreTokens()) {
String token = st.nextToken();
index = token.indexOf('=');
if (index != -1) {
String key = token.substring(0, index);
String value = token.substring(index + 1);
m.put(key, value);
}
}
}
return m;
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.server");
}

View File

@ -1,156 +0,0 @@
/*
* Message - A protocol message which can be send through a DataOutputStream.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.DataOutputStream;
import java.io.IOException;
// Used to queue outgoing connections
// sendMessage() should be used to translate them to wire format.
class Message
{
final static byte KEEP_ALIVE = -1;
final static byte CHOKE = 0;
final static byte UNCHOKE = 1;
final static byte INTERESTED = 2;
final static byte UNINTERESTED = 3;
final static byte HAVE = 4;
final static byte BITFIELD = 5;
final static byte REQUEST = 6;
final static byte PIECE = 7;
final static byte CANCEL = 8;
// Not all fields are used for every message.
// KEEP_ALIVE doesn't have a real wire representation
byte type;
// Used for HAVE, REQUEST, PIECE and CANCEL messages.
int piece;
// Used for REQUEST, PIECE and CANCEL messages.
int begin;
int length;
// Used for PIECE and BITFIELD messages
byte[] data;
int off;
int len;
/** Utility method for sending a message through a DataStream. */
void sendMessage (DataOutputStream dos) throws IOException
{
// KEEP_ALIVE is special.
if (type == KEEP_ALIVE) {
dos.writeInt(0);
return;
}
// Calculate the total length in bytes
// Type is one byte.
int datalen = 1;
// piece is 4 bytes.
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL) {
datalen += 4;
}
// begin/offset is 4 bytes
if (type == REQUEST || type == PIECE || type == CANCEL) {
datalen += 4;
}
// length is 4 bytes
if (type == REQUEST || type == CANCEL) {
datalen += 4;
}
// add length of data for piece or bitfield array.
if (type == BITFIELD || type == PIECE) {
datalen += len;
}
// Send length
dos.writeInt(datalen);
dos.writeByte(type & 0xFF);
// Send additional info (piece number)
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL) {
dos.writeInt(piece);
}
// Send additional info (begin/offset)
if (type == REQUEST || type == PIECE || type == CANCEL) {
dos.writeInt(begin);
}
// Send additional info (length); for PIECE this is implicit.
if (type == REQUEST || type == CANCEL) {
dos.writeInt(length);
}
// Send actual data
if (type == BITFIELD || type == PIECE) {
dos.write(data, off, len);
}
}
@Override
public String toString ()
{
switch (type) {
case KEEP_ALIVE:
return "KEEP_ALIVE";
case CHOKE:
return "CHOKE";
case UNCHOKE:
return "UNCHOKE";
case INTERESTED:
return "INTERESTED";
case UNINTERESTED:
return "UNINTERESTED";
case HAVE:
return "HAVE(" + piece + ")";
case BITFIELD:
return "BITFIELD";
case REQUEST:
return "REQUEST(" + piece + "," + begin + "," + length + ")";
case PIECE:
return "PIECE(" + piece + "," + begin + "," + length + ")";
case CANCEL:
return "CANCEL(" + piece + "," + begin + "," + length + ")";
default:
return "<UNKNOWN>";
}
}
}

View File

@ -1,389 +0,0 @@
/*
* MetaInfo - Holds all information gotten from a torrent file. Copyright (C)
* 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.BEncoder;
import org.klomp.snark.bencode.InvalidBEncodingException;
public class MetaInfo
{
private final String announce;
private final byte[] info_hash;
private final String name;
private final List<List<String>> files;
private final List<Long> lengths;
private final int piece_length;
private final byte[] piece_hashes;
private final long length;
private byte[] torrentdata;
MetaInfo (String announce, String name, List<List<String>> files,
List<Long> lengths, int piece_length, byte[] piece_hashes, long length)
{
this.announce = announce;
this.name = name;
this.files = files;
this.lengths = lengths;
this.piece_length = piece_length;
this.piece_hashes = piece_hashes;
this.length = length;
this.info_hash = calculateInfoHash();
}
/**
* Creates a new MetaInfo from the given InputStream. The InputStream must
* start with a correctly bencoded dictonary describing the torrent.
*/
public MetaInfo (InputStream in) throws IOException
{
this(new BDecoder(in));
}
/**
* Creates a new MetaInfo from the given BDecoder. The BDecoder must have a
* complete dictionary describing the torrent.
*/
public MetaInfo (BDecoder be) throws IOException
{
// Note that evaluation order matters here...
this(be.bdecodeMap().getMap());
}
/**
* Creates a new MetaInfo from a Map of BEValues and the SHA1 over the
* original bencoded info dictonary (this is a hack, we could reconstruct
* the bencoded stream and recalculate the hash). Will throw a
* InvalidBEncodingException if the given map does not contain a valid
* announce string or info dictonary.
*/
public MetaInfo (Map m) throws InvalidBEncodingException
{
BEValue val = (BEValue)m.get("announce");
if (val == null) {
throw new InvalidBEncodingException("Missing announce string");
}
this.announce = val.getString();
val = (BEValue)m.get("info");
if (val == null) {
throw new InvalidBEncodingException("Missing info map");
}
Map info = val.getMap();
val = (BEValue)info.get("name");
if (val == null) {
throw new InvalidBEncodingException("Missing name string");
}
name = val.getString();
val = (BEValue)info.get("piece length");
if (val == null) {
throw new InvalidBEncodingException("Missing piece length number");
}
piece_length = val.getInt();
val = (BEValue)info.get("pieces");
if (val == null) {
throw new InvalidBEncodingException("Missing piece bytes");
}
piece_hashes = val.getBytes();
val = (BEValue)info.get("length");
if (val != null) {
// Single file case.
length = val.getLong();
files = null;
lengths = null;
} else {
// Multi file case.
val = (BEValue)info.get("files");
if (val == null) {
throw new InvalidBEncodingException(
"Missing length number and/or files list");
}
List list = val.getList();
int size = list.size();
if (size == 0) {
throw new InvalidBEncodingException("zero size files list");
}
files = new ArrayList<List<String>>(size);
lengths = new ArrayList<Long>(size);
long l = 0;
for (int i = 0; i < list.size(); i++) {
Map desc = ((BEValue)list.get(i)).getMap();
val = (BEValue)desc.get("length");
if (val == null) {
throw new InvalidBEncodingException("Missing length number");
}
long len = val.getLong();
lengths.add(len);
l += len;
val = (BEValue)desc.get("path");
if (val == null) {
throw new InvalidBEncodingException("Missing path list");
}
List<BEValue> path_list = val.getList();
int path_length = path_list.size();
if (path_length == 0) {
throw new InvalidBEncodingException(
"zero size file path list");
}
List<String> file = new ArrayList<String>(path_length);
for (BEValue value : path_list) {
file.add(value.getString());
}
files.add(file);
}
length = l;
}
info_hash = calculateInfoHash();
}
/**
* Returns the string representing the URL of the tracker for this torrent.
*/
public String getAnnounce ()
{
return announce;
}
/**
* Returns the original 20 byte SHA1 hash over the bencoded info map.
*/
public byte[] getInfoHash ()
{
// XXX - Should we return a clone, just to be sure?
return info_hash;
}
public String getHexInfoHash ()
{
return hexencode(info_hash);
}
/**
* Returns the piece hashes. Only used by storage so package local.
*/
byte[] getPieceHashes ()
{
return piece_hashes;
}
/**
* Returns the requested name for the file or toplevel directory. If it is a
* toplevel directory name getFiles() will return a non-null List of file
* name hierarchy name.
*/
public String getName ()
{
return name;
}
/**
* Returns a list of lists of file name hierarchies or null if it is a
* single name. It has the same size as the list returned by getLengths().
*/
public List getFiles ()
{
// XXX - Immutable?
return files;
}
/**
* Returns a list of Longs indication the size of the individual files, or
* null if it is a single file. It has the same size as the list returned by
* getFiles().
*/
public List getLengths ()
{
// XXX - Immutable?
return lengths;
}
/**
* Returns the number of pieces.
*/
public int getPieces ()
{
return piece_hashes.length / 20;
}
/**
* Return the length of a piece. All pieces are of equal length except for
* the last one (<code>getPieces()-1</code>).
*
* @exception IndexOutOfBoundsException
* when piece is equal to or greater then the number of
* pieces in the torrent.
*/
public int getPieceLength (int piece)
{
int pieces = getPieces();
if (piece >= 0 && piece < pieces - 1) {
return piece_length;
} else if (piece == pieces - 1) {
return (int)(length - piece * piece_length);
} else {
throw new IndexOutOfBoundsException("no piece: " + piece);
}
}
/**
* Checks that the given piece has the same SHA1 hash as the given byte
* array. Returns random results or IndexOutOfBoundsExceptions when the
* piece number is unknown.
*/
public boolean checkPiece (int piece, byte[] bs, int off, int length)
{
// Check digest
MessageDigest sha1;
try {
sha1 = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("No SHA digest available: " + nsae);
}
sha1.update(bs, off, length);
byte[] hash = sha1.digest();
for (int i = 0; i < 20; i++) {
if (hash[i] != piece_hashes[20 * piece + i]) {
return false;
}
}
return true;
}
/**
* Returns the total length of the torrent in bytes.
*/
public long getTotalLength ()
{
return length;
}
@Override
public String toString ()
{
return "MetaInfo[info_hash='" + hexencode(info_hash) + "', announce='"
+ announce + "', name='" + name + "', files=" + files
+ ", #pieces='" + piece_hashes.length / 20 + "', piece_length='"
+ piece_length + "', length='" + length + "']";
}
/**
* Encode a byte array as a hex encoded string.
*/
private static String hexencode (byte[] bs)
{
StringBuffer sb = new StringBuffer(bs.length * 2);
for (byte element : bs) {
int c = element & 0xFF;
if (c < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
/**
* Creates a copy of this MetaInfo that shares everything except the
* announce URL.
*/
public MetaInfo reannounce (String announce)
{
return new MetaInfo(announce, name, files, lengths, piece_length,
piece_hashes, length);
}
public byte[] getTorrentData ()
{
if (torrentdata == null) {
Map<String, Object> m = new HashMap<String, Object>();
m.put("announce", announce);
Map info = createInfoMap();
m.put("info", info);
torrentdata = BEncoder.bencode(m);
}
return torrentdata;
}
private Map<String, Object> createInfoMap ()
{
Map<String, Object> info = new HashMap<String, Object>();
info.put("name", name);
info.put("piece length", piece_length);
info.put("pieces", piece_hashes);
if (files == null) {
info.put("length", new Long(length));
} else {
List<Map<String, Object>> l = new ArrayList<Map<String, Object>>();
for (int i = 0; i < files.size(); i++) {
Map<String, Object> file = new HashMap<String, Object>();
file.put("path", files.get(i));
file.put("length", lengths.get(i));
l.add(file);
}
info.put("files", l);
}
return info;
}
private byte[] calculateInfoHash ()
{
Map<String, Object> info = createInfoMap();
byte[] infoBytes = BEncoder.bencode(info);
try {
MessageDigest digest = MessageDigest.getInstance("SHA");
return digest.digest(infoBytes);
} catch (NoSuchAlgorithmException nsa) {
throw new InternalError(nsa.toString());
}
}
}

View File

@ -1,393 +0,0 @@
/*
* Peer - All public information concerning a peer. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Peer implements Comparable<Peer>
{
// Identifying property, the peer id of the other side.
private final PeerID peerID;
private final byte[] my_id;
private final MetaInfo metainfo;
// The data in/output streams set during the handshake and used by
// the actual connections.
private DataInputStream din;
private DataOutputStream dout;
// Keeps state for in/out connections. Non-null when the handshake
// was successful, the connection setup and runs
PeerState state;
private boolean deregister = true;
/**
* Creates a disconnected peer given a PeerID, your own id and the relevant
* MetaInfo.
*/
public Peer (PeerID peerID, byte[] my_id, MetaInfo metainfo)
throws IOException
{
this.peerID = peerID;
this.my_id = my_id;
this.metainfo = metainfo;
}
/**
* Creates a unconnected peer from the input and output stream got from the
* socket. Note that the complete handshake (which can take some time or
* block indefinitely) is done in the calling Thread to get the remote peer
* id. To completely start the connection call the connect() method.
*
* @exception IOException
* when an error occurred during the handshake.
*/
public Peer (final Socket sock, BufferedInputStream bis,
BufferedOutputStream bos, byte[] my_id, MetaInfo metainfo)
throws IOException
{
this.my_id = my_id;
this.metainfo = metainfo;
byte[] id = handshake(bis, bos);
this.peerID = new PeerID(id, sock.getInetAddress(), sock.getPort());
}
/**
* Returns the id of the peer.
*/
public PeerID getPeerID ()
{
return peerID;
}
/**
* Returns the String representation of the peerID.
*/
@Override
public String toString ()
{
return peerID.toString();
}
/**
* The hash code of a Peer is the hash code of the peerID.
*/
@Override
public int hashCode ()
{
return peerID.hashCode();
}
/**
* Two Peers are equal when they have the same PeerID. All other properties
* are ignored.
*/
@Override
public boolean equals (Object o)
{
if (o instanceof Peer) {
Peer p = (Peer)o;
return peerID.equals(p.peerID);
} else {
return false;
}
}
/**
* Compares the PeerIDs.
*/
public int compareTo (Peer p)
{
return peerID.compareTo(p.peerID);
}
/**
* Runs the connection to the other peer. This method does not return until
* the connection is terminated.
*
* When the connection is correctly started the connected() method of the
* given PeerListener is called. If the connection ends or the connection
* could not be setup correctly the disconnected() method is called.
*
* If the given BitField is non-null it is send to the peer as first
* message.
*/
public void runConnection (PeerListener listener, BitField bitfield)
{
if (state != null) {
throw new IllegalStateException("Peer already started");
}
try {
// Do we need to handshake?
if (din == null) {
Socket sock = new Socket(peerID.getAddress(), peerID.getPort());
BufferedInputStream bis = new BufferedInputStream(
sock.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(
sock.getOutputStream());
byte[] id = handshake(bis, bos);
byte[] expected_id = peerID.getID();
if (!Arrays.equals(expected_id, id)) {
throw new IOException("Unexpected peerID '"
+ PeerID.idencode(id) + "' expected '"
+ PeerID.idencode(expected_id) + "'");
}
}
PeerConnectionIn in = new PeerConnectionIn(this, din);
PeerConnectionOut out = new PeerConnectionOut(this, dout);
PeerState s = new PeerState(this, listener, metainfo, in, out);
// Send our bitmap
if (bitfield != null) {
s.out.sendBitfield(bitfield);
}
// We are up and running!
state = s;
listener.connected(this);
// Use this thread for running the incomming connection.
// The outgoing connection has created its own Thread.
s.in.run();
} catch (IOException eofe) {
log.log(Level.FINE, "Peer connection to " + peerID.getAddress() + " failed ", eofe);
} catch (Throwable t) {
log.log(Level.SEVERE, "Peer connection failed " + toString(), t);
t.printStackTrace();
} finally {
if (deregister) {
listener.disconnected(this);
}
}
}
/**
* Sets DataIn/OutputStreams, does the handshake and returns the id reported
* by the other side.
*/
private byte[] handshake (BufferedInputStream bis, BufferedOutputStream bos)
throws IOException
{
din = new DataInputStream(bis);
dout = new DataOutputStream(bos);
// Handshake write - header
dout.write(19);
dout.write("BitTorrent protocol".getBytes("UTF-8"));
// Handshake write - zeros
byte[] zeros = new byte[8];
dout.write(zeros);
// Handshake write - metainfo hash
byte[] shared_hash = metainfo.getInfoHash();
dout.write(shared_hash);
// Handshake write - peer id
dout.write(my_id);
dout.flush();
// Handshake read - header
byte b = din.readByte();
if (b != 19) {
throw new IOException("Handshake failure, expected 19, got "
+ (b & 0xff));
}
byte[] bs = new byte[19];
din.readFully(bs);
String bittorrentProtocol = new String(bs, "UTF-8");
if (!"BitTorrent protocol".equals(bittorrentProtocol)) {
throw new IOException("Handshake failure, expected "
+ "'Bittorrent protocol', got '" + bittorrentProtocol + "'");
}
// Handshake read - zeros
din.readFully(zeros);
// Handshake read - metainfo hash
bs = new byte[20];
din.readFully(bs);
if (!Arrays.equals(shared_hash, bs)) {
throw new IOException("Unexpected MetaInfo hash");
}
// Handshake read - peer id
din.readFully(bs);
return bs;
}
public boolean isConnected ()
{
return state != null;
}
/**
* Disconnects this peer if it was connected. If deregister is true,
* PeerListener.disconnected() will be called when the connection is
* completely terminated. Otherwise the connection is silently terminated.
*/
public void disconnect (boolean deregister)
{
// Both in and out connection will call this.
this.deregister = deregister;
disconnect();
}
void disconnect ()
{
PeerState s = state;
if (s != null) {
state = null;
PeerConnectionIn in = s.in;
if (in != null) {
in.disconnect();
}
PeerConnectionOut out = s.out;
if (out != null) {
out.disconnect();
}
}
}
/**
* Tell the peer we have another piece.
*/
public void have (int piece)
{
PeerState s = state;
if (s != null) {
s.havePiece(piece);
}
}
/**
* Whether or not the peer is interested in pieces we have. Returns false if
* not connected.
*/
public boolean isInterested ()
{
PeerState s = state;
return (s != null) && s.interested;
}
/**
* Sets whether or not we are interested in pieces from this peer. Defaults
* to false. When interest is true and this peer unchokes us then we start
* downloading from it. Has no effect when not connected.
*/
public void setInteresting (boolean interest)
{
PeerState s = state;
if (s != null) {
s.setInteresting(interest);
}
}
/**
* Whether or not the peer has pieces we want from it. Returns false if not
* connected.
*/
public boolean isInteresting ()
{
PeerState s = state;
return (s != null) && s.interesting;
}
/**
* Sets whether or not we are choking the peer. Defaults to true. When choke
* is false and the peer requests some pieces we upload them, otherwise
* requests of this peer are ignored.
*/
public void setChoking (boolean choke)
{
PeerState s = state;
if (s != null) {
s.setChoking(choke);
}
}
/**
* Whether or not we are choking the peer. Returns true when not connected.
*/
public boolean isChoking ()
{
PeerState s = state;
return (s == null) || s.choking;
}
/**
* Whether or not the peer choked us. Returns true when not connected.
*/
public boolean isChoked ()
{
PeerState s = state;
return (s == null) || s.choked;
}
/**
* Returns the number of bytes that have been downloaded. Can be reset to
* zero with <code>resetCounters()</code>/
*/
public long getDownloaded ()
{
PeerState s = state;
return (s != null) ? s.downloaded : 0;
}
/**
* Returns the number of bytes that have been uploaded. Can be reset to zero
* with <code>resetCounters()</code>/
*/
public long getUploaded ()
{
PeerState s = state;
return (s != null) ? s.uploaded : 0;
}
/**
* Resets the downloaded and uploaded counters to zero.
*/
public void resetCounters ()
{
PeerState s = state;
if (s != null) {
s.downloaded = 0;
s.uploaded = 0;
}
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,54 +0,0 @@
/*
* PeerAcceptor - Accepts incomming connections from peers. Copyright (C) 2003
* Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
/**
* Accepts incomming connections from peers. The ConnectionAcceptor will call
* the connection() method when it detects an incomming BT protocol connection.
* The PeerAcceptor will then create a new peer if the PeerCoordinator wants
* more peers.
*/
public class PeerAcceptor
{
private final PeerCoordinator coordinator;
public PeerAcceptor (PeerCoordinator coordinator)
{
this.coordinator = coordinator;
}
public void connection (Socket socket, BufferedInputStream bis,
BufferedOutputStream bos) throws IOException
{
if (coordinator.needPeers()) {
Peer peer = new Peer(socket, bis, bos, coordinator.getID(),
coordinator.getMetaInfo());
coordinator.addPeer(peer);
} else {
socket.close();
}
}
}

View File

@ -1,187 +0,0 @@
/*
* PeerCheckTasks - TimerTask that checks for good/bad up/downloaders. Copyright
* (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* TimerTask that checks for good/bad up/downloader. Works together with the
* PeerCoordinator to select which Peers get (un)choked.
*/
class PeerCheckerTask extends TimerTask
{
private static final long KILOPERSECOND = 1024 * (PeerCoordinator.CHECK_PERIOD / 1000);
private final PeerCoordinator coordinator;
PeerCheckerTask (PeerCoordinator coordinator)
{
this.coordinator = coordinator;
}
@Override
public void run ()
{
synchronized (coordinator.peers) {
// Calculate total uploading and worst downloader.
long worstdownload = Long.MAX_VALUE;
Peer worstDownloader = null;
int peers = 0;
int uploaders = 0;
int downloaders = 0;
int interested = 0;
int interesting = 0;
int choking = 0;
int choked = 0;
long uploaded = 0;
long downloaded = 0;
// Keep track of peers we remove now,
// we will add them back to the end of the list.
List<Peer> removed = new ArrayList<Peer>();
Iterator it = coordinator.peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
// Remove dying peers
if (!peer.isConnected()) {
it.remove();
continue;
}
peers++;
if (!peer.isChoking()) {
uploaders++;
}
if (!peer.isChoked() && peer.isInteresting()) {
downloaders++;
}
if (peer.isInterested()) {
interested++;
}
if (peer.isInteresting()) {
interesting++;
}
if (peer.isChoking()) {
choking++;
}
if (peer.isChoked()) {
choked++;
}
// XXX - We should calculate the up/download rate a bit
// more intelligently
long upload = peer.getUploaded();
uploaded += upload;
long download = peer.getDownloaded();
downloaded += download;
peer.resetCounters();
log.log(Level.FINEST, peer + ":" + " ul: " + upload
/ KILOPERSECOND + " dl: " + download / KILOPERSECOND
+ " i: " + peer.isInterested() + " I: "
+ peer.isInteresting() + " c: " + peer.isChoking() + " C: "
+ peer.isChoked());
// If we are at our max uploaders and we have lots of other
// interested peers try to make some room.
// (Note use of coordinator.uploaders)
if (coordinator.uploaders >= PeerCoordinator.MAX_UPLOADERS
&& interested > PeerCoordinator.MAX_UPLOADERS
&& !peer.isChoking()) {
// Check if it still wants pieces from us.
if (!peer.isInterested()) {
log.log(Level.FINER, "Choke uninterested peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
// Put it at the back of the list
it.remove();
removed.add(peer);
} else if (peer.isChoked()) {
// If they are choking us make someone else a downloader
log.log(Level.FINEST, "Choke choking peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
// Put it at the back of the list
it.remove();
removed.add(peer);
} else if (peer.isInteresting() && !peer.isChoked()
&& download == 0) {
// We are downloading but didn't receive anything...
log.log(Level.FINEST,
"Choke downloader that doesn't deliver:" + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
// Put it at the back of the list
it.remove();
removed.add(peer);
} else if (!peer.isChoking() && download < worstdownload) {
// Make sure download is good if we are uploading
worstdownload = download;
worstDownloader = peer;
}
}
}
// Resync actual uploaders value
// (can shift a bit by disconnecting peers)
coordinator.uploaders = uploaders;
// Remove the worst downloader if needed.
if (uploaders >= PeerCoordinator.MAX_UPLOADERS
&& interested > PeerCoordinator.MAX_UPLOADERS
&& worstDownloader != null) {
log.log(Level.FINEST, "Choke worst downloader: "
+ worstDownloader);
worstDownloader.setChoking(true);
coordinator.uploaders--;
// Put it at the back of the list
coordinator.peers.remove(worstDownloader);
removed.add(worstDownloader);
}
// Optimistically unchoke a peer
coordinator.unchokePeer();
// Put peers back at the end of the list that we removed earlier.
coordinator.peers.addAll(removed);
}
}
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,150 +0,0 @@
/*
* PeerConnectionIn - Handles incomming messages and hands them to PeerState.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
class PeerConnectionIn implements Runnable
{
private final Peer peer;
private final DataInputStream din;
private Thread thread;
private boolean quit;
public PeerConnectionIn (Peer peer, DataInputStream din)
{
this.peer = peer;
this.din = din;
quit = false;
}
void disconnect ()
{
if (quit == true) {
return;
}
quit = true;
Thread t = thread;
if (t != null) {
t.interrupt();
}
}
public void run ()
{
thread = Thread.currentThread();
try {
PeerState ps = peer.state;
while (!quit && ps != null) {
// Common variables used for some messages.
int piece;
int begin;
int len;
// Wait till we hear something...
// The length of a complete message in bytes.
int i = din.readInt();
if (i < 0) {
throw new IOException("Unexpected length prefix: " + i);
}
if (i == 0) {
ps.keepAliveMessage();
continue;
}
byte b = din.readByte();
Message m = new Message();
m.type = b;
switch (b) {
case 0:
ps.chokeMessage(true);
break;
case 1:
ps.chokeMessage(false);
break;
case 2:
ps.interestedMessage(true);
break;
case 3:
ps.interestedMessage(false);
break;
case 4:
piece = din.readInt();
ps.haveMessage(piece);
break;
case 5:
byte[] bitmap = new byte[i - 1];
din.readFully(bitmap);
ps.bitfieldMessage(bitmap);
break;
case 6:
piece = din.readInt();
begin = din.readInt();
len = din.readInt();
ps.requestMessage(piece, begin, len);
break;
case 7:
piece = din.readInt();
begin = din.readInt();
len = i - 9;
Request req = ps.getOutstandingRequest(piece, begin, len);
byte[] piece_bytes;
if (req != null) {
piece_bytes = req.bs;
din.readFully(piece_bytes, begin, len);
ps.pieceMessage(req);
} else {
// XXX - Consume but throw away afterwards.
piece_bytes = new byte[len];
din.readFully(piece_bytes);
}
break;
case 8:
piece = din.readInt();
begin = din.readInt();
len = din.readInt();
ps.cancelMessage(piece, begin, len);
break;
default:
byte[] bs = new byte[i - 1];
din.readFully(bs);
ps.unknownMessage(b, bs);
}
}
} catch (IOException ioe) {
// Ignore, probably the other side closed connection.
} catch (Throwable t) {
log.log(Level.SEVERE, peer + " failed", t);
} finally {
peer.disconnect();
}
}
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,319 +0,0 @@
/*
* PeerConnectionOut - Keeps a queue of outgoing messages and delivers them.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
class PeerConnectionOut implements Runnable
{
private final Peer peer;
private final DataOutputStream dout;
private Thread thread;
private boolean quit;
private List<Message> sendQueue = new ArrayList<Message>();
public PeerConnectionOut (Peer peer, DataOutputStream dout)
{
this.peer = peer;
this.dout = dout;
quit = false;
thread = new Thread(this);
thread.start();
}
/**
* Continuesly monitors for more outgoing messages that have to be send.
* Stops if quit is true of an IOException occurs.
*/
public void run ()
{
try {
while (!quit) {
Message m = null;
PeerState state = null;
synchronized (sendQueue) {
while (!quit && sendQueue.isEmpty()) {
try {
// Make sure everything will reach the other side.
dout.flush();
// Wait till more data arrives.
sendQueue.wait();
} catch (InterruptedException ie) {
/* ignored */
}
}
state = peer.state;
if (!quit && state != null) {
// Piece messages are big. So if there are other
// (control) messages make sure they are send first.
// Also remove request messages from the queue if
// we are currently being choked to prevent them from
// being send even if we get unchoked a little later.
// (Since we will resent them anyway in that case.)
// And remove piece messages if we are choking.
Iterator it = sendQueue.iterator();
while (m == null && it.hasNext()) {
Message nm = (Message)it.next();
if (nm.type == Message.PIECE) {
if (state.choking) {
it.remove();
}
nm = null;
} else if (nm.type == Message.REQUEST
&& state.choked) {
it.remove();
nm = null;
}
if (m == null && nm != null) {
m = nm;
it.remove();
}
}
if (m == null && sendQueue.size() > 0) {
m = sendQueue.remove(0);
}
}
}
if (m != null) {
log.log(Level.ALL, "Send " + peer + ": " + m);
m.sendMessage(dout);
// Remove all piece messages after sending a choke message.
if (m.type == Message.CHOKE) {
removeMessage(Message.PIECE);
}
// XXX - Should also register overhead...
if (m.type == Message.PIECE) {
state.uploaded(m.len);
}
m = null;
}
}
} catch (IOException ioe) {
// Ignore, probably other side closed connection.
} catch (Throwable t) {
log.log(Level.SEVERE, peer + " failed", t);
} finally {
quit = true;
peer.disconnect();
}
}
public void disconnect ()
{
synchronized (sendQueue) {
if (quit == true) {
return;
}
quit = true;
thread.interrupt();
sendQueue.clear();
sendQueue.notify();
}
}
/**
* Adds a message to the sendQueue and notifies the method waiting on the
* sendQueue to change.
*/
private void addMessage (Message m)
{
synchronized (sendQueue) {
sendQueue.add(m);
sendQueue.notify();
}
}
/**
* Removes a particular message type from the queue.
*
* @param type
* the Message type to remove.
* @returns true when a message of the given type was removed, false
* otherwise.
*/
private boolean removeMessage (int type)
{
boolean removed = false;
synchronized (sendQueue) {
Iterator it = sendQueue.iterator();
while (it.hasNext()) {
Message m = (Message)it.next();
if (m.type == type) {
it.remove();
removed = true;
}
}
}
return removed;
}
void sendAlive ()
{
Message m = new Message();
m.type = Message.KEEP_ALIVE;
addMessage(m);
}
void sendChoke (boolean choke)
{
// We cancel the (un)choke but keep PIECE messages.
// PIECE messages are purged if a choke is actually send.
synchronized (sendQueue) {
int inverseType = choke ? Message.UNCHOKE : Message.CHOKE;
if (!removeMessage(inverseType)) {
Message m = new Message();
if (choke) {
m.type = Message.CHOKE;
} else {
m.type = Message.UNCHOKE;
}
addMessage(m);
}
}
}
void sendInterest (boolean interest)
{
synchronized (sendQueue) {
int inverseType = interest ? Message.UNINTERESTED
: Message.INTERESTED;
if (!removeMessage(inverseType)) {
Message m = new Message();
if (interest) {
m.type = Message.INTERESTED;
} else {
m.type = Message.UNINTERESTED;
}
addMessage(m);
}
}
}
void sendHave (int piece)
{
Message m = new Message();
m.type = Message.HAVE;
m.piece = piece;
addMessage(m);
}
void sendBitfield (BitField bitfield)
{
Message m = new Message();
m.type = Message.BITFIELD;
m.data = bitfield.getFieldBytes();
m.off = 0;
m.len = m.data.length;
addMessage(m);
}
void sendRequests (List requests)
{
Iterator it = requests.iterator();
while (it.hasNext()) {
Request req = (Request)it.next();
sendRequest(req);
}
}
void sendRequest (Request req)
{
Message m = new Message();
m.type = Message.REQUEST;
m.piece = req.piece;
m.begin = req.off;
m.length = req.len;
addMessage(m);
}
void sendPiece (int piece, int begin, int length, byte[] bytes)
{
Message m = new Message();
m.type = Message.PIECE;
m.piece = piece;
m.begin = begin;
m.length = length;
m.data = bytes;
m.off = begin;
m.len = length;
addMessage(m);
}
void sendCancel (Request req)
{
// See if it is still in our send queue
synchronized (sendQueue) {
Iterator it = sendQueue.iterator();
while (it.hasNext()) {
Message m = (Message)it.next();
if (m.type == Message.REQUEST && m.piece == req.piece
&& m.begin == req.off && m.length == req.len) {
it.remove();
}
}
}
// Always send, just to be sure it it is really canceled.
Message m = new Message();
m.type = Message.CANCEL;
m.piece = req.piece;
m.begin = req.off;
m.length = req.len;
addMessage(m);
}
// Called by the PeerState when the other side doesn't want this
// request to be handled anymore. Removes any pending Piece Message
// from out send queue.
void cancelRequest (int piece, int begin, int length)
{
synchronized (sendQueue) {
Iterator it = sendQueue.iterator();
while (it.hasNext()) {
Message m = (Message)it.next();
if (m.type == Message.PIECE && m.piece == piece
&& m.begin == begin && m.length == length) {
it.remove();
}
}
}
}
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,498 +0,0 @@
/*
* PeerCoordinator - Coordinates which peers do what (up and downloading).
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Coordinates what peer does what.
*/
public class PeerCoordinator implements PeerListener
{
final MetaInfo metainfo;
final Storage storage;
// package local for access by CheckDownLoadersTask
final static long CHECK_PERIOD = 20 * 1000; // 20 seconds
final static int MAX_CONNECTIONS = 24;
final static int MAX_UPLOADERS = 4;
// Approximation of the number of current uploaders.
// Resynced by PeerChecker once in a while.
int uploaders = 0;
// final static int MAX_DOWNLOADERS = MAX_CONNECTIONS;
// int downloaders = 0;
private long uploaded;
private long downloaded;
// synchronize on this when changing peers or downloaders
public final List<Peer> peers = new ArrayList<Peer>();
/** Timer to handle all periodical tasks. */
private final Timer timer = new Timer(true);
private final byte[] id;
// Some random wanted pieces
private final List<Integer> wantedPieces;
private boolean halted = false;
private final CoordinatorListener listener;
private TrackerClient client;
public PeerCoordinator (byte[] id, MetaInfo metainfo, Storage storage,
CoordinatorListener listener)
{
this.id = id;
this.metainfo = metainfo;
this.storage = storage;
this.listener = listener;
// Make a random list of piece numbers
wantedPieces = new ArrayList<Integer>();
BitField bitfield = storage.getBitField();
for (int i = 0; i < metainfo.getPieces(); i++) {
if (!bitfield.get(i)) {
wantedPieces.add(i);
}
}
Collections.shuffle(wantedPieces);
// Install a timer to check the uploaders.
timer.schedule(new PeerCheckerTask(this), CHECK_PERIOD, CHECK_PERIOD);
}
public void setTracker (TrackerClient client)
{
this.client = client;
}
public byte[] getID ()
{
return id;
}
public boolean completed ()
{
return storage.complete();
}
public int getPeers ()
{
synchronized (peers) {
return peers.size();
}
}
/**
* Returns how many bytes are still needed to get the complete file.
*/
public long getLeft ()
{
// XXX - Only an approximation.
return storage.needed() * metainfo.getPieceLength(0);
}
/**
* Returns the total number of uploaded bytes of all peers.
*/
public long getUploaded ()
{
return uploaded;
}
/**
* Returns the total number of downloaded bytes of all peers.
*/
public long getDownloaded ()
{
return downloaded;
}
public MetaInfo getMetaInfo ()
{
return metainfo;
}
public boolean needPeers ()
{
synchronized (peers) {
return !halted && peers.size() < MAX_CONNECTIONS;
}
}
public void halt ()
{
halted = true;
synchronized (peers) {
// Stop peer checker task.
timer.cancel();
// Stop peers.
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
peer.disconnect();
it.remove();
}
}
}
public void connected (Peer peer)
{
if (halted) {
peer.disconnect(false);
return;
}
synchronized (peers) {
if (peerIDInList(peer.getPeerID(), peers)) {
log.log(Level.FINER, "Already connected to: " + peer);
peer.disconnect(false); // Don't deregister this
// connection/peer.
} else {
log.log(Level.FINER, "New connection to peer: " + peer);
// Add it to the beginning of the list.
// And try to optimistically make it a uploader.
peers.add(0, peer);
unchokePeer();
if (listener != null) {
listener.peerChange(this, peer);
}
}
}
}
private static boolean peerIDInList (PeerID pid, List peers)
{
Iterator it = peers.iterator();
while (it.hasNext()) {
if (pid.sameID(((Peer)it.next()).getPeerID())) {
return true;
}
}
return false;
}
public void addPeer (final Peer peer)
{
if (halted) {
peer.disconnect(false);
return;
}
boolean need_more;
synchronized (peers) {
need_more = !peer.isConnected() && peers.size() < MAX_CONNECTIONS;
}
if (need_more) {
// Run the peer with us as listener and the current bitfield.
final PeerListener listener = this;
final BitField bitfield = storage.getBitField();
Runnable r = new Runnable() {
public void run ()
{
peer.runConnection(listener, bitfield);
}
};
String threadName = peer.toString();
new Thread(r, threadName).start();
} else if (log.getLevel().intValue() <= Level.FINER.intValue()) {
if (peer.isConnected()) {
log.log(Level.FINER, "Add peer already connected: " + peer);
} else {
log.log(Level.FINER, "MAX_CONNECTIONS = " + MAX_CONNECTIONS
+ " not accepting extra peer: " + peer);
}
}
}
// (Optimistically) unchoke. Should be called with peers synchronized
void unchokePeer ()
{
// linked list will contain all interested peers that we choke.
// At the start are the peers that have us unchoked at the end the
// other peer that are interested, but are choking us.
List<Peer> interested = new LinkedList<Peer>();
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
if (uploaders < MAX_UPLOADERS && peer.isChoking()
&& peer.isInterested()) {
if (!peer.isChoked()) {
interested.add(0, peer);
} else {
interested.add(peer);
}
}
}
while (uploaders < MAX_UPLOADERS && interested.size() > 0) {
Peer peer = interested.remove(0);
log.log(Level.FINER, "Unchoke: " + peer);
peer.setChoking(false);
uploaders++;
// Put peer back at the end of the list.
peers.remove(peer);
peers.add(peer);
}
}
public byte[] getBitMap ()
{
return storage.getBitField().getFieldBytes();
}
/**
* Returns true if we don't have the given piece yet.
*/
public boolean gotHave (Peer peer, int piece)
{
if (listener != null) {
listener.peerChange(this, peer);
}
synchronized (wantedPieces) {
return wantedPieces.contains(new Integer(piece));
}
}
/**
* Returns true if the given bitfield contains at least one piece we are
* interested in.
*/
public boolean gotBitField (Peer peer, BitField bitfield)
{
if (listener != null) {
listener.peerChange(this, peer);
}
synchronized (wantedPieces) {
Iterator it = wantedPieces.iterator();
while (it.hasNext()) {
int i = ((Integer)it.next()).intValue();
if (bitfield.get(i)) {
return true;
}
}
}
return false;
}
/**
* Returns one of pieces in the given BitField that is still wanted or -1 if
* none of the given pieces are wanted.
*/
public int wantPiece (Peer peer, BitField havePieces)
{
if (halted) {
return -1;
}
synchronized (wantedPieces) {
Integer piece = null;
Iterator it = wantedPieces.iterator();
while (piece == null && it.hasNext()) {
Integer i = (Integer)it.next();
if (havePieces.get(i.intValue())) {
it.remove();
piece = i;
}
}
if (piece == null) {
return -1;
}
// We add it back at the back of the list. It will be removed
// if gotPiece is called later. This means that the last
// couple of pieces might very well be asked from multiple
// peers but that is OK.
wantedPieces.add(piece);
return piece.intValue();
}
}
/**
* Returns a byte array containing the requested piece or null of the piece
* is unknown.
*/
public byte[] gotRequest (Peer peer, int piece)
throws IOException
{
if (halted) {
return null;
}
try {
return storage.getPiece(piece);
} catch (IOException ioe) {
Snark.abort("Error reading storage", ioe);
return null; // Never reached.
}
}
/**
* Called when a peer has uploaded some bytes of a piece.
*/
public void uploaded (Peer peer, int size)
{
uploaded += size;
if (listener != null) {
listener.peerChange(this, peer);
}
}
/**
* Called when a peer has downloaded some bytes of a piece.
*/
public void downloaded (Peer peer, int size)
{
downloaded += size;
if (listener != null) {
listener.peerChange(this, peer);
}
}
/**
* Returns false if the piece is no good (according to the hash). In that
* case the peer that supplied the piece should probably be blacklisted.
*/
public boolean gotPiece (Peer peer, int piece, byte[] bs)
throws IOException
{
if (halted) {
return true; // We don't actually care anymore.
}
synchronized (wantedPieces) {
Integer p = new Integer(piece);
if (!wantedPieces.contains(p)) {
log.log(Level.FINER, peer + " piece " + piece
+ " no longer needed");
// No need to announce have piece to peers.
// Assume we got a good piece, we don't really care anymore.
return true;
}
try {
if (storage.putPiece(piece, bs)) {
log.log(Level.FINER, "Recv p" + piece + " " + peer);
} else {
// Oops. We didn't actually download this then... :(
downloaded -= metainfo.getPieceLength(piece);
log.log(Level.INFO, "Got BAD piece " + piece + " from "
+ peer);
return false; // No need to announce BAD piece to peers.
}
} catch (IOException ioe) {
Snark.abort("Error writing storage", ioe);
}
wantedPieces.remove(p);
}
// Announce to the world we have it!
synchronized (peers) {
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer p = (Peer)it.next();
if (p.isConnected()) {
p.have(piece);
}
}
}
if (completed()) {
client.interrupt();
}
return true;
}
public void gotChoke (Peer peer, boolean choke)
{
log.log(Level.FINER, "Got choke(" + choke + "): " + peer);
if (listener != null) {
listener.peerChange(this, peer);
}
}
public void gotInterest (Peer peer, boolean interest)
{
if (interest) {
synchronized (peers) {
if (uploaders < MAX_UPLOADERS) {
if (peer.isChoking()) {
uploaders++;
peer.setChoking(false);
log.log(Level.FINER, "Unchoke: " + peer);
}
}
}
}
if (listener != null) {
listener.peerChange(this, peer);
}
}
public void disconnected (Peer peer)
{
log.log(Level.FINER, "Disconnected " + peer);
synchronized (peers) {
// Make sure it is no longer in our lists
if (peers.remove(peer)) {
// Unchoke some random other peer
unchokePeer();
}
}
if (listener != null) {
listener.peerChange(this, peer);
}
}
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,210 +0,0 @@
/*
* PeerID - All public information concerning a peer. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
public class PeerID implements Comparable
{
private final byte[] id;
private final InetAddress address;
private final int port;
private final int hash;
public PeerID (byte[] id, InetAddress address, int port)
{
this.id = id;
this.address = address;
this.port = port;
hash = calculateHash();
}
/**
* Creates a PeerID from a BDecoder.
*/
public PeerID (BDecoder be) throws IOException
{
this(be.bdecodeMap().getMap());
}
/**
* Creates a PeerID from a Map containing BEncoded peer id, ip and port.
*/
public PeerID (Map m)
throws InvalidBEncodingException, UnknownHostException
{
BEValue bevalue = (BEValue)m.get("peer id");
if (bevalue == null) {
throw new InvalidBEncodingException("peer id missing");
}
id = bevalue.getBytes();
bevalue = (BEValue)m.get("ip");
if (bevalue == null) {
throw new InvalidBEncodingException("ip missing");
}
address = InetAddress.getByName(bevalue.getString());
bevalue = (BEValue)m.get("port");
if (bevalue == null) {
throw new InvalidBEncodingException("port missing");
}
port = bevalue.getInt();
hash = calculateHash();
}
public byte[] getID ()
{
return id;
}
public InetAddress getAddress ()
{
return address;
}
public int getPort ()
{
return port;
}
private int calculateHash ()
{
int b = 0;
for (byte element : id) {
b ^= element;
}
return (b ^ address.hashCode()) ^ port;
}
/**
* The hash code of a PeerID is the exclusive or of all id bytes.
*/
@Override
public int hashCode ()
{
return hash;
}
/**
* Returns true if and only if this peerID and the given peerID have the
* same 20 bytes as ID.
*/
public boolean sameID (PeerID pid)
{
boolean equal = true;
for (int i = 0; equal && i < id.length; i++) {
equal = id[i] == pid.id[i];
}
return equal;
}
/**
* Two PeerIDs are equal when they have the same id, address and port.
*/
@Override
public boolean equals (Object o)
{
if (o instanceof PeerID) {
PeerID pid = (PeerID)o;
return port == pid.port && address.equals(pid.address)
&& sameID(pid);
} else {
return false;
}
}
/**
* Compares port, address and id.
*/
public int compareTo (Object o)
{
PeerID pid = (PeerID)o;
int result = port - pid.port;
if (result != 0) {
return result;
}
result = address.hashCode() - pid.address.hashCode();
if (result != 0) {
return result;
}
for (byte element : id) {
result = element - element;
if (result != 0) {
return result;
}
}
return 0;
}
/**
* Returns the String "id@address:port" where id is the hex encoded id with
* leading zeros removed.
*/
@Override
public String toString ()
{
return idencode(id) + "@" + address + ":" + port;
}
/**
* Encode an id as a hex encoded string and remove leading zeros.
*/
public static String idencode (byte[] bs)
{
boolean leading_zeros = true;
StringBuffer sb = new StringBuffer(bs.length * 2);
for (byte element : bs) {
int c = element & 0xFF;
if (leading_zeros && c == 0) {
continue;
} else {
leading_zeros = false;
}
if (c < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
}

View File

@ -1,166 +0,0 @@
/*
* PeerListener - Interface for listening to peer events. Copyright (C) 2003
* Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
/**
* Listener for Peer events.
*/
public interface PeerListener
{
/**
* Called when the connection to the peer has started and the handshake was
* successfull.
*
* @param peer
* the Peer that just got connected.
*/
void connected (Peer peer);
/**
* Called when the connection to the peer was terminated or the connection
* handshake failed.
*
* @param peer
* the Peer that just got disconnected.
*/
void disconnected (Peer peer);
/**
* Called when a choke message is received.
*
* @param peer
* the Peer that got the message.
* @param choke
* true when the peer got a choke message, false when the peer
* got an unchoke message.
*/
void gotChoke (Peer peer, boolean choke);
/**
* Called when an interested message is received.
*
* @param peer
* the Peer that got the message.
* @param interest
* true when the peer got a interested message, false when the
* peer got an uninterested message.
*/
void gotInterest (Peer peer, boolean interest);
/**
* Called when a have piece message is received. If the method returns true
* and the peer has not yet received a interested message or we indicated
* earlier to be not interested then an interested message will be send.
*
* @param peer
* the Peer that got the message.
* @param piece
* the piece number that the per just got.
*
* @return true when it is a piece that we want, false if the piece is
* already known.
*/
boolean gotHave (Peer peer, int piece);
/**
* Called when a bitmap message is received. If this method returns true a
* interested message will be send back to the peer.
*
* @param peer
* the Peer that got the message.
* @param bitfield
* a BitField containing the pieces that the other side has.
*
* @return true when the BitField contains pieces we want, false if the
* piece is already known.
*/
boolean gotBitField (Peer peer, BitField bitfield);
/**
* Called when a piece is received from the peer. The piece must be
* requested by Peer.request() first. If this method returns false that
* means the Peer provided a corrupted piece and the connection will be
* closed.
*
* @param peer
* the Peer that got the piece.
* @param piece
* the piece number received.
* @param bs
* the byte array containing the piece.
*
* @return true when the bytes represent the piece, false otherwise.
* @throws IOException
*/
boolean gotPiece (Peer peer, int piece, byte[] bs) throws IOException;
/**
* Called when the peer wants (part of) a piece from us. Only called when
* the peer is not choked by us (<code>peer.choke(false)</code> was
* called).
*
* @param peer
* the Peer that wants the piece.
* @param piece
* the piece number requested.
*
* @return a byte array containing the piece or null when the piece is not
* available (which is a protocol error).
*/
byte[] gotRequest (Peer peer, int piece) throws IOException;
/**
* Called when a (partial) piece has been downloaded from the peer.
*
* @param peer
* the Peer from which size bytes where downloaded.
* @param size
* the number of bytes that where downloaded.
*/
void downloaded (Peer peer, int size);
/**
* Called when a (partial) piece has been uploaded to the peer.
*
* @param peer
* the Peer to which size bytes where uploaded.
* @param size
* the number of bytes that where uploaded.
*/
void uploaded (Peer peer, int size);
/**
* Called when we are downloading from the peer and need to ask for a new
* piece. Might be called multiple times before <code>gotPiece()</code> is
* called.
*
* @param peer
* the Peer that will be asked to provide the piece.
* @param bitfield
* a BitField containing the pieces that the other side has.
*
* @return one of the pieces from the bitfield that we want or -1 if we are
* no longer interested in the peer.
*/
int wantPiece (Peer peer, BitField bitfield);
}

View File

@ -1,130 +0,0 @@
/*
* PeerMonitorTasks - TimerTask that monitors the peers and total up/down speed
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.util.Iterator;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* TimerTask that monitors the peers and total up/download speeds. Works
* together with the main Snark class to report periodical statistics.
*/
public class PeerMonitorTask extends TimerTask
{
public static final long MONITOR_PERIOD = 10 * 1000; // Ten seconds.
private static final long KILOPERSECOND = 1024 * (MONITOR_PERIOD / 1000);
private final PeerCoordinator coordinator;
private long lastDownloaded = 0;
private long lastUploaded = 0;
public PeerMonitorTask (PeerCoordinator coordinator)
{
this.coordinator = coordinator;
}
@Override
public void run ()
{
// Get some statistics
int peers = 0;
int uploaders = 0;
int downloaders = 0;
int interested = 0;
int interesting = 0;
int choking = 0;
int choked = 0;
synchronized (coordinator.peers) {
Iterator it = coordinator.peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
// Don't list dying peers
if (!peer.isConnected()) {
continue;
}
peers++;
if (!peer.isChoking()) {
uploaders++;
}
if (!peer.isChoked() && peer.isInteresting()) {
downloaders++;
}
if (peer.isInterested()) {
interested++;
}
if (peer.isInteresting()) {
interesting++;
}
if (peer.isChoking()) {
choking++;
}
if (peer.isChoked()) {
choked++;
}
}
}
// Print some statistics
long downloaded = coordinator.getDownloaded();
String totalDown;
if (downloaded >= 10 * 1024 * 1024) {
totalDown = (downloaded / (1024 * 1024)) + "MB";
} else {
totalDown = (downloaded / 1024) + "KB";
}
long uploaded = coordinator.getUploaded();
String totalUp;
if (uploaded >= 10 * 1024 * 1024) {
totalUp = (uploaded / (1024 * 1024)) + "MB";
} else {
totalUp = (uploaded / 1024) + "KB";
}
int needP = coordinator.storage.needed();
long needMB = needP * coordinator.metainfo.getPieceLength(0)
/ (1024 * 1024);
int totalP = coordinator.metainfo.getPieces();
long totalMB = coordinator.metainfo.getTotalLength() / (1024 * 1024);
log.log(Level.INFO, "Down: " + (downloaded - lastDownloaded)
/ KILOPERSECOND + "KB/s" + " (" + totalDown + ")" + " Up: "
+ (uploaded - lastUploaded) / KILOPERSECOND + "KB/s" + " ("
+ totalUp + ")" + " Need " + needP + " (" + needMB + "MB)" + " of "
+ totalP + " (" + totalMB + "MB)" + " pieces");
log.log(Level.INFO, peers + ": Download #" + downloaders + " Upload #"
+ uploaders + " Interested #" + interested + " Interesting #"
+ interesting + " Choking #" + choking + " Choked #" + choked);
lastDownloaded = downloaded;
lastUploaded = uploaded;
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.status");
}

View File

@ -1,481 +0,0 @@
/*
* PeerState - Keeps track of the Peer state through connection callbacks.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
class PeerState
{
final Peer peer;
final PeerListener listener;
final MetaInfo metainfo;
// Interesting and choking describes whether we are interested in or
// are choking the other side.
boolean interesting = false;
boolean choking = true;
// Interested and choked describes whether the other side is
// interested in us or choked us.
boolean interested = false;
boolean choked = true;
// Package local for use by Peer.
long downloaded;
long uploaded;
BitField bitfield;
// Package local for use by Peer.
final PeerConnectionIn in;
final PeerConnectionOut out;
// Outstanding request
private final List<Request> outstandingRequests = new ArrayList<Request>();
private Request lastRequest = null;
// If we have te resend outstanding requests (true after we got choked).
private boolean resend = false;
private final static int MAX_PIPELINE = 5;
private final static int PARTSIZE = 16384; // 16K
PeerState (Peer peer, PeerListener listener, MetaInfo metainfo,
PeerConnectionIn in, PeerConnectionOut out)
{
this.peer = peer;
this.listener = listener;
this.metainfo = metainfo;
this.in = in;
this.out = out;
}
// NOTE Methods that inspect or change the state synchronize (on this).
void keepAliveMessage ()
{
log.log(Level.FINEST, peer + " rcv alive");
/* XXX - ignored */
}
void chokeMessage (boolean choke)
{
log.log(Level.FINEST, peer + " rcv " + (choke ? "" : "un") + "choked");
choked = choke;
if (choked) {
resend = true;
}
listener.gotChoke(peer, choke);
if (!choked && interesting) {
request();
}
}
void interestedMessage (boolean interest)
{
log.log(Level.FINEST, peer + " rcv " + (interest ? "" : "un")
+ "interested");
interested = interest;
listener.gotInterest(peer, interest);
}
void haveMessage (int piece)
{
log.log(Level.FINEST, peer + " rcv have(" + piece + ")");
// Sanity check
if (piece < 0 || piece >= metainfo.getPieces()) {
// XXX disconnect?
log.log(Level.FINER, "Got strange 'have: " + piece
+ "' message from " + peer);
return;
}
synchronized (this) {
// Can happen if the other side never send a bitfield message.
if (bitfield == null) {
bitfield = new BitField(metainfo.getPieces());
}
bitfield.set(piece);
}
if (listener.gotHave(peer, piece)) {
setInteresting(true);
}
}
void bitfieldMessage (byte[] bitmap)
{
synchronized (this) {
log.log(Level.FINEST, peer + " rcv bitfield");
if (bitfield != null) {
// XXX - Be liberal in what you accept?
log.log(Level.FINER, "Got unexpected bitfield message from "
+ peer);
return;
}
// XXX - Check for weird bitfield and disconnect?
bitfield = new BitField(bitmap, metainfo.getPieces());
}
setInteresting(listener.gotBitField(peer, bitfield));
}
void requestMessage (int piece, int begin, int length)
throws IOException
{
log.log(Level.FINEST, peer + " rcv request(" + piece + ", " + begin
+ ", " + length + ") ");
if (choking) {
log.log(Level.FINER, "Request received, but choking " + peer);
return;
}
// Sanity check
if (piece < 0 || piece >= metainfo.getPieces() || begin < 0
|| begin > metainfo.getPieceLength(piece) || length <= 0
|| length > 4 * PARTSIZE) {
// XXX - Protocol error -> disconnect?
log.log(Level.FINER, "Got strange 'request: " + piece + ", "
+ begin + ", " + length + "' message from " + peer);
return;
}
byte[] pieceBytes = listener.gotRequest(peer, piece);
if (pieceBytes == null) {
// XXX - Protocol error-> diconnect?
log.log(Level.FINER, "Got request for unknown piece: " + piece);
return;
}
// More sanity checks
if (begin >= pieceBytes.length || begin + length > pieceBytes.length) {
// XXX - Protocol error-> disconnect?
log.log(Level.FINER, "Got out of range 'request: " + piece + ", "
+ begin + ", " + length + "' message from " + peer);
return;
}
log.log(Level.FINEST, "Sending (" + piece + ", " + begin + ", "
+ length + ")" + " to " + peer);
out.sendPiece(piece, begin, length, pieceBytes);
// Tell about last subpiece delivery.
if (begin + length == pieceBytes.length) {
log.log(Level.FINEST, "Send p" + piece + " " + peer);
}
}
/**
* Called when some bytes have left the outgoing connection. XXX - Should
* indicate whether it was a real piece or overhead.
*/
void uploaded (int size)
{
uploaded += size;
listener.uploaded(peer, size);
}
/**
* Called when a partial piece request has been handled by PeerConnectionIn.
*/
void pieceMessage (Request req)
throws IOException
{
int size = req.len;
downloaded += size;
listener.downloaded(peer, size);
// Last chunk needed for this piece?
if (getFirstOutstandingRequest(req.piece) == -1) {
if (listener.gotPiece(peer, req.piece, req.bs)) {
log.log(Level.FINEST, "Got " + req.piece + ": " + peer);
} else {
log.log(Level.FINEST, "Got BAD " + req.piece + " from " + peer);
// XXX ARGH What now !?!
downloaded = 0;
}
}
}
synchronized private int getFirstOutstandingRequest (int piece)
{
for (int i = 0; i < outstandingRequests.size(); i++) {
if ((outstandingRequests.get(i)).piece == piece) {
return i;
}
}
return -1;
}
/**
* Called when a piece message is being processed by the incoming
* connection. Returns null when there was no such request. It also
* requeues/sends requests when it thinks that they must have been lost.
*/
Request getOutstandingRequest (int piece, int begin, int length)
{
log.log(Level.FINEST, "getChunk(" + piece + "," + begin + "," + length
+ ") " + peer);
int r = getFirstOutstandingRequest(piece);
// Unrequested piece number?
if (r == -1) {
log.log(Level.FINER, "Unrequested 'piece: " + piece + ", " + begin
+ ", " + length + "' received from " + peer);
downloaded = 0; // XXX - punishment?
return null;
}
// Lookup the correct piece chunk request from the list.
Request req;
synchronized (this) {
req = outstandingRequests.get(r);
while (req.piece == piece && req.off != begin
&& r < outstandingRequests.size() - 1) {
r++;
req = outstandingRequests.get(r);
}
// Something wrong?
if (req.piece != piece || req.off != begin || req.len != length) {
log.log(Level.FINER, "Unrequested or unneeded 'piece: " + piece
+ ", " + begin + ", " + length + "' received from " + peer);
downloaded = 0; // XXX - punishment?
return null;
}
// Report missing requests.
if (r != 0) {
String errmsg = "Some requests dropped, got " + req +
", wanted:";
for (int i = 0; i < r; i++) {
Request dropReq = outstandingRequests.remove(0);
outstandingRequests.add(dropReq);
// We used to rerequest the missing chunks but that mostly
// just confuses the other side. So now we just keep
// waiting for them. They will be rerequested when we get
// choked/unchoked again.
/*
* if (!choked) out.sendRequest(dropReq);
*/
errmsg += " " + dropReq;
}
errmsg += " " + peer;
log.log(Level.FINER, errmsg);
}
outstandingRequests.remove(0);
}
// Request more if necessary to keep the pipeline filled.
addRequest();
return req;
}
void cancelMessage (int piece, int begin, int length)
{
log.log(Level.FINEST, "Got cancel message (" + piece + ", " + begin
+ ", " + length + ")");
out.cancelRequest(piece, begin, length);
}
void unknownMessage (int type, byte[] bs)
{
log.log(Level.WARNING, "Ignoring unknown message type: " + type
+ " length: " + bs.length);
}
void havePiece (int piece)
{
log.log(Level.FINEST, "Tell " + peer + " havePiece(" + piece + ")");
synchronized (this) {
// Tell the other side that we are no longer interested in any of
// the outstanding requests for this piece.
if (lastRequest != null && lastRequest.piece == piece) {
lastRequest = null;
}
Iterator it = outstandingRequests.iterator();
while (it.hasNext()) {
Request req = (Request)it.next();
if (req.piece == piece) {
it.remove();
// Send cancel even when we are choked to make sure that it
// is
// really never ever send.
out.sendCancel(req);
}
}
}
// Tell the other side that we really have this piece.
out.sendHave(piece);
// Request something else if necessary.
addRequest();
synchronized (this) {
// Is the peer still interesting?
if (lastRequest == null) {
setInteresting(false);
}
}
}
// Starts or resumes requesting pieces.
private void request ()
{
// Are there outstanding requests that have to be resend?
if (resend) {
out.sendRequests(outstandingRequests);
resend = false;
}
// Add/Send some more requests if necessary.
addRequest();
}
/**
* Adds a new request to the outstanding requests list.
*/
private void addRequest ()
{
boolean more_pieces = true;
while (more_pieces) {
synchronized (this) {
more_pieces = outstandingRequests.size() < MAX_PIPELINE;
}
// We want something and we don't have outstanding requests?
if (more_pieces && lastRequest == null) {
more_pieces = requestNextPiece();
} else if (more_pieces) // We want something
{
int pieceLength;
boolean isLastChunk;
synchronized (this) {
pieceLength = metainfo.getPieceLength(lastRequest.piece);
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
}
// Last part of a piece?
if (isLastChunk) {
more_pieces = requestNextPiece();
} else {
synchronized (this) {
int nextPiece = lastRequest.piece;
int nextBegin = lastRequest.off + PARTSIZE;
byte[] bs = lastRequest.bs;
int maxLength = pieceLength - nextBegin;
int nextLength = maxLength > PARTSIZE ? PARTSIZE
: maxLength;
Request req = new Request(nextPiece, bs, nextBegin,
nextLength);
outstandingRequests.add(req);
if (!choked) {
out.sendRequest(req);
}
lastRequest = req;
}
}
}
}
log.log(Level.FINEST, peer + " requests " + outstandingRequests);
}
// Starts requesting first chunk of next piece. Returns true if
// something has been added to the requests, false otherwise.
private boolean requestNextPiece ()
{
// Check that we already know what the other side has.
if (bitfield != null) {
int nextPiece = listener.wantPiece(peer, bitfield);
log.log(Level.FINEST, peer + " want piece " + nextPiece);
synchronized (this) {
if (nextPiece != -1
&& (lastRequest == null || lastRequest.piece != nextPiece)) {
int piece_length = metainfo.getPieceLength(nextPiece);
byte[] bs = new byte[piece_length];
int length = Math.min(piece_length, PARTSIZE);
Request req = new Request(nextPiece, bs, 0, length);
outstandingRequests.add(req);
if (!choked) {
out.sendRequest(req);
}
lastRequest = req;
return true;
}
}
}
return false;
}
synchronized void setInteresting (boolean interest)
{
log.log(Level.FINEST, peer + " setInteresting(" + interest + ")");
if (interest != interesting) {
interesting = interest;
out.sendInterest(interest);
if (interesting && !choked) {
request();
}
}
}
synchronized void setChoking (boolean choke)
{
log.log(Level.FINEST, peer + " setChoking(" + choke + ")");
if (choking != choke) {
choking = choke;
out.sendChoke(choke);
}
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.peer");
}

View File

@ -1,83 +0,0 @@
/*
* Request - Holds all information needed for a (partial) piece request.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Holds all information needed for a partial piece request.
*/
class Request
{
final int piece;
final byte[] bs;
final int off;
final int len;
/**
* Creates a new Request.
*
* @param piece
* Piece number requested.
* @param bs
* byte array where response should be stored.
* @param off
* the offset in the array.
* @param len
* the number of bytes requested.
*/
Request (int piece, byte[] bs, int off, int len)
{
this.piece = piece;
this.bs = bs;
this.off = off;
this.len = len;
// Sanity check
if (piece < 0 || off < 0 || len <= 0 || off + len > bs.length) {
throw new IndexOutOfBoundsException("Illegal Request " + toString());
}
}
@Override
public int hashCode ()
{
return piece ^ off ^ len;
}
@Override
public boolean equals (Object o)
{
if (o instanceof Request) {
Request req = (Request)o;
return req.piece == piece && req.off == off && req.len == len;
}
return false;
}
@Override
public String toString ()
{
return "(" + piece + "," + off + "," + len + ")";
}
}

View File

@ -1,34 +0,0 @@
/*
* ShutdownListener - Callback for end of shutdown sequence
*
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Callback for end of shutdown sequence.
*/
public interface ShutdownListener
{
/**
* Called when the SnarkShutdown hook has finished shutting down all
* subcomponents.
*/
void shutdown ();
}

View File

@ -1,380 +0,0 @@
/*
* Snark - Main snark program startup class. Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Random;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.klomp.snark.bencode.BDecoder;
/**
* Main Snark object used to fetch or serve a given file.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class Snark
{
/** The lowest port Snark will listen on for connections */
public final static int MIN_PORT = 6881;
/** The highest port Snark will listen on for connections */
public final static int MAX_PORT = 6889;
/** The path to the file being torrented */
public String torrent;
/** The metadata known about the torrent */
public MetaInfo meta;
/** The storage helper assisting us */
public Storage storage;
/** The coordinator managing our peers */
public PeerCoordinator coordinator;
/** Parcels out incoming requests to the appropriate places */
public ConnectionAcceptor acceptor;
/** Obtains information on new peers. */
public TrackerClient trackerclient;
/**
* Constructs a Snark client.
* @param torrent The address of the torrent to download or file to serve
* @param ip The IP address to use when serving data
* @param user_port The port number to use
* @param slistener A custom {@link StorageListener} to use
* @param clistener A custom {@link CoordinatorListener} to use
*/
public Snark (String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener)
{
this.slistener = slistener;
this.clistener = clistener;
this.torrent = torrent;
this.user_port = user_port;
this.ip = ip;
// Create a new ID and fill it with something random. First nine
// zeros bytes, then three bytes filled with snark and then
// sixteen random bytes.
Random random = new Random();
int i;
for (i = 0; i < 9; i++) {
id[i] = 0;
}
id[i++] = snark;
id[i++] = snark;
id[i++] = snark;
while (i < 20) {
id[i++] = (byte)random.nextInt(256);
}
log.log(Level.FINE, "My peer id: " + PeerID.idencode(id));
}
/**
* Sets the global logging level of Snark.
*/
public static void setLogLevel (Level level)
{
log.setLevel(level);
log.setUseParentHandlers(false);
Handler handler = new ConsoleHandler();
handler.setLevel(level);
log.addHandler(handler);
}
/**
* Returns a human-readable state of Snark.
*/
public String getStateString ()
{
return activities[activity];
}
/**
* Returns the integer code for the human-readable state of Snark.
*/
public int getState ()
{
return activity;
}
/**
* Establishes basic information such as {@link #id}, opens ports,
* and determines whether to act as a peer or seed.
*/
public void setupNetwork ()
throws IOException
{
activity = NETWORK_SETUP;
IOException lastException = null;
if (user_port != -1) {
port = user_port;
try {
serversocket = new ServerSocket(port);
} catch (IOException ioe) {
lastException = ioe;
}
} else {
for (port = MIN_PORT; serversocket == null && port <= MAX_PORT; port++) {
try {
serversocket = new ServerSocket(port);
} catch (IOException ioe) {
lastException = ioe;
}
}
}
if (serversocket == null) {
String message = "Cannot accept incoming connections ";
if (user_port == -1) {
message = message + "tried ports " + MIN_PORT + " - "
+ MAX_PORT;
} else {
message = message + "on port " + user_port;
}
if (ip != null || user_port != -1) {
abort(message, lastException);
} else {
log.log(Level.WARNING, message);
}
port = -1;
} else {
port = serversocket.getLocalPort();
log.log(Level.FINE, "Listening on port: " + port);
}
// Figure out what the torrent argument represents.
meta = null;
File f = null;
try {
InputStream in;
f = new File(torrent);
if (f.exists()) {
in = new FileInputStream(f);
} else {
activity = GETTING_TORRENT;
URL u = new URL(torrent);
URLConnection c = u.openConnection();
c.connect();
in = c.getInputStream();
if (c instanceof HttpURLConnection) {
// Check whether the page exists
int code = ((HttpURLConnection)c).getResponseCode();
if (code / 100 != 2) {
// responses
abort("Loading page '" + torrent + "' gave error code "
+ code + ", it probably doesn't exists");
}
}
}
meta = new MetaInfo(new BDecoder(in));
} catch (IOException ioe) {
// OK, so it wasn't a torrent metainfo file.
if (f != null && f.exists()) {
if (ip == null) {
abort("'" + torrent + "' exists,"
+ " but is not a valid torrent metainfo file."
+ System.getProperty("line.separator")
+ " (use --share to create a torrent from it"
+ " and start sharing)", ioe);
} else {
// Try to create a new metainfo file
log.log(Level.INFO,
"Trying to create metainfo torrent for '" + torrent
+ "'");
try {
activity = CREATING_TORRENT;
storage = new Storage(f, "http://" + ip + ":" + port
+ "/announce", slistener);
storage.create();
meta = storage.getMetaInfo();
} catch (IOException ioe2) {
abort("Could not create torrent for '" + torrent + "'",
ioe2);
}
}
} else {
abort("Cannot open '" + torrent + "'", ioe);
}
}
log.log(Level.INFO, meta.toString());
}
/**
* Start the upload/download process and begins exchanging pieces
* with other peers.
*/
public void collectPieces ()
throws IOException
{
// When the metainfo torrent was created from an existing file/dir
// it already exists.
if (storage == null) {
try {
activity = CHECKING_STORAGE;
storage = new Storage(meta, slistener);
storage.check();
} catch (IOException ioe) {
abort("Could not create storage", ioe);
}
}
activity = COLLECTING_PIECES;
coordinator = new PeerCoordinator(id, meta, storage, clistener);
HttpAcceptor httpacceptor;
if (ip != null) {
MetaInfo m = meta.reannounce("http://" + ip + ":" + port
+ "/announce");
Tracker tracker = new Tracker(m);
try {
tracker.addPeer(meta.getHexInfoHash(),
new PeerID(id, InetAddress.getByName(ip), port));
} catch (UnknownHostException oops) {
abort("Could not start tracker for " + ip, oops);
}
httpacceptor = new HttpAcceptor(tracker);
// Debug code for writing out .torrent to disk
/*
byte[] torrentData = tracker.getMetaInfo(
meta.getHexInfoHash()).getTorrentData();
try {
log.log(Level.INFO, "Writing torrent to file " + torrent
+ ".torrent");
FileOutputStream fos = new FileOutputStream(torrent
+ ".torrent");
fos.write(torrentData);
fos.close();
} catch (IOException e) {
log.log(Level.WARNING, "Could not save torrent file.");
}
*/
} else {
httpacceptor = null;
}
PeerAcceptor peeracceptor = new PeerAcceptor(coordinator);
acceptor = new ConnectionAcceptor(serversocket, httpacceptor,
peeracceptor);
acceptor.start();
if (ip != null) {
log.log(Level.INFO, "Torrent available on " + "http://" + ip + ":"
+ port + "/" + meta.getHexInfoHash() + ".torrent");
}
trackerclient = new TrackerClient(meta, coordinator, port);
trackerclient.start();
coordinator.setTracker(trackerclient);
}
/**
* Aborts program abnormally.
*/
public static void abort (String s)
throws IOException
{
abort(s, null);
}
/**
* Aborts program abnormally.
*/
public static void abort (String s, IOException ioe)
throws IOException
{
log.log(Level.SEVERE, s, ioe);
throw new IOException(s);
}
/** The listen port requested by the user */
protected int user_port;
/** The port number Snark listens on */
protected int port;
/** The IP address to listen on, if applicable */
protected String ip;
/** The {@link StorageListener} to send updates to */
protected StorageListener slistener;
/** The {@link CoordinatorListener} to send updates to */
protected CoordinatorListener clistener;
/** Our BitTorrent client id number, randomly assigned */
protected byte[] id = new byte[20];
/** The server socket that we are using to listen for connections */
protected ServerSocket serversocket;
/**
* A magic constant used to identify the Snark library in the clientid.
*
* <pre>Taking Three as the subject to reason about--
* A convenient number to state--
* We add Seven, and Ten, and then multiply out
* By One Thousand diminished by Eight.
*
* The result we proceed to divide, as you see,
* By Nine Hundred and Ninety Two:
* Then subtract Seventeen, and the answer must be
* Exactly and perfectly true.</pre>
*/
protected static final byte snark =
(((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
/** An integer indicating Snark's current activity. */
protected int activity = NOT_STARTED;
/** The list of possible activities */
protected static final String[] activities =
{"Not started", "Network setup", "Getting torrent", "Creating torrent",
"Checking storage", "Collecting pieces", "Seeding"};
public static final int NOT_STARTED = 0;
public static final int NETWORK_SETUP = 1;
public static final int GETTING_TORRENT = 2;
public static final int CREATING_TORRENT = 3;
public static final int CHECKING_STORAGE = 4;
public static final int COLLECTING_PIECES = 5;
public static final int SEEDING = 6;
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark");
}

View File

@ -1,83 +0,0 @@
/*
* TrackerShutdown - Makes sure everything ends correctly when shutting down.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Makes sure everything ends correctly when shutting down.
*/
public class SnarkShutdown extends Thread
{
private final Snark snark;
private final ShutdownListener listener;
public SnarkShutdown (Snark snark, ShutdownListener listener)
{
this.snark = snark;
this.listener = listener;
}
@Override
public void run ()
{
log.log(Level.INFO, "Shutting down...");
log.log(Level.FINE, "Halting ConnectionAcceptor...");
if (snark.acceptor != null) {
snark.acceptor.halt();
}
log.log(Level.FINE, "Halting TrackerClient...");
if (snark.trackerclient != null) {
snark.trackerclient.halt();
}
log.log(Level.FINE, "Halting PeerCoordinator...");
if (snark.coordinator != null) {
snark.coordinator.halt();
}
log.log(Level.FINE, "Closing Storage...");
if (snark.storage != null) {
try {
snark.storage.close();
} catch (IOException ioe) {
log.log(Level.SEVERE, "Couldn't properly close storage", ioe);
}
}
// XXX - Should actually wait till done...
try {
log.log(Level.FINE, "Waiting 5 seconds...");
Thread.sleep(5 * 1000);
} catch (InterruptedException ie) { /* ignored */
}
listener.shutdown();
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.server");
}

View File

@ -1,52 +0,0 @@
/*
* StaticSnark - Main snark startup class for staticly linking with gcj.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.security.Provider;
import java.security.Security;
import org.klomp.snark.cmd.SnarkApplication;
/**
* Main snark startup class for staticly linking with gcj. It references somee
* necessary classes that are normally loaded through reflection.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class StaticSnark
{
public static void main (String[] args)
{
try {
// The GNU security provider is needed for SHA-1 MessageDigest
// checking. So make sure it is available as a security provider.
Provider gnu = (Provider)Class.forName(
"gnu.java.security.provider.Gnu").newInstance();
Security.addProvider(gnu);
} catch (Exception e) {
System.err.println("Unable to load GNU security provider");
System.exit(-1);
}
// And finally call the normal starting point.
SnarkApplication.main(args);
}
}

View File

@ -1,519 +0,0 @@
/*
* Storage - Class used to store and retrieve pieces. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Maintains pieces on disk. Can be used to store and retrieve pieces.
*/
public class Storage
{
private MetaInfo metainfo;
private long[] lengths;
private RandomAccessFile[] rafs;
private String[] names;
private final StorageListener listener;
private final BitField bitfield;
private int needed;
// XXX - Not always set correctly
int piece_size;
int pieces;
/** The default piece size. */
private static int MIN_PIECE_SIZE = 256 * 1024;
/** The maximum number of pieces in a torrent. */
private static long MAX_PIECES = 100 * 1024 / 20;
/**
* Creates a new storage based on the supplied MetaInfo. This will try to
* create and/or check all needed files in the MetaInfo.
*
* @exception IOException
* when creating and/or checking files fails.
*/
public Storage (MetaInfo metainfo, StorageListener listener)
throws IOException
{
this.metainfo = metainfo;
this.listener = listener;
needed = metainfo.getPieces();
bitfield = new BitField(needed);
}
/**
* Creates a storage from the existing file or directory together with an
* appropriate MetaInfo file as can be announced on the given announce
* String location.
*/
public Storage (File baseFile, String announce, StorageListener listener)
throws IOException
{
this.listener = listener;
// Create names, rafs and lengths arrays.
getFiles(baseFile);
long total = 0;
ArrayList<Long> lengthsList = new ArrayList<Long>();
for (long length : lengths) {
total += length;
lengthsList.add(length);
}
piece_size = MIN_PIECE_SIZE;
pieces = (int)((total - 1) / piece_size) + 1;
while (pieces > MAX_PIECES) {
piece_size = piece_size * 2;
pieces = (int)((total - 1) / piece_size) + 1;
}
// Note that piece_hashes and the bitfield will be filled after
// the MetaInfo is created.
byte[] piece_hashes = new byte[20 * pieces];
bitfield = new BitField(pieces);
needed = 0;
List<List<String>> files = new ArrayList<List<String>>();
for (String element : names) {
List<String> file = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(element, File.separator);
while (st.hasMoreTokens()) {
String part = st.nextToken();
file.add(part);
}
files.add(file);
}
if (files.size() == 1) {
files = null;
lengthsList = null;
}
// Note that the piece_hashes are not correctly setup yet.
metainfo = new MetaInfo(announce, baseFile.getName(), files,
lengthsList, piece_size, piece_hashes, total);
}
// Creates piece hases for a new storage.
public void create () throws IOException
{
// Calculate piece_hashes
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException nsa) {
throw new InternalError(nsa.toString());
}
byte[] piece_hashes = metainfo.getPieceHashes();
byte[] piece = new byte[piece_size];
for (int i = 0; i < pieces; i++) {
int length = getUncheckedPiece(i, piece, 0);
digest.update(piece, 0, length);
byte[] hash = digest.digest();
for (int j = 0; j < 20; j++) {
piece_hashes[20 * i + j] = hash[j];
}
bitfield.set(i);
if (listener != null) {
listener.storageChecked(this, i, true);
}
}
if (listener != null) {
listener.storageAllChecked(this);
}
// Reannounce to force recalculating the info_hash.
metainfo = metainfo.reannounce(metainfo.getAnnounce());
}
private void getFiles (File base) throws IOException
{
ArrayList<File> files = new ArrayList<File>();
addFiles(files, base);
int size = files.size();
names = new String[size];
lengths = new long[size];
rafs = new RandomAccessFile[size];
int i = 0;
Iterator it = files.iterator();
while (it.hasNext()) {
File f = (File)it.next();
names[i] = f.getPath();
lengths[i] = f.length();
rafs[i] = new RandomAccessFile(f, "r");
i++;
}
}
private static void addFiles (List<File> l, File f)
{
if (!f.isDirectory()) {
l.add(f);
} else {
File[] files = f.listFiles();
if (files == null) {
log.log(Level.WARNING, "Skipping '" + f
+ "' not a normal file.");
return;
}
for (File element : files) {
addFiles(l, element);
}
}
}
/**
* Returns the MetaInfo associated with this Storage.
*/
public MetaInfo getMetaInfo ()
{
return metainfo;
}
/**
* How many pieces are still missing from this storage.
*/
public int needed ()
{
return needed;
}
/**
* Whether or not this storage contains all pieces if the MetaInfo.
*/
public boolean complete ()
{
return needed == 0;
}
/**
* The BitField that tells which pieces this storage contains. Do not change
* this since this is the current state of the storage.
*/
public BitField getBitField ()
{
return bitfield;
}
/**
* Creates (and/or checks) all files from the metainfo file list.
*/
public void check () throws IOException
{
File base = new File(filterName(metainfo.getName()));
List files = metainfo.getFiles();
if (files == null) {
// Create base as file.
log.log(Level.INFO, "Creating/Checking file: " + base);
if (!base.createNewFile() && !base.exists()) {
throw new IOException("Could not create file " + base);
}
lengths = new long[1];
rafs = new RandomAccessFile[1];
names = new String[1];
lengths[0] = metainfo.getTotalLength();
rafs[0] = new RandomAccessFile(base, "rw");
names[0] = base.getName();
} else {
// Create base as dir.
log.log(Level.INFO, "Creating/Checking directory: " + base);
if (!base.mkdir() && !base.isDirectory()) {
throw new IOException("Could not create directory " + base);
}
List ls = metainfo.getLengths();
int size = files.size();
long total = 0;
lengths = new long[size];
rafs = new RandomAccessFile[size];
names = new String[size];
for (int i = 0; i < size; i++) {
File f = createFileFromNames(base, (List)files.get(i));
lengths[i] = ((Long)ls.get(i)).longValue();
total += lengths[i];
rafs[i] = new RandomAccessFile(f, "rw");
names[i] = f.getName();
}
// Sanity check for metainfo file.
long metalength = metainfo.getTotalLength();
if (total != metalength) {
throw new IOException("File lengths do not add up " + total
+ " != " + metalength);
}
}
checkCreateFiles();
}
/**
* Removes 'suspicious' characters from the give file name.
*/
private String filterName (String name)
{
// XXX - Is this enough?
return name.replace(File.separatorChar, '_');
}
private File createFileFromNames (File base, List names) throws IOException
{
File f = null;
Iterator it = names.iterator();
while (it.hasNext()) {
String name = filterName((String)it.next());
if (it.hasNext()) {
// Another dir in the hierarchy.
f = new File(base, name);
if (!f.mkdir() && !f.isDirectory()) {
throw new IOException("Could not create directory " + f);
}
base = f;
} else {
// The final element (file) in the hierarchy.
f = new File(base, name);
if (!f.createNewFile() && !f.exists()) {
throw new IOException("Could not create file " + f);
}
}
}
return f;
}
private void checkCreateFiles () throws IOException
{
// Whether we are resuming or not,
// if any of the files already exists we assume we are resuming.
boolean resume = false;
// Make sure all files are available and of correct length
for (int i = 0; i < rafs.length; i++) {
long length = rafs[i].length();
if (length == lengths[i]) {
if (listener != null) {
listener.storageAllocated(this, length);
}
resume = true; // XXX Could dynamicly check
} else if (length == 0) {
allocateFile(i);
} else {
log.log(Level.FINE, "Truncating '" + names[i]
+ "' from " + lengths + " to " + lengths[i] + "bytes");
rafs[i].setLength(lengths[i]);
allocateFile(i);
}
}
// Check which pieces match and which don't
if (resume) {
pieces = metainfo.getPieces();
byte[] piece = new byte[metainfo.getPieceLength(0)];
for (int i = 0; i < pieces; i++) {
int length = getUncheckedPiece(i, piece, 0);
boolean correctHash = metainfo.checkPiece(i, piece, 0, length);
if (correctHash) {
bitfield.set(i);
needed--;
}
if (listener != null) {
listener.storageChecked(this, i, correctHash);
}
}
}
if (listener != null) {
listener.storageAllChecked(this);
}
}
private void allocateFile (int nr) throws IOException
{
// XXX - Is this the best way to make sure we have enough space for
// the whole file?
listener.storageCreateFile(this, names[nr], lengths[nr]);
final int ZEROBLOCKSIZE = metainfo.getPieceLength(0);
byte[] zeros = new byte[ZEROBLOCKSIZE];
int i;
for (i = 0; i < lengths[nr] / ZEROBLOCKSIZE; i++) {
rafs[nr].write(zeros);
if (listener != null) {
listener.storageAllocated(this, ZEROBLOCKSIZE);
}
}
int size = (int)(lengths[nr] - i * ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
if (listener != null) {
listener.storageAllocated(this, size);
}
}
/**
* Closes the Storage and makes sure that all RandomAccessFiles are closed.
* The Storage is unusable after this.
*/
public void close () throws IOException
{
for (RandomAccessFile element : rafs) {
synchronized (element) {
element.close();
}
}
}
/**
* Returns a byte array containing the requested piece or null if the
* storage doesn't contain the piece yet.
*/
public byte[] getPiece (int piece) throws IOException
{
if (!bitfield.get(piece)) {
return null;
}
byte[] bs = new byte[metainfo.getPieceLength(piece)];
getUncheckedPiece(piece, bs, 0);
return bs;
}
/**
* Put the piece in the Storage if it is correct.
*
* @return true if the piece was correct (sha metainfo hash matches),
* otherwise false.
* @exception IOException
* when some storage related error occurs.
*/
public boolean putPiece (int piece, byte[] bs) throws IOException
{
// First check if the piece is correct.
// If we were paranoia we could copy the array first.
int length = bs.length;
boolean correctHash = metainfo.checkPiece(piece, bs, 0, length);
if (listener != null) {
listener.storageChecked(this, piece, correctHash);
}
if (!correctHash) {
return false;
}
synchronized (bitfield) {
if (bitfield.get(piece)) {
return true; // No need to store twice.
} else {
bitfield.set(piece);
needed--;
}
}
long start = piece * metainfo.getPieceLength(0);
int i = 0;
long raflen = lengths[i];
while (start > raflen) {
i++;
start -= raflen;
raflen = lengths[i];
}
int written = 0;
int off = 0;
while (written < length) {
int need = length - written;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized (rafs[i]) {
rafs[i].seek(start);
rafs[i].write(bs, off + written, len);
}
written += len;
if (need - len > 0) {
i++;
raflen = lengths[i];
start = 0;
}
}
return true;
}
private int getUncheckedPiece (int piece, byte[] bs, int off)
throws IOException
{
// XXX - copy/paste code from putPiece().
long start = piece * metainfo.getPieceLength(0);
int length = metainfo.getPieceLength(piece);
int i = 0;
long raflen = lengths[i];
while (start > raflen) {
i++;
start -= raflen;
raflen = lengths[i];
}
int read = 0;
while (read < length) {
int need = length - read;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized (rafs[i]) {
rafs[i].seek(start);
rafs[i].readFully(bs, off + read, len);
}
read += len;
if (need - len > 0) {
i++;
raflen = lengths[i];
start = 0;
}
}
return length;
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.Storage");
}

View File

@ -1,51 +0,0 @@
/*
* StorageListener.java - Interface used as callback when storage changes.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Callback used when Storage changes.
*/
public interface StorageListener
{
/**
* Called when the storage creates a new file of a given length.
*/
void storageCreateFile (Storage storage, String name, long length);
/**
* Called to indicate that length bytes have been allocated.
*/
void storageAllocated (Storage storage, long length);
/**
* Called when storage is being checked and the num piece of that total
* pieces has been checked. When the piece hash matches the expected piece
* hash checked will be true, otherwise it will be false.
*/
void storageChecked (Storage storage, int num, boolean checked);
/**
* Called when all pieces in the storage have been checked. Does not mean
* that the storage is complete, just that the state of the storage is
* known.
*/
void storageAllChecked (Storage storage);
}

View File

@ -1,202 +0,0 @@
/*
* Tracker - Keeps track of clients sharing a particular torrent MetaInfo.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.klomp.snark.bencode.BEncoder;
/**
* Keeps track of clients sharing a particular torrent MetaInfo.
*/
public class Tracker
{
private static final int INTERVAL_SEC = 15 * 60; // 15 minutes.
private final Map<String, MetaInfo> metainfo =
new HashMap<String, MetaInfo>();
private final Set<String> info_hashes = new HashSet<String>();
private Map<String, HashSet<PeerID>> peers =
new HashMap<String, HashSet<PeerID>>();
public Tracker (HashSet<String> hashes)
{
for (String hash : hashes) {
info_hashes.add(hash);
peers.put(hash, new HashSet<PeerID>());
}
}
public Tracker (MetaInfo info)
{
String hash = info.getHexInfoHash();
info_hashes.add(hash);
metainfo.put(hash, info);
peers.put(hash, new HashSet<PeerID>());
}
public MetaInfo getMetaInfo (String hash)
{
return metainfo.get(hash);
}
public void addPeer (String info_hash, PeerID peer)
{
HashSet<PeerID> peerset = peers.get(info_hash);
if (peerset != null) {
synchronized (peerset) {
peerset.add(peer);
}
}
}
public byte[] handleRequest (InetAddress address, int port, Map params)
{
log.log(Level.FINE, "TrackerReq " + address + ":" + port + " -> "
+ params);
String info_hash_value = (String)params.get("info_hash");
if (info_hash_value == null) {
return failure("No info_hash given");
}
info_hash_value = info_hash_value.replace("%", "");
boolean found = false;
for (String hash : info_hashes) {
if (hash.equals(info_hash_value)) {
found = true;
}
}
if (!found) {
return failure("Tracker doesn't handle given info_hash");
}
byte[] peer_id;
String peer_id_value = (String)params.get("peer_id");
if (peer_id_value == null) {
return failure("No peer_id given");
}
peer_id = urldecode(peer_id_value);
if (peer_id.length != 20) {
return failure("peer_id must be 20 bytes long");
}
int peer_port;
String peer_port_value = (String)params.get("port");
if (peer_port_value == null) {
return failure("No port given");
}
try {
peer_port = Integer.parseInt(peer_port_value);
} catch (NumberFormatException nfe) {
return failure("port not a number: " + nfe);
}
// This is unsafe although other trackers support it.
// It is nice for people that use proxies, but opens up
// a whole can of worms (filling the tracker with fake ips).
//
// It could bee allowed for private use and local addresses
// See RFC1918 and 127.0.0.0/8.
/*
* String ip = (String)params.get("ip"); if (ip != null) { try { address =
* InetAddress.getByName(ip); } catch (UnknownHostException uhe) { } }
*/
PeerID peer = new PeerID(peer_id, address, peer_port);
Map<String, Object> response = new HashMap<String, Object>();
Set<PeerID> peerset = peers.get(info_hash_value);
synchronized (peerset) {
String event = (String)params.get("event");
if ("stopped".equals(event)) {
peerset.remove(peer);
} else {
peerset.add(peer);
}
response.put("interval", new Integer(INTERVAL_SEC));
List<Map<String, Object>> peerList = new ArrayList<Map<String, Object>>();
Iterator it = peerset.iterator();
while (it.hasNext()) {
PeerID peerID = (PeerID)it.next();
Map<String, Object> m = new HashMap<String, Object>();
m.put("peer id", peerID.getID());
m.put("ip", peerID.getAddress().getHostAddress());
m.put("port", new Integer(peerID.getPort()));
peerList.add(m);
}
response.put("peers", peerList);
}
log.log(Level.FINE, "Tracker response: " + response);
return BEncoder.bencode(response);
}
private static byte[] failure (String s)
{
Map<String, String> m = new HashMap<String, String>();
m.put("failure reason", s);
return BEncoder.bencode(m);
}
/**
* Cheap (but slow) urldecode String to byte array.
*/
static byte[] urldecode (String s)
{
s = s.replace('+', ' ');
char[] cs = s.toCharArray();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = 0;
while (i < cs.length) {
if (cs[i] != '%') {
baos.write((byte)cs[i]);
i++;
} else if (i + 2 < cs.length) {
int val = 16 * Character.digit(cs[i + 1], 16)
+ Character.digit(cs[i + 2], 16);
baos.write((byte)val);
i += 3;
} else {
i++;
}
}
return baos.toByteArray();
}
protected static final Logger log = Logger.getLogger("org.klomp.snark.Tracker");
}

View File

@ -1,258 +0,0 @@
/*
* TrackerClient - Class that informs a tracker and gets new peers. Copyright
* (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Informs metainfo tracker of events and gets new peers for peer coordinator.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class TrackerClient extends Thread
{
private static final String NO_EVENT = "";
private static final String STARTED_EVENT = "started";
private static final String COMPLETED_EVENT = "completed";
private static final String STOPPED_EVENT = "stopped";
private final static int SLEEP = 1; // Check in with tracker every minute
private final MetaInfo meta;
private final PeerCoordinator coordinator;
private final int port;
private boolean stop;
private long interval;
private long lastRequestTime;
public TrackerClient (MetaInfo meta, PeerCoordinator coordinator, int port)
{
// Set unique name.
super("TrackerClient-" + urlencode(coordinator.getID()));
this.meta = meta;
this.coordinator = coordinator;
// XXX - No way to actaully give the tracker feedback that we
// don't run a peer acceptor on any port so use discard 9/tcp sink null
this.port = (port == -1) ? 9 : port;
stop = false;
}
/**
* Interrupts this Thread to stop it.
*/
public void halt ()
{
stop = true;
this.interrupt();
}
@Override
public void run ()
{
// XXX - Support other IPs
String announce = meta.getAnnounce();
String infoHash = urlencode(meta.getInfoHash());
String peerID = urlencode(coordinator.getID());
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft();
boolean completed = coordinator.completed();
boolean started = false;
try {
int failures = 0;
while (!started && failures < MAX_FAILURE_COUNT) {
try {
// Send start.
TrackerInfo info = doRequest(announce, infoHash, peerID,
uploaded, downloaded, left, STARTED_EVENT);
Iterator it = info.getPeers().iterator();
while (it.hasNext()) {
coordinator.addPeer((Peer)it.next());
}
started = true;
} catch (IOException ioe) {
// Probably not fatal (if it doesn't last to long...)
log.log(Level.WARNING, "Could not contact tracker at '"
+ announce, ioe);
}
if (!started) {
failures++;
log.log(Level.FINER, " Retrying in 5s...");
try {
// Sleep five seconds...
Thread.sleep(5 * 1000);
} catch (InterruptedException interrupt) {
// ignore
}
}
}
if (failures >= MAX_FAILURE_COUNT) {
throw new IOException("Could not establish initial connection");
}
while (!stop) {
try {
// Sleep some minutes...
Thread.sleep(SLEEP * 60 * 1000);
} catch (InterruptedException interrupt) {
// ignore
}
if (stop) {
break;
}
uploaded = coordinator.getUploaded();
downloaded = coordinator.getDownloaded();
left = coordinator.getLeft();
// First time we got a complete download?
String event;
if (!completed && coordinator.completed()) {
completed = true;
event = COMPLETED_EVENT;
} else {
event = NO_EVENT;
}
// Only do a request when necessary.
if (event == COMPLETED_EVENT || coordinator.needPeers()
|| System.currentTimeMillis() > lastRequestTime + interval) {
try {
TrackerInfo info = doRequest(announce, infoHash,
peerID, uploaded, downloaded, left, event);
Iterator it = info.getPeers().iterator();
while (it.hasNext()) {
coordinator.addPeer((Peer)it.next());
}
} catch (IOException ioe) {
// Probably not fatal (if it doesn't last to long...)
log.log(Level.WARNING, "Could not contact tracker at '"
+ announce, ioe);
}
}
}
} catch (Throwable t) {
log.log(Level.SEVERE, "Fatal exception in TrackerClient", t);
} finally {
try {
if (started) {
doRequest(announce, infoHash, peerID, uploaded, downloaded,
left, STOPPED_EVENT);
}
} catch (IOException ioe) { /* ignored */
}
}
}
private TrackerInfo doRequest (String announce, String infoHash,
String peerID, long uploaded, long downloaded, long left, String event)
throws IOException
{
String s = announce + "?info_hash=" + infoHash + "&peer_id=" + peerID
+ "&port=" + port + "&uploaded=" + uploaded + "&downloaded="
+ downloaded + "&left=" + left
+ ((event != NO_EVENT) ? ("&event=" + event) : "");
URL u = new URL(s);
log.log(Level.FINE, "Sending TrackerClient request: " + u);
URLConnection c = u.openConnection();
c.connect();
InputStream in = c.getInputStream();
if (c instanceof HttpURLConnection) {
// Check whether the page exists
int code = ((HttpURLConnection)c).getResponseCode();
if (code == HttpURLConnection.HTTP_FORBIDDEN) {
throw new IOException("Tracker doesn't handle given info_hash");
} else if (code / 100 != 2) {
throw new IOException("Loading '" + s + "' gave error code "
+ code + ", it probably doesn't exist");
}
}
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
coordinator.getMetaInfo());
log.log(Level.FINE, "TrackerClient response: " + info);
lastRequestTime = System.currentTimeMillis();
String failure = info.getFailureReason();
if (failure != null) {
throw new IOException(failure);
}
interval = info.getInterval() * 1000;
return info;
}
/**
* Very lazy byte[] to URL encoder. Just encodes everything, even "normal"
* chars.
*/
static String urlencode (byte[] bs)
{
StringBuffer sb = new StringBuffer(bs.length * 3);
for (byte element : bs) {
int c = element & 0xFF;
sb.append('%');
if (c < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.TrackerClient");
/**
* The maximum number of times that we are allowed to fail to make an
* initial contact with the tracker before we bail
*/
protected static final int MAX_FAILURE_COUNT = 2;
}

View File

@ -1,131 +0,0 @@
/*
* TrackerInfo - Holds information returned by a tracker, mainly the peer list.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
public class TrackerInfo
{
private final String failure_reason;
private final int interval;
private final Set peers;
public TrackerInfo (InputStream in, byte[] my_id, MetaInfo metainfo)
throws IOException
{
this(new BDecoder(in), my_id, metainfo);
}
public TrackerInfo (BDecoder be, byte[] my_id, MetaInfo metainfo)
throws IOException
{
this(be.bdecodeMap().getMap(), my_id, metainfo);
}
public TrackerInfo (Map m, byte[] my_id, MetaInfo metainfo)
throws IOException
{
BEValue reason = (BEValue)m.get("failure reason");
if (reason != null) {
failure_reason = reason.getString();
interval = -1;
peers = null;
} else {
failure_reason = null;
BEValue beInterval = (BEValue)m.get("interval");
if (beInterval == null) {
throw new InvalidBEncodingException("No interval given");
} else {
interval = beInterval.getInt();
}
BEValue bePeers = (BEValue)m.get("peers");
if (bePeers == null) {
throw new InvalidBEncodingException("No peer list");
} else {
peers = getPeers(bePeers.getList(), my_id, metainfo);
}
}
}
public static Set getPeers (InputStream in, byte[] my_id, MetaInfo metainfo)
throws IOException
{
return getPeers(new BDecoder(in), my_id, metainfo);
}
public static Set getPeers (BDecoder be, byte[] my_id, MetaInfo metainfo)
throws IOException
{
return getPeers(be.bdecodeList().getList(), my_id, metainfo);
}
public static Set<Peer> getPeers (List l, byte[] my_id, MetaInfo metainfo)
throws IOException
{
Set<Peer> peers = new HashSet<Peer>(l.size());
Iterator it = l.iterator();
while (it.hasNext()) {
PeerID peerID = new PeerID(((BEValue)it.next()).getMap());
peers.add(new Peer(peerID, my_id, metainfo));
}
return peers;
}
public Set getPeers ()
{
return peers;
}
public String getFailureReason ()
{
return failure_reason;
}
public int getInterval ()
{
return interval;
}
@Override
public String toString ()
{
if (failure_reason != null) {
return "TrackerInfo[FAILED: " + failure_reason + "]";
} else {
return "TrackerInfo[interval=" + interval + ", peers=" + peers
+ "]";
}
}
}

View File

@ -1,358 +0,0 @@
/*
* BDecoder - Converts an InputStream to BEValues. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark.bencode;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Decodes a bencoded stream to <code>BEValue</code>s.
*
* A bencoded byte stream can represent byte arrays, numbers, lists and maps
* (dictionaries).
*
* It currently contains a hack to indicate a name of a dictionary of which a
* SHA-1 digest hash should be calculated (the hash over the original bencoded
* bytes).
*
* @author Mark Wielaard (mark@klomp.org).
*/
public class BDecoder
{
// The InputStream to BDecode.
private final InputStream in;
// The last indicator read.
// Zero if unknown.
// '0'..'9' indicates a byte[].
// 'i' indicates an Number.
// 'l' indicates a List.
// 'd' indicates a Map.
// 'e' indicates end of Number, List or Map (only used internally).
// -1 indicates end of stream.
// Call getNextIndicator to get the current value (will never return zero).
private int indicator = 0;
// Used for ugly hack to get SHA hash over the metainfo info map
private String special_map = "info";
private boolean in_special_map = false;
private final MessageDigest sha_digest;
// Ugly hack. Return the SHA has over bytes that make up the special map.
public byte[] get_special_map_digest ()
{
byte[] result = sha_digest.digest();
return result;
}
// Ugly hack. Name defaults to "info".
public void set_special_map_name (String name)
{
special_map = name;
}
/**
* Initalizes a new BDecoder. Nothing is read from the given
* <code>InputStream</code> yet.
*/
public BDecoder (InputStream in)
{
this.in = in;
// XXX - Used for ugly hack.
try {
sha_digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException nsa) {
throw new InternalError(nsa.toString());
}
}
/**
* Creates a new BDecoder and immediatly decodes the first value it sees.
*
* @return The first BEValue on the stream or null when the stream has
* ended.
*
* @exception InvalidBEncoding
* when the stream doesn't start with a bencoded value or the
* stream isn't a bencoded stream at all.
* @exception IOException
* when somthing bad happens with the stream to read from.
*/
public static BEValue bdecode (InputStream in) throws IOException
{
return new BDecoder(in).bdecode();
}
/**
* Returns what the next bencoded object will be on the stream or -1 when
* the end of stream has been reached. Can return something unexpected (not
* '0' .. '9', 'i', 'l' or 'd') when the stream isn't bencoded.
*
* This might or might not read one extra byte from the stream.
*/
public int getNextIndicator () throws IOException
{
if (indicator == 0) {
indicator = in.read();
// XXX - Used for ugly hack
if (in_special_map) {
sha_digest.update((byte)indicator);
}
}
return indicator;
}
/**
* Gets the next indicator and returns either null when the stream has ended
* or bdecodes the rest of the stream and returns the appropriate BEValue
* encoded object.
*/
public BEValue bdecode () throws IOException
{
indicator = getNextIndicator();
if (indicator == -1) {
return null;
}
if (indicator >= '0' && indicator <= '9') {
return bdecodeBytes();
} else if (indicator == 'i') {
return bdecodeNumber();
} else if (indicator == 'l') {
return bdecodeList();
} else if (indicator == 'd') {
return bdecodeMap();
} else {
throw new InvalidBEncodingException("Unknown indicator '"
+ indicator + "'");
}
}
/**
* Returns the next bencoded value on the stream and makes sure it is a byte
* array. If it is not a bencoded byte array it will throw
* InvalidBEncodingException.
*/
public BEValue bdecodeBytes () throws IOException
{
int c = getNextIndicator();
int num = c - '0';
if (num < 0 || num > 9) {
throw new InvalidBEncodingException("Number expected, not '"
+ (char)c + "'");
}
indicator = 0;
c = read();
int i = c - '0';
while (i >= 0 && i <= 9) {
// XXX - This can overflow!
num = num * 10 + i;
c = read();
i = c - '0';
}
if (c != ':') {
throw new InvalidBEncodingException("Colon expected, not '"
+ (char)c + "'");
}
return new BEValue(read(num));
}
/**
* Returns the next bencoded value on the stream and makes sure it is a
* number. If it is not a number it will throw InvalidBEncodingException.
*/
public BEValue bdecodeNumber () throws IOException
{
int c = getNextIndicator();
if (c != 'i') {
throw new InvalidBEncodingException("Expected 'i', not '" + (char)c
+ "'");
}
indicator = 0;
c = read();
if (c == '0') {
c = read();
if (c == 'e') {
return new BEValue(BigInteger.ZERO);
} else {
throw new InvalidBEncodingException("'e' expected after zero,"
+ " not '" + (char)c + "'");
}
}
// XXX - We don't support more the 255 char big integers
char[] chars = new char[256];
int off = 0;
if (c == '-') {
c = read();
if (c == '0') {
throw new InvalidBEncodingException("Negative zero not allowed");
}
chars[off] = (char)c;
off++;
}
if (c < '1' || c > '9') {
throw new InvalidBEncodingException("Invalid Integer start '"
+ (char)c + "'");
}
chars[off] = (char)c;
off++;
c = read();
int i = c - '0';
while (i >= 0 && i <= 9) {
chars[off] = (char)c;
off++;
c = read();
i = c - '0';
}
if (c != 'e') {
throw new InvalidBEncodingException("Integer should end with 'e'");
}
String s = new String(chars, 0, off);
return new BEValue(new BigInteger(s));
}
/**
* Returns the next bencoded value on the stream and makes sure it is a
* list. If it is not a list it will throw InvalidBEncodingException.
*/
public BEValue bdecodeList () throws IOException
{
int c = getNextIndicator();
if (c != 'l') {
throw new InvalidBEncodingException("Expected 'l', not '" + (char)c
+ "'");
}
indicator = 0;
List<BEValue> result = new ArrayList<BEValue>();
c = getNextIndicator();
while (c != 'e') {
result.add(bdecode());
c = getNextIndicator();
}
indicator = 0;
return new BEValue(result);
}
/**
* Returns the next bencoded value on the stream and makes sure it is a map
* (dictonary). If it is not a map it will throw InvalidBEncodingException.
*/
public BEValue bdecodeMap () throws IOException
{
int c = getNextIndicator();
if (c != 'd') {
throw new InvalidBEncodingException("Expected 'd', not '" + (char)c
+ "'");
}
indicator = 0;
Map<String, BEValue> result = new HashMap<String, BEValue>();
c = getNextIndicator();
while (c != 'e') {
// Dictonary keys are always strings.
String key = bdecode().getString();
// XXX ugly hack
boolean special = special_map.equals(key);
if (special) {
in_special_map = true;
}
BEValue value = bdecode();
result.put(key, value);
// XXX ugly hack continued
if (special) {
in_special_map = false;
}
c = getNextIndicator();
}
indicator = 0;
return new BEValue(result);
}
/**
* Returns the next byte read from the InputStream (as int). Throws
* EOFException if InputStream.read() returned -1.
*/
private int read () throws IOException
{
int c = in.read();
if (c == -1) {
throw new EOFException();
}
if (in_special_map) {
sha_digest.update((byte)c);
}
return c;
}
/**
* Returns a byte[] containing length valid bytes starting at offset zero.
* Throws EOFException if InputStream.read() returned -1 before all
* requested bytes could be read. Note that the byte[] returned might be
* bigger then requested but will only contain length valid bytes. The
* returned byte[] will be reused when this method is called again.
*/
private byte[] read (int length) throws IOException
{
byte[] result = new byte[length];
int read = 0;
while (read < length) {
int i = in.read(result, read, length - read);
if (i == -1) {
throw new EOFException();
}
read += i;
}
if (in_special_map) {
sha_digest.update(result, 0, length);
}
return result;
}
}

View File

@ -1,172 +0,0 @@
/*
* BEValue - Holds different types that a bencoded byte array can represent.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark.bencode;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
/**
* Holds different types that a bencoded byte array can represent. You need to
* call the correct get method to get the correct java type object. If the
* BEValue wasn't actually of the requested type you will get a
* InvalidBEncodingException.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class BEValue
{
// This is either a byte[], Number, List or Map.
private final Object value;
public BEValue (byte[] value)
{
this.value = value;
}
public BEValue (Number value)
{
this.value = value;
}
public BEValue (List value)
{
this.value = value;
}
public BEValue (Map value)
{
this.value = value;
}
/**
* Returns this BEValue as a String. This operation only succeeds when the
* BEValue is a byte[], otherwise it will throw a InvalidBEncodingException.
* The byte[] will be interpreted as UTF-8 encoded characters.
*/
public String getString () throws InvalidBEncodingException
{
try {
return new String(getBytes(), "UTF-8");
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString());
} catch (UnsupportedEncodingException uee) {
throw new InternalError(uee.toString());
}
}
/**
* Returns this BEValue as a byte[]. This operation only succeeds when the
* BEValue is actually a byte[], otherwise it will throw a
* InvalidBEncodingException.
*/
public byte[] getBytes () throws InvalidBEncodingException
{
try {
return (byte[])value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString());
}
}
/**
* Returns this BEValue as a Number. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException.
*/
public Number getNumber () throws InvalidBEncodingException
{
try {
return (Number)value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString());
}
}
/**
* Returns this BEValue as int. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException. The returned int is the result of
* <code>Number.intValue()</code>.
*/
public int getInt () throws InvalidBEncodingException
{
return getNumber().intValue();
}
/**
* Returns this BEValue as long. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException. The returned long is the result of
* <code>Number.longValue()</code>.
*/
public long getLong () throws InvalidBEncodingException
{
return getNumber().longValue();
}
/**
* Returns this BEValue as a List of BEValues. This operation only succeeds
* when the BEValue is actually a List, otherwise it will throw a
* InvalidBEncodingException.
*/
public List<BEValue> getList () throws InvalidBEncodingException
{
try {
return (List<BEValue>)value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString());
}
}
/**
* Returns this BEValue as a Map of BEValue keys and BEValue values. This
* operation only succeeds when the BEValue is actually a Map, otherwise it
* will throw a InvalidBEncodingException.
*/
public Map getMap () throws InvalidBEncodingException
{
try {
return (Map)value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString());
}
}
@Override
public String toString ()
{
String valueString;
if (value instanceof byte[]) {
byte[] bs = (byte[])value;
// XXX - Stupid heuristic...
if (bs.length <= 12) {
valueString = new String(bs);
} else {
valueString = "bytes:" + bs.length;
}
} else {
valueString = value.toString();
}
return "BEValue[" + valueString + "]";
}
}

View File

@ -1,171 +0,0 @@
/*
* BDecoder - Converts an InputStream to BEValues. Copyright (C) 2003 Mark J.
* Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark.bencode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class BEncoder
{
public static byte[] bencode (Object o) throws IllegalArgumentException
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(o, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (Object o, OutputStream out) throws IOException,
IllegalArgumentException
{
if (o instanceof String) {
bencode((String)o, out);
} else if (o instanceof byte[]) {
bencode((byte[])o, out);
} else if (o instanceof Number) {
bencode((Number)o, out);
} else if (o instanceof List) {
bencode((List)o, out);
} else if (o instanceof Map) {
bencode((Map<String, Object>)o, out);
} else {
throw new IllegalArgumentException("Cannot bencode: "
+ o.getClass());
}
}
public static byte[] bencode (String s)
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(s, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (String s, OutputStream out) throws IOException
{
byte[] bs = s.getBytes("UTF-8");
bencode(bs, out);
}
public static byte[] bencode (Number n)
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(n, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (Number n, OutputStream out) throws IOException
{
out.write('i');
String s = n.toString();
out.write(s.getBytes("UTF-8"));
out.write('e');
}
public static byte[] bencode (List l)
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(l, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (List l, OutputStream out) throws IOException
{
out.write('l');
Iterator it = l.iterator();
while (it.hasNext()) {
bencode(it.next(), out);
}
out.write('e');
}
public static byte[] bencode (byte[] bs)
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(bs, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (byte[] bs, OutputStream out) throws IOException
{
String l = Integer.toString(bs.length);
out.write(l.getBytes("UTF-8"));
out.write(':');
out.write(bs);
}
public static byte[] bencode (Map<String, Object> m)
{
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bencode(m, baos);
return baos.toByteArray();
} catch (IOException ioe) {
throw new InternalError(ioe.toString());
}
}
public static void bencode (Map<String, Object> m, OutputStream out)
throws IOException
{
out.write('d');
// Keys must be sorted. XXX - But is this the correct order?
Set<String> s = m.keySet();
List<String> l = new ArrayList<String>(s);
Collections.sort(l);
for (String key : l) {
Object value = m.get(key);
bencode(key, out);
bencode(value, out);
}
out.write('e');
}
}

View File

@ -1,36 +0,0 @@
/*
* InvalidBEncodingException - Thrown when a bencoded stream is corrupted.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark.bencode;
import java.io.IOException;
/**
* Exception thrown when a bencoded stream is corrupted.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class InvalidBEncodingException extends IOException
{
public InvalidBEncodingException (String message)
{
super(message);
}
}

View File

@ -1,73 +0,0 @@
package org.klomp.snark.cmd;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.klomp.snark.MetaInfo;
import org.klomp.snark.Storage;
import org.klomp.snark.StorageListener;
/**
* Reports the status of allocation of space via logging data to
* the console.
*
* @author Elizabeth Fong (elizabeth@ctyalcove.org)
*/
public class ConsoleStorageReporter implements StorageListener
{
public void storageCreateFile (Storage storage, String name, long length)
{
log.log(Level.FINE, "Creating file '" + name + "' of length " +
length + ": ");
}
// How much storage space has been allocated
private long allocated = 0;
public void storageAllocated (Storage storage, long length)
{
System.err.print(".");
allocated += length;
if (allocated == storage.getMetaInfo().getTotalLength()) {
System.err.println();
log.log(Level.INFO, "Finished allocating storage space");
}
}
boolean allChecked = false;
boolean checking = false;
public void storageChecked (Storage storage, int num, boolean checked)
{
if (!allChecked && !checking) {
// Use the MetaInfo from the storage since our own might not
// yet be setup correctly.
MetaInfo meta = storage.getMetaInfo();
if (meta != null) {
log.log(Level.INFO, "Checking existing " + meta.getPieces()
+ " pieces: ");
}
checking = true;
}
if (checking) {
if (checked) {
System.err.print("+");
} else {
System.err.print("-");
}
} else {
log.log(Level.FINE, "Got " + (checked ? "" : "BAD ") + "piece: "
+ num);
}
}
public void storageAllChecked (Storage storage)
{
allChecked = true;
checking = false;
}
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.storage");
}

View File

@ -1,293 +0,0 @@
package org.klomp.snark.cmd;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.Timer;
import java.util.TimerTask;
import org.klomp.snark.CoordinatorListener;
import org.klomp.snark.Peer;
import org.klomp.snark.PeerMonitorTask;
import org.klomp.snark.ShutdownListener;
import org.klomp.snark.Snark;
import org.klomp.snark.SnarkShutdown;
import org.klomp.snark.StorageListener;
/**
* A basic command line interface to the Snark library.
*
* @author Elizabeth Fong (elizabeth@threerings.net)
*/
public class SnarkApplication
{
public static void main (String[] args)
{
System.out.println(copyright);
System.out.println();
// Parse debug, share/ip and torrent file options.
Snark snark = parseArguments(args, new ConsoleStorageReporter(), null);
boolean interactive = true;
boolean showPeers = false;
for (String arg : args) {
if (arg.equals("--no-commands")) {
interactive = false;
}
if (arg.equals("--show-peers") || arg.equals("--share")) {
showPeers = true;
}
};
// Set things up to exit gracefully
ShutdownListener listener = new ShutdownListener() {
// documentation inherited from interface ShutdownListener
public void shutdown ()
{
// Should not be necessary since all non-deamon threads should
// have died. But in reality this does not always happen.
System.exit(0);
}
};
SnarkShutdown hook = new SnarkShutdown(snark, listener);
Runtime.getRuntime().addShutdownHook(hook);
// Let's start grabbing files!
try {
snark.setupNetwork();
snark.collectPieces();
} catch (IOException ioe) {
System.exit(-1);
}
// If requested, periodically monitor progress.
if (showPeers) {
Timer timer = new Timer(true);
TimerTask monitor = new PeerMonitorTask(snark.coordinator);
timer.schedule(monitor, PeerMonitorTask.MONITOR_PERIOD,
PeerMonitorTask.MONITOR_PERIOD);
}
// Start interactive command interpreter if desired
if (interactive) {
doInteractive(snark, hook);
}
}
/**
* Initializes the user-interactive readline interface to Snark
*/
protected static void doInteractive (Snark snark, SnarkShutdown hook)
{
boolean quit = false;
System.out.println();
System.out.println(usage);
System.out.println();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
String line = br.readLine();
while (!quit && line != null) {
line = line.toLowerCase();
if ("quit".equals(line)) {
quit = true;
} else if ("list".equals(line)) {
synchronized (snark.coordinator.peers) {
System.out.println(snark.coordinator.peers.size()
+ " peers -" + " (i)nterested," + " (I)nteresting,"
+ " (c)hoking," + " (C)hoked:");
Iterator it = snark.coordinator.peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
System.out.println(peer);
System.out.println("\ti: " + peer.isInterested()
+ " I: " + peer.isInteresting() + " c: "
+ peer.isChoking() + " C: " + peer.isChoked());
}
}
} else if ("info".equals(line)) {
System.out.println("Name: " + snark.meta.getName());
System.out.println("Torrent: " + snark.torrent);
System.out.println("Tracker: " + snark.meta.getAnnounce());
List files = snark.meta.getFiles();
System.out.println("Files: "
+ ((files == null) ? 1 : files.size()));
System.out.println("Pieces: " + snark.meta.getPieces());
System.out.println("Piece size: "
+ snark.meta.getPieceLength(0) / 1024 + " KB");
System.out.println("Total size: "
+ snark.meta.getTotalLength() / (1024 * 1024) + " MB");
} else if ("state".equals(line)) {
System.out.println(
snark.storage.getBitField().getHumanReadable());
System.out.println("Total peers: "
+ snark.coordinator.getPeers());
System.out.println("Total size: "
+ snark.meta.getTotalLength() / (1024 * 1024) + " MB");
System.out.println("Total remaining: "
+ snark.coordinator.getLeft() / (1024 * 1024) + " MB");
System.out.println("Total downloaded: "
+ snark.coordinator.getDownloaded());
System.out.println("Total uploaded: "
+ snark.coordinator.getUploaded());
} else if ("".equals(line) || "help".equals(line)) {
System.out.println(usage);
System.out.println(help);
} else {
System.out.println("Unknown command: " + line);
System.out.println(usage);
}
if (!quit) {
System.out.println();
line = br.readLine();
}
}
} catch (IOException ioe) {
log.log(Level.SEVERE, "Unable to read stdin", ioe);
}
// Explicit shutdown.
Runtime.getRuntime().removeShutdownHook(hook);
hook.start();
}
/**
* Prints messages about proper usage of the Snark application.
*/
protected static void usage (String s)
{
PrintStream stream = System.out;
if (s != null) {
stream = System.err;
stream.println("snark: " + s);
}
stream.println("Usage: snark [--debug [level]] [--no-commands] [--port <port>]");
stream.println(" [--show-peers] [--share (<ip>|<host>)] (<url>|<file>|<dir>)");
stream.println(" --debug\tShows some extra info and stacktraces");
stream.println(" level\tHow much debug details to show");
stream.println(" \t(defaults to " + Level.SEVERE
+ ", with --debug to " + Level.INFO + ", highest level is "
+ Level.ALL + ").");
stream.println(" --no-commands\tDon't read interactive commands or show usage info.");
stream.println(" --port\tThe port to listen on for incomming connections");
stream.println(" \t(if not given defaults to first free port between "
+ Snark.MIN_PORT + "-" + Snark.MAX_PORT + ").");
stream.println(" --show-peers\tIf enabled, periodically prints peer information.");
stream.println(" --share\tStart torrent tracker on <ip> address or <host> name.");
stream.println(" <url> \tURL pointing to .torrent metainfo file to download/share.");
stream.println(" <file> \tEither a local .torrent metainfo file to download");
stream.println(" \tor (with --share) a file to share.");
stream.println(" <dir> \tA directory with files to share (needs --share).");
System.exit(-1);
}
/**
* A convenience method for parsing arguments passed via the command line
* where no overriding of the listeners is required.
*/
public static Snark parseArguments (String[] args)
{
return parseArguments(args, null, null);
}
/**
* Sets debug, ip and torrent variables then creates a Snark instance. Calls
* usage(), which terminates the program, if non-valid argument list. The
* given listeners will be passed to all components that take one.
*/
public static Snark parseArguments (String[] args,
StorageListener slistener, CoordinatorListener clistener)
{
int user_port = -1;
String ip = null;
String torrent = null;
Level level = Level.INFO;
int i = 0;
while (i < args.length) {
if (args[i].equals("--debug")) {
level = Level.FINE;
i++;
// Try if there is an level argument.
if (i < args.length) {
try {
level = Level.parse(args[i]);
} catch (IllegalArgumentException iae) {
// continue parsing arguments
}
i++;
}
} else if (args[i].equals("--port")) {
if (args.length - 1 < i + 1) {
usage("--port needs port number to listen on");
}
try {
user_port = Integer.parseInt(args[i + 1]);
} catch (NumberFormatException nfe) {
usage("--port argument must be a number (" + nfe + ")");
}
i += 2;
} else if (args[i].equals("--share")) {
if (args.length - 1 < i + 1) {
usage("--share needs local ip-address or host-name");
}
ip = args[i + 1];
i += 2;
} else if (args[i].equals("--no-commands") ||
args[i].equals("--show-peers")) {
// ignore, processed elsewhere.
i++;
} else if (args[i].equals("--help")) {
usage(null);
} else {
torrent = args[i];
i++;
break;
}
}
log.setLevel(level);
Snark.setLogLevel(level);
if (torrent == null || i != args.length) {
if (torrent != null && torrent.startsWith("-")) {
usage("Unknown option '" + torrent + "'.");
} else {
usage("Need exactly one <url>, <file> or <dir>.");
}
}
Snark snark = new Snark(torrent, ip, user_port, slistener, clistener);
return snark;
}
protected static final String newline = System.getProperty("line.separator");
protected static final String copyright =
"The Hunting of the Snark Project - "
+ "Copyright (C) 2003 Mark J. Wielaard, (c) 2006 Three Rings Design"
+ newline
+ newline
+ "Snark comes with ABSOLUTELY NO WARRANTY. This is free software, and"
+ newline
+ "you are welcome to redistribute it under certain conditions; read the"
+ newline + "COPYING file for details.";
/** The message displayed when entering the interactive interface */
protected static final String usage =
"Press return for help. Type \"quit\" and return to stop.";
/** A list of commands that the interactive interface accepts */
protected static final String help = "Commands: 'info', 'list', 'quit'.";
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.cmd");
}

View File

@ -1,138 +0,0 @@
package org.klomp.snark.tracker;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.util.HashSet;
import java.util.logging.Logger;
import java.util.logging.Level;
import org.klomp.snark.ConnectionAcceptor;
import org.klomp.snark.HttpAcceptor;
import org.klomp.snark.Snark;
import org.klomp.snark.Tracker;
/**
* A basic command line interface to the Snark library.
*
* @author Elizabeth Fong (elizabeth@threerings.net)
*/
public class TrackerApplication
{
public static void main (String[] args)
{
System.out.println(copyright);
System.out.println();
// Parse debug, share/ip and torrent file options.
try {
ConnectionAcceptor acceptor = parseArguments(args);
acceptor.start();
/*
while (true) {
}
*/
} catch (IOException ioe) {
log.log(Level.SEVERE, "Could not open port", ioe);
}
}
/**
* Prints messages about proper usage of the Snark application.
*/
protected static void usage (String s)
{
PrintStream stream = System.out;
if (s != null) {
stream = System.err;
stream.println("snark: " + s);
}
stream.println(
"Usage: snark [--debug [level]] [--no-commands] [--port <port>] <hash> [<hash> ...]");
stream.println(" --debug\tShows some extra info and stacktraces");
stream.println(" level\tHow much debug details to show");
stream.println(" \t(defaults to " + Level.SEVERE
+ ", with --debug to " + Level.INFO + ", highest level is "
+ Level.ALL + ").");
stream.println(" --port\tThe port to listen on for incomming connections");
stream.println(" \t(if not given defaults to 6969)");
stream.println(" <hash> \tAn infohash for a torrent file shared using the tracker.");
System.exit(-1);
}
/**
* Sets debug, ip and torrent variables then creates a Snark instance. Calls
* usage(), which terminates the program, if non-valid argument list. The
* given listeners will be passed to all components that take one.
*/
public static ConnectionAcceptor parseArguments (String[] args)
throws IOException
{
int user_port = DEFAULT_PORT;
Level level = Level.INFO;
HashSet<String> hashes = new HashSet<String>();
int i = 0;
while (i < args.length) {
if (args[i].equals("--debug")) {
level = Level.FINE;
i++;
// Try if there is an level argument.
if (i < args.length) {
try {
level = Level.parse(args[i]);
} catch (IllegalArgumentException iae) {
// continue parsing arguments
}
}
} else if (args[i].equals("--port")) {
if (args.length - 1 < i + 1) {
usage("--port needs port number to listen on");
}
try {
user_port = Integer.parseInt(args[i + 1]);
} catch (NumberFormatException nfe) {
usage("--port argument must be a number (" + nfe + ")");
}
i += 2;
} else if (args[i].equals("--help")) {
usage(null);
} else {
hashes.add(args[i]);
i++;
break;
}
}
log.setLevel(level);
Snark.setLogLevel(level);
if (hashes.isEmpty()) {
usage("Need at least one <hash>.");
}
Tracker tracker = new Tracker(hashes);
HttpAcceptor httpacceptor = new HttpAcceptor(tracker);
ConnectionAcceptor acceptor = new ConnectionAcceptor(
new ServerSocket(user_port), httpacceptor, null);
return acceptor;
}
protected static final String newline = System.getProperty("line.separator");
protected static final String copyright =
"The Hunting of the Snark Project - "
+ "Copyright (C) 2003 Mark J. Wielaard, (c) 2006 Three Rings Design"
+ newline
+ newline
+ "Snark comes with ABSOLUTELY NO WARRANTY. This is free software, and"
+ newline
+ "you are welcome to redistribute it under certain conditions; read the"
+ newline + "COPYING file for details.";
/** The Java logger used to process our log events. */
protected static final Logger log = Logger.getLogger("org.klomp.snark.cmd");
protected static final int DEFAULT_PORT = 6969;
}

View File

@ -1,73 +0,0 @@
/* VirtualDNS - A modular DNS server.
* Copyright (C) 2000 Eric Kidd
* Copyright (C) 1999 Brian Wellington
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.*;
import org.xbill.DNS.*;
import org.xbill.DNS.utils.*;
/*************************************************************************
* Routines for creating different kinds of DNS error responses.
*************************************************************************
* This code was adapted from Brian Wellington's jnamed code.
* @see org.xbill.DNS.Message
*/
public class ErrorMessages {
/*********************************************************************
* Create a format error message (FORMERR).
*********************************************************************
* @param in The malformed packet.
* @return A DNS error message.
*/
public static Message makeFormatErrorMessage(byte [] in) {
Header header;
try {
header = new Header(in);
}
catch (IOException e) {
header = new Header(0);
}
Message response = new Message();
response.setHeader(header);
for (int i = 0; i < 4; i++)
response.removeAllRecords(i);
header.setRcode(Rcode.FORMERR);
return response;
}
/*********************************************************************
* Create an arbitrary DNS error message.
*********************************************************************
* @param query The query sent by the user.
* @param rcode The response code to use for this error.
* @return A DNS error message.
* @see org.xbill.DNS.Rcode
*/
public static Message makeErrorMessage(SOARecord soa, Message response, short rcode) {
Header header = response.getHeader();
// Message response = new Message();
// response.setHeader(header);
for (int i = 1; i < 4; i++)
response.removeAllRecords(i);
response.addRecord(soa, Section.AUTHORITY);
header.setRcode(rcode);
return response;
}
}

View File

@ -1,311 +0,0 @@
import java.io.*;
import java.lang.reflect.Method;
import java.net.*;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.xbill.DNS.*;
/*
* A simple DNS server that maps a-b-c-d.foo.com to a.b.c.d and rejects everything else
*/
public class VirtualDNS {
static Logger logger = Logger.getLogger(VirtualDNS.class.getName());
String domain;
Zone zone;
// Timeout values, in milliseconds. These are pretty arbitrary. We're
// just trying to shut down unused connections promptly.
static private final int TCP_TIMEOUT = 60000;
/*********************************************************************
* Create and run a new DNS server.
*********************************************************************
* @param port The port on which to run the server.
*/
public VirtualDNS(String domain, String zonefile, short port) throws IOException {
this.domain = domain;
this.zone = new Zone(new Name(domain + "."), zonefile);
// Start our two server processes.
addUDP(port);
addTCP(port);
}
// Create a new TCP listener process.
private void addTCP(final short port) {
Thread t;
t = new Thread(new Runnable() {public void run() {serveTCP(port);}});
t.start();
}
// Create a new UDP listener process.
private void addUDP(final short port) {
Thread t;
t = new Thread(new Runnable() {public void run() {serveUDP(port);}});
t.start();
}
// Our TCP listener process.
private void serveTCP(short port) {
try {
ServerSocket sock = new ServerSocket(port);
while (true) {
final Socket s = sock.accept();
Thread t = new Thread(new Runnable() {
public void run () {
processTCP(s);
}
});
t.start();
}
}
catch (IOException e) {
logger.error("serveTCP failed: " + e);
}
}
// Read and respond to a TCP request.
private void processTCP (Socket s)
{
try {
int inLength;
DataInputStream dataIn;
DataOutputStream dataOut;
byte [] in;
s.setSoTimeout(TCP_TIMEOUT);
try {
InputStream is = s.getInputStream();
dataIn = new DataInputStream(is);
inLength = dataIn.readUnsignedShort();
in = new byte[inLength];
dataIn.readFully(in);
}
catch (InterruptedIOException e) {
s.close();
return;
}
Message query, response;
try {
query = new Message(in);
response = generateReply(query, in, s, s.getInetAddress());
if (response == null)
return;
}
catch (IOException e) {
response = ErrorMessages.makeFormatErrorMessage(in);
}
byte [] out = response.toWire();
dataOut = new DataOutputStream(s.getOutputStream());
dataOut.writeShort(out.length);
dataOut.write(out);
} catch (IOException e) {
logger.error("processTCP: " + e);
} finally {
try {
s.close();
} catch (IOException e) {}
}
}
// Our UDP listener process.
private void serveUDP(short port) {
try {
DatagramSocket sock = new DatagramSocket(port);
while (true) {
short udpLength = 512;
DatagramPacket dp = new DatagramPacket(new byte[512],
512);
try {
sock.receive(dp);
}
catch (InterruptedIOException e) {
continue;
}
byte [] in = new byte[dp.getLength()];
System.arraycopy(dp.getData(), 0, in, 0, in.length);
Message query, response;
try {
query = new Message(in);
response = generateReply(query, in, null, dp.getAddress());
if (response == null)
continue;
}
catch (IOException e) {
response = ErrorMessages.makeFormatErrorMessage(in);
}
byte [] out = response.toWire();
dp = new DatagramPacket(out, out.length,
dp.getAddress(), dp.getPort());
sock.send(dp);
}
}
catch (IOException e) {
logger.error("serveUDP: " + e);
}
}
byte[] getAddr(String hostname) {
byte[] result = new byte[4];
String[] fields = hostname.split("-", 10);
if (fields.length != 4) {
return null;
}
for (int i = 0; i < 4; i++) {
try {
int n = Integer.parseInt(fields[i]);
if (n > 255) {
return null;
}
result[i] = (byte)n;
} catch (NumberFormatException e) {
return null;
}
}
return result;
}
void addRRset(Message response, RRset rrset, int section) {
Iterator it = rrset.rrs();
while(it.hasNext()) {
Record r = (Record)it.next();
response.addRecord(r, section);
}
}
// Construct a proper reply packet.
private Message generateReply(Message query, byte [] in, Socket s, InetAddress src) {
// Refuse everything but standard DNS queries.
if (query.getHeader().getOpcode() != Opcode.QUERY)
return ErrorMessages.makeErrorMessage(zone.getSOA(), query, (short)Rcode.NOTIMPL);
// Get some useful information from the query.
// XXX - What should we do if we get the wrong query version?
Record queryRecord = query.getQuestion();
OPTRecord queryOPT = query.getOPT();
Name name = queryRecord.getName();
short type = (short)queryRecord.getType();
short dclass = (short)queryRecord.getDClass();
logger.info("request id=" + query.getHeader().getID() + " src=" + src + " name=" + name + " type=" + type);
if (dclass != DClass.IN) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), query, (short)Rcode.NOTIMPL);
}
// XXX - Is this the right thing to do with TSIGs?
if (query.getTSIG() != null)
return ErrorMessages.makeErrorMessage(zone.getSOA(), query, (short)Rcode.NOTIMPL);
// Start building our response packet.
Message response = new Message();
response.getHeader().setID(query.getHeader().getID());
response.getHeader().setFlag(Flags.QR);
response.getHeader().setFlag(Flags.AA);
response.addRecord(queryRecord, Section.QUESTION);
// Reject zone transfer requests--our zone is dynamic.
if (type == Type.AXFR && s != null)
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.REFUSED);
// Return an error if we get asked for unsupported record types.
if (!Type.isRR(type) && type != Type.ANY)
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NOTIMPL);
if (type == Type.SIG)
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NOTIMPL);
logger.trace("Querying zone name=" + name + " type=" + type);
response.getHeader().setFlag(Flags.AA);
SetResponse staticResponse = zone.findRecords(name, type);
if (staticResponse.isSuccessful()) {
logger.trace("Zone query successful");
RRset [] rrsets = staticResponse.answers();
for (int j = 0; j < rrsets.length; j++) {
addRRset(response, rrsets[j], Section.ANSWER);
}
return response;
}
if (staticResponse.isNXRRSET()) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NOERROR);
}
// logger.trace("Zone query failed isNXDOMAIN="+staticResponse.isNXDOMAIN() + " isNXRRSET=" + staticResponse.isNXRRSET());
//System.out.println("name = " + name);
String fullname = name.toString();
if (fullname.charAt(fullname.length() - 1) != '.') {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.FORMERR);
}
fullname = fullname.substring(0, fullname.length() - 1);
int i = fullname.indexOf('.');
if (i < 0) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NXDOMAIN);
}
String hostname = fullname.substring(0, i);
String domainname = fullname.substring(i+1);
if (!domainname.equals(domain)) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NXDOMAIN);
}
//System.out.println("hostname = " + hostname);
byte[] addr = getAddr(hostname);
if (addr == null) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NXDOMAIN);
}
InetAddress iaddr;
try {
iaddr = InetAddress.getByAddress(fullname, addr);
} catch (UnknownHostException e) {
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NXDOMAIN);
}
if (type != Type.A) {
// DNS servers return NOERROR for entries that exist but have different type of records
return ErrorMessages.makeErrorMessage(zone.getSOA(), response, (short)Rcode.NOERROR);
}
ARecord record = new ARecord(name, DClass.IN, 24 * 3600, iaddr);
response.addRecord(record, Section.ANSWER);
RRset nss = zone.getNS();
addRRset(response, nss, Section.AUTHORITY);
Iterator it = nss.rrs();
while(it.hasNext()) {
NSRecord r = (NSRecord)it.next();
RRset a = zone.findExactMatch(r.getTarget(), Type.A);
addRRset(response, a, Section.ADDITIONAL);
}
return response;
}
public static void main(String [] args) {
if (args.length != 4) {
System.err.println("Usage: VirtualDNS <domain name> <zonefile> <port> <log4j config>");
System.exit(1);
}
try {
PropertyConfigurator.configure(args[3]);
short port = (short)Integer.parseInt(args[2]);
VirtualDNS s = new VirtualDNS(args[0], args[1], port);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1 +0,0 @@
javac -target 1.5 -g -cp dnsjava-2.0.6.jar:log4j-1.2.15.jar -d classes VirtualDNS.java ErrorMessages.java

View File

@ -1,18 +0,0 @@
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, R
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd MMM HH:mm:ss,SSS} %-5p - %m%n
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd MMM HH:mm:ss,SSS} %-5p - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=/var/log/dns/dns.log
log4j.appender.R.MaxFileSize=32MB
log4j.appender.R.MaxBackupIndex=1000

View File

@ -1,19 +0,0 @@
; Zone file for realhostip.com
;
; The full zone file
;
@ IN SOA realhostip.com. admin.realhostip.com. (
201006211 ; serial, todays date + todays serial #
8H ; refresh, seconds
2H ; retry, seconds
4W ; expire, seconds
1D ) ; minimum, seconds
TXT "realhostip.com"
NS ns.realhostip.com.
NS ns2.realhostip.com.
localhost A 127.0.0.1
ns A 184.72.55.159
ns2 A 184.72.250.40
test A 1.2.3.4

View File

@ -1 +0,0 @@
java -cp dnsjava-2.0.6.jar:log4j-1.2.15.jar:classes VirtualDNS $1 $2 $3 $4 $5