mirror of https://github.com/apache/cloudstack.git
Remove outdated thridparty pacakge
This commit is contained in:
parent
346ca43714
commit
946413dd88
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ...
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
extern
|
||||
void hardware(const int write_to_file, FILE *global_ofile);
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include <stdio.h>
|
||||
int main () {printf("hello.\n");return(0);}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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]);
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#include <stdio.h>
|
||||
int main(){
|
||||
printf("%d",(int)sizeof(long));
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
sprintf(buffer,"C compiler : %CCVERSION%\n");
|
||||
output_string(buffer);
|
||||
sprintf(buffer,"libc : %LIBCVERSION%\n");
|
||||
output_string(buffer);
|
||||
|
|
@ -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(®isters,®isters); /* 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(®isters,®isters,&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
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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" };
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
Mark Wielaard <mark@klomp.org>
|
||||
Elizabeth Fong <elizabeth@threerings.net>
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
gtk2.8.jar
|
||||
gnome2.12.jar
|
||||
glib0.2.jar
|
||||
retroweaver-all-1.2.2.jar
|
||||
|
|
@ -1 +0,0 @@
|
|||
Main-Class: org.klomp.snark.gtk.SnarkGnome
|
||||
|
|
@ -1 +0,0 @@
|
|||
Main-Class: org.klomp.snark.cmd.SnarkApplication
|
||||
|
|
@ -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>
|
||||
|
|
@ -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} $*
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -1 +0,0 @@
|
|||
java -cp dnsjava-2.0.6.jar:log4j-1.2.15.jar:classes VirtualDNS $1 $2 $3 $4 $5
|
||||
Loading…
Reference in New Issue