mirror of
git://erdgeist.org/opentracker
synced 2025-04-07 21:56:52 +08:00
Compare commits
1 Commits
master
...
OPENTRACKE
Author | SHA1 | Date | |
---|---|---|---|
![]() |
35dbfb637b |
246
.clang-format
246
.clang-format
@ -1,246 +0,0 @@
|
|||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
# BasedOnStyle: LLVM
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignArrayOfStructures: None
|
|
||||||
AlignConsecutiveAssignments:
|
|
||||||
Enabled: true
|
|
||||||
AcrossEmptyLines: true
|
|
||||||
AcrossComments: true
|
|
||||||
AlignCompound: true
|
|
||||||
AlignFunctionPointers: false
|
|
||||||
PadOperators: true
|
|
||||||
AlignConsecutiveBitFields:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: true
|
|
||||||
AcrossComments: true
|
|
||||||
AlignCompound: false
|
|
||||||
AlignFunctionPointers: false
|
|
||||||
PadOperators: false
|
|
||||||
AlignConsecutiveDeclarations:
|
|
||||||
Enabled: true
|
|
||||||
AcrossEmptyLines: true
|
|
||||||
AcrossComments: true
|
|
||||||
AlignCompound: true
|
|
||||||
AlignFunctionPointers: false
|
|
||||||
PadOperators: true
|
|
||||||
AlignConsecutiveMacros:
|
|
||||||
Enabled: true
|
|
||||||
AcrossEmptyLines: true
|
|
||||||
AcrossComments: true
|
|
||||||
AlignCompound: true
|
|
||||||
AlignFunctionPointers: false
|
|
||||||
PadOperators: false
|
|
||||||
AlignConsecutiveShortCaseStatements:
|
|
||||||
Enabled: true
|
|
||||||
AcrossEmptyLines: true
|
|
||||||
AcrossComments: true
|
|
||||||
AlignCaseColons: false
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AlignOperands: Align
|
|
||||||
AlignTrailingComments:
|
|
||||||
Kind: Always
|
|
||||||
OverEmptyLines: 0
|
|
||||||
AllowAllArgumentsOnNextLine: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
|
||||||
AllowBreakBeforeNoexceptSpecifier: Never
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortCompoundRequirementOnASingleLine: true
|
|
||||||
AllowShortEnumsOnASingleLine: true
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: MultiLine
|
|
||||||
AttributeMacros:
|
|
||||||
- __capability
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BitFieldColonSpacing: Both
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: Never
|
|
||||||
AfterEnum: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeLambdaBody: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakAdjacentStringLiterals: true
|
|
||||||
BreakAfterAttributes: Leave
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakArrays: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeConceptDeclarations: Always
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInlineASMColon: OnlyMultiline
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakInheritanceList: BeforeColon
|
|
||||||
BreakStringLiterals: false
|
|
||||||
ColumnLimit: 160
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
EmptyLineAfterAccessModifier: Never
|
|
||||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IfMacros:
|
|
||||||
- KJ_IF_MAYBE
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
IncludeIsMainRegex: '(Test)?$'
|
|
||||||
IncludeIsMainSourceRegex: ''
|
|
||||||
IndentAccessModifiers: false
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentExternBlock: AfterExternBlock
|
|
||||||
IndentGotoLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentRequiresClause: true
|
|
||||||
IndentWidth: 2
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
InsertBraces: false
|
|
||||||
InsertNewlineAtEOF: false
|
|
||||||
InsertTrailingCommas: None
|
|
||||||
IntegerLiteralSeparator:
|
|
||||||
Binary: 0
|
|
||||||
BinaryMinDigits: 0
|
|
||||||
Decimal: 0
|
|
||||||
DecimalMinDigits: 0
|
|
||||||
Hex: 0
|
|
||||||
HexMinDigits: 0
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
KeepEmptyLinesAtEOF: false
|
|
||||||
LambdaBodyIndentation: Signature
|
|
||||||
LineEnding: DeriveLF
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCBreakBeforeNestedBlockParam: true
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PackConstructorInitializers: BinPack
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakOpenParenthesis: 0
|
|
||||||
PenaltyBreakScopeResolution: 500
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyIndentedWhitespace: 0
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
PointerAlignment: Right
|
|
||||||
PPIndentWidth: -1
|
|
||||||
QualifierAlignment: Leave
|
|
||||||
ReferenceAlignment: Pointer
|
|
||||||
ReflowComments: true
|
|
||||||
RemoveBracesLLVM: false
|
|
||||||
RemoveParentheses: Leave
|
|
||||||
RemoveSemicolon: false
|
|
||||||
RequiresClausePosition: OwnLine
|
|
||||||
RequiresExpressionIndentation: OuterScope
|
|
||||||
SeparateDefinitionBlocks: Leave
|
|
||||||
ShortNamespaceLines: 1
|
|
||||||
SkipMacroDefinitionBody: false
|
|
||||||
SortIncludes: CaseSensitive
|
|
||||||
SortJavaStaticImport: Before
|
|
||||||
SortUsingDeclarations: LexicographicNumeric
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: true
|
|
||||||
SpaceAroundPointerQualifiers: Default
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCaseColon: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeJsonColon: false
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceBeforeParensOptions:
|
|
||||||
AfterControlStatements: true
|
|
||||||
AfterForeachMacros: true
|
|
||||||
AfterFunctionDefinitionName: false
|
|
||||||
AfterFunctionDeclarationName: false
|
|
||||||
AfterIfMacros: true
|
|
||||||
AfterOverloadedOperator: false
|
|
||||||
AfterPlacementOperator: true
|
|
||||||
AfterRequiresInClause: false
|
|
||||||
AfterRequiresInExpression: false
|
|
||||||
BeforeNonEmptyParentheses: false
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: Never
|
|
||||||
SpacesInContainerLiterals: true
|
|
||||||
SpacesInLineCommentPrefix:
|
|
||||||
Minimum: 1
|
|
||||||
Maximum: -1
|
|
||||||
SpacesInParens: Never
|
|
||||||
SpacesInParensOptions:
|
|
||||||
InCStyleCasts: false
|
|
||||||
InConditionalStatements: false
|
|
||||||
InEmptyParentheses: false
|
|
||||||
Other: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
Standard: Latest
|
|
||||||
StatementAttributeLikeMacros:
|
|
||||||
- Q_EMIT
|
|
||||||
StatementMacros:
|
|
||||||
- Q_UNUSED
|
|
||||||
- QT_REQUIRE_VERSION
|
|
||||||
TabWidth: 8
|
|
||||||
UseTab: Never
|
|
||||||
VerilogBreakBetweenInstancePorts: true
|
|
||||||
WhitespaceSensitiveMacros:
|
|
||||||
- BOOST_PP_STRINGIZE
|
|
||||||
- CF_SWIFT_NAME
|
|
||||||
- NS_SWIFT_NAME
|
|
||||||
- PP_STRINGIZE
|
|
||||||
- STRINGIZE
|
|
||||||
...
|
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*.o
|
|
||||||
|
|
66
Makefile
66
Makefile
@ -1,5 +1,7 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
|
CC?=gcc
|
||||||
|
|
||||||
# Linux flavour
|
# Linux flavour
|
||||||
# PREFIX?=/opt/diet
|
# PREFIX?=/opt/diet
|
||||||
# LIBOWFAT_HEADERS=$(PREFIX)/include
|
# LIBOWFAT_HEADERS=$(PREFIX)/include
|
||||||
@ -16,65 +18,35 @@ LIBOWFAT_HEADERS=$(PREFIX)/libowfat
|
|||||||
LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
|
LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
|
||||||
|
|
||||||
BINDIR?=$(PREFIX)/bin
|
BINDIR?=$(PREFIX)/bin
|
||||||
STRIP?=strip
|
|
||||||
|
|
||||||
#FEATURES+=-DWANT_V4_ONLY
|
|
||||||
#FEATURES+=-DWANT_ACCESSLIST_BLACK
|
#FEATURES+=-DWANT_ACCESSLIST_BLACK
|
||||||
#FEATURES+=-DWANT_ACCESSLIST_WHITE
|
#FEATURES+=-DWANT_ACCESSLIST_WHITE
|
||||||
#FEATURES+=-DWANT_DYNAMIC_ACCESSLIST
|
|
||||||
|
|
||||||
|
#FEATURES+=-DWANT_SYNC_BATCH
|
||||||
#FEATURES+=-DWANT_SYNC_LIVE
|
#FEATURES+=-DWANT_SYNC_LIVE
|
||||||
|
|
||||||
|
#FEATURES+=-DWANT_UTORRENT1600_WORKAROUND
|
||||||
#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
|
#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
|
||||||
|
#FEATURES+=-DWANT_COMPRESSION_GZIP
|
||||||
# If you want gzip support to be compiled in, uncomment the next include.
|
|
||||||
# You can further modify the behaviour by setting DWANT_COMPRESSION_GZIP_ALWAYS
|
|
||||||
# in Makefile.gzip
|
|
||||||
include Makefile.gzip
|
|
||||||
|
|
||||||
# If you want zstd support to be compiled in, uncomment the next include.
|
|
||||||
# You can further modify the behaviour by setting DWANT_COMPRESSION_ZSTD_ALWAYS
|
|
||||||
# in Makefile.zstd
|
|
||||||
#include Makefile.zstd
|
|
||||||
|
|
||||||
#FEATURES+=-DWANT_LOG_NETWORKS
|
#FEATURES+=-DWANT_LOG_NETWORKS
|
||||||
#FEATURES+=-DWANT_RESTRICT_STATS
|
#FEATURES+=-DWANT_RESTRICT_STATS
|
||||||
#FEATURES+=-DWANT_IP_FROM_PROXY
|
#FEATURES+=-D_DEBUG_HTTPERROR
|
||||||
#FEATURES+=-DWANT_FULLLOG_NETWORKS
|
#FEATURES+=-D_DEBUG_VECTOR
|
||||||
#FEATURES+=-DWANT_LOG_NUMWANT
|
|
||||||
#FEATURES+=-DWANT_MODEST_FULLSCRAPES
|
|
||||||
#FEATURES+=-DWANT_SPOT_WOODPECKER
|
|
||||||
#FEATURES+=-DWANT_SYSLOGS
|
|
||||||
#FEATURES+=-DWANT_DEV_RANDOM
|
|
||||||
FEATURES+=-DWANT_FULLSCRAPE
|
FEATURES+=-DWANT_FULLSCRAPE
|
||||||
|
|
||||||
# You need libowfat version 0.34 to allow for automatic release of chunks during
|
OPTS_debug=-D_DEBUG -g -ggdb #-pg # -fprofile-arcs -ftest-coverage
|
||||||
# full scrape transfer, if you rely on an older versions, enable this flag
|
OPTS_production=-Os
|
||||||
#FEATURES+=-DWANT_NO_AUTO_FREE
|
|
||||||
|
|
||||||
# Is enabled on BSD systems by default in trackerlogic.h
|
CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-pedantic -ansi
|
||||||
# on Linux systems the include Makefile adds -lbsd
|
LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz
|
||||||
#include Makefile.arc4random
|
|
||||||
|
|
||||||
#FEATURES+=-D_DEBUG_HTTPERROR
|
|
||||||
#FEATURES+=-D_DEBUG_RANDOMTORRENTS
|
|
||||||
|
|
||||||
GIT_VERSION=$(shell sh -c 'command -v git >/dev/null && test -d .git && git rev-parse HEAD || echo _git_or_commit_not_found_')
|
|
||||||
|
|
||||||
OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
|
|
||||||
OPTS_production=-O3
|
|
||||||
|
|
||||||
CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra #-ansi -pedantic
|
|
||||||
LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread
|
|
||||||
|
|
||||||
BINARY =opentracker
|
BINARY =opentracker
|
||||||
HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h
|
HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_sync.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h
|
||||||
SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c
|
SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_sync.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c
|
||||||
SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c
|
|
||||||
|
|
||||||
OBJECTS = $(SOURCES:%.c=%.o)
|
OBJECTS = $(SOURCES:%.c=%.o)
|
||||||
OBJECTS_debug = $(SOURCES:%.c=%.debug.o)
|
OBJECTS_debug = $(SOURCES:%.c=%.debug.o)
|
||||||
OBJECTS_proxy = $(SOURCES_proxy:%.c=%.o)
|
|
||||||
OBJECTS_proxy_debug = $(SOURCES_proxy:%.c=%.debug.o)
|
|
||||||
|
|
||||||
.SUFFIXES: .debug.o .o .c
|
.SUFFIXES: .debug.o .o .c
|
||||||
|
|
||||||
@ -85,13 +57,9 @@ CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES)
|
|||||||
|
|
||||||
$(BINARY): $(OBJECTS) $(HEADERS)
|
$(BINARY): $(OBJECTS) $(HEADERS)
|
||||||
$(CC) -o $@ $(OBJECTS) $(LDFLAGS)
|
$(CC) -o $@ $(OBJECTS) $(LDFLAGS)
|
||||||
$(STRIP) $@
|
strip $@
|
||||||
$(BINARY).debug: $(OBJECTS_debug) $(HEADERS)
|
$(BINARY).debug: $(OBJECTS_debug) $(HEADERS)
|
||||||
$(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS)
|
$(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS)
|
||||||
proxy: $(OBJECTS_proxy) $(HEADERS)
|
|
||||||
$(CC) -o $@ $(OBJECTS_proxy) $(CFLAGS_production) $(LDFLAGS)
|
|
||||||
proxy.debug: $(OBJECTS_proxy_debug) $(HEADERS)
|
|
||||||
$(CC) -o $@ $(OBJECTS_proxy_debug) $(LDFLAGS)
|
|
||||||
|
|
||||||
.c.debug.o : $(HEADERS)
|
.c.debug.o : $(HEADERS)
|
||||||
$(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c)
|
$(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c)
|
||||||
@ -103,4 +71,4 @@ clean:
|
|||||||
rm -rf opentracker opentracker.debug *.o *~
|
rm -rf opentracker opentracker.debug *.o *~
|
||||||
|
|
||||||
install:
|
install:
|
||||||
install -m 755 opentracker $(DESTDIR)$(BINDIR)
|
install -m 755 opentracker $(BINDIR)
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
FEATURES+=-DWANT_ARC4RANDOM
|
|
||||||
LDFLAGS+=-lbsd
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
FEATURES+=-DWANT_COMPRESSION_GZIP
|
|
||||||
#FEATURES+=-DWANT_COMPRESSION_GZIP_ALWAYS
|
|
||||||
|
|
||||||
LDFLAGS+=-lz
|
|
@ -1,3 +0,0 @@
|
|||||||
FEATURES+=-DWANT_COMPRESSION_ZSTD
|
|
||||||
#FEATURES+=-DWANT_COMPRESSION_ZSTD_ALWAYS
|
|
||||||
LDFLAGS+=-lzstd
|
|
2
README
2
README
@ -27,4 +27,4 @@ sysctl kern.maxfiles=10240
|
|||||||
|
|
||||||
License information:
|
License information:
|
||||||
|
|
||||||
Although the libowfat library is under GPL, Felix von Leitner agreed that the compiled binary may be distributed under the same beer ware license as the source code for opentracker. However, we like to hear from happy customers.
|
Although the libowfat library is under GPL, Felix von Leitner aggreed that the compiled binary may be distributed under the same beer ware license as the source code for opentracker. However, we like to hear from happy customers.
|
||||||
|
@ -1 +1,8 @@
|
|||||||
IPv6 is implemented in opentracker now. You can chose whether your tracker runs in v4 or v6 mode in Makefile. YMMV.
|
Q: Why is there no v6-support in opentracker?
|
||||||
|
|
||||||
|
A: Although I tried very hard, implementing v6 right now would be a terrible waste of bandwidth, there is no compact format for v6 addresses, so instead of
|
||||||
|
answering "d5:peers6:AAAAPPe" I'd have to send "d5:peersld2:ip39:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA4:port2:PPPPeee" for a single peer. Even if there was a
|
||||||
|
compact mode, v6 addresses still would eat up thrice the memory, v4 addresses take. This, however, wouldn't be a show stopper.
|
||||||
|
|
||||||
|
Other problems concern efficient peer selection for obviously v6-capable peers and how to select peers for non-v6 clients. v6 addresses eat up more memory on the
|
||||||
|
host, too ;)
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
.Dd 15/4/2024
|
|
||||||
.Dt opentracker 1
|
|
||||||
.Os Unix
|
|
||||||
.Sh opentracker
|
|
||||||
.Nm opentracker
|
|
||||||
.Nd a free and open bittorrent tracker
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op Fl f Ar config
|
|
||||||
.Op Fl i Ar ip-select
|
|
||||||
.Op Fl p Ar port-bind-tcp
|
|
||||||
.Op Fl P Ar port-bind-udp
|
|
||||||
.Op Fl A Ar blessed-ip
|
|
||||||
.Op Fl r Ar redirect-url
|
|
||||||
.Op Fl d Ar chdir
|
|
||||||
.Op Fl u Ar user
|
|
||||||
.Op Fl w| Fl b accesslist
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
is a bittorrent tracker that implements announce and scrape actions over the
|
|
||||||
UDP and the plain http protocol, aiming for minimal resource usage.
|
|
||||||
.Pp
|
|
||||||
When invoked with parameters, it binds to TCP and UDP port 6969 on all
|
|
||||||
interfaces. The recommended way to configure opentracker is by providing a
|
|
||||||
config file using the
|
|
||||||
.Op Fl f Ar config
|
|
||||||
option. See
|
|
||||||
.Xr opentracker.conf 4
|
|
||||||
for details.
|
|
||||||
.Pp
|
|
||||||
.Sh OPTIONS
|
|
||||||
The following options are available:
|
|
||||||
.Bl -tag -width -indent=8
|
|
||||||
.It Fl f Ar config
|
|
||||||
Parse a config file with a list of options. Consecutive command options
|
|
||||||
will override options from the config file. See
|
|
||||||
.Xr opentracker.conf 4
|
|
||||||
for details.
|
|
||||||
.It Fl i Ar ip-select
|
|
||||||
Select an ip address that will be used with the next
|
|
||||||
.Op Fl p
|
|
||||||
or
|
|
||||||
.Op Fl P
|
|
||||||
command to actually bind to this address. Setting this option without any bind
|
|
||||||
options in the config file or
|
|
||||||
.Op Fl p
|
|
||||||
or
|
|
||||||
.Op Fl P
|
|
||||||
commands will limit opentracker to only bind to this address.
|
|
||||||
.It Fl p Ar port-bind-tcp
|
|
||||||
Bind to the TCP port on the last preceding ip address set with the
|
|
||||||
.Op Fl i ip-select
|
|
||||||
option or to all available addresses if none has been set. Can be given multiple
|
|
||||||
times.
|
|
||||||
.It Fl P Ar port-bind-udp
|
|
||||||
Bind to the UDP port on the last preceding ip address set with the
|
|
||||||
.Op Fl i ip-select
|
|
||||||
option or to all available addresses if none has been set. Can be given multiple
|
|
||||||
times.
|
|
||||||
.It Fl A Ar blessed-ip
|
|
||||||
Set an ip address in IPv4 or IPv6 or a net in CIDR notation to bless the network
|
|
||||||
for access to restricted resources.
|
|
||||||
.It Fl r Ar redirect-url
|
|
||||||
Set the URL that
|
|
||||||
.Nm
|
|
||||||
will redirect users to when the / address is requested via HTTP.
|
|
||||||
.It Fl d Ar chdir
|
|
||||||
Sets the directory
|
|
||||||
.Nm
|
|
||||||
will
|
|
||||||
.Xr chroot 2
|
|
||||||
to if ran as root or
|
|
||||||
.Xr chdir 2
|
|
||||||
to if ran as unprivileged user. Note that any accesslist files need to be
|
|
||||||
relative to and within that directory.
|
|
||||||
.It Fl u Ar user
|
|
||||||
User to run
|
|
||||||
.Nm
|
|
||||||
under after all operations that need privileges have finished.
|
|
||||||
.It Fl w Ar accesslist | Fl b Ar accesslist
|
|
||||||
If
|
|
||||||
.Nm
|
|
||||||
has been compiled with the
|
|
||||||
.B WANT_ACCESSLIST_BLACK
|
|
||||||
or
|
|
||||||
.Br WANT_ACCESSLIST_WHITE
|
|
||||||
options, this option sets the location of the accesslist.
|
|
||||||
.El
|
|
||||||
.Sh EXAMPLES
|
|
||||||
Start
|
|
||||||
.Nm
|
|
||||||
bound on UDP and TCP ports 6969 on IPv6 localhost.
|
|
||||||
.Dl # ./opentracker -i ::1 -p 6969 -P 6969
|
|
||||||
.Pp
|
|
||||||
Start
|
|
||||||
.Nm
|
|
||||||
bound on UDP port 6868 and TCP port 6868 on IPv4 localhost and allow
|
|
||||||
privileged access from the network 192.168/16 while redirecting
|
|
||||||
HTTP clients accessing the root directory, which is not covered by the
|
|
||||||
bittorrent tracker protocol, to https://my-trackersite.com/.
|
|
||||||
.Dl # ./opentracker -i 192.168.0.4 -p 6868 -P 6969 -A 192.168/16 -r https://my-trackersite.com/
|
|
||||||
The announce URLs are http://192.168.0.4:6868/announce and
|
|
||||||
udp://192.168.0.4:6868/announce respectively.
|
|
||||||
.Sh FILES
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Pa opentracker.conf
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
config file.
|
|
||||||
.El
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr opentracker.conf 4
|
|
||||||
.Pp
|
|
||||||
opentracker documentation
|
|
||||||
.Lk https://erdgeist.org/arts/software/opentracker
|
|
||||||
.Pp
|
|
||||||
Bittorrent tracker protocol
|
|
||||||
.Lk http://www.bittorrent.org/beps/bep_0015.html
|
|
||||||
.Sh AUTHOR
|
|
||||||
.An Dirk Engling
|
|
||||||
.Aq Mt erdgeist@erdgeist.org .
|
|
||||||
.Sh LICENSE
|
|
||||||
This software is released under the Beerware License:
|
|
||||||
.Pp
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
||||||
and associated documentation files (the "Software"), to deal in the Software with the following
|
|
||||||
terms and conditions:
|
|
||||||
.Pp
|
|
||||||
If you meet the author(s) someday, and you think this software is worth it, you can buy them
|
|
||||||
a beer in return.
|
|
@ -1,86 +0,0 @@
|
|||||||
.Dd 2024-04-18
|
|
||||||
.Dt opentracker.conf 5
|
|
||||||
.Os Unix
|
|
||||||
.Sh NAME
|
|
||||||
.Nm opentracker.conf
|
|
||||||
.Nd configuration file for opentracker
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
configuration file specifies various options for configuring the behavior of the opentracker program.
|
|
||||||
.Pp
|
|
||||||
Lines starting with '#' are comments and are ignored. Options are specified as 'keyword value' pairs.
|
|
||||||
.Pp
|
|
||||||
The following options are available:
|
|
||||||
.Pp
|
|
||||||
.Bl -tag -width ".It access.proxy" -compact
|
|
||||||
.It listen.tcp_udp Ar address
|
|
||||||
Specifies an address opentracker will listen on for both TCP and UDP connections. If none are specified, opentracker listens on 0.0.0.0:6969 by default. Can be added more than once.
|
|
||||||
.Pp
|
|
||||||
.It listen.tcp Ar address
|
|
||||||
Specifies the address opentracker will listen on for TCP connections. Can be added more than once.
|
|
||||||
.Pp
|
|
||||||
.It listen.udp Ar address
|
|
||||||
Specifies the address opentracker will listen on for UDP connections. Can be added more than once.
|
|
||||||
.Pp
|
|
||||||
.It listen.udp.workers Ar threads
|
|
||||||
Specifies how many threads will be spawned to handle UDP connections. Defaults to 4.
|
|
||||||
.Pp
|
|
||||||
.It access.whitelist Ar path/to/whitelist
|
|
||||||
Specifies the path to the whitelist file containing all torrent hashes that opentracker will serve. Use this option if opentracker runs in a non-open mode.
|
|
||||||
.Pp
|
|
||||||
.It access.blacklist Ar path/to/blacklist
|
|
||||||
Specifies the path to the blacklist file containing all torrent hashes that opentracker will not serve. Use this option if opentracker was compiled to allow blacklisting.
|
|
||||||
.Pp
|
|
||||||
.It access.fifo_add Ar path/to/adder.fifo
|
|
||||||
Specifies the path to the FIFO (named pipe) used for dynamic changesets to accesslists. Info hashes written to this FIFO will be added to the main accesslist file.
|
|
||||||
.Pp
|
|
||||||
.It access.fifo_delete Ar path/to/deleter.fifo
|
|
||||||
Specifies the path to the FIFO (named pipe) used for dynamic changesets to accesslists. Info hashes written to this FIFO will be removed from the main accesslist file.
|
|
||||||
.Pp
|
|
||||||
.It access.stats Ar ip_address_or_network
|
|
||||||
Specifies the IP address or network in CIDR notation allowed to fetch stats from opentracker.
|
|
||||||
.Pp
|
|
||||||
.It access.stats_path Ar path
|
|
||||||
Specifies the path to the stats location. You can configure opentracker to appear anywhere on your tracker. Defaults to /stats.
|
|
||||||
.Pp
|
|
||||||
.It access.proxy Ar ip_address_or_network
|
|
||||||
Specifies the IP address or network of the reverse proxies. Opentracker will take the X-Forwarded-For address instead of the source IP address. Can be added more than once.
|
|
||||||
.Pp
|
|
||||||
.It livesync.cluster.listen Ar ip_address:port
|
|
||||||
Specifies the IP address and port opentracker will listen on for incoming live sync packets to keep a cluster of opentrackers synchronized.
|
|
||||||
.Pp
|
|
||||||
.It livesync.cluster.node_ip Ar ip_address
|
|
||||||
Specifies one trusted IP address for sync between trackers running in a cluster. Can be added more than once.
|
|
||||||
.Pp
|
|
||||||
.It batchsync.cluster.admin_ip Ar ip_address
|
|
||||||
Specifies the admin IP address for old-style (HTTP-based) asynchronous tracker syncing.
|
|
||||||
.Pp
|
|
||||||
.It tracker.rootdir Ar path
|
|
||||||
Specifies the directory opentracker will chroot/chdir to. All black/white list files must be located in this directory.
|
|
||||||
.Pp
|
|
||||||
.It tracker.user Ar username
|
|
||||||
Specifies the user opentracker will setuid to after binding to potentially privileged ports.
|
|
||||||
.Pp
|
|
||||||
.It tracker.redirect_url Ar URL
|
|
||||||
Specifies the URL opentracker will redirect to in response to a "GET / HTTP" request.
|
|
||||||
.El
|
|
||||||
.Sh EXAMPLES
|
|
||||||
To specify the address opentracker will listen on for both TCP and UDP connections:
|
|
||||||
.Dl listen.tcp_udp 0.0.0.0:6969
|
|
||||||
.Pp
|
|
||||||
To specify the address opentracker will listen on for TCP connections:
|
|
||||||
.Dl listen.tcp 0.0.0.0
|
|
||||||
.Pp
|
|
||||||
To specify the address opentracker will listen on for UDP connections:
|
|
||||||
.Dl listen.udp 0.0.0.0:6969
|
|
||||||
.Pp
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr opentracker 1
|
|
||||||
.Pp
|
|
||||||
.Sh AUTHOR
|
|
||||||
.An Dirk Engling
|
|
||||||
.Aq Mt erdgeist@erdgeist.org
|
|
||||||
.Pp
|
|
770
opentracker.c
770
opentracker.c
@ -5,50 +5,50 @@
|
|||||||
$Id$ */
|
$Id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <ctype.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <pwd.h>
|
||||||
#include <string.h>
|
#include <ctype.h>
|
||||||
#include <sys/socket.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
|
||||||
#ifdef WANT_SYSLOGS
|
|
||||||
#include <syslog.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "byte.h"
|
#include "socket.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "iob.h"
|
#include "iob.h"
|
||||||
#include "ip6.h"
|
#include "array.h"
|
||||||
|
#include "byte.h"
|
||||||
|
#include "fmt.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "socket.h"
|
#include "ip4.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_accesslist.h"
|
|
||||||
#include "ot_http.h"
|
|
||||||
#include "ot_livesync.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "ot_udp.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_iovec.h"
|
||||||
|
#include "ot_mutex.h"
|
||||||
|
#include "ot_http.h"
|
||||||
|
#include "ot_udp.h"
|
||||||
|
#include "ot_clean.h"
|
||||||
|
#include "ot_accesslist.h"
|
||||||
|
#include "ot_stats.h"
|
||||||
|
#include "ot_livesync.h"
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
time_t g_now_seconds;
|
time_t g_now;
|
||||||
char *g_redirecturl;
|
char * g_redirecturl = NULL;
|
||||||
uint32_t g_tracker_id;
|
uint32_t g_tracker_id;
|
||||||
volatile int g_opentracker_running = 1;
|
|
||||||
int g_self_pipe[2];
|
|
||||||
|
|
||||||
static char *g_serverdir;
|
static char * g_serverdir = NULL;
|
||||||
static char *g_serveruser;
|
|
||||||
static unsigned int g_udp_workers;
|
/* To always have space for error messages ;) */
|
||||||
|
static char static_inbuf[8192];
|
||||||
|
|
||||||
static void panic(const char *routine) __attribute__((noreturn));
|
|
||||||
static void panic( const char *routine ) {
|
static void panic( const char *routine ) {
|
||||||
fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
|
fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
|
||||||
exit( 111 );
|
exit( 111 );
|
||||||
@ -56,58 +56,24 @@ static void panic(const char *routine) {
|
|||||||
|
|
||||||
static void signal_handler( int s ) {
|
static void signal_handler( int s ) {
|
||||||
if( s == SIGINT ) {
|
if( s == SIGINT ) {
|
||||||
/* Any new interrupt signal quits the application */
|
signal( SIGINT, SIG_IGN);
|
||||||
signal(SIGINT, SIG_DFL);
|
|
||||||
|
|
||||||
/* Tell all other threads to not acquire any new lock on a bucket
|
|
||||||
but cancel their operations and return */
|
|
||||||
g_opentracker_running = 0;
|
|
||||||
|
|
||||||
trackerlogic_deinit();
|
trackerlogic_deinit();
|
||||||
|
|
||||||
#ifdef WANT_SYSLOGS
|
|
||||||
closelog();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
|
} else if( s == SIGALRM ) {
|
||||||
|
g_now = time(NULL);
|
||||||
|
alarm(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void defaul_signal_handlers(void) {
|
|
||||||
sigset_t signal_mask;
|
|
||||||
sigemptyset(&signal_mask);
|
|
||||||
sigaddset(&signal_mask, SIGPIPE);
|
|
||||||
sigaddset(&signal_mask, SIGHUP);
|
|
||||||
sigaddset(&signal_mask, SIGINT);
|
|
||||||
sigaddset(&signal_mask, SIGALRM);
|
|
||||||
pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void install_signal_handlers(void) {
|
|
||||||
struct sigaction sa;
|
|
||||||
sigset_t signal_mask;
|
|
||||||
sigemptyset(&signal_mask);
|
|
||||||
|
|
||||||
sa.sa_handler = signal_handler;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART;
|
|
||||||
if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1))
|
|
||||||
panic("install_signal_handlers");
|
|
||||||
|
|
||||||
sigaddset(&signal_mask, SIGINT);
|
|
||||||
pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage( char *name ) {
|
static void usage( char *name ) {
|
||||||
fprintf(stderr,
|
fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-A ip] [-f config] [-s livesyncport]"
|
||||||
"Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]"
|
|
||||||
#ifdef WANT_ACCESSLIST_BLACK
|
#ifdef WANT_ACCESSLIST_BLACK
|
||||||
" [-b blacklistfile]"
|
" [-b blacklistfile]"
|
||||||
#elif defined ( WANT_ACCESSLIST_WHITE )
|
#elif defined ( WANT_ACCESSLIST_WHITE )
|
||||||
" [-w whitelistfile]"
|
" [-w whitelistfile]"
|
||||||
#endif
|
#endif
|
||||||
"\n",
|
"\n", name );
|
||||||
name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HELPLINE(opt,desc) fprintf(stderr, "\t%-10s%s\n",opt,desc)
|
#define HELPLINE(opt,desc) fprintf(stderr, "\t%-10s%s\n",opt,desc)
|
||||||
@ -115,13 +81,12 @@ static void help(char *name) {
|
|||||||
usage( name );
|
usage( name );
|
||||||
|
|
||||||
HELPLINE("-f config","include and execute the config file");
|
HELPLINE("-f config","include and execute the config file");
|
||||||
HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)");
|
HELPLINE("-i ip","specify ip to bind to (default: *, you may specify more than one)");
|
||||||
HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)");
|
HELPLINE("-p port","specify tcp port to bind to (default: 6969, you may specify more than one)");
|
||||||
HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)");
|
HELPLINE("-P port","specify udp port to bind to (default: 6969, you may specify more than one)");
|
||||||
HELPLINE("-r redirecturl","specify url where / should be redirected to (default none)");
|
HELPLINE("-r redirecturl","specify url where / should be redirected to (default none)");
|
||||||
HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")");
|
HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")");
|
||||||
HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
|
HELPLINE("-A ip","bless an ip address as admin address (e.g. to allow syncs from this address)");
|
||||||
HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
|
|
||||||
#ifdef WANT_ACCESSLIST_BLACK
|
#ifdef WANT_ACCESSLIST_BLACK
|
||||||
HELPLINE("-b file","specify blacklist file.");
|
HELPLINE("-b file","specify blacklist file.");
|
||||||
#elif defined( WANT_ACCESSLIST_WHITE )
|
#elif defined( WANT_ACCESSLIST_WHITE )
|
||||||
@ -129,321 +94,200 @@ static void help(char *name) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf( stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n" );
|
fprintf( stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n" );
|
||||||
fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n");
|
|
||||||
fprintf(stderr, " If no port is bound from config file or command line, the last address given\n");
|
|
||||||
fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n");
|
|
||||||
}
|
}
|
||||||
#undef HELPLINE
|
#undef HELPLINE
|
||||||
|
|
||||||
static ssize_t header_complete(char *request, ssize_t byte_count) {
|
static void handle_dead( const int64 socket ) {
|
||||||
ssize_t i = 0, state = 0;
|
struct http_data* h=io_getcookie( socket );
|
||||||
|
if( h ) {
|
||||||
|
if( h->flag & STRUCT_HTTP_FLAG_IOB_USED )
|
||||||
|
iob_reset( &h->batch );
|
||||||
|
if( h->flag & STRUCT_HTTP_FLAG_ARRAY_USED )
|
||||||
|
array_reset( &h->request );
|
||||||
|
if( h->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK )
|
||||||
|
mutex_workqueue_canceltask( socket );
|
||||||
|
free( h );
|
||||||
|
}
|
||||||
|
io_close( socket );
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 1; i < byte_count; i += 2)
|
static ssize_t handle_read( const int64 clientsocket ) {
|
||||||
if (request[i] <= 13) {
|
struct http_data* h = io_getcookie( clientsocket );
|
||||||
i--;
|
ssize_t l;
|
||||||
for (state = 0; i < byte_count; ++i) {
|
|
||||||
char c = request[i];
|
if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) {
|
||||||
if (c == '\r' || c == '\n')
|
handle_dead( clientsocket );
|
||||||
state = (state >> 2) | ((c << 6) & 0xc0);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
if (state >= 0xa0 || state == 0x99)
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_dead(const int64 sock) {
|
|
||||||
struct http_data *cookie = io_getcookie(sock);
|
|
||||||
if (cookie) {
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < cookie->batches; ++i)
|
|
||||||
iob_reset(cookie->batch + i);
|
|
||||||
free(cookie->batch);
|
|
||||||
array_reset(&cookie->request);
|
|
||||||
if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))
|
|
||||||
mutex_workqueue_canceltask(sock);
|
|
||||||
free(cookie);
|
|
||||||
}
|
|
||||||
io_close(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_read(const int64 sock, struct ot_workstruct *ws) {
|
|
||||||
struct http_data *cookie = io_getcookie(sock);
|
|
||||||
ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE);
|
|
||||||
|
|
||||||
if (byte_count == 0 || byte_count == -3) {
|
|
||||||
handle_dead(sock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (byte_count == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* If we get the whole request in one packet, handle it without copying */
|
/* If we get the whole request in one packet, handle it without copying */
|
||||||
if (!array_start(&cookie->request)) {
|
if( !array_start( &h->request ) ) {
|
||||||
if ((ws->header_size = header_complete(ws->inbuf, byte_count))) {
|
if( memchr( static_inbuf, '\n', l ) )
|
||||||
ws->request = ws->inbuf;
|
return http_handle_request( clientsocket, static_inbuf, l );
|
||||||
ws->request_size = byte_count;
|
h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
|
||||||
http_handle_request(sock, ws);
|
array_catb( &h->request, static_inbuf, l );
|
||||||
} else
|
return 0;
|
||||||
array_catb(&cookie->request, ws->inbuf, (size_t)byte_count);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
array_catb(&cookie->request, ws->inbuf, byte_count);
|
h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
|
||||||
if (array_failed(&cookie->request) || array_bytes(&cookie->request) > 8192) {
|
array_catb( &h->request, static_inbuf, l );
|
||||||
http_issue_error(sock, ws, CODE_HTTPERROR_500);
|
|
||||||
return;
|
if( array_failed( &h->request ) )
|
||||||
|
return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
|
||||||
|
|
||||||
|
if( ( array_bytes( &h->request ) > 8192 ) && !accesslist_isblessed( (char*)&h->ip, OT_PERMISSION_MAY_SYNC ) )
|
||||||
|
return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
|
||||||
|
|
||||||
|
if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) )
|
||||||
|
return http_handle_request( clientsocket, array_start( &h->request ), array_bytes( &h->request ) );
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((ws->header_size = header_complete(array_start(&cookie->request), array_bytes(&cookie->request)))) {
|
static void handle_write( const int64 clientsocket ) {
|
||||||
ws->request = array_start(&cookie->request);
|
struct http_data* h=io_getcookie( clientsocket );
|
||||||
ws->request_size = array_bytes(&cookie->request);
|
if( !h || ( iob_send( clientsocket, &h->batch ) <= 0 ) )
|
||||||
http_handle_request(sock, ws);
|
handle_dead( clientsocket );
|
||||||
#ifdef WANT_KEEPALIVE
|
|
||||||
if (!ws->keep_alive)
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_write(const int64 sock) {
|
|
||||||
struct http_data *cookie = io_getcookie(sock);
|
|
||||||
size_t i;
|
|
||||||
int chunked = 0;
|
|
||||||
|
|
||||||
/* Look for the first io_batch still containing bytes to write */
|
|
||||||
if (cookie) {
|
|
||||||
if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)
|
|
||||||
chunked = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < cookie->batches; ++i) {
|
|
||||||
if (cookie->batch[i].bytesleft) {
|
|
||||||
int64 res = iob_send(sock, cookie->batch + i);
|
|
||||||
|
|
||||||
if (res == -3) {
|
|
||||||
handle_dead(sock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cookie->batch[i].bytesleft)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (res == -1 || res > 0 || i < cookie->batches - 1)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In a chunked transfer after all batches accumulated have been sent, wait for the next one */
|
|
||||||
if (chunked)
|
|
||||||
io_dontwantwrite(sock);
|
|
||||||
else
|
|
||||||
handle_dead(sock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_accept( const int64 serversocket ) {
|
static void handle_accept( const int64 serversocket ) {
|
||||||
struct http_data *cookie;
|
struct http_data *h;
|
||||||
int64 sock;
|
unsigned char ip[4];
|
||||||
ot_ip6 ip;
|
|
||||||
uint16 port;
|
uint16 port;
|
||||||
tai6464 t;
|
tai6464 t;
|
||||||
|
int64 i;
|
||||||
|
|
||||||
while ((sock = socket_accept6(serversocket, ip, &port, NULL)) != -1) {
|
while( ( i = socket_accept4( serversocket, (char*)ip, &port) ) != -1 ) {
|
||||||
|
|
||||||
/* Put fd into a non-blocking mode */
|
/* Put fd into a non-blocking mode */
|
||||||
io_nonblock(sock);
|
io_nonblock( i );
|
||||||
|
|
||||||
if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
|
if( !io_fd( i ) ||
|
||||||
io_close(sock);
|
!( h = (struct http_data*)malloc( sizeof( struct http_data ) ) ) ) {
|
||||||
|
io_close( i );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
memset(cookie, 0, sizeof(struct http_data));
|
io_setcookie( i, h );
|
||||||
memcpy(cookie->ip, ip, sizeof(ot_ip6));
|
io_wantread( i );
|
||||||
|
|
||||||
io_setcookie(sock, cookie);
|
memset( h, 0, sizeof( struct http_data ) );
|
||||||
io_wantread(sock);
|
memmove( h->ip, ip, sizeof( ip ) );
|
||||||
|
|
||||||
stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
|
stats_issue_event( EVENT_ACCEPT, FLAG_TCP, ntohl(*(uint32_t*)ip));
|
||||||
|
|
||||||
/* That breaks taia encapsulation. But there is no way to take system
|
/* That breaks taia encapsulation. But there is no way to take system
|
||||||
time this often in FreeBSD and libowfat does not allow to set unix time */
|
time this often in FreeBSD and libowfat does not allow to set unix time */
|
||||||
taia_uint( &t, 0 ); /* Clear t */
|
taia_uint( &t, 0 ); /* Clear t */
|
||||||
tai_unix(&(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT));
|
tai_unix( &(t.sec), (g_now + OT_CLIENT_TIMEOUT) );
|
||||||
io_timeout(sock, t);
|
io_timeout( i, t );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( errno == EAGAIN )
|
||||||
io_eagain( serversocket );
|
io_eagain( serversocket );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *server_mainloop(void *args) {
|
static void server_mainloop( ) {
|
||||||
struct ot_workstruct ws;
|
static time_t ot_last_clean_time;
|
||||||
time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
||||||
struct iovec *iovector;
|
struct iovec *iovector;
|
||||||
int iovec_entries, is_partial;
|
int iovec_entries;
|
||||||
|
|
||||||
(void)args;
|
|
||||||
|
|
||||||
/* Initialize our "thread local storage" */
|
|
||||||
ws.inbuf = malloc(G_INBUF_SIZE);
|
|
||||||
ws.outbuf = malloc(G_OUTBUF_SIZE);
|
|
||||||
#ifdef _DEBUG_HTTPERROR
|
|
||||||
ws.debugbuf = malloc(G_DEBUGBUF_SIZE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!ws.inbuf || !ws.outbuf)
|
|
||||||
panic("Initializing worker failed");
|
|
||||||
|
|
||||||
#ifdef WANT_ARC4RANDOM
|
|
||||||
arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t));
|
|
||||||
#else
|
|
||||||
ws.rand48_state[0] = (uint16_t)random();
|
|
||||||
ws.rand48_state[1] = (uint16_t)random();
|
|
||||||
ws.rand48_state[2] = (uint16_t)random();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for( ; ; ) {
|
for( ; ; ) {
|
||||||
int64 sock;
|
int64 i;
|
||||||
|
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
while ((sock = io_canread()) != -1) {
|
while( ( i = io_canread( ) ) != -1 ) {
|
||||||
const void *cookie = io_getcookie(sock);
|
const void *cookie = io_getcookie( i );
|
||||||
if ((intptr_t)cookie == FLAG_TCP)
|
if( (int)cookie == FLAG_TCP )
|
||||||
handle_accept(sock);
|
handle_accept( i );
|
||||||
else if ((intptr_t)cookie == FLAG_UDP)
|
else if( (int)cookie == FLAG_UDP )
|
||||||
handle_udp6(sock, &ws);
|
handle_udp4( i );
|
||||||
else if ((intptr_t)cookie == FLAG_SELFPIPE)
|
|
||||||
io_tryread(sock, ws.inbuf, G_INBUF_SIZE);
|
|
||||||
else
|
else
|
||||||
handle_read(sock, &ws);
|
handle_read( i );
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
|
while( ( i = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 )
|
||||||
http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
|
http_sendiovecdata( i, iovec_entries, iovector );
|
||||||
|
|
||||||
while ((sock = io_canwrite()) != -1)
|
while( ( i = io_canwrite( ) ) != -1 )
|
||||||
handle_write(sock);
|
handle_write( i );
|
||||||
|
|
||||||
if (g_now_seconds > next_timeout_check) {
|
if( g_now > next_timeout_check ) {
|
||||||
while ((sock = io_timeouted()) != -1)
|
while( ( i = io_timeouted() ) != -1 )
|
||||||
handle_dead(sock);
|
handle_dead( i );
|
||||||
next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
livesync_ticker();
|
livesync_ticker();
|
||||||
}
|
|
||||||
return 0;
|
/* See if we need to move our pools */
|
||||||
|
if( NOW != ot_last_clean_time ) {
|
||||||
|
ot_last_clean_time = NOW;
|
||||||
|
clean_all_torrents();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) {
|
/* Enforce setting the clock */
|
||||||
int64 sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6();
|
signal_handler( SIGALRM );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t ot_try_bind( char ip[4], uint16_t port, PROTO_FLAG proto ) {
|
||||||
|
int64 s = proto == FLAG_TCP ? socket_tcp4( ) : socket_udp4();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
{
|
|
||||||
char *protos[] = {"TCP","UDP","UDP mcast"};
|
char *protos[] = {"TCP","UDP","UDP mcast"};
|
||||||
char _debug[512];
|
uint8_t *_ip = (uint8_t *)ip;
|
||||||
int off = snprintf(_debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto]);
|
fprintf( stderr, "Binding socket type %s to address %d.%d.%d.%d:%d...", protos[proto],_ip[0],_ip[1],_ip[2],_ip[3],port);
|
||||||
off += fmt_ip6c(_debug + off, ip);
|
|
||||||
snprintf(_debug + off, sizeof(_debug) - off, "]:%d...", port);
|
|
||||||
fputs(_debug, stderr);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (socket_bind6_reuse(sock, ip, port, 0) == -1)
|
if( socket_bind4_reuse( s, ip, port ) == -1 )
|
||||||
panic("socket_bind6_reuse");
|
panic( "socket_bind4_reuse" );
|
||||||
|
|
||||||
if ((proto == FLAG_TCP) && (socket_listen(sock, SOMAXCONN) == -1))
|
if( ( proto == FLAG_TCP ) && ( socket_listen( s, SOMAXCONN) == -1 ) )
|
||||||
panic( "socket_listen" );
|
panic( "socket_listen" );
|
||||||
|
|
||||||
if (!io_fd(sock))
|
if( !io_fd( s ) )
|
||||||
panic( "io_fd" );
|
panic( "io_fd" );
|
||||||
|
|
||||||
io_setcookie(sock, (void *)proto);
|
io_setcookie( s, (void*)proto );
|
||||||
|
|
||||||
if ((proto == FLAG_UDP) && g_udp_workers) {
|
io_wantread( s );
|
||||||
io_block(sock);
|
|
||||||
udp_init(sock, g_udp_workers);
|
|
||||||
} else
|
|
||||||
io_wantread(sock);
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
fputs( " success.\n", stderr);
|
fputs( " success.\n", stderr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return sock;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * set_config_option( char **option, char *value ) {
|
char * set_config_option( char **option, char *value ) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
fprintf( stderr, "Setting config option: %s\n", value );
|
fprintf( stderr, "Setting config option: %s\n", value );
|
||||||
#endif
|
#endif
|
||||||
while (isspace(*value))
|
while( isspace(*value) ) ++value;
|
||||||
++value;
|
if( *option ) free( *option );
|
||||||
free(*option);
|
|
||||||
return *option = strdup( value );
|
return *option = strdup( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scan_ip6_port(const char *src, ot_ip6 ip, uint16 *port) {
|
static int scan_ip4_port( const char *src, char *ip, uint16 *port ) {
|
||||||
const char *s = src;
|
const char *s = src;
|
||||||
int off, bracket = 0;
|
int off;
|
||||||
while (isspace(*s))
|
while( isspace(*s) ) ++s;
|
||||||
++s;
|
if( !(off = scan_ip4( s, ip ) ) )
|
||||||
if (*s == '[')
|
|
||||||
++s, ++bracket; /* for v6 style notation */
|
|
||||||
if (!(off = scan_ip6(s, ip)))
|
|
||||||
return 0;
|
return 0;
|
||||||
s += off;
|
s += off;
|
||||||
if (bracket && *s == ']')
|
if( *s == 0 || isspace(*s)) return s-src;
|
||||||
++s;
|
|
||||||
if (*s == 0 || isspace(*s))
|
|
||||||
return s - src;
|
|
||||||
if (!ip6_isv4mapped(ip)) {
|
|
||||||
if (*s != ':' && *s != '.')
|
|
||||||
return 0;
|
|
||||||
if (!bracket && *(s) == ':')
|
|
||||||
return 0;
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
if( *(s++) != ':' )
|
if( *(s++) != ':' )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
if( !(off = scan_ushort (s, port ) ) )
|
if( !(off = scan_ushort (s, port ) ) )
|
||||||
return 0;
|
return 0;
|
||||||
return off+s-src;
|
return off+s-src;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scan_ip6_net(const char *src, ot_net *net) {
|
|
||||||
const char *s = src;
|
|
||||||
int off;
|
|
||||||
while (isspace(*s))
|
|
||||||
++s;
|
|
||||||
if (!(off = scan_ip6(s, net->address)))
|
|
||||||
return 0;
|
|
||||||
s += off;
|
|
||||||
if (*s != '/')
|
|
||||||
net->bits = 128;
|
|
||||||
else {
|
|
||||||
s++;
|
|
||||||
if (!(off = scan_int(s, &net->bits)))
|
|
||||||
return 0;
|
|
||||||
if (ip6_isv4mapped(net->address))
|
|
||||||
net->bits += 96;
|
|
||||||
if (net->bits > 128)
|
|
||||||
return 0;
|
|
||||||
s += off;
|
|
||||||
}
|
|
||||||
return off + s - src;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_configfile( char * config_filename ) {
|
int parse_configfile( char * config_filename ) {
|
||||||
FILE * accesslist_filehandle;
|
FILE * accesslist_filehandle;
|
||||||
char inbuf[512];
|
char inbuf[512], tmpip[4];
|
||||||
ot_ip6 tmpip;
|
|
||||||
#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
|
|
||||||
ot_net tmpnet;
|
|
||||||
#endif
|
|
||||||
int bound = 0;
|
int bound = 0;
|
||||||
|
|
||||||
accesslist_filehandle = fopen( config_filename, "r" );
|
accesslist_filehandle = fopen( config_filename, "r" );
|
||||||
@ -454,52 +298,36 @@ int parse_configfile(char *config_filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
|
while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
|
||||||
|
char *newl;
|
||||||
char *p = inbuf;
|
char *p = inbuf;
|
||||||
size_t strl;
|
|
||||||
|
|
||||||
/* Skip white spaces */
|
/* Skip white spaces */
|
||||||
while (isspace(*p))
|
while(isspace(*p)) ++p;
|
||||||
++p;
|
|
||||||
|
|
||||||
/* Ignore comments and empty lines */
|
/* Ignore comments and empty lines */
|
||||||
if ((*p == '#') || (*p == '\n') || (*p == 0))
|
if((*p=='#')||(*p=='\n')||(*p==0)) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* consume trailing new lines and spaces */
|
/* chomp */
|
||||||
strl = strlen(p);
|
if(( newl = strchr(p, '\n' ))) *newl = 0;
|
||||||
while (strl && isspace(p[strl - 1]))
|
|
||||||
p[--strl] = 0;
|
|
||||||
|
|
||||||
/* Scan for commands */
|
/* Scan for commands */
|
||||||
if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) {
|
if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) {
|
||||||
set_config_option( &g_serverdir, p+16 );
|
set_config_option( &g_serverdir, p+16 );
|
||||||
} else if (!byte_diff(p, 12, "tracker.user") && isspace(p[12])) {
|
|
||||||
set_config_option(&g_serveruser, p + 13);
|
|
||||||
} else if(!byte_diff(p,14,"listen.tcp_udp" ) && isspace(p[14])) {
|
} else if(!byte_diff(p,14,"listen.tcp_udp" ) && isspace(p[14])) {
|
||||||
uint16_t tmpport = 6969;
|
uint16_t tmpport = 6969;
|
||||||
if (!scan_ip6_port(p + 15, tmpip, &tmpport))
|
if( !scan_ip4_port( p+15, tmpip, &tmpport )) goto parse_error;
|
||||||
goto parse_error;
|
ot_try_bind( tmpip, tmpport, FLAG_TCP ); ++bound;
|
||||||
ot_try_bind(tmpip, tmpport, FLAG_TCP);
|
ot_try_bind( tmpip, tmpport, FLAG_UDP ); ++bound;
|
||||||
++bound;
|
|
||||||
ot_try_bind(tmpip, tmpport, FLAG_UDP);
|
|
||||||
++bound;
|
|
||||||
} else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) {
|
} else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) {
|
||||||
uint16_t tmpport = 6969;
|
uint16_t tmpport = 6969;
|
||||||
if (!scan_ip6_port(p + 11, tmpip, &tmpport))
|
if( !scan_ip4_port( p+11, tmpip, &tmpport )) goto parse_error;
|
||||||
goto parse_error;
|
|
||||||
ot_try_bind( tmpip, tmpport, FLAG_TCP );
|
ot_try_bind( tmpip, tmpport, FLAG_TCP );
|
||||||
++bound;
|
++bound;
|
||||||
} else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) {
|
} else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) {
|
||||||
uint16_t tmpport = 6969;
|
uint16_t tmpport = 6969;
|
||||||
if (!scan_ip6_port(p + 11, tmpip, &tmpport))
|
if( !scan_ip4_port( p+11, tmpip, &tmpport )) goto parse_error;
|
||||||
goto parse_error;
|
|
||||||
ot_try_bind( tmpip, tmpport, FLAG_UDP );
|
ot_try_bind( tmpip, tmpport, FLAG_UDP );
|
||||||
++bound;
|
++bound;
|
||||||
} else if (!byte_diff(p, 18, "listen.udp.workers") && isspace(p[18])) {
|
|
||||||
char *value = p + 18;
|
|
||||||
while (isspace(*value))
|
|
||||||
++value;
|
|
||||||
scan_uint(value, &g_udp_workers);
|
|
||||||
#ifdef WANT_ACCESSLIST_WHITE
|
#ifdef WANT_ACCESSLIST_WHITE
|
||||||
} else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
|
} else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
|
||||||
set_config_option( &g_accesslist_filename, p+17 );
|
set_config_option( &g_accesslist_filename, p+17 );
|
||||||
@ -507,37 +335,25 @@ int parse_configfile(char *config_filename) {
|
|||||||
} else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
|
} else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
|
||||||
set_config_option( &g_accesslist_filename, p+17 );
|
set_config_option( &g_accesslist_filename, p+17 );
|
||||||
#endif
|
#endif
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
} else if (!byte_diff(p, 15, "access.fifo_add") && isspace(p[15])) {
|
|
||||||
set_config_option(&g_accesslist_pipe_add, p + 16);
|
|
||||||
} else if (!byte_diff(p, 18, "access.fifo_delete") && isspace(p[18])) {
|
|
||||||
set_config_option(&g_accesslist_pipe_delete, p + 19);
|
|
||||||
#endif
|
|
||||||
#ifdef WANT_RESTRICT_STATS
|
#ifdef WANT_RESTRICT_STATS
|
||||||
} else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) {
|
} else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) {
|
||||||
if (!scan_ip6_net(p + 13, &tmpnet))
|
if( !scan_ip4( p+13, tmpip )) goto parse_error;
|
||||||
goto parse_error;
|
accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT );
|
||||||
accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT);
|
|
||||||
#endif
|
|
||||||
} else if (!byte_diff(p, 17, "access.stats_path") && isspace(p[17])) {
|
|
||||||
set_config_option(&g_stats_path, p + 18);
|
|
||||||
#ifdef WANT_IP_FROM_PROXY
|
|
||||||
} else if (!byte_diff(p, 12, "access.proxy") && isspace(p[12])) {
|
|
||||||
if (!scan_ip6_net(p + 13, &tmpnet))
|
|
||||||
goto parse_error;
|
|
||||||
accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY);
|
|
||||||
#endif
|
#endif
|
||||||
} else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
|
} else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
|
||||||
set_config_option( &g_redirecturl, p+21 );
|
set_config_option( &g_redirecturl, p+21 );
|
||||||
|
#ifdef WANT_SYNC_BATCH
|
||||||
|
} else if(!byte_diff(p, 26, "batchsync.cluster.admin_ip" ) && isspace(p[26])) {
|
||||||
|
if(!scan_ip4( p+27, tmpip )) goto parse_error;
|
||||||
|
accesslist_blessip( tmpip, OT_PERMISSION_MAY_SYNC );
|
||||||
|
#endif
|
||||||
#ifdef WANT_SYNC_LIVE
|
#ifdef WANT_SYNC_LIVE
|
||||||
} else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
|
} else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
|
||||||
if (!scan_ip6_net(p + 25, &tmpnet))
|
if( !scan_ip4( p+25, tmpip )) goto parse_error;
|
||||||
goto parse_error;
|
accesslist_blessip( tmpip, OT_PERMISSION_MAY_LIVESYNC );
|
||||||
accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC);
|
|
||||||
} else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) {
|
} else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) {
|
||||||
uint16_t tmpport = LIVESYNC_PORT;
|
uint16_t tmpport = LIVESYNC_PORT;
|
||||||
if (!scan_ip6_port(p + 24, tmpip, &tmpport))
|
if( !scan_ip4_port( p+24, tmpip, &tmpport )) goto parse_error;
|
||||||
goto parse_error;
|
|
||||||
livesync_bind_mcast( tmpip, tmpport );
|
livesync_bind_mcast( tmpip, tmpport );
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
@ -550,208 +366,51 @@ int parse_configfile(char *config_filename) {
|
|||||||
return bound;
|
return bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_state(const char *const state_filename) {
|
|
||||||
FILE *state_filehandle;
|
|
||||||
char inbuf[512];
|
|
||||||
ot_hash infohash;
|
|
||||||
unsigned long long base, downcount;
|
|
||||||
int consumed;
|
|
||||||
|
|
||||||
state_filehandle = fopen(state_filename, "r");
|
|
||||||
|
|
||||||
if (state_filehandle == NULL) {
|
|
||||||
fprintf(stderr, "Warning: Can't open config file: %s.", state_filename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
|
|
||||||
while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (int)sizeof(ot_hash); ++i) {
|
|
||||||
int eger = 16 * scan_fromhex(inbuf[2 * i]) + scan_fromhex(inbuf[1 + 2 * i]);
|
|
||||||
if (eger < 0)
|
|
||||||
continue;
|
|
||||||
infohash[i] = eger;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i != (int)sizeof(ot_hash))
|
|
||||||
continue;
|
|
||||||
i *= 2;
|
|
||||||
|
|
||||||
if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &base)))
|
|
||||||
continue;
|
|
||||||
i += consumed;
|
|
||||||
if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &downcount)))
|
|
||||||
continue;
|
|
||||||
add_torrent_from_saved_state(infohash, base, downcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(state_filehandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
int drop_privileges(const char *const serveruser, const char *const serverdir) {
|
|
||||||
struct passwd *pws = NULL;
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (!geteuid())
|
|
||||||
fprintf(stderr, "Dropping to user %s.\n", serveruser);
|
|
||||||
if (serverdir)
|
|
||||||
fprintf(stderr, "ch%s'ing to directory %s.\n", geteuid() ? "dir" : "root", serverdir);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Grab pws entry before chrooting */
|
|
||||||
pws = getpwnam(serveruser);
|
|
||||||
endpwent();
|
|
||||||
|
|
||||||
if (geteuid() == 0) {
|
|
||||||
/* Running as root: chroot and drop privileges */
|
|
||||||
if (serverdir && chroot(serverdir)) {
|
|
||||||
fprintf(stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chdir("/"))
|
|
||||||
panic("chdir() failed after chrooting: ");
|
|
||||||
|
|
||||||
/* If we can't find server user, revert to nobody's default uid */
|
|
||||||
if (!pws) {
|
|
||||||
fprintf(stderr, "Warning: Could not get password entry for %s. Reverting to uid -2.\n", serveruser);
|
|
||||||
if (setegid((gid_t)-2) || setgid((gid_t)-2) || setuid((uid_t)-2) || seteuid((uid_t)-2))
|
|
||||||
panic("Could not set uid to value -2");
|
|
||||||
} else {
|
|
||||||
if (setegid(pws->pw_gid) || setgid(pws->pw_gid) || setuid(pws->pw_uid) || seteuid(pws->pw_uid))
|
|
||||||
panic("Could not set uid to specified value");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geteuid() == 0 || getegid() == 0)
|
|
||||||
panic("Still running with root privileges?!");
|
|
||||||
} else {
|
|
||||||
/* Normal user, just chdir() */
|
|
||||||
if (serverdir && chdir(serverdir)) {
|
|
||||||
fprintf(stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Maintain our copy of the clock. time() on BSDs is very expensive. */
|
|
||||||
static void *time_caching_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
while (1) {
|
|
||||||
g_now_seconds = time(NULL);
|
|
||||||
sleep(5);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main( int argc, char **argv ) {
|
int main( int argc, char **argv ) {
|
||||||
ot_ip6 serverip;
|
struct passwd *pws = NULL;
|
||||||
ot_net tmpnet;
|
char serverip[4] = {0,0,0,0}, tmpip[4];
|
||||||
int bound = 0, scanon = 1;
|
int bound = 0, scanon = 1;
|
||||||
uint16_t tmpport;
|
uint16_t tmpport;
|
||||||
char *statefile = 0;
|
|
||||||
pthread_t thread_id; /* time cacher */
|
|
||||||
|
|
||||||
memset(serverip, 0, sizeof(ot_ip6));
|
|
||||||
#ifdef WANT_V4_ONLY
|
|
||||||
serverip[10] = serverip[11] = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WANT_DEV_RANDOM
|
|
||||||
srandomdev();
|
|
||||||
#else
|
|
||||||
srandom(time(NULL));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while( scanon ) {
|
while( scanon ) {
|
||||||
switch (getopt(argc, argv,
|
switch( getopt( argc, argv, ":i:p:A:P:d:r:s:f:v"
|
||||||
":i:p:A:P:d:u:r:s:f:l:v"
|
|
||||||
#ifdef WANT_ACCESSLIST_BLACK
|
#ifdef WANT_ACCESSLIST_BLACK
|
||||||
"b:"
|
"b:"
|
||||||
#elif defined( WANT_ACCESSLIST_WHITE )
|
#elif defined( WANT_ACCESSLIST_WHITE )
|
||||||
"w:"
|
"w:"
|
||||||
#endif
|
#endif
|
||||||
"h" ) ) {
|
"h" ) ) {
|
||||||
case -1:
|
case -1 : scanon = 0; break;
|
||||||
scanon = 0;
|
|
||||||
break;
|
|
||||||
case 'i':
|
case 'i':
|
||||||
if (!scan_ip6(optarg, serverip)) {
|
if( !scan_ip4( optarg, serverip )) { usage( argv[0] ); exit( 1 ); }
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#ifdef WANT_ACCESSLIST_BLACK
|
#ifdef WANT_ACCESSLIST_BLACK
|
||||||
case 'b':
|
case 'b': set_config_option( &g_accesslist_filename, optarg); break;
|
||||||
set_config_option(&g_accesslist_filename, optarg);
|
|
||||||
break;
|
|
||||||
#elif defined( WANT_ACCESSLIST_WHITE )
|
#elif defined( WANT_ACCESSLIST_WHITE )
|
||||||
case 'w':
|
case 'w': set_config_option( &g_accesslist_filename, optarg); break;
|
||||||
set_config_option(&g_accesslist_filename, optarg);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case 'p':
|
case 'p':
|
||||||
if (!scan_ushort(optarg, &tmpport)) {
|
if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
|
||||||
usage(argv[0]);
|
ot_try_bind( serverip, tmpport, FLAG_TCP ); bound++; break;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ot_try_bind(serverip, tmpport, FLAG_TCP);
|
|
||||||
bound++;
|
|
||||||
break;
|
|
||||||
case 'P':
|
case 'P':
|
||||||
if (!scan_ushort(optarg, &tmpport)) {
|
if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
|
||||||
usage(argv[0]);
|
ot_try_bind( serverip, tmpport, FLAG_UDP ); bound++; break;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ot_try_bind(serverip, tmpport, FLAG_UDP);
|
|
||||||
bound++;
|
|
||||||
break;
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
#ifdef WANT_SYNC_LIVE
|
||||||
case 's':
|
case 's':
|
||||||
if (!scan_ushort(optarg, &tmpport)) {
|
if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
|
||||||
usage(argv[0]);
|
livesync_bind_mcast( serverip, tmpport); break;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
livesync_bind_mcast(serverip, tmpport);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case 'd':
|
case 'd': set_config_option( &g_serverdir, optarg ); break;
|
||||||
set_config_option(&g_serverdir, optarg);
|
case 'r': set_config_option( &g_redirecturl, optarg ); break;
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
set_config_option(&g_serveruser, optarg);
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
set_config_option(&g_redirecturl, optarg);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
statefile = optarg;
|
|
||||||
break;
|
|
||||||
case 'A':
|
case 'A':
|
||||||
if (!scan_ip6_net(optarg, &tmpnet)) {
|
if( !scan_ip4( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); }
|
||||||
usage(argv[0]);
|
accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */
|
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f': bound += parse_configfile( optarg ); break;
|
||||||
bound += parse_configfile(optarg);
|
case 'h': help( argv[0] ); exit( 0 );
|
||||||
break;
|
case 'v': write( 2, static_inbuf, stats_return_tracker_version( static_inbuf )); exit( 0 );
|
||||||
case 'h':
|
|
||||||
help(argv[0]);
|
|
||||||
exit(0);
|
|
||||||
case 'v': {
|
|
||||||
char buffer[8192];
|
|
||||||
stats_return_tracker_version(buffer);
|
|
||||||
fputs(buffer, stderr);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
case '?':
|
case '?': usage( argv[0] ); exit( 1 );
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,48 +420,31 @@ int main(int argc, char **argv) {
|
|||||||
ot_try_bind( serverip, 6969, FLAG_UDP );
|
ot_try_bind( serverip, 6969, FLAG_UDP );
|
||||||
}
|
}
|
||||||
|
|
||||||
defaul_signal_handlers();
|
/* Drop permissions */
|
||||||
|
pws = getpwnam( "nobody" );
|
||||||
|
if( !pws ) {
|
||||||
|
setegid( (gid_t)-2 ); setuid( (uid_t)-2 );
|
||||||
|
setgid( (gid_t)-2 ); seteuid( (uid_t)-2 );
|
||||||
|
} else {
|
||||||
|
setegid( pws->pw_gid ); setuid( pws->pw_uid );
|
||||||
|
setgid( pws->pw_gid ); seteuid( pws->pw_uid );
|
||||||
|
}
|
||||||
|
endpwent();
|
||||||
|
|
||||||
#ifdef WANT_SYSLOGS
|
signal( SIGPIPE, SIG_IGN );
|
||||||
openlog("opentracker", 0, LOG_USER);
|
signal( SIGINT, signal_handler );
|
||||||
setlogmask(LOG_UPTO(LOG_INFO));
|
signal( SIGALRM, signal_handler );
|
||||||
#endif
|
|
||||||
|
|
||||||
if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1)
|
g_now = time( NULL );
|
||||||
panic("drop_privileges failed, exiting. Last error");
|
|
||||||
|
|
||||||
g_now_seconds = time(NULL);
|
if( trackerlogic_init( g_serverdir ? g_serverdir : "." ) == -1 )
|
||||||
pthread_create(&thread_id, NULL, time_caching_worker, NULL);
|
panic( "Logic not started" );
|
||||||
|
|
||||||
/* Create our self pipe which allows us to interrupt mainloops
|
alarm(5);
|
||||||
io_wait in case some data is available to send out */
|
|
||||||
if (pipe(g_self_pipe) == -1)
|
|
||||||
panic("selfpipe failed: ");
|
|
||||||
if (!io_fd(g_self_pipe[0]))
|
|
||||||
panic("selfpipe io_fd failed: ");
|
|
||||||
if (!io_fd(g_self_pipe[1]))
|
|
||||||
panic("selfpipe io_fd failed: ");
|
|
||||||
io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE);
|
|
||||||
io_wantread(g_self_pipe[0]);
|
|
||||||
|
|
||||||
/* Init all sub systems. This call may fail with an exit() */
|
server_mainloop( );
|
||||||
trackerlogic_init();
|
|
||||||
|
|
||||||
#ifdef _DEBUG_RANDOMTORRENTS
|
|
||||||
fprintf(stderr, "DEBUG: Generating %d random peers on random torrents. This may take a while. (Setting RANDOMTORRENTS in trackerlogic.h)\n", RANDOMTORRENTS);
|
|
||||||
trackerlogic_add_random_torrents(RANDOMTORRENTS);
|
|
||||||
fprintf(stderr, "... done.\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (statefile)
|
|
||||||
load_state(statefile);
|
|
||||||
|
|
||||||
install_signal_handlers();
|
|
||||||
|
|
||||||
if (!g_udp_workers)
|
|
||||||
udp_init(-1, 0);
|
|
||||||
|
|
||||||
server_mainloop(0);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_version_opentracker_c = "$Source$: $Revision$\n";
|
||||||
|
@ -2,20 +2,11 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
# I) Address opentracker will listen on, using both, tcp AND udp family
|
# I) Address opentracker will listen on, using both, tcp AND udp family
|
||||||
# (note, that port 6969 is implicit if omitted).
|
# (note, that port 6969 is implicite if ommitted).
|
||||||
#
|
#
|
||||||
# If no listen option is given (here or on the command line), opentracker
|
# If no listen option is given (here or on the command line), opentracker
|
||||||
# listens on 0.0.0.0:6969 tcp and udp.
|
# listens on 0.0.0.0:6969 tcp and udp.
|
||||||
#
|
#
|
||||||
# The next variable determines if udp sockets are handled in the event
|
|
||||||
# loop (set it to 0, the default) or are handled in blocking reads in
|
|
||||||
# dedicated worker threads. You have to set this value before the
|
|
||||||
# listen.tcp_udp or listen.udp statements before it takes effect, but you
|
|
||||||
# can re-set it for each listen statement. Normally you should keep it at
|
|
||||||
# the top of the config file.
|
|
||||||
#
|
|
||||||
# listen.udp.workers 4
|
|
||||||
#
|
|
||||||
# listen.tcp_udp 0.0.0.0
|
# listen.tcp_udp 0.0.0.0
|
||||||
# listen.tcp_udp 192.168.0.1:80
|
# listen.tcp_udp 192.168.0.1:80
|
||||||
# listen.tcp_udp 10.0.0.5:6969
|
# listen.tcp_udp 10.0.0.5:6969
|
||||||
@ -44,64 +35,11 @@
|
|||||||
# listing, so choose one of those options at compile time. File format
|
# listing, so choose one of those options at compile time. File format
|
||||||
# is straight forward: "<hex info hash>\n<hex info hash>\n..."
|
# is straight forward: "<hex info hash>\n<hex info hash>\n..."
|
||||||
#
|
#
|
||||||
# IIa) You can enable dynamic changesets to accesslists by enabling
|
|
||||||
# WANT_DYNAMIC_ACCESSLIST.
|
|
||||||
#
|
|
||||||
# The suggested way to work with dynamic changeset lists is to keep a
|
|
||||||
# main accesslist file that is loaded when opentracker (re)starts and
|
|
||||||
# reloaded infrequently (hourly or daily).
|
|
||||||
#
|
|
||||||
# All changes to the accesslist (e.g. from a web frontend) should be
|
|
||||||
# both appended to or removed from that file and sent to opentracker. By
|
|
||||||
# keeping dynamic changeset lists, you can avoid reloading huge
|
|
||||||
# accesslists whenever just a single entry is added or removed.
|
|
||||||
#
|
|
||||||
# Any info_hash (format see above) written to the fifo_add file will be
|
|
||||||
# kept on a dynamic add-changeset, removed from the dynamic
|
|
||||||
# delete-changeset and treated as if it was in the main accesslist file.
|
|
||||||
# The semantic of the respective dynamic changeset depends on whether
|
|
||||||
# WANT_ACCESSLIST_WHITE or WANT_ACCESSLIST_BLACK is enabled.
|
|
||||||
#
|
|
||||||
# access.fifo_add /var/run/opentracker/adder.fifo
|
|
||||||
#
|
|
||||||
# Any info_hash (format see above) written to the fifo_delete file will
|
|
||||||
# be kept on a dynamic delete-changeset, removed from the dynamic
|
|
||||||
# add-changeset and treated as if it was not in the main accesslist
|
|
||||||
# file.
|
|
||||||
#
|
|
||||||
# access.fifo_delete /var/run/opentracker/deleter.fifo
|
|
||||||
#
|
|
||||||
# If you reload the accesslist by sending SIGHUP to the tracker process,
|
|
||||||
# the dynamic lists are flushed, as opentracker assumes thoses lists are
|
|
||||||
# merged into the main accesslist.
|
|
||||||
#
|
|
||||||
# NOTE: While you can have multiple writers sending lines to the fifos,
|
|
||||||
# any writes larger than PIPE_BUF (see your limits.h, minimally 512
|
|
||||||
# bytes but usually 4096) may be interleaved with data sent by other
|
|
||||||
# writers. This can lead to unparsable lines of info_hashes.
|
|
||||||
#
|
|
||||||
# IIb)
|
|
||||||
# If you do not want to grant anyone access to your stats, enable the
|
# If you do not want to grant anyone access to your stats, enable the
|
||||||
# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses
|
# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses
|
||||||
# or network allowed to fetch stats here.
|
# allowed to fetch stats here.
|
||||||
#
|
#
|
||||||
# access.stats 192.168.0.23
|
# access.stats 192.168.0.23
|
||||||
# access.stats 10.1.1.23
|
|
||||||
#
|
|
||||||
# There is another way of hiding your stats. You can obfuscate the path
|
|
||||||
# to them. Normally it is located at /stats but you can configure it to
|
|
||||||
# appear anywhere on your tracker.
|
|
||||||
#
|
|
||||||
# access.stats_path stats
|
|
||||||
#
|
|
||||||
# II
|
|
||||||
# If opentracker lives behind one or multiple reverse proxies,
|
|
||||||
# every http connection appears to come from these proxies. In order to
|
|
||||||
# take the X-Forwarded-For address instead, compile opentracker with the
|
|
||||||
# WANT_IP_FROM_PROXY option and set your proxy addresses or networkss here.
|
|
||||||
#
|
|
||||||
# access.proxy 10.0.1.23
|
|
||||||
# access.proxy 192.0.0.0/8
|
|
||||||
#
|
#
|
||||||
|
|
||||||
# III) Live sync uses udp multicast packets to keep a cluster of opentrackers
|
# III) Live sync uses udp multicast packets to keep a cluster of opentrackers
|
||||||
@ -136,17 +74,11 @@
|
|||||||
# batchsync.cluster.admin_ip 10.1.1.1
|
# batchsync.cluster.admin_ip 10.1.1.1
|
||||||
#
|
#
|
||||||
|
|
||||||
# V) Control privilege drop behaviour.
|
# V) Control directory where opentracker will chdir to. So all black/white
|
||||||
# Put in the directory opentracker will chroot/chdir to. All black/white
|
# list files may be put in that directory (shell option -d).
|
||||||
# list files must be put in that directory (shell option -d).
|
|
||||||
#
|
|
||||||
#
|
#
|
||||||
# tracker.rootdir /usr/local/etc/opentracker
|
# tracker.rootdir /usr/local/etc/opentracker
|
||||||
#
|
#
|
||||||
# Tell opentracker which user to setuid to.
|
|
||||||
#
|
|
||||||
# tracker.user nobody
|
|
||||||
#
|
|
||||||
|
|
||||||
# VI) opentracker can be told to answer to a "GET / HTTP"-request with a
|
# VI) opentracker can be told to answer to a "GET / HTTP"-request with a
|
||||||
# redirect to another location (shell option -r).
|
# redirect to another location (shell option -r).
|
||||||
|
@ -1,320 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 44;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
6520B7530D036AAF00A43B1F /* libowfat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6520B7520D036AAF00A43B1F /* libowfat.a */; };
|
|
||||||
653A320C0CE7F475007F0D03 /* ot_accesslist.c in Sources */ = {isa = PBXBuildFile; fileRef = 653A320B0CE7F475007F0D03 /* ot_accesslist.c */; };
|
|
||||||
653A56B50CE28EC5000CF140 /* ot_iovec.c in Sources */ = {isa = PBXBuildFile; fileRef = 653A56B40CE28EC5000CF140 /* ot_iovec.c */; };
|
|
||||||
654A80890CD832FD009035DE /* opentracker.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80840CD832FC009035DE /* opentracker.c */; };
|
|
||||||
654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80850CD832FC009035DE /* scan_urlencoded_query.c */; };
|
|
||||||
654A808B0CD832FD009035DE /* trackerlogic.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80870CD832FC009035DE /* trackerlogic.c */; };
|
|
||||||
65542D8B0CE078E800469330 /* ot_vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8A0CE078E800469330 /* ot_vector.c */; };
|
|
||||||
65542D930CE07CED00469330 /* ot_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8F0CE07CED00469330 /* ot_mutex.c */; };
|
|
||||||
65542D940CE07CED00469330 /* ot_stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D910CE07CED00469330 /* ot_stats.c */; };
|
|
||||||
65542E750CE08B9100469330 /* ot_clean.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542E740CE08B9100469330 /* ot_clean.c */; };
|
|
||||||
65542EE80CE0CA6B00469330 /* ot_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542EE70CE0CA6B00469330 /* ot_udp.c */; };
|
|
||||||
65542F920CE17CA900469330 /* ot_fullscrape.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542F910CE17CA900469330 /* ot_fullscrape.c */; };
|
|
||||||
65B8DF3C0D0310D20017149E /* ot_http.c in Sources */ = {isa = PBXBuildFile; fileRef = 65B8DF3B0D0310D20017149E /* ot_http.c */; };
|
|
||||||
65FA33990E7EF09200F7D5A5 /* ot_livesync.c in Sources */ = {isa = PBXBuildFile; fileRef = 65FA33980E7EF09200F7D5A5 /* ot_livesync.c */; };
|
|
||||||
8DD76FB00486AB0100D96B5E /* opentracker.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6A0FF2C0290799A04C91782 /* opentracker.1 */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
8DD76FAF0486AB0100D96B5E /* CopyFiles */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 8;
|
|
||||||
dstPath = /usr/share/man/man1/;
|
|
||||||
dstSubfolderSpec = 0;
|
|
||||||
files = (
|
|
||||||
8DD76FB00486AB0100D96B5E /* opentracker.1 in CopyFiles */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 1;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
6520B7520D036AAF00A43B1F /* libowfat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libowfat.a; path = ../libowfat/libowfat.a; sourceTree = SOURCE_ROOT; };
|
|
||||||
653A320A0CE7F475007F0D03 /* ot_accesslist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_accesslist.h; sourceTree = "<group>"; };
|
|
||||||
653A320B0CE7F475007F0D03 /* ot_accesslist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_accesslist.c; sourceTree = "<group>"; };
|
|
||||||
653A56AC0CE201FF000CF140 /* opentracker */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = opentracker; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
653A56B30CE28EC5000CF140 /* ot_iovec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_iovec.h; sourceTree = "<group>"; };
|
|
||||||
653A56B40CE28EC5000CF140 /* ot_iovec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_iovec.c; sourceTree = "<group>"; };
|
|
||||||
654A80840CD832FC009035DE /* opentracker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opentracker.c; sourceTree = "<group>"; };
|
|
||||||
654A80850CD832FC009035DE /* scan_urlencoded_query.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scan_urlencoded_query.c; sourceTree = "<group>"; };
|
|
||||||
654A80860CD832FC009035DE /* scan_urlencoded_query.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scan_urlencoded_query.h; sourceTree = "<group>"; };
|
|
||||||
654A80870CD832FC009035DE /* trackerlogic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trackerlogic.c; sourceTree = "<group>"; };
|
|
||||||
654A80880CD832FC009035DE /* trackerlogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trackerlogic.h; sourceTree = "<group>"; };
|
|
||||||
65542D890CE078E800469330 /* ot_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_vector.h; sourceTree = "<group>"; };
|
|
||||||
65542D8A0CE078E800469330 /* ot_vector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_vector.c; sourceTree = "<group>"; };
|
|
||||||
65542D8F0CE07CED00469330 /* ot_mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_mutex.c; sourceTree = "<group>"; };
|
|
||||||
65542D900CE07CED00469330 /* ot_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_mutex.h; sourceTree = "<group>"; };
|
|
||||||
65542D910CE07CED00469330 /* ot_stats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_stats.c; sourceTree = "<group>"; };
|
|
||||||
65542D920CE07CED00469330 /* ot_stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_stats.h; sourceTree = "<group>"; };
|
|
||||||
65542E730CE08B9100469330 /* ot_clean.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_clean.h; sourceTree = "<group>"; };
|
|
||||||
65542E740CE08B9100469330 /* ot_clean.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_clean.c; sourceTree = "<group>"; };
|
|
||||||
65542EE60CE0CA6B00469330 /* ot_udp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_udp.h; sourceTree = "<group>"; };
|
|
||||||
65542EE70CE0CA6B00469330 /* ot_udp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_udp.c; sourceTree = "<group>"; };
|
|
||||||
65542F900CE17CA900469330 /* ot_fullscrape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_fullscrape.h; sourceTree = "<group>"; };
|
|
||||||
65542F910CE17CA900469330 /* ot_fullscrape.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_fullscrape.c; sourceTree = "<group>"; };
|
|
||||||
65B8DF3A0D0310D20017149E /* ot_http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_http.h; sourceTree = "<group>"; };
|
|
||||||
65B8DF3B0D0310D20017149E /* ot_http.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_http.c; sourceTree = "<group>"; };
|
|
||||||
65FA33970E7EF09200F7D5A5 /* ot_livesync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_livesync.h; sourceTree = "<group>"; };
|
|
||||||
65FA33980E7EF09200F7D5A5 /* ot_livesync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_livesync.c; sourceTree = "<group>"; };
|
|
||||||
C6A0FF2C0290799A04C91782 /* opentracker.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = opentracker.1; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
8DD76FAD0486AB0100D96B5E /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
6520B7530D036AAF00A43B1F /* libowfat.a in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
08FB7794FE84155DC02AAC07 /* opentracker */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
65542D810CE0786F00469330 /* Headers */,
|
|
||||||
08FB7795FE84155DC02AAC07 /* Source */,
|
|
||||||
92762AC9104EDED700FDCB60 /* Libraries */,
|
|
||||||
C6A0FF2B0290797F04C91782 /* Documentation */,
|
|
||||||
653A56AD0CE201FF000CF140 /* Products */,
|
|
||||||
);
|
|
||||||
name = opentracker;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
654A80840CD832FC009035DE /* opentracker.c */,
|
|
||||||
653A320B0CE7F475007F0D03 /* ot_accesslist.c */,
|
|
||||||
65542E740CE08B9100469330 /* ot_clean.c */,
|
|
||||||
65542F910CE17CA900469330 /* ot_fullscrape.c */,
|
|
||||||
65B8DF3B0D0310D20017149E /* ot_http.c */,
|
|
||||||
65FA33980E7EF09200F7D5A5 /* ot_livesync.c */,
|
|
||||||
653A56B40CE28EC5000CF140 /* ot_iovec.c */,
|
|
||||||
65542D8F0CE07CED00469330 /* ot_mutex.c */,
|
|
||||||
65542D910CE07CED00469330 /* ot_stats.c */,
|
|
||||||
65542EE70CE0CA6B00469330 /* ot_udp.c */,
|
|
||||||
65542D8A0CE078E800469330 /* ot_vector.c */,
|
|
||||||
654A80850CD832FC009035DE /* scan_urlencoded_query.c */,
|
|
||||||
654A80870CD832FC009035DE /* trackerlogic.c */,
|
|
||||||
);
|
|
||||||
name = Source;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
653A56AD0CE201FF000CF140 /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
653A56AC0CE201FF000CF140 /* opentracker */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
65542D810CE0786F00469330 /* Headers */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
653A320A0CE7F475007F0D03 /* ot_accesslist.h */,
|
|
||||||
65542E730CE08B9100469330 /* ot_clean.h */,
|
|
||||||
65542F900CE17CA900469330 /* ot_fullscrape.h */,
|
|
||||||
65B8DF3A0D0310D20017149E /* ot_http.h */,
|
|
||||||
653A56B30CE28EC5000CF140 /* ot_iovec.h */,
|
|
||||||
65FA33970E7EF09200F7D5A5 /* ot_livesync.h */,
|
|
||||||
65542D900CE07CED00469330 /* ot_mutex.h */,
|
|
||||||
65542D920CE07CED00469330 /* ot_stats.h */,
|
|
||||||
65542EE60CE0CA6B00469330 /* ot_udp.h */,
|
|
||||||
65542D890CE078E800469330 /* ot_vector.h */,
|
|
||||||
654A80860CD832FC009035DE /* scan_urlencoded_query.h */,
|
|
||||||
654A80880CD832FC009035DE /* trackerlogic.h */,
|
|
||||||
);
|
|
||||||
name = Headers;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
92762AC9104EDED700FDCB60 /* Libraries */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
6520B7520D036AAF00A43B1F /* libowfat.a */,
|
|
||||||
);
|
|
||||||
name = Libraries;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C6A0FF2B0290797F04C91782 /* Documentation */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
C6A0FF2C0290799A04C91782 /* opentracker.1 */,
|
|
||||||
);
|
|
||||||
name = Documentation;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
8DD76FA90486AB0100D96B5E /* opentracker */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "opentracker" */;
|
|
||||||
buildPhases = (
|
|
||||||
8DD76FAB0486AB0100D96B5E /* Sources */,
|
|
||||||
8DD76FAD0486AB0100D96B5E /* Frameworks */,
|
|
||||||
8DD76FAF0486AB0100D96B5E /* CopyFiles */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = opentracker;
|
|
||||||
productInstallPath = "$(HOME)/bin";
|
|
||||||
productName = opentracker;
|
|
||||||
productReference = 653A56AC0CE201FF000CF140 /* opentracker */;
|
|
||||||
productType = "com.apple.product-type.tool";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "opentracker" */;
|
|
||||||
compatibilityVersion = "Xcode 3.0";
|
|
||||||
hasScannedForEncodings = 1;
|
|
||||||
mainGroup = 08FB7794FE84155DC02AAC07 /* opentracker */;
|
|
||||||
productRefGroup = 653A56AD0CE201FF000CF140 /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
8DD76FA90486AB0100D96B5E /* opentracker */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
8DD76FAB0486AB0100D96B5E /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
654A80890CD832FD009035DE /* opentracker.c in Sources */,
|
|
||||||
654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */,
|
|
||||||
654A808B0CD832FD009035DE /* trackerlogic.c in Sources */,
|
|
||||||
65542D8B0CE078E800469330 /* ot_vector.c in Sources */,
|
|
||||||
65542D930CE07CED00469330 /* ot_mutex.c in Sources */,
|
|
||||||
65542D940CE07CED00469330 /* ot_stats.c in Sources */,
|
|
||||||
65542E750CE08B9100469330 /* ot_clean.c in Sources */,
|
|
||||||
65542EE80CE0CA6B00469330 /* ot_udp.c in Sources */,
|
|
||||||
65542F920CE17CA900469330 /* ot_fullscrape.c in Sources */,
|
|
||||||
653A56B50CE28EC5000CF140 /* ot_iovec.c in Sources */,
|
|
||||||
653A320C0CE7F475007F0D03 /* ot_accesslist.c in Sources */,
|
|
||||||
65B8DF3C0D0310D20017149E /* ot_http.c in Sources */,
|
|
||||||
65FA33990E7EF09200F7D5A5 /* ot_livesync.c in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
1DEB928608733DD80010E9CD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"\"$(SRCROOT)/../libowfat\"",
|
|
||||||
);
|
|
||||||
PRODUCT_NAME = opentracker;
|
|
||||||
ZERO_LINK = YES;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
1DEB928708733DD80010E9CD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"\"$(SRCROOT)/../libowfat\"",
|
|
||||||
);
|
|
||||||
PRODUCT_NAME = opentracker;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
1DEB928A08733DD80010E9CD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ARCHS = "$(ONLY_ACTIVE_ARCH_PRE_XCODE_3_1)";
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
WANT_ACCESSLIST_WHITE,
|
|
||||||
WANT_IP_FROM_QUERY_STRING,
|
|
||||||
WANT_FULLSCRAPE,
|
|
||||||
);
|
|
||||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
HEADER_SEARCH_PATHS = ../libowfat/;
|
|
||||||
LIBRARY_SEARCH_PATHS = ../libowfat/;
|
|
||||||
ONLY_ACTIVE_ARCH_PRE_XCODE_3_1 = "$(NATIVE_ARCH_ACTUAL)";
|
|
||||||
PREBINDING = NO;
|
|
||||||
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.6.sdk";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
1DEB928B08733DD80010E9CD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ARCHS = "$(ONLY_ACTIVE_ARCH_PRE_XCODE_3_1)";
|
|
||||||
DEAD_CODE_STRIPPING = NO;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
WANT_ACCESSLIST_WHITE,
|
|
||||||
WANT_IP_FROM_QUERY_STRING,
|
|
||||||
WANT_FULLSCRAPE,
|
|
||||||
);
|
|
||||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
HEADER_SEARCH_PATHS = ../libowfat/;
|
|
||||||
LIBRARY_SEARCH_PATHS = ../libowfat/;
|
|
||||||
ONLY_ACTIVE_ARCH_PRE_XCODE_3_1 = "$(NATIVE_ARCH_ACTUAL)";
|
|
||||||
PREBINDING = NO;
|
|
||||||
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.6.sdk";
|
|
||||||
ZERO_LINK = NO;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "opentracker" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
1DEB928608733DD80010E9CD /* Debug */,
|
|
||||||
1DEB928708733DD80010E9CD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "opentracker" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
1DEB928A08733DD80010E9CD /* Debug */,
|
|
||||||
1DEB928B08733DD80010E9CD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
|
||||||
}
|
|
572
ot_accesslist.c
572
ot_accesslist.c
@ -4,558 +4,126 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <pthread.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <stdio.h>
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
#include <signal.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
#include "fmt.h"
|
|
||||||
#include "ip6.h"
|
|
||||||
#include "mmap.h"
|
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_accesslist.h"
|
|
||||||
#include "ot_vector.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_accesslist.h"
|
||||||
|
|
||||||
/* GLOBAL VARIABLES */
|
/* GLOBAL VARIABLES */
|
||||||
#ifdef WANT_ACCESSLIST
|
#ifdef WANT_ACCESSLIST
|
||||||
char *g_accesslist_filename = NULL;
|
char *g_accesslist_filename = NULL;
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
static ot_vector accesslist;
|
||||||
char *g_accesslist_pipe_add = NULL;
|
|
||||||
char *g_accesslist_pipe_delete = NULL;
|
|
||||||
#endif
|
|
||||||
static pthread_mutex_t g_accesslist_mutex;
|
|
||||||
|
|
||||||
/* Accesslists are lock free linked lists. We can not make them locking, because every announce
|
static void accesslist_reset( void ) {
|
||||||
would try to acquire the mutex, making it the most contested mutex in the whole of opentracker,
|
free( accesslist.data );
|
||||||
basically creating a central performance choke point.
|
byte_zero( &accesslist, sizeof( accesslist ) );
|
||||||
|
|
||||||
The idea is that updating the list heads happens under the g_accesslist_mutex guard and is
|
|
||||||
done atomically, while consumers might potentially still hold pointers deeper inside the list.
|
|
||||||
|
|
||||||
Consumers (for now only via accesslist_hashisvalid) will always fetch the list head pointer
|
|
||||||
that is guaranteed to live for at least five minutes. This should be many orders of magnitudes
|
|
||||||
more than how long it will be needed by the bsearch done on the list. */
|
|
||||||
struct ot_accesslist;
|
|
||||||
typedef struct ot_accesslist ot_accesslist;
|
|
||||||
struct ot_accesslist {
|
|
||||||
ot_hash *list;
|
|
||||||
size_t size;
|
|
||||||
ot_time base;
|
|
||||||
ot_accesslist *next;
|
|
||||||
};
|
|
||||||
static ot_accesslist *_Atomic g_accesslist = NULL;
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
static ot_accesslist *_Atomic g_accesslist_add = NULL;
|
|
||||||
static ot_accesslist *_Atomic g_accesslist_delete = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Helpers to work on access lists */
|
|
||||||
static int vector_compare_hash(const void *hash1, const void *hash2) { return memcmp(hash1, hash2, OT_HASH_COMPARE_SIZE); }
|
|
||||||
|
|
||||||
static ot_accesslist *accesslist_free(ot_accesslist *accesslist) {
|
|
||||||
while (accesslist) {
|
|
||||||
ot_accesslist *this_accesslist = accesslist;
|
|
||||||
accesslist = this_accesslist->next;
|
|
||||||
free(this_accesslist->list);
|
|
||||||
free(this_accesslist);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ot_accesslist *accesslist_make(ot_accesslist *next, size_t size) {
|
static int accesslist_addentry( ot_hash *infohash ) {
|
||||||
ot_accesslist *accesslist_new = malloc(sizeof(ot_accesslist));
|
int eger;
|
||||||
if (accesslist_new) {
|
void *insert = vector_find_or_insert( &accesslist, infohash, OT_HASH_COMPARE_SIZE, OT_HASH_COMPARE_SIZE, &eger );
|
||||||
accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL;
|
|
||||||
accesslist_new->size = size;
|
|
||||||
accesslist_new->base = g_now_minutes;
|
|
||||||
accesslist_new->next = next;
|
|
||||||
if (size && !accesslist_new->list) {
|
|
||||||
free(accesslist_new);
|
|
||||||
accesslist_new = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return accesslist_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This must be called with g_accesslist_mutex held.
|
if( !insert )
|
||||||
This will never delete head, because that might still be in use. */
|
return -1;
|
||||||
static void accesslist_clean(ot_accesslist *accesslist) {
|
|
||||||
while (accesslist && accesslist->next) {
|
memmove( insert, infohash, OT_HASH_COMPARE_SIZE );
|
||||||
if (accesslist->next->base + 5 < g_now_minutes)
|
|
||||||
accesslist->next = accesslist_free(accesslist->next);
|
return 0;
|
||||||
accesslist = accesslist->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read initial access list */
|
/* Read initial access list */
|
||||||
static void accesslist_readfile(void) {
|
static void accesslist_readfile( int foo ) {
|
||||||
ot_accesslist *accesslist_new;
|
FILE * accesslist_filehandle;
|
||||||
ot_hash *info_hash;
|
ot_hash infohash;
|
||||||
const char *map, *map_end, *read_offs;
|
char inbuf[512];
|
||||||
size_t maplen;
|
foo = foo;
|
||||||
|
|
||||||
if ((map = mmap_read(g_accesslist_filename, &maplen)) == NULL) {
|
accesslist_filehandle = fopen( g_accesslist_filename, "r" );
|
||||||
char *wd = getcwd(NULL, 0);
|
|
||||||
fprintf(stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).\nPWD: %s\n", g_accesslist_filename, wd);
|
/* Free accesslist vector in trackerlogic.c*/
|
||||||
free(wd);
|
accesslist_reset();
|
||||||
|
|
||||||
|
if( accesslist_filehandle == NULL ) {
|
||||||
|
fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).", g_accesslist_filename );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* You need at least 41 bytes to pass an info_hash, make enough room
|
|
||||||
for the maximum amount of them */
|
|
||||||
accesslist_new = accesslist_make(g_accesslist, maplen / 41);
|
|
||||||
if (!accesslist_new) {
|
|
||||||
fprintf(stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", (maplen / 41) * 20);
|
|
||||||
mmap_unmap(map, maplen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
info_hash = accesslist_new->list;
|
|
||||||
|
|
||||||
/* No use to scan if there's not enough room for another full info_hash */
|
|
||||||
map_end = map + maplen - 40;
|
|
||||||
read_offs = map;
|
|
||||||
|
|
||||||
/* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
|
/* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
|
||||||
while (read_offs <= map_end) {
|
while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < (int)sizeof(ot_hash); ++i) {
|
for( i=0; i<20; ++i ) {
|
||||||
int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]);
|
int eger = 16 * scan_fromhex( inbuf[ 2*i ] ) + scan_fromhex( inbuf[ 1 + 2*i ] );
|
||||||
int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]);
|
if( eger < 0 )
|
||||||
if (eger1 < 0 || eger2 < 0)
|
continue;
|
||||||
break;
|
infohash[i] = eger;
|
||||||
(*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
|
|
||||||
}
|
}
|
||||||
|
if( scan_fromhex( inbuf[ 40 ] ) >= 0 )
|
||||||
if (i == sizeof(ot_hash)) {
|
continue;
|
||||||
read_offs += 40;
|
|
||||||
|
|
||||||
/* Append accesslist to accesslist vector */
|
/* Append accesslist to accesslist vector */
|
||||||
if (read_offs == map_end || scan_fromhex((unsigned char)*read_offs) < 0)
|
accesslist_addentry( &infohash );
|
||||||
++info_hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find start of next line */
|
fclose( accesslist_filehandle );
|
||||||
while (read_offs <= map_end && *(read_offs++) != '\n')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
#ifdef _DEBUG
|
|
||||||
fprintf(stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mmap_unmap(map, maplen);
|
|
||||||
|
|
||||||
qsort(accesslist_new->list, info_hash - accesslist_new->list, sizeof(*info_hash), vector_compare_hash);
|
|
||||||
accesslist_new->size = info_hash - accesslist_new->list;
|
|
||||||
|
|
||||||
/* Now exchange the accesslist vector in the least race condition prone way */
|
|
||||||
pthread_mutex_lock(&g_accesslist_mutex);
|
|
||||||
accesslist_new->next = g_accesslist;
|
|
||||||
g_accesslist = accesslist_new; /* Only now set a new list */
|
|
||||||
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
/* If we have dynamic accesslists, reloading a new one will always void the add/delete lists.
|
|
||||||
Insert empty ones at the list head */
|
|
||||||
if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL)
|
|
||||||
g_accesslist_add = accesslist_new;
|
|
||||||
if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL)
|
|
||||||
g_accesslist_delete = accesslist_new;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
accesslist_clean(g_accesslist);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_accesslist_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int accesslist_hashisvalid(ot_hash hash) {
|
int accesslist_hashisvalid( ot_hash *hash ) {
|
||||||
/* Get working copy of current access list */
|
int exactmatch;
|
||||||
ot_accesslist *accesslist = g_accesslist;
|
binary_search( hash, accesslist.data, accesslist.size, OT_HASH_COMPARE_SIZE, OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
ot_accesslist *accesslist_add, *accesslist_delete;
|
|
||||||
#endif
|
|
||||||
void *exactmatch = NULL;
|
|
||||||
|
|
||||||
if (accesslist)
|
|
||||||
exactmatch = bsearch(hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
|
|
||||||
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
/* If we had no match on the main list, scan the list of dynamically added hashes */
|
|
||||||
accesslist_add = g_accesslist_add;
|
|
||||||
if ((exactmatch == NULL) && accesslist_add)
|
|
||||||
exactmatch = bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
|
|
||||||
|
|
||||||
/* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */
|
|
||||||
accesslist_delete = g_accesslist_delete;
|
|
||||||
if ((exactmatch != NULL) && accesslist_delete && bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash))
|
|
||||||
exactmatch = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WANT_ACCESSLIST_BLACK
|
#ifdef WANT_ACCESSLIST_BLACK
|
||||||
return exactmatch == NULL;
|
exactmatch = !exactmatch;
|
||||||
#else
|
|
||||||
return exactmatch != NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *accesslist_worker(void *args) {
|
|
||||||
int sig;
|
|
||||||
sigset_t signal_mask;
|
|
||||||
|
|
||||||
sigemptyset(&signal_mask);
|
|
||||||
sigaddset(&signal_mask, SIGHUP);
|
|
||||||
|
|
||||||
(void)args;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (!g_opentracker_running)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Initial attempt to read accesslist */
|
|
||||||
accesslist_readfile();
|
|
||||||
|
|
||||||
/* Wait for signals */
|
|
||||||
while (sigwait(&signal_mask, &sig) != 0 && sig != SIGHUP)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
static pthread_t thread_adder_id, thread_deleter_id;
|
|
||||||
static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic *adding_to, ot_accesslist *_Atomic *removing_from) {
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (!stat(fifoname, &st)) {
|
|
||||||
if (!S_ISFIFO(st.st_mode)) {
|
|
||||||
fprintf(stderr, "Error when starting dynamic accesslists: Found Non-FIFO file at %s.\nPlease remove it and restart opentracker.\n", fifoname);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int error = mkfifo(fifoname, 0755);
|
|
||||||
if (error && error != EEXIST) {
|
|
||||||
fprintf(stderr, "Error when starting dynamic accesslists: Couldn't create FIFO at %s, error: %s\n", fifoname, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (g_opentracker_running) {
|
|
||||||
FILE *fifo = fopen(fifoname, "r");
|
|
||||||
char *line = NULL;
|
|
||||||
size_t linecap = 0;
|
|
||||||
ssize_t linelen;
|
|
||||||
|
|
||||||
if (!fifo) {
|
|
||||||
fprintf(stderr, "Error when reading dynamic accesslists: Couldn't open FIFO at %s, error: %s\n", fifoname, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((linelen = getline(&line, &linecap, fifo)) > 0) {
|
|
||||||
ot_hash info_hash;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf("Got line %*s", (int)linelen, line);
|
|
||||||
/* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*"
|
|
||||||
If there's not enough characters for an info_hash in the line, skip it. */
|
|
||||||
if (linelen < 41)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (i = 0; i < (int)sizeof(ot_hash); ++i) {
|
|
||||||
int eger1 = scan_fromhex((unsigned char)line[2 * i]);
|
|
||||||
int eger2 = scan_fromhex((unsigned char)line[1 + 2 * i]);
|
|
||||||
if (eger1 < 0 || eger2 < 0)
|
|
||||||
break;
|
|
||||||
((uint8_t *)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
|
|
||||||
}
|
|
||||||
printf("parsed info_hash %20s\n", info_hash);
|
|
||||||
if (i != sizeof(ot_hash))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the
|
|
||||||
other worker threads from doing the same */
|
|
||||||
pthread_mutex_lock(&g_accesslist_mutex);
|
|
||||||
|
|
||||||
/* If the info hash is in the removing_from list, create a new head without that entry */
|
|
||||||
if (*removing_from && (*removing_from)->list) {
|
|
||||||
ot_hash *exactmatch = bsearch(info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
|
|
||||||
if (exactmatch) {
|
|
||||||
ptrdiff_t off = exactmatch - (*removing_from)->list;
|
|
||||||
ot_accesslist *accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1);
|
|
||||||
if (accesslist_new) {
|
|
||||||
memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off);
|
|
||||||
memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1);
|
|
||||||
*removing_from = accesslist_new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple case: there's no adding_to list yet, create one with one member */
|
|
||||||
if (!*adding_to) {
|
|
||||||
ot_accesslist *accesslist_new = accesslist_make(NULL, 1);
|
|
||||||
if (accesslist_new) {
|
|
||||||
memcpy(accesslist_new->list, info_hash, sizeof(ot_hash));
|
|
||||||
*adding_to = accesslist_new;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int exactmatch = 0;
|
|
||||||
ot_hash *insert_point = binary_search(info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch);
|
|
||||||
|
|
||||||
/* Only if the info hash is not in the adding_to list, create a new head with that entry */
|
|
||||||
if (!exactmatch) {
|
|
||||||
ot_accesslist *accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1);
|
|
||||||
ptrdiff_t off = insert_point - (*adding_to)->list;
|
|
||||||
if (accesslist_new) {
|
|
||||||
memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off);
|
|
||||||
memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash));
|
|
||||||
memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, (*adding_to)->size - off);
|
|
||||||
*adding_to = accesslist_new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_accesslist_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fifo);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *accesslist_adder_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete);
|
|
||||||
}
|
|
||||||
static void *accesslist_deleter_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static pthread_t thread_id;
|
return exactmatch;
|
||||||
|
}
|
||||||
|
|
||||||
void accesslist_init( ) {
|
void accesslist_init( ) {
|
||||||
pthread_mutex_init(&g_accesslist_mutex, NULL);
|
byte_zero( &accesslist, sizeof( accesslist ) );
|
||||||
pthread_create(&thread_id, NULL, accesslist_worker, NULL);
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
/* Passing "0" since read_blacklist_file also is SIGHUP handler */
|
||||||
if (g_accesslist_pipe_add)
|
if( g_accesslist_filename ) {
|
||||||
pthread_create(&thread_adder_id, NULL, accesslist_adder_worker, NULL);
|
accesslist_readfile( 0 );
|
||||||
if (g_accesslist_pipe_delete)
|
signal( SIGHUP, accesslist_readfile );
|
||||||
pthread_create(&thread_deleter_id, NULL, accesslist_deleter_worker, NULL);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void accesslist_deinit(void) {
|
|
||||||
/* Wake up sleeping worker */
|
|
||||||
pthread_kill(thread_id, SIGHUP);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_accesslist_mutex);
|
|
||||||
|
|
||||||
g_accesslist = accesslist_free(g_accesslist);
|
|
||||||
|
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
g_accesslist_add = accesslist_free(g_accesslist_add);
|
|
||||||
g_accesslist_delete = accesslist_free(g_accesslist_delete);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_accesslist_mutex);
|
|
||||||
pthread_cancel(thread_id);
|
|
||||||
pthread_mutex_destroy(&g_accesslist_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void accesslist_cleanup(void) {
|
|
||||||
pthread_mutex_lock(&g_accesslist_mutex);
|
|
||||||
|
|
||||||
accesslist_clean(g_accesslist);
|
|
||||||
#if WANT_DYNAMIC_ACCESSLIST
|
|
||||||
accesslist_clean(g_accesslist_add);
|
|
||||||
accesslist_clean(g_accesslist_delete);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_accesslist_mutex);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int address_in_net(const ot_ip6 address, const ot_net *net) {
|
static uint32_t g_adminip_addresses[OT_ADMINIP_MAX];
|
||||||
int bits = net->bits, checkbits = (0x7f00 >> (bits & 7));
|
static ot_permissions g_adminip_permissions[OT_ADMINIP_MAX];
|
||||||
int result = memcmp(address, &net->address, bits >> 3);
|
static unsigned int g_adminip_count = 0;
|
||||||
if (!result && (bits & 7))
|
|
||||||
result = (checkbits & address[bits >> 3]) - (checkbits & net->address[bits >> 3]);
|
|
||||||
return result == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *set_value_for_net(const ot_net *net, ot_vector *vector, const void *value, const size_t member_size) {
|
int accesslist_blessip( char *ip, ot_permissions permissions ) {
|
||||||
size_t i;
|
if( g_adminip_count >= OT_ADMINIP_MAX )
|
||||||
int exactmatch;
|
|
||||||
|
|
||||||
/* Caller must have a concept of ot_net in it's member */
|
|
||||||
if (member_size < sizeof(ot_net))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Check each net in vector for overlap */
|
|
||||||
uint8_t *member = ((uint8_t *)vector->data);
|
|
||||||
for (i = 0; i < vector->size; ++i) {
|
|
||||||
if (address_in_net(*(ot_ip6 *)member, net) || address_in_net(net->address, (ot_net *)member))
|
|
||||||
return 0;
|
|
||||||
member += member_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
member = vector_find_or_insert(vector, (void *)net, member_size, sizeof(ot_net), &exactmatch);
|
|
||||||
if (member) {
|
|
||||||
memcpy(member, net, sizeof(ot_net));
|
|
||||||
memcpy(member + sizeof(ot_net), value, member_size - sizeof(ot_net));
|
|
||||||
}
|
|
||||||
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Takes a vector filled with { ot_net net, uint8_t[x] value };
|
|
||||||
Returns value associated with the net, or NULL if not found */
|
|
||||||
void *get_value_for_net(const ot_ip6 address, const ot_vector *vector, const size_t member_size) {
|
|
||||||
int exactmatch;
|
|
||||||
/* This binary search will return a pointer to the first non-containing network... */
|
|
||||||
ot_net *net = binary_search(address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch);
|
|
||||||
if (!net)
|
|
||||||
return NULL;
|
|
||||||
/* ... so we'll need to move back one step unless we've exactly hit the first address in network */
|
|
||||||
if (!exactmatch && ((void *)net > vector->data))
|
|
||||||
--net;
|
|
||||||
if (!address_in_net(address, net))
|
|
||||||
return NULL;
|
|
||||||
return (void *)net;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WANT_FULLLOG_NETWORKS
|
|
||||||
static ot_vector g_lognets_list;
|
|
||||||
ot_log *g_logchain_first, *g_logchain_last;
|
|
||||||
static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
void loglist_add_network(const ot_net *net) {
|
|
||||||
pthread_mutex_lock(&g_lognets_list_mutex);
|
|
||||||
set_value_for_net(net, &g_lognets_list, NULL, sizeof(ot_net));
|
|
||||||
pthread_mutex_unlock(&g_lognets_list_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loglist_reset() {
|
|
||||||
pthread_mutex_lock(&g_lognets_list_mutex);
|
|
||||||
free(g_lognets_list.data);
|
|
||||||
g_lognets_list.data = 0;
|
|
||||||
g_lognets_list.size = g_lognets_list.space = 0;
|
|
||||||
pthread_mutex_unlock(&g_lognets_list_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int loglist_check_address(const ot_ip6 address) {
|
|
||||||
int result;
|
|
||||||
pthread_mutex_lock(&g_lognets_list_mutex);
|
|
||||||
result = (NULL != get_value_for_net(address, &g_lognets_list, sizeof(ot_net)));
|
|
||||||
pthread_mutex_unlock(&g_lognets_list_mutex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WANT_IP_FROM_PROXY
|
|
||||||
typedef struct {
|
|
||||||
ot_net *proxy;
|
|
||||||
ot_vector networks;
|
|
||||||
} ot_proxymap;
|
|
||||||
|
|
||||||
static ot_vector g_proxies_list;
|
|
||||||
static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
int proxylist_add_network(const ot_net *proxy, const ot_net *net) {
|
|
||||||
ot_proxymap *map;
|
|
||||||
int exactmatch, result = 1;
|
|
||||||
pthread_mutex_lock(&g_proxies_list_mutex);
|
|
||||||
|
|
||||||
/* If we have a direct hit, use and extend the vector there */
|
|
||||||
map = binary_search(proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch);
|
|
||||||
|
|
||||||
if (!map || !exactmatch) {
|
|
||||||
/* else see, if we've got overlapping networks
|
|
||||||
and get a new empty vector if not */
|
|
||||||
ot_vector empty;
|
|
||||||
memset(&empty, 0, sizeof(ot_vector));
|
|
||||||
map = set_value_for_net(proxy, &g_proxies_list, &empty, sizeof(ot_proxymap));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map && set_value_for_net(net, &map->networks, NULL, sizeof(ot_net)))
|
|
||||||
result = 1;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_proxies_list_mutex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int proxylist_check_proxy(const ot_ip6 proxy, const ot_ip6 address) {
|
|
||||||
int result = 0;
|
|
||||||
ot_proxymap *map;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_proxies_list_mutex);
|
|
||||||
|
|
||||||
if ((map = get_value_for_net(proxy, &g_proxies_list, sizeof(ot_proxymap))))
|
|
||||||
if (!address || get_value_for_net(address, &map->networks, sizeof(ot_net)))
|
|
||||||
result = 1;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_proxies_list_mutex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static ot_net g_admin_nets[OT_ADMINIP_MAX];
|
|
||||||
static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX];
|
|
||||||
static unsigned int g_admin_nets_count = 0;
|
|
||||||
|
|
||||||
int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
|
|
||||||
if (g_admin_nets_count >= OT_ADMINIP_MAX)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
memmove( g_adminip_addresses + g_adminip_count, ip, 4 );
|
||||||
memcpy(g_admin_nets + g_admin_nets_count, net, sizeof(ot_net));
|
g_adminip_permissions[ g_adminip_count++ ] = permissions;
|
||||||
g_admin_nets_permissions[g_admin_nets_count++] = permissions;
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
{
|
uint8_t *_ip = (uint8_t*)ip;
|
||||||
char _debug[512];
|
fprintf( stderr, "Blessing ip address %d.%d.%d.%d with:", _ip[0], _ip[1], _ip[2], _ip[3]);
|
||||||
int off = snprintf(_debug, sizeof(_debug), "Blessing ip net ");
|
if( permissions & OT_PERMISSION_MAY_STAT ) fputs( " may_fetch_stats", stderr );
|
||||||
off += fmt_ip6c(_debug + off, net->address);
|
if( permissions & OT_PERMISSION_MAY_SYNC ) fputs( " may_sync_batch", stderr );
|
||||||
if (net->bits < 128) {
|
if( permissions & OT_PERMISSION_MAY_LIVESYNC ) fputs( " may_sync_live", stderr );
|
||||||
_debug[off++] = '/';
|
if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) fputs( " may_fetch_fullscrapes", stderr );
|
||||||
if (ip6_isv4mapped(net->address))
|
if( !permissions ) fputs(" nothing.\n", stderr); else fputs(".\n", stderr );
|
||||||
off += fmt_long(_debug + off, net->bits - 96);
|
|
||||||
else
|
|
||||||
off += fmt_long(_debug + off, net->bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (permissions & OT_PERMISSION_MAY_STAT)
|
|
||||||
off += snprintf(_debug + off, 512 - off, " may_fetch_stats");
|
|
||||||
if (permissions & OT_PERMISSION_MAY_LIVESYNC)
|
|
||||||
off += snprintf(_debug + off, 512 - off, " may_sync_live");
|
|
||||||
if (permissions & OT_PERMISSION_MAY_FULLSCRAPE)
|
|
||||||
off += snprintf(_debug + off, 512 - off, " may_fetch_fullscrapes");
|
|
||||||
if (permissions & OT_PERMISSION_MAY_PROXY)
|
|
||||||
off += snprintf(_debug + off, 512 - off, " may_proxy");
|
|
||||||
if (!permissions)
|
|
||||||
off += snprintf(_debug + off, sizeof(_debug) - off, " nothing");
|
|
||||||
_debug[off++] = '.';
|
|
||||||
_debug[off++] = '\n';
|
|
||||||
(void)write(2, _debug, off);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
|
int accesslist_isblessed( char *ip, ot_permissions permissions ) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < g_admin_nets_count; ++i)
|
for( i=0; i<g_adminip_count; ++i )
|
||||||
if (address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[i] & permissions))
|
if( !memcmp( g_adminip_addresses + i, ip, 4) && ( g_adminip_permissions[ i ] & permissions ) )
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_version_accesslist_c = "$Source$: $Revision$\n";
|
||||||
|
@ -3,10 +3,8 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_ACCESSLIST_H__
|
#ifndef __OT_ACCESSLIST_H__
|
||||||
#define OT_ACCESSLIST_H__
|
#define __OT_ACCESSLIST_H__
|
||||||
|
|
||||||
#include "trackerlogic.h"
|
|
||||||
|
|
||||||
#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE )
|
#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE )
|
||||||
#error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
|
#error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
|
||||||
@ -14,76 +12,24 @@
|
|||||||
|
|
||||||
#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE )
|
#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE )
|
||||||
#define WANT_ACCESSLIST
|
#define WANT_ACCESSLIST
|
||||||
void accesslist_init(void);
|
void accesslist_init( );
|
||||||
void accesslist_deinit(void);
|
int accesslist_hashisvalid( ot_hash *hash );
|
||||||
int accesslist_hashisvalid(ot_hash hash);
|
|
||||||
void accesslist_cleanup(void);
|
|
||||||
|
|
||||||
extern char *g_accesslist_filename;
|
extern char *g_accesslist_filename;
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
extern char *g_accesslist_pipe_add;
|
|
||||||
extern char *g_accesslist_pipe_delete;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#ifdef WANT_DYNAMIC_ACCESSLIST
|
|
||||||
#error WANT_DYNAMIC_ACCESSLIST needs either WANT_ACCESSLIST_BLACK or WANT_ACCESSLIST_WHITE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define accesslist_init( accesslist_filename )
|
#define accesslist_init( accesslist_filename )
|
||||||
#define accesslist_deinit()
|
|
||||||
#define accesslist_hashisvalid( hash ) 1
|
#define accesslist_hashisvalid( hash ) 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Test if an address is subset of an ot_net, return value is considered a bool */
|
|
||||||
int address_in_net(const ot_ip6 address, const ot_net *net);
|
|
||||||
|
|
||||||
/* Store a value into a vector of struct { ot_net net, uint8_t[x] value } member;
|
|
||||||
returns NULL
|
|
||||||
if member_size is too small, or
|
|
||||||
if one of the nets inside the vector are a subnet of _net_, or
|
|
||||||
if _net_ is a subnet of one of the nets inside the vector, or
|
|
||||||
if the vector could not be resized
|
|
||||||
returns pointer to new member in vector for success
|
|
||||||
member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping
|
|
||||||
*/
|
|
||||||
void *set_value_for_net(const ot_net *net, ot_vector *vector, const void *value, const size_t member_size);
|
|
||||||
|
|
||||||
/* Takes a vector filled with struct { ot_net net, uint8_t[x] value } member;
|
|
||||||
Returns pointer to _member_ associated with the net, or NULL if not found
|
|
||||||
member_size can be sizeof(ot_net) to reduce the lookup to a boolean mapping
|
|
||||||
*/
|
|
||||||
void *get_value_for_net(const ot_ip6 address, const ot_vector *vector, const size_t member_size);
|
|
||||||
|
|
||||||
#ifdef WANT_IP_FROM_PROXY
|
|
||||||
int proxylist_add_network(const ot_net *proxy, const ot_net *net);
|
|
||||||
int proxylist_check_network(const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WANT_FULLLOG_NETWORKS
|
|
||||||
typedef struct ot_log ot_log;
|
|
||||||
struct ot_log {
|
|
||||||
ot_ip6 ip;
|
|
||||||
uint8_t *data;
|
|
||||||
size_t size;
|
|
||||||
ot_time time;
|
|
||||||
ot_log *next;
|
|
||||||
};
|
|
||||||
extern ot_log *g_logchain_first, *g_logchain_last;
|
|
||||||
|
|
||||||
void loglist_add_network(const ot_net *net);
|
|
||||||
void loglist_reset();
|
|
||||||
int loglist_check_address(const ot_ip6 address);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OT_PERMISSION_MAY_FULLSCRAPE = 0x1,
|
OT_PERMISSION_MAY_FULLSCRAPE = 0x1,
|
||||||
OT_PERMISSION_MAY_STAT = 0x2,
|
OT_PERMISSION_MAY_SYNC = 0x2,
|
||||||
OT_PERMISSION_MAY_LIVESYNC = 0x4,
|
OT_PERMISSION_MAY_STAT = 0x4,
|
||||||
OT_PERMISSION_MAY_PROXY = 0x8
|
OT_PERMISSION_MAY_LIVESYNC = 0x8
|
||||||
} ot_permissions;
|
} ot_permissions;
|
||||||
|
|
||||||
int accesslist_bless_net(ot_net *net, ot_permissions permissions);
|
int accesslist_blessip( char * ip, ot_permissions permissions );
|
||||||
int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions);
|
int accesslist_isblessed( char * ip, ot_permissions permissions );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
175
ot_clean.c
175
ot_clean.c
@ -4,55 +4,32 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <pthread.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
|
#include "byte.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_accesslist.h"
|
|
||||||
#include "ot_clean.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "ot_vector.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_mutex.h"
|
||||||
|
|
||||||
/* Returns amount of removed peers */
|
/* Clean a single torrent
|
||||||
static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) {
|
return 1 if torrent timed out
|
||||||
ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
|
*/
|
||||||
|
int clean_single_torrent( ot_torrent *torrent ) {
|
||||||
|
ot_peerlist *peer_list = torrent->peer_list;
|
||||||
|
size_t peers_count = 0, seeds_count;
|
||||||
|
time_t timedout = (int)( NOW - peer_list->base );
|
||||||
|
int i;
|
||||||
|
#ifdef WANT_SYNC_BATCH
|
||||||
|
char *new_peers;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Two scan modes: unless there is one peer removed, just increase ot_peertime */
|
|
||||||
while (peers < last_peer) {
|
|
||||||
time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
|
|
||||||
if (timediff >= OT_PEER_TIMEOUT)
|
|
||||||
break;
|
|
||||||
OT_PEERTIME(peers, peer_size) = timediff;
|
|
||||||
peers += peer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we at least remove one peer, we have to copy */
|
|
||||||
for (insert_point = peers; peers < last_peer; peers += peer_size) {
|
|
||||||
time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
|
|
||||||
|
|
||||||
if (timediff < OT_PEER_TIMEOUT) {
|
|
||||||
OT_PEERTIME(peers, peer_size) = timediff;
|
|
||||||
memcpy(insert_point, peers, peer_size);
|
|
||||||
insert_point += peer_size;
|
|
||||||
} else if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING)
|
|
||||||
(*removed_seeders)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (peers - insert_point) / peer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
|
|
||||||
ot_vector *peer_vector = &peer_list->peers;
|
|
||||||
time_t timedout = (time_t)(g_now_minutes - peer_list->base);
|
|
||||||
int num_buckets = 1, removed_seeders = 0;
|
|
||||||
|
|
||||||
/* No need to clean empty torrent */
|
|
||||||
if( !timedout )
|
if( !timedout )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -61,84 +38,104 @@ int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Nothing to be cleaned here? Test if torrent is worth keeping */
|
/* Nothing to be cleaned here? Test if torrent is worth keeping */
|
||||||
if (timedout > OT_PEER_TIMEOUT) {
|
if( timedout > OT_POOLS_COUNT ) {
|
||||||
if( !peer_list->peer_count )
|
if( !peer_list->peer_count )
|
||||||
return peer_list->down_count ? 0 : 1;
|
return peer_list->down_count ? 0 : 1;
|
||||||
timedout = OT_PEER_TIMEOUT;
|
timedout = OT_POOLS_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list)) {
|
/* Release vectors that have timed out */
|
||||||
num_buckets = peer_vector->size;
|
for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i )
|
||||||
peer_vector = (ot_vector *)peer_vector->data;
|
free( peer_list->peers[i].data);
|
||||||
|
|
||||||
|
/* Shift vectors back by the amount of pools that were shifted out */
|
||||||
|
memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) );
|
||||||
|
byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
|
||||||
|
|
||||||
|
/* Shift back seed counts as well */
|
||||||
|
memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
|
||||||
|
byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout );
|
||||||
|
|
||||||
|
#ifdef WANT_SYNC_BATCH
|
||||||
|
/* Save the block modified within last OT_POOLS_TIMEOUT */
|
||||||
|
if( peer_list->peers[1].size &&
|
||||||
|
( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) )
|
||||||
|
{
|
||||||
|
memmove( new_peers, peer_list->peers[1].data, peer_list->peers[1].size );
|
||||||
|
peer_list->changeset.data = new_peers;
|
||||||
|
peer_list->changeset.size = sizeof( ot_peer ) * peer_list->peers[1].size;
|
||||||
|
} else {
|
||||||
|
free( peer_list->changeset.data );
|
||||||
|
|
||||||
|
memset( &peer_list->changeset, 0, sizeof( ot_vector ) );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
while (num_buckets--) {
|
peers_count = seeds_count = 0;
|
||||||
size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders);
|
for( i = 0; i < OT_POOLS_COUNT; ++i ) {
|
||||||
peer_list->peer_count -= removed_peers;
|
peers_count += peer_list->peers[i].size;
|
||||||
peer_vector->size -= removed_peers;
|
seeds_count += peer_list->seed_counts[i];
|
||||||
if (removed_peers)
|
|
||||||
vector_fixup_peers(peer_vector, peer_size);
|
|
||||||
|
|
||||||
/* Skip to next bucket, a vector containing peers */
|
|
||||||
++peer_vector;
|
|
||||||
}
|
}
|
||||||
|
peer_list->seed_count = seeds_count;
|
||||||
|
peer_list->peer_count = peers_count;
|
||||||
|
|
||||||
peer_list->seed_count -= removed_seeders;
|
if( peers_count )
|
||||||
|
peer_list->base = NOW;
|
||||||
/* See if we need to convert a torrent from simple vector to bucket list */
|
|
||||||
if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list))
|
|
||||||
vector_redistribute_buckets(peer_list, peer_size);
|
|
||||||
|
|
||||||
if (peer_list->peer_count)
|
|
||||||
peer_list->base = g_now_minutes;
|
|
||||||
else {
|
else {
|
||||||
/* When we got here, the last time that torrent
|
/* When we got here, the last time that torrent
|
||||||
has been touched is OT_PEER_TIMEOUT Minutes before */
|
has been touched is OT_POOLS_COUNT units before */
|
||||||
peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
|
peer_list->base = NOW - OT_POOLS_COUNT;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean a single torrent
|
static void clean_make() {
|
||||||
return 1 if torrent timed out
|
int bucket;
|
||||||
*/
|
|
||||||
int clean_single_torrent(ot_torrent *torrent) {
|
|
||||||
return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up all peers in current bucket, remove timedout pools and
|
for( bucket = OT_BUCKET_COUNT - 1; bucket >= 0; --bucket ) {
|
||||||
torrents */
|
|
||||||
static void *clean_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
while (1) {
|
|
||||||
int bucket = OT_BUCKET_COUNT;
|
|
||||||
while (bucket--) {
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
||||||
size_t toffs;
|
size_t toffs;
|
||||||
int delta_torrentcount = 0;
|
|
||||||
|
|
||||||
for( toffs=0; toffs<torrents_list->size; ++toffs ) {
|
for( toffs=0; toffs<torrents_list->size; ++toffs ) {
|
||||||
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
|
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
|
||||||
if( clean_single_torrent( torrent ) ) {
|
if( clean_single_torrent( torrent ) ) {
|
||||||
vector_remove_torrent( torrents_list, torrent );
|
vector_remove_torrent( torrents_list, torrent );
|
||||||
--delta_torrentcount;
|
--toffs; continue;
|
||||||
--toffs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_bucket_unlock(bucket, delta_torrentcount);
|
mutex_bucket_unlock( bucket );
|
||||||
if (!g_opentracker_running)
|
|
||||||
return NULL;
|
/* We want the cleanup to be spread about 2 Minutes to reduce load spikes
|
||||||
usleep(OT_CLEAN_SLEEP);
|
during cleanup. Sleeping around two minutes was chosen to allow enough
|
||||||
|
time for the actual work and fluctuations in timer. */
|
||||||
|
usleep( ( 2 * 60 * 1000000 ) / OT_BUCKET_COUNT );
|
||||||
}
|
}
|
||||||
stats_cleanup();
|
}
|
||||||
#ifdef WANT_ACCESSLIST
|
|
||||||
accesslist_cleanup();
|
/* Clean up all peers in current bucket, remove timedout pools and
|
||||||
#endif
|
torrents */
|
||||||
|
static void * clean_worker( void * args ) {
|
||||||
|
args = args;
|
||||||
|
while( 1 ) {
|
||||||
|
ot_tasktype tasktype = TASK_CLEAN;
|
||||||
|
ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
|
||||||
|
clean_make( );
|
||||||
|
mutex_workqueue_pushsuccess( taskid );
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clean_all_torrents( ) {
|
||||||
|
mutex_workqueue_pushtask( 0, TASK_CLEAN );
|
||||||
|
}
|
||||||
|
|
||||||
static pthread_t thread_id;
|
static pthread_t thread_id;
|
||||||
void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); }
|
void clean_init( void ) {
|
||||||
|
pthread_create( &thread_id, NULL, clean_worker, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
void clean_deinit(void) { pthread_cancel(thread_id); }
|
void clean_deinit( void ) {
|
||||||
|
pthread_cancel( thread_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *g_version_clean_c = "$Source$: $Revision$\n";
|
||||||
|
12
ot_clean.h
12
ot_clean.h
@ -3,17 +3,13 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_CLEAN_H__
|
#ifndef __OT_CLEAN_H__
|
||||||
#define OT_CLEAN_H__
|
#define __OT_CLEAN_H__
|
||||||
|
|
||||||
/* The amount of time a clean cycle should take */
|
|
||||||
#define OT_CLEAN_INTERVAL_MINUTES 2
|
|
||||||
|
|
||||||
/* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */
|
|
||||||
#define OT_CLEAN_SLEEP (((OT_CLEAN_INTERVAL_MINUTES) * 60 * 1000000) / (OT_BUCKET_COUNT))
|
|
||||||
|
|
||||||
void clean_init( void );
|
void clean_init( void );
|
||||||
void clean_deinit( void );
|
void clean_deinit( void );
|
||||||
|
|
||||||
|
void clean_all_torrents( void );
|
||||||
int clean_single_torrent( ot_torrent *torrent );
|
int clean_single_torrent( ot_torrent *torrent );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
482
ot_fullscrape.c
482
ot_fullscrape.c
@ -6,18 +6,15 @@
|
|||||||
#ifdef WANT_FULLSCRAPE
|
#ifdef WANT_FULLSCRAPE
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <arpa/inet.h>
|
#include <sys/param.h>
|
||||||
#include <pthread.h>
|
#include <sys/uio.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/param.h>
|
#include <pthread.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#ifdef WANT_COMPRESSION_GZIP
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef WANT_COMPRESSION_ZSTD
|
|
||||||
#include <zstd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
@ -25,64 +22,50 @@
|
|||||||
#include "textcode.h"
|
#include "textcode.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_fullscrape.h"
|
|
||||||
#include "ot_iovec.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_mutex.h"
|
||||||
|
#include "ot_iovec.h"
|
||||||
|
#include "ot_fullscrape.h"
|
||||||
|
|
||||||
/* Fetch full scrape info for all torrents
|
/* Fetch full scrape info for all torrents
|
||||||
Full scrapes usually are huge and one does not want to
|
Full scrapes usually are huge and one does not want to
|
||||||
allocate more memory. So lets get them in 512k units
|
allocate more memory. So lets get them in 512k units
|
||||||
*/
|
*/
|
||||||
#define OT_SCRAPE_CHUNK_SIZE (1024 * 1024)
|
#define OT_SCRAPE_CHUNK_SIZE (512*1024)
|
||||||
|
|
||||||
/* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */
|
/* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */
|
||||||
#define OT_SCRAPE_MAXENTRYLEN 256
|
#define OT_SCRAPE_MAXENTRYLEN 256
|
||||||
|
|
||||||
/* Forward declaration */
|
|
||||||
static void fullscrape_make(int taskid, ot_tasktype mode);
|
|
||||||
#ifdef WANT_COMPRESSION_GZIP
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
static void fullscrape_make_gzip(int taskid, ot_tasktype mode);
|
#define IF_COMPRESSION( TASK ) if( mode & TASK_FLAG_GZIP ) TASK
|
||||||
#endif
|
#define WANT_COMPRESSION_GZIP_PARAM( param1, param2, param3 ) , param1, param2, param3
|
||||||
#ifdef WANT_COMPRESSION_ZSTD
|
#else
|
||||||
static void fullscrape_make_zstd(int taskid, ot_tasktype mode);
|
#define IF_COMPRESSION( TASK )
|
||||||
|
#define WANT_COMPRESSION_GZIP_PARAM( param1, param2, param3 )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode );
|
||||||
|
|
||||||
/* Converter function from memory to human readable hex strings
|
/* Converter function from memory to human readable hex strings
|
||||||
XXX - Duplicated from ot_stats. Needs fix. */
|
XXX - Duplicated from ot_stats. Needs fix. */
|
||||||
static char *to_hex(char *d, uint8_t *s) {
|
static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;}
|
||||||
char *m = "0123456789ABCDEF";
|
|
||||||
char *t = d;
|
|
||||||
char *e = d + 40;
|
|
||||||
while (d < e) {
|
|
||||||
*d++ = m[*s >> 4];
|
|
||||||
*d++ = m[*s++ & 15];
|
|
||||||
}
|
|
||||||
*d = 0;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is the entry point into this worker thread
|
/* This is the entry point into this worker thread
|
||||||
It grabs tasks from mutex_tasklist and delivers results back
|
It grabs tasks from mutex_tasklist and delivers results back
|
||||||
*/
|
*/
|
||||||
static void * fullscrape_worker( void * args ) {
|
static void * fullscrape_worker( void * args ) {
|
||||||
(void)args;
|
int iovec_entries;
|
||||||
|
struct iovec *iovector;
|
||||||
|
|
||||||
while (g_opentracker_running) {
|
args = args;
|
||||||
|
|
||||||
|
while( 1 ) {
|
||||||
ot_tasktype tasktype = TASK_FULLSCRAPE;
|
ot_tasktype tasktype = TASK_FULLSCRAPE;
|
||||||
ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
|
ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
|
||||||
#ifdef WANT_COMPRESSION_ZSTD
|
fullscrape_make( &iovec_entries, &iovector, tasktype );
|
||||||
if (tasktype & TASK_FLAG_ZSTD)
|
if( mutex_workqueue_pushresult( taskid, iovec_entries, iovector ) )
|
||||||
fullscrape_make_zstd(taskid, tasktype);
|
iovec_free( &iovec_entries, &iovector );
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef WANT_COMPRESSION_GZIP
|
|
||||||
if (tasktype & TASK_FLAG_GZIP)
|
|
||||||
fullscrape_make_gzip(taskid, tasktype);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
fullscrape_make(taskid, tasktype);
|
|
||||||
mutex_workqueue_pushchunked(taskid, NULL);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -96,71 +79,70 @@ void fullscrape_deinit( ) {
|
|||||||
pthread_cancel( thread_id );
|
pthread_cancel( thread_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) {
|
void fullscrape_deliver( int64 socket, ot_tasktype tasktype ) {
|
||||||
mutex_workqueue_pushtask( sock, tasktype );
|
mutex_workqueue_pushtask( socket, tasktype );
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torrent, ot_hash *hash ) {
|
static int fullscrape_increase( int *iovec_entries, struct iovec **iovector,
|
||||||
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
|
char **r, char **re WANT_COMPRESSION_GZIP_PARAM( z_stream *strm, ot_tasktype mode, int zaction ) ) {
|
||||||
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
|
/* Allocate a fresh output buffer at the end of our buffers list */
|
||||||
size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
|
if( !( *r = iovec_fix_increase_or_free( iovec_entries, iovector, *r, OT_SCRAPE_CHUNK_SIZE ) ) ) {
|
||||||
|
|
||||||
switch (mode & TASK_TASK_MASK) {
|
/* Deallocate gzip buffers */
|
||||||
case TASK_FULLSCRAPE:
|
IF_COMPRESSION( deflateEnd(strm); )
|
||||||
default:
|
|
||||||
/* push hash as bencoded string */
|
|
||||||
*r++ = '2';
|
|
||||||
*r++ = '0';
|
|
||||||
*r++ = ':';
|
|
||||||
memcpy(r, hash, sizeof(ot_hash));
|
|
||||||
r += sizeof(ot_hash);
|
|
||||||
/* push rest of the scrape string */
|
|
||||||
r += sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count - seed_count);
|
|
||||||
|
|
||||||
break;
|
/* Release lock on current bucket and return */
|
||||||
case TASK_FULLSCRAPE_TPB_ASCII:
|
return -1;
|
||||||
to_hex(r, *hash);
|
|
||||||
r += 2 * sizeof(ot_hash);
|
|
||||||
r += sprintf(r, ":%zd:%zd\n", seed_count, peer_count - seed_count);
|
|
||||||
break;
|
|
||||||
case TASK_FULLSCRAPE_TPB_ASCII_PLUS:
|
|
||||||
to_hex(r, *hash);
|
|
||||||
r += 2 * sizeof(ot_hash);
|
|
||||||
r += sprintf(r, ":%zd:%zd:%zd\n", seed_count, peer_count - seed_count, down_count);
|
|
||||||
break;
|
|
||||||
case TASK_FULLSCRAPE_TPB_BINARY:
|
|
||||||
memcpy(r, *hash, sizeof(ot_hash));
|
|
||||||
r += sizeof(ot_hash);
|
|
||||||
*(uint32_t *)(r + 0) = htonl((uint32_t)seed_count);
|
|
||||||
*(uint32_t *)(r + 4) = htonl((uint32_t)(peer_count - seed_count));
|
|
||||||
r += 8;
|
|
||||||
break;
|
|
||||||
case TASK_FULLSCRAPE_TPB_URLENCODED:
|
|
||||||
r += fmt_urlencoded(r, (char *)*hash, 20);
|
|
||||||
r += sprintf(r, ":%zd:%zd\n", seed_count, peer_count - seed_count);
|
|
||||||
break;
|
|
||||||
case TASK_FULLSCRAPE_TRACKERSTATE:
|
|
||||||
to_hex(r, *hash);
|
|
||||||
r += 2 * sizeof(ot_hash);
|
|
||||||
r += sprintf(r, ":%zd:%zd\n", torrent->peer_list6->base, down_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fullscrape_make(int taskid, ot_tasktype mode) {
|
/* Adjust new end of output buffer */
|
||||||
|
*re = *r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
|
||||||
|
|
||||||
|
/* When compressing, we have all the bytes in output buffer */
|
||||||
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
|
if( mode & TASK_FLAG_GZIP ) {
|
||||||
|
*re -= OT_SCRAPE_MAXENTRYLEN;
|
||||||
|
strm->next_out = (uint8_t*)*r;
|
||||||
|
strm->avail_out = OT_SCRAPE_CHUNK_SIZE;
|
||||||
|
if( deflate( strm, zaction ) < Z_OK )
|
||||||
|
fprintf( stderr, "deflate() failed while in fullscrape_increase(%d).\n", zaction );
|
||||||
|
*r = (char*)strm->next_out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) {
|
||||||
int bucket;
|
int bucket;
|
||||||
char *r, *re;
|
char *r, *re;
|
||||||
struct iovec iovector = {NULL, 0};
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
|
char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
|
||||||
|
z_stream strm;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Setup return vector... */
|
/* Setup return vector... */
|
||||||
r = iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
*iovec_entries = 0;
|
||||||
if (!r)
|
*iovector = NULL;
|
||||||
|
if( !( r = iovec_increase( iovec_entries, iovector, OT_SCRAPE_CHUNK_SIZE ) ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* re points to low watermark */
|
/* re points to low watermark */
|
||||||
re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
|
re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
|
||||||
|
|
||||||
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
|
if( mode & TASK_FLAG_GZIP ) {
|
||||||
|
re += OT_SCRAPE_MAXENTRYLEN;
|
||||||
|
byte_zero( &strm, sizeof(strm) );
|
||||||
|
strm.next_in = (uint8_t*)compress_buffer;
|
||||||
|
strm.next_out = (uint8_t*)r;
|
||||||
|
strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
|
||||||
|
if( deflateInit2(&strm,7,Z_DEFLATED,31,8,Z_DEFAULT_STRATEGY) != Z_OK )
|
||||||
|
fprintf( stderr, "not ok.\n" );
|
||||||
|
r = compress_buffer;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE )
|
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE )
|
||||||
r += sprintf( r, "d5:filesd" );
|
r += sprintf( r, "d5:filesd" );
|
||||||
|
|
||||||
@ -168,290 +150,84 @@ static void fullscrape_make(int taskid, ot_tasktype mode) {
|
|||||||
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
||||||
/* Get exclusive access to that bucket */
|
/* Get exclusive access to that bucket */
|
||||||
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
||||||
ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
|
size_t tor_offset;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* For each torrent in this bucket.. */
|
/* For each torrent in this bucket.. */
|
||||||
for (i = 0; i < torrents_list->size; ++i) {
|
for( tor_offset=0; tor_offset<torrents_list->size; ++tor_offset ) {
|
||||||
r = fullscrape_write_one(mode, r, torrents + i, &torrents[i].hash);
|
/* Address torrents members */
|
||||||
|
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[tor_offset] ).peer_list;
|
||||||
|
ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[tor_offset] ).hash;
|
||||||
|
|
||||||
if (r > re) {
|
switch( mode & TASK_TASK_MASK ) {
|
||||||
iovector.iov_len = r - (char *)iovector.iov_base;
|
case TASK_FULLSCRAPE:
|
||||||
|
default:
|
||||||
|
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector)) {
|
/* push hash as bencoded string */
|
||||||
free(iovector.iov_base);
|
*r++='2'; *r++='0'; *r++=':';
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
memmove( r, hash, 20 ); r+=20;
|
||||||
}
|
|
||||||
/* Allocate a fresh output buffer */
|
|
||||||
r = iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
if (!r)
|
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
|
||||||
|
|
||||||
/* re points to low watermark */
|
/* push rest of the scrape string */
|
||||||
re = r + OT_SCRAPE_CHUNK_SIZE - OT_SCRAPE_MAXENTRYLEN;
|
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count );
|
||||||
}
|
|
||||||
|
break;
|
||||||
|
case TASK_FULLSCRAPE_TPB_ASCII:
|
||||||
|
to_hex( r, *hash ); r+=40;
|
||||||
|
r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
|
||||||
|
break;
|
||||||
|
case TASK_FULLSCRAPE_TPB_BINARY:
|
||||||
|
memmove( r, hash, 20 ); r+=20;
|
||||||
|
*(uint32_t*)r++ = htonl( (uint32_t)peer_list->seed_count );
|
||||||
|
*(uint32_t*)r++ = htonl( (uint32_t)( peer_list->peer_count-peer_list->seed_count) );
|
||||||
|
break;
|
||||||
|
case TASK_FULLSCRAPE_TPB_URLENCODED:
|
||||||
|
r += fmt_urlencoded( r, (char *)*hash, 20 );
|
||||||
|
r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All torrents done: release lock on current bucket */
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
mutex_bucket_unlock(bucket, 0);
|
if( mode & TASK_FLAG_GZIP ) {
|
||||||
|
strm.next_in = (uint8_t*)compress_buffer;
|
||||||
|
strm.avail_in = r - compress_buffer;
|
||||||
|
if( deflate( &strm, Z_NO_FLUSH ) < Z_OK )
|
||||||
|
fprintf( stderr, "deflate() failed while in fullscrape_make().\n" );
|
||||||
|
r = (char*)strm.next_out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Parent thread died? */
|
/* Check if there still is enough buffer left */
|
||||||
if (!g_opentracker_running)
|
while( r >= re )
|
||||||
return;
|
if( fullscrape_increase( iovec_entries, iovector, &r, &re WANT_COMPRESSION_GZIP_PARAM( &strm, mode, Z_NO_FLUSH ) ) )
|
||||||
|
return mutex_bucket_unlock( bucket );
|
||||||
|
|
||||||
|
IF_COMPRESSION( r = compress_buffer; )
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All torrents done: release lock on currenct bucket */
|
||||||
|
mutex_bucket_unlock( bucket );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE )
|
if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE )
|
||||||
r += sprintf( r, "ee" );
|
r += sprintf( r, "ee" );
|
||||||
|
|
||||||
/* Send rest of data */
|
|
||||||
iovector.iov_len = r - (char *)iovector.iov_base;
|
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector))
|
|
||||||
free(iovector.iov_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WANT_COMPRESSION_GZIP
|
#ifdef WANT_COMPRESSION_GZIP
|
||||||
|
if( mode & TASK_FLAG_GZIP ) {
|
||||||
static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
|
|
||||||
int bucket;
|
|
||||||
char *r;
|
|
||||||
struct iovec iovector = {NULL, 0};
|
|
||||||
int zres;
|
|
||||||
z_stream strm;
|
|
||||||
/* Setup return vector... */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
if (!iovector.iov_base)
|
|
||||||
return;
|
|
||||||
|
|
||||||
byte_zero(&strm, sizeof(strm));
|
|
||||||
strm.next_out = (uint8_t *)iovector.iov_base;
|
|
||||||
strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
if (deflateInit2(&strm, 7, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY) != Z_OK)
|
|
||||||
fprintf(stderr, "not ok.\n");
|
|
||||||
|
|
||||||
if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
|
|
||||||
strm.next_in = (uint8_t *)"d5:filesd";
|
|
||||||
strm.avail_in = strlen("d5:filesd");
|
|
||||||
zres = deflate(&strm, Z_NO_FLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For each bucket... */
|
|
||||||
for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
|
|
||||||
/* Get exclusive access to that bucket */
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock(bucket);
|
|
||||||
ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* For each torrent in this bucket.. */
|
|
||||||
for (i = 0; i < torrents_list->size; ++i) {
|
|
||||||
char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
|
|
||||||
r = fullscrape_write_one(mode, compress_buffer, torrents + i, &torrents[i].hash);
|
|
||||||
strm.next_in = (uint8_t*)compress_buffer;
|
strm.next_in = (uint8_t*)compress_buffer;
|
||||||
strm.avail_in = r - compress_buffer;
|
strm.avail_in = r - compress_buffer;
|
||||||
zres = deflate(&strm, Z_NO_FLUSH);
|
|
||||||
if ((zres < Z_OK) && (zres != Z_BUF_ERROR))
|
|
||||||
fprintf(stderr, "deflate() failed while in fullscrape_make().\n");
|
|
||||||
|
|
||||||
/* Check if there still is enough buffer left */
|
|
||||||
while (!strm.avail_out) {
|
|
||||||
iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
|
|
||||||
|
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector)) {
|
|
||||||
free(iovector.iov_base);
|
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
|
||||||
}
|
|
||||||
/* Allocate a fresh output buffer */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
if (!iovector.iov_base) {
|
|
||||||
fprintf(stderr, "Out of memory trying to claim ouput buffer\n");
|
|
||||||
deflateEnd(&strm);
|
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
|
||||||
}
|
|
||||||
strm.next_out = (uint8_t *)iovector.iov_base;
|
|
||||||
strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
zres = deflate(&strm, Z_NO_FLUSH);
|
|
||||||
if ((zres < Z_OK) && (zres != Z_BUF_ERROR))
|
|
||||||
fprintf(stderr, "deflate() failed while in fullscrape_make().\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All torrents done: release lock on current bucket */
|
|
||||||
mutex_bucket_unlock(bucket, 0);
|
|
||||||
|
|
||||||
/* Parent thread died? */
|
|
||||||
if (!g_opentracker_running) {
|
|
||||||
deflateEnd(&strm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
|
|
||||||
strm.next_in = (uint8_t *)"ee";
|
|
||||||
strm.avail_in = strlen("ee");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( deflate( &strm, Z_FINISH ) < Z_OK )
|
if( deflate( &strm, Z_FINISH ) < Z_OK )
|
||||||
fprintf( stderr, "deflate() failed while in fullscrape_make()'s endgame.\n" );
|
fprintf( stderr, "deflate() failed while in fullscrape_make()'s endgame.\n" );
|
||||||
|
r = (char*)strm.next_out;
|
||||||
|
|
||||||
iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
|
while( r >= re )
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector)) {
|
if( fullscrape_increase( iovec_entries, iovector, &r, &re WANT_COMPRESSION_GZIP_PARAM( &strm, mode, Z_FINISH ) ) )
|
||||||
free(iovector.iov_base);
|
return mutex_bucket_unlock( bucket );
|
||||||
deflateEnd(&strm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if there's a last batch of data in the zlib buffer */
|
|
||||||
if (!strm.avail_out) {
|
|
||||||
/* Allocate a fresh output buffer */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
|
|
||||||
if (!iovector.iov_base) {
|
|
||||||
fprintf(stderr, "Problem with iovec_fix_increase_or_free\n");
|
|
||||||
deflateEnd(&strm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strm.next_out = iovector.iov_base;
|
|
||||||
strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
if (deflate(&strm, Z_FINISH) < Z_OK)
|
|
||||||
fprintf(stderr, "deflate() failed while in fullscrape_make()'s endgame.\n");
|
|
||||||
|
|
||||||
/* Only pass the new buffer if there actually was some data left in the buffer */
|
|
||||||
iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
|
|
||||||
if (!iovector.iov_len || mutex_workqueue_pushchunked(taskid, &iovector))
|
|
||||||
free(iovector.iov_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
deflateEnd(&strm);
|
deflateEnd(&strm);
|
||||||
}
|
}
|
||||||
/* WANT_COMPRESSION_GZIP */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WANT_COMPRESSION_ZSTD
|
/* Release unused memory in current output buffer */
|
||||||
|
iovec_fixlast( iovec_entries, iovector, r );
|
||||||
static void fullscrape_make_zstd(int taskid, ot_tasktype mode) {
|
|
||||||
int bucket;
|
|
||||||
char *r;
|
|
||||||
struct iovec iovector = {NULL, 0};
|
|
||||||
ZSTD_CCtx *zstream = ZSTD_createCCtx();
|
|
||||||
ZSTD_inBuffer inbuf;
|
|
||||||
ZSTD_outBuffer outbuf;
|
|
||||||
size_t more_bytes;
|
|
||||||
|
|
||||||
if (!zstream)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Setup return vector... */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
if (!iovector.iov_base) {
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Working with a compression level 6 is half as fast as level 3, but
|
|
||||||
seems to be the last reasonable bump that's worth extra cpu */
|
|
||||||
ZSTD_CCtx_setParameter(zstream, ZSTD_c_compressionLevel, 6);
|
|
||||||
|
|
||||||
outbuf.dst = iovector.iov_base;
|
|
||||||
outbuf.size = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
outbuf.pos = 0;
|
|
||||||
|
|
||||||
if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
|
|
||||||
inbuf.src = (const void *)"d5:filesd";
|
|
||||||
inbuf.size = strlen("d5:filesd");
|
|
||||||
inbuf.pos = 0;
|
|
||||||
ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For each bucket... */
|
|
||||||
for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
|
|
||||||
/* Get exclusive access to that bucket */
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock(bucket);
|
|
||||||
ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* For each torrent in this bucket.. */
|
|
||||||
for (i = 0; i < torrents_list->size; ++i) {
|
|
||||||
char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
|
|
||||||
r = fullscrape_write_one(mode, compress_buffer, torrents + i, &torrents[i].hash);
|
|
||||||
inbuf.src = compress_buffer;
|
|
||||||
inbuf.size = r - compress_buffer;
|
|
||||||
inbuf.pos = 0;
|
|
||||||
ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
|
|
||||||
|
|
||||||
/* Check if there still is enough buffer left */
|
|
||||||
while (outbuf.pos + OT_SCRAPE_MAXENTRYLEN > outbuf.size) {
|
|
||||||
iovector.iov_len = outbuf.size;
|
|
||||||
|
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector)) {
|
|
||||||
free(iovector.iov_base);
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
|
||||||
}
|
|
||||||
/* Allocate a fresh output buffer */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
if (!iovector.iov_base) {
|
|
||||||
fprintf(stderr, "Out of memory trying to claim ouput buffer\n");
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
return mutex_bucket_unlock(bucket, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
outbuf.dst = iovector.iov_base;
|
|
||||||
outbuf.size = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
outbuf.pos = 0;
|
|
||||||
|
|
||||||
ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All torrents done: release lock on current bucket */
|
|
||||||
mutex_bucket_unlock(bucket, 0);
|
|
||||||
|
|
||||||
/* Parent thread died? */
|
|
||||||
if (!g_opentracker_running)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
|
|
||||||
inbuf.src = (const void *)"ee";
|
|
||||||
inbuf.size = strlen("ee");
|
|
||||||
inbuf.pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
more_bytes = ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_end);
|
|
||||||
|
|
||||||
iovector.iov_len = outbuf.pos;
|
|
||||||
if (mutex_workqueue_pushchunked(taskid, &iovector)) {
|
|
||||||
free(iovector.iov_base);
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if there's a last batch of data in the zlib buffer */
|
|
||||||
if (more_bytes) {
|
|
||||||
/* Allocate a fresh output buffer */
|
|
||||||
iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
|
|
||||||
|
|
||||||
if (!iovector.iov_base) {
|
|
||||||
fprintf(stderr, "Problem with iovec_fix_increase_or_free\n");
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
outbuf.dst = iovector.iov_base;
|
|
||||||
outbuf.size = OT_SCRAPE_CHUNK_SIZE;
|
|
||||||
outbuf.pos = 0;
|
|
||||||
|
|
||||||
ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_end);
|
|
||||||
|
|
||||||
/* Only pass the new buffer if there actually was some data left in the buffer */
|
|
||||||
iovector.iov_len = outbuf.pos;
|
|
||||||
if (!iovector.iov_len || mutex_workqueue_pushchunked(taskid, &iovector))
|
|
||||||
free(iovector.iov_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_freeCCtx(zstream);
|
|
||||||
}
|
|
||||||
/* WANT_COMPRESSION_ZSTD */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* WANT_FULLSCRAPE */
|
const char *g_version_fullscrape_c = "$Source$: $Revision$\n";
|
||||||
#endif
|
|
||||||
|
@ -3,16 +3,14 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_FULLSCRAPE_H__
|
#ifndef __OT_FULLSCRAPE_H__
|
||||||
#define OT_FULLSCRAPE_H__
|
#define __OT_FULLSCRAPE_H__
|
||||||
|
|
||||||
#ifdef WANT_FULLSCRAPE
|
#ifdef WANT_FULLSCRAPE
|
||||||
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
|
|
||||||
void fullscrape_init( );
|
void fullscrape_init( );
|
||||||
void fullscrape_deinit( );
|
void fullscrape_deinit( );
|
||||||
void fullscrape_deliver(int64 sock, ot_tasktype tasktype);
|
void fullscrape_deliver( int64 socket, ot_tasktype tasktype );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
31
ot_http.h
31
ot_http.h
@ -3,31 +3,28 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_HTTP_H__
|
#ifndef __OT_HTTP_H__
|
||||||
#define OT_HTTP_H__
|
#define __OT_HTTP_H__
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STRUCT_HTTP_FLAG_WAITINGFORTASK = 1,
|
STRUCT_HTTP_FLAG_ARRAY_USED = 1,
|
||||||
STRUCT_HTTP_FLAG_GZIP = 2,
|
STRUCT_HTTP_FLAG_IOB_USED = 2,
|
||||||
STRUCT_HTTP_FLAG_BZIP2 = 4,
|
STRUCT_HTTP_FLAG_WAITINGFORTASK = 4,
|
||||||
STRUCT_HTTP_FLAG_ZSTD = 8,
|
STRUCT_HTTP_FLAG_GZIP = 8,
|
||||||
STRUCT_HTTP_FLAG_CHUNKED = 16,
|
STRUCT_HTTP_FLAG_BZIP2 = 16
|
||||||
STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER = 32
|
|
||||||
} STRUCT_HTTP_FLAG;
|
} STRUCT_HTTP_FLAG;
|
||||||
|
|
||||||
struct http_data {
|
struct http_data {
|
||||||
|
union {
|
||||||
array request;
|
array request;
|
||||||
io_batch *batch;
|
io_batch batch;
|
||||||
size_t batches;
|
};
|
||||||
ot_ip6 ip;
|
char ip[4];
|
||||||
STRUCT_HTTP_FLAG flag;
|
STRUCT_HTTP_FLAG flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws);
|
ssize_t http_handle_request( const int64 s, char *data, size_t l );
|
||||||
ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector, int is_partial);
|
ssize_t http_sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovector );
|
||||||
ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code);
|
ssize_t http_issue_error( const int64 s, int code );
|
||||||
|
|
||||||
extern char *g_stats_path;
|
|
||||||
extern ssize_t g_stats_path_len;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
76
ot_iovec.c
76
ot_iovec.c
@ -4,10 +4,11 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/mman.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
|
|
||||||
@ -15,78 +16,61 @@
|
|||||||
#include "ot_iovec.h"
|
#include "ot_iovec.h"
|
||||||
|
|
||||||
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ) {
|
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ) {
|
||||||
void *new_data;
|
void *new_ptr = realloc( *iovector, (1 + *iovec_entries ) * sizeof( struct iovec ) );
|
||||||
int new_entries = 1 + *iovec_entries;
|
if( !new_ptr )
|
||||||
struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
|
|
||||||
|
|
||||||
if (!new_vec)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
*iovector = new_ptr;
|
||||||
/* Only allocate after we have a place to store the pointer */
|
new_ptr = mmap( NULL, new_alloc, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 );
|
||||||
new_data = malloc(new_alloc);
|
if( !new_ptr )
|
||||||
if (!new_data)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
((*iovector)[*iovec_entries]).iov_base = new_ptr;
|
||||||
new_vec[new_entries - 1].iov_base = new_data;
|
((*iovector)[*iovec_entries]).iov_len = new_alloc;
|
||||||
new_vec[new_entries - 1].iov_len = new_alloc;
|
|
||||||
|
|
||||||
*iovector = new_vec;
|
|
||||||
++*iovec_entries;
|
++*iovec_entries;
|
||||||
return new_data;
|
return new_ptr;
|
||||||
}
|
|
||||||
|
|
||||||
void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector) {
|
|
||||||
int new_entries = *iovec_entries + 1;
|
|
||||||
struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
|
|
||||||
if (!new_vec)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Take over data from appended iovec */
|
|
||||||
new_vec[*iovec_entries].iov_base = append_iovector->iov_base;
|
|
||||||
new_vec[*iovec_entries].iov_len = append_iovector->iov_len;
|
|
||||||
|
|
||||||
append_iovector->iov_base = NULL;
|
|
||||||
append_iovector->iov_len = 0;
|
|
||||||
|
|
||||||
*iovector = new_vec;
|
|
||||||
*iovec_entries = new_entries;
|
|
||||||
|
|
||||||
return new_vec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iovec_free( int *iovec_entries, struct iovec **iovector ) {
|
void iovec_free( int *iovec_entries, struct iovec **iovector ) {
|
||||||
int i;
|
int i;
|
||||||
for( i=0; i<*iovec_entries; ++i )
|
for( i=0; i<*iovec_entries; ++i )
|
||||||
free(((*iovector)[i]).iov_base);
|
munmap( ((*iovector)[i]).iov_base, ((*iovector)[i]).iov_len );
|
||||||
*iovector = NULL;
|
|
||||||
*iovec_entries = 0;
|
*iovec_entries = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ) {
|
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ) {
|
||||||
if (*iovec_entries) {
|
int page_size = getpagesize();
|
||||||
|
size_t old_alloc, new_alloc, old_pages, new_pages;
|
||||||
char * base = (char*)((*iovector)[ *iovec_entries - 1 ]).iov_base;
|
char * base = (char*)((*iovector)[ *iovec_entries - 1 ]).iov_base;
|
||||||
size_t new_alloc = ((char *)last_ptr) - base;
|
|
||||||
|
|
||||||
((*iovector)[*iovec_entries - 1]).iov_base = realloc(base, new_alloc);
|
if( !*iovec_entries ) return;
|
||||||
|
|
||||||
|
old_alloc = ((*iovector)[ *iovec_entries - 1 ]).iov_len;
|
||||||
|
new_alloc = ((char*)last_ptr) - base;
|
||||||
|
old_pages = 1 + old_alloc / page_size;
|
||||||
|
new_pages = 1 + new_alloc / page_size;
|
||||||
|
|
||||||
|
if( old_pages != new_pages )
|
||||||
|
munmap( base + new_pages * page_size, old_alloc - new_pages * page_size );
|
||||||
((*iovector)[*iovec_entries - 1 ]).iov_len = new_alloc;
|
((*iovector)[*iovec_entries - 1 ]).iov_len = new_alloc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc ) {
|
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc ) {
|
||||||
void *new_data;
|
void *new_ptr;
|
||||||
|
|
||||||
iovec_fixlast( iovec_entries, iovector, last_ptr );
|
iovec_fixlast( iovec_entries, iovector, last_ptr );
|
||||||
|
|
||||||
if (!(new_data = iovec_increase(iovec_entries, iovector, new_alloc)))
|
if( !( new_ptr = iovec_increase( iovec_entries, iovector, new_alloc ) ) )
|
||||||
iovec_free( iovec_entries, iovector );
|
iovec_free( iovec_entries, iovector );
|
||||||
|
|
||||||
return new_data;
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t iovec_length(const int *iovec_entries, const struct iovec **iovector) {
|
|
||||||
|
size_t iovec_length( int *iovec_entries, struct iovec **iovector ) {
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
int i;
|
int i;
|
||||||
for( i=0; i<*iovec_entries; ++i )
|
for( i=0; i<*iovec_entries; ++i )
|
||||||
length += ((*iovector)[i]).iov_len;
|
length += ((*iovector)[i]).iov_len;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_version_iovec_c = "$Source$: $Revision$\n";
|
||||||
|
@ -3,17 +3,14 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_IOVEC_H__
|
#ifndef __OT_IOVEC_H__
|
||||||
#define OT_IOVEC_H__
|
#define __OT_IOVEC_H__
|
||||||
|
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc );
|
void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc );
|
||||||
void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector);
|
|
||||||
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr );
|
void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr );
|
||||||
void iovec_free( int *iovec_entries, struct iovec **iovector );
|
void iovec_free( int *iovec_entries, struct iovec **iovector );
|
||||||
|
|
||||||
size_t iovec_length(const int *iovec_entries, const struct iovec **iovector);
|
size_t iovec_length( int *iovec_entries, struct iovec **iovector );
|
||||||
|
|
||||||
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc );
|
void *iovec_fix_increase_or_free( int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc );
|
||||||
|
|
||||||
|
239
ot_livesync.c
239
ot_livesync.c
@ -4,236 +4,159 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "byte.h"
|
|
||||||
#include "ip6.h"
|
|
||||||
#include "ndelay.h"
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
#include "ndelay.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_accesslist.h"
|
|
||||||
#include "ot_livesync.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_livesync.h"
|
||||||
|
#include "ot_accesslist.h"
|
||||||
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
#ifdef WANT_SYNC_LIVE
|
||||||
|
|
||||||
char groupip_1[4] = {224, 0, 23, 5};
|
char groupip_1[4] = { 224,0,23,42 };
|
||||||
|
|
||||||
#define LIVESYNC_INCOMING_BUFFSIZE (256 * 256)
|
#define LIVESYNC_BUFFINSIZE (256*256)
|
||||||
|
#define LIVESYNC_BUFFSIZE 1504
|
||||||
|
#define LIVESYNC_BUFFWATER (sizeof(ot_peer)+sizeof(ot_hash))
|
||||||
|
|
||||||
#define LIVESYNC_OUTGOING_BUFFSIZE_PEERS 1480
|
#define LIVESYNC_MAXDELAY 15
|
||||||
#define LIVESYNC_OUTGOING_WATERMARK_PEERS (sizeof(ot_peer) + sizeof(ot_hash))
|
|
||||||
|
|
||||||
#define LIVESYNC_MAXDELAY 15 /* seconds */
|
|
||||||
|
|
||||||
enum { OT_SYNC_PEER4, OT_SYNC_PEER6 };
|
|
||||||
|
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static void * livesync_worker( void * args );
|
static void * livesync_worker( void * args );
|
||||||
|
|
||||||
/* For outgoing packets */
|
/* For outgoing packets */
|
||||||
static int64 g_socket_in = -1;
|
static int64 g_livesync_socket_in = -1;
|
||||||
|
|
||||||
/* For incoming packets */
|
/* For incoming packets */
|
||||||
static int64 g_socket_out = -1;
|
static int64 g_livesync_socket_out = -1;
|
||||||
|
|
||||||
static pthread_mutex_t g_outbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static uint8_t livesync_inbuffer[LIVESYNC_BUFFINSIZE];
|
||||||
typedef struct {
|
static uint8_t livesync_outbuffer_start[ LIVESYNC_BUFFSIZE ];
|
||||||
uint8_t data[LIVESYNC_OUTGOING_BUFFSIZE_PEERS];
|
static uint8_t *livesync_outbuffer_pos;
|
||||||
size_t fill;
|
static uint8_t *livesync_outbuffer_highwater = livesync_outbuffer_start + LIVESYNC_BUFFSIZE - LIVESYNC_BUFFWATER;
|
||||||
ot_time next_packet_time;
|
static ot_time livesync_lastpacket_time;
|
||||||
} sync_buffer;
|
|
||||||
|
|
||||||
static sync_buffer g_v6_buf;
|
|
||||||
static sync_buffer g_v4_buf;
|
|
||||||
|
|
||||||
static pthread_t thread_id;
|
static pthread_t thread_id;
|
||||||
void livesync_init( ) {
|
void livesync_init( ) {
|
||||||
|
if( g_livesync_socket_in == -1 )
|
||||||
if (g_socket_in == -1)
|
|
||||||
exerr( "No socket address for live sync specified." );
|
exerr( "No socket address for live sync specified." );
|
||||||
|
livesync_outbuffer_pos = livesync_outbuffer_start;
|
||||||
/* Prepare outgoing peers buffer */
|
memmove( livesync_outbuffer_pos, &g_tracker_id, sizeof( g_tracker_id ) );
|
||||||
memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id));
|
livesync_outbuffer_pos += sizeof( g_tracker_id );
|
||||||
memcpy(g_v4_buf.data, &g_tracker_id, sizeof(g_tracker_id));
|
livesync_lastpacket_time = g_now;
|
||||||
|
|
||||||
uint32_pack_big((char *)g_v6_buf.data + sizeof(g_tracker_id), OT_SYNC_PEER6);
|
|
||||||
uint32_pack_big((char *)g_v4_buf.data + sizeof(g_tracker_id), OT_SYNC_PEER4);
|
|
||||||
|
|
||||||
g_v6_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
g_v4_buf.fill = sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
|
|
||||||
g_v6_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
|
|
||||||
g_v4_buf.next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
|
|
||||||
|
|
||||||
pthread_create( &thread_id, NULL, livesync_worker, NULL );
|
pthread_create( &thread_id, NULL, livesync_worker, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
void livesync_deinit() {
|
void livesync_deinit() {
|
||||||
if (g_socket_in != -1)
|
|
||||||
close(g_socket_in);
|
|
||||||
if (g_socket_out != -1)
|
|
||||||
close(g_socket_out);
|
|
||||||
|
|
||||||
pthread_cancel( thread_id );
|
pthread_cancel( thread_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
void livesync_bind_mcast(ot_ip6 ip, uint16_t port) {
|
void livesync_bind_mcast( char *ip, uint16_t port) {
|
||||||
char tmpip[4] = {0,0,0,0};
|
char tmpip[4] = {0,0,0,0};
|
||||||
char *v4ip;
|
|
||||||
|
|
||||||
if (!ip6_isv4mapped(ip))
|
if( g_livesync_socket_in != -1 )
|
||||||
exerr("v6 mcast support not yet available.");
|
|
||||||
v4ip = ip + 12;
|
|
||||||
|
|
||||||
if (g_socket_in != -1)
|
|
||||||
exerr("Error: Livesync listen ip specified twice.");
|
exerr("Error: Livesync listen ip specified twice.");
|
||||||
|
|
||||||
if ((g_socket_in = socket_udp4()) < 0)
|
if( ( g_livesync_socket_in = socket_udp4( )) < 0)
|
||||||
exerr("Error: Cant create live sync incoming socket." );
|
exerr("Error: Cant create live sync incoming socket." );
|
||||||
ndelay_off(g_socket_in);
|
ndelay_off(g_livesync_socket_in);
|
||||||
|
|
||||||
if (socket_bind4_reuse(g_socket_in, tmpip, port) == -1)
|
if( socket_bind4_reuse( g_livesync_socket_in, tmpip, port ) == -1 )
|
||||||
exerr("Error: Cant bind live sync incoming socket." );
|
exerr("Error: Cant bind live sync incoming socket." );
|
||||||
|
|
||||||
if (socket_mcjoin4(g_socket_in, groupip_1, v4ip))
|
if( socket_mcjoin4( g_livesync_socket_in, groupip_1, ip ) )
|
||||||
exerr("Error: Cant make live sync incoming socket join mcast group.");
|
exerr("Error: Cant make live sync incoming socket join mcast group.");
|
||||||
|
|
||||||
if ((g_socket_out = socket_udp4()) < 0)
|
if( ( g_livesync_socket_out = socket_udp4()) < 0)
|
||||||
exerr("Error: Cant create live sync outgoing socket." );
|
exerr("Error: Cant create live sync outgoing socket." );
|
||||||
if (socket_bind4_reuse(g_socket_out, v4ip, port) == -1)
|
if( socket_bind4_reuse( g_livesync_socket_out, ip, port ) == -1 )
|
||||||
exerr("Error: Cant bind live sync outgoing socket." );
|
exerr("Error: Cant bind live sync outgoing socket." );
|
||||||
|
|
||||||
socket_mcttl4(g_socket_out, 1);
|
socket_mcttl4(g_livesync_socket_out, 1);
|
||||||
socket_mcloop4(g_socket_out, 0);
|
socket_mcloop4(g_livesync_socket_out, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller MUST hold g_outbuf_mutex. Returns with g_outbuf_mutex unlocked */
|
static void livesync_issuepacket( ) {
|
||||||
static void livesync_issue_peersync(sync_buffer *buf) {
|
socket_send4(g_livesync_socket_out, (char*)livesync_outbuffer_start, livesync_outbuffer_pos - livesync_outbuffer_start,
|
||||||
char mycopy[LIVESYNC_OUTGOING_BUFFSIZE_PEERS];
|
groupip_1, LIVESYNC_PORT);
|
||||||
size_t fill = buf->fill;
|
livesync_outbuffer_pos = livesync_outbuffer_start + sizeof( g_tracker_id );
|
||||||
|
livesync_lastpacket_time = g_now;
|
||||||
memcpy(mycopy, buf->data, fill);
|
|
||||||
buf->fill = sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
buf->next_packet_time = g_now_seconds + LIVESYNC_MAXDELAY;
|
|
||||||
|
|
||||||
/* From now this thread has a local copy of the buffer and
|
|
||||||
has modified the protected element */
|
|
||||||
pthread_mutex_unlock(&g_outbuf_mutex);
|
|
||||||
|
|
||||||
socket_send4(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) {
|
/* Inform live sync about whats going on. */
|
||||||
size_t off = sizeof(g_tracker_id) + sizeof(uint32_t);
|
void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag ) {
|
||||||
|
memmove( livesync_outbuffer_pos , info_hash, sizeof(ot_hash));
|
||||||
|
memmove( livesync_outbuffer_pos + sizeof(ot_hash), peer, sizeof(ot_peer));
|
||||||
|
OT_FLAG( livesync_outbuffer_pos + sizeof(ot_hash) ) |= peerflag;
|
||||||
|
|
||||||
/* Now basic sanity checks have been done on the live sync packet
|
livesync_outbuffer_pos += sizeof(ot_hash) + sizeof(ot_peer);
|
||||||
We might add more testing and logging. */
|
if( livesync_outbuffer_pos >= livesync_outbuffer_highwater )
|
||||||
while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) {
|
livesync_issuepacket();
|
||||||
memcpy(&ws->peer, ws->request + off + sizeof(ot_hash), peer_size);
|
|
||||||
ws->hash = (ot_hash *)(ws->request + off);
|
|
||||||
|
|
||||||
if (!g_opentracker_running)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED)
|
|
||||||
remove_peer_from_torrent(FLAG_MCA, ws);
|
|
||||||
else
|
|
||||||
add_peer_to_torrent_and_return_peers(FLAG_MCA, ws, /* amount = */ 0);
|
|
||||||
|
|
||||||
off += sizeof(ot_hash) + peer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
stats_issue_event(EVENT_SYNC, 0, (ws->request_size - sizeof(g_tracker_id) - sizeof(uint32_t)) / ((ssize_t)sizeof(ot_hash) + peer_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tickle the live sync module from time to time, so no events get
|
/* Tickle the live sync module from time to time, so no events get
|
||||||
stuck when there's not enough traffic to fill udp packets fast
|
stuck when there's not enough traffic to fill udp packets fast
|
||||||
enough */
|
enough */
|
||||||
void livesync_ticker( ) {
|
void livesync_ticker( ) {
|
||||||
/* livesync_issue_peersync sets g_next_packet_time */
|
if( ( g_now - livesync_lastpacket_time > LIVESYNC_MAXDELAY) &&
|
||||||
pthread_mutex_lock(&g_outbuf_mutex);
|
( livesync_outbuffer_pos > livesync_outbuffer_start + sizeof( g_tracker_id ) ) )
|
||||||
if (g_now_seconds > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t))
|
livesync_issuepacket();
|
||||||
livesync_issue_peersync(&g_v6_buf);
|
|
||||||
else
|
|
||||||
pthread_mutex_unlock(&g_outbuf_mutex);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_outbuf_mutex);
|
|
||||||
if (g_now_seconds > g_v4_buf.next_packet_time && g_v4_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t))
|
|
||||||
livesync_issue_peersync(&g_v4_buf);
|
|
||||||
else
|
|
||||||
pthread_mutex_unlock(&g_outbuf_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inform live sync about whats going on. */
|
|
||||||
void livesync_tell(struct ot_workstruct *ws) {
|
|
||||||
size_t peer_size; /* initialized in next line */
|
|
||||||
ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
|
|
||||||
sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_outbuf_mutex);
|
|
||||||
|
|
||||||
memcpy(dest_buf->data + dest_buf->fill, ws->hash, sizeof(ot_hash));
|
|
||||||
dest_buf->fill += sizeof(ot_hash);
|
|
||||||
|
|
||||||
memcpy(dest_buf->data + dest_buf->fill, peer_src, peer_size);
|
|
||||||
dest_buf->fill += peer_size;
|
|
||||||
|
|
||||||
if (dest_buf->fill >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS)
|
|
||||||
livesync_issue_peersync(dest_buf);
|
|
||||||
else
|
|
||||||
pthread_mutex_unlock(&g_outbuf_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void * livesync_worker( void * args ) {
|
static void * livesync_worker( void * args ) {
|
||||||
struct ot_workstruct ws;
|
uint8_t in_ip[4]; uint16_t in_port;
|
||||||
ot_ip6 in_ip;
|
ssize_t datalen;
|
||||||
uint16_t in_port;
|
int off;
|
||||||
|
|
||||||
(void)args;
|
args = args;
|
||||||
|
|
||||||
/* Initialize our "thread local storage" */
|
|
||||||
ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE);
|
|
||||||
ws.outbuf = ws.reply = 0;
|
|
||||||
|
|
||||||
memcpy(in_ip, V4mappedprefix, sizeof(V4mappedprefix));
|
|
||||||
|
|
||||||
while( 1 ) {
|
while( 1 ) {
|
||||||
ws.request_size = socket_recv4(g_socket_in, (char *)ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, 12 + (char *)in_ip, &in_port);
|
datalen = socket_recv4(g_livesync_socket_in, (char*)livesync_inbuffer, LIVESYNC_BUFFINSIZE, (char*)in_ip, &in_port);
|
||||||
|
off = 4;
|
||||||
|
|
||||||
/* Expect at least tracker id and packet type */
|
if( datalen <= 0 )
|
||||||
if (ws.request_size <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t)))
|
|
||||||
continue;
|
continue;
|
||||||
if (!accesslist_is_blessed(in_ip, OT_PERMISSION_MAY_LIVESYNC))
|
|
||||||
continue;
|
if( datalen < (ssize_t)(sizeof( g_tracker_id ) + sizeof( ot_hash ) + sizeof( ot_peer ) ) ) {
|
||||||
if (!memcmp(ws.inbuf, &g_tracker_id, sizeof(g_tracker_id))) {
|
// TODO: log invalid sync packet
|
||||||
/* TODO: log packet coming from ourselves */
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (uint32_read_big(sizeof(g_tracker_id) + (char *)ws.inbuf)) {
|
if( !accesslist_isblessed((char*)in_ip, OT_PERMISSION_MAY_LIVESYNC)) {
|
||||||
case OT_SYNC_PEER6:
|
// TODO: log invalid sync packet
|
||||||
livesync_handle_peersync(&ws, OT_PEER_SIZE6);
|
continue;
|
||||||
break;
|
|
||||||
case OT_SYNC_PEER4:
|
|
||||||
livesync_handle_peersync(&ws, OT_PEER_SIZE4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !memcmp( livesync_inbuffer, &g_tracker_id, sizeof( g_tracker_id ) ) ) {
|
||||||
|
// TODO: log packet coming from ourselves
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now basic sanity checks have been done on the live sync packet
|
||||||
|
// We might add more testing and logging.
|
||||||
|
while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= datalen ) {
|
||||||
|
ot_peer *peer = (ot_peer*)(livesync_inbuffer + off + sizeof(ot_hash));
|
||||||
|
ot_hash *hash = (ot_hash*)(livesync_inbuffer + off);
|
||||||
|
|
||||||
|
if( OT_FLAG(peer) & PEER_FLAG_STOPPED )
|
||||||
|
remove_peer_from_torrent(hash, peer, NULL, FLAG_MCA);
|
||||||
|
else
|
||||||
|
add_peer_to_torrent( hash, peer WANT_SYNC_PARAM(1));
|
||||||
|
|
||||||
|
off += sizeof( ot_hash ) + sizeof( ot_peer );
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Never returns. */
|
/* Never returns. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
const char *g_version_livesync_c = "$Source$: $Revision$\n";
|
||||||
|
@ -3,44 +3,39 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_LIVESYNC_H__
|
#ifndef __OT_LIVESYNC_H__
|
||||||
#define OT_LIVESYNC_H__
|
#define __OT_LIVESYNC_H__
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Syncing is done as udp packets in the multicast domain 224.0.42.5 port 9696
|
Syncing is done as udp packets in the multicast domain 224.0.42.N port 9696
|
||||||
|
|
||||||
Each tracker should join the multicast group and send its live sync packets
|
Each tracker should join the multicast group and send its live sync packets
|
||||||
to that group, using a ttl of 1
|
to that group, using a ttl of 1
|
||||||
|
|
||||||
Format of all sync packets is straight forward, packet type determines
|
Format of a live sync packet is straight forward and depends on N:
|
||||||
which kind of packet this is:
|
|
||||||
|
|
||||||
|
For N == 23: (simple tracker2tracker sync)
|
||||||
0x0000 0x04 id of tracker instance
|
0x0000 0x04 id of tracker instance
|
||||||
0x0004 0x04 packet type
|
[ 0x0004 0x14 info_hash
|
||||||
|
0x0018 0x04 peer's ipv4 address
|
||||||
########
|
0x001c 0x02 peer's port
|
||||||
######## PEER SYNC PROTOCOL ########
|
0x0020 0x02 peer flags v1 ( SEEDING = 0x80, COMPLETE = 0x40, STOPPED = 0x20 )
|
||||||
########
|
|
||||||
|
|
||||||
Each tracker instance accumulates announce requests until its buffer is
|
|
||||||
full or a timeout is reached. Then it broadcasts its live sync packer:
|
|
||||||
|
|
||||||
packet type SYNC_LIVE4
|
|
||||||
[ 0x0008 0x14 info_hash
|
|
||||||
0x001c 0x04 peer's ipv4 address
|
|
||||||
0x0020 0x02 peer's port
|
|
||||||
0x0024 0x02 peer flags v1 ( SEEDING = 0x80, COMPLETE = 0x40, STOPPED = 0x20 )
|
|
||||||
]*
|
]*
|
||||||
|
|
||||||
packet type SYNC_LIVE6
|
For N == 24: (aggregator syncs)
|
||||||
[ 0x0008 0x14 info_hash
|
0x0000 0x04 id of tracker instance
|
||||||
0x001c 0x10 peer's ipv6 address
|
[ 0x0004 0x14 info_hash
|
||||||
0x002c 0x02 peer's port
|
0x0018 0x01 number of peers
|
||||||
0x002e 0x02 peer flags v1 ( SEEDING = 0x80, COMPLETE = 0x40, STOPPED = 0x20 )
|
[ 0x0019 0x04 peer's ipv4 address
|
||||||
|
0x001a 0x02 peer's port
|
||||||
|
0x0021 0x02 peer flags v1 ( SEEDING = 0x80, COMPLETE = 0x40, STOPPED = 0x20 )
|
||||||
|
]+
|
||||||
]*
|
]*
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
#ifdef WANT_SYNC_LIVE
|
||||||
@ -54,7 +49,7 @@ void livesync_deinit();
|
|||||||
void livesync_bind_mcast( char *ip, uint16_t port );
|
void livesync_bind_mcast( char *ip, uint16_t port );
|
||||||
|
|
||||||
/* Inform live sync about whats going on. */
|
/* Inform live sync about whats going on. */
|
||||||
void livesync_tell(struct ot_workstruct *ws);
|
void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag );
|
||||||
|
|
||||||
/* Tickle the live sync module from time to time, so no events get
|
/* Tickle the live sync module from time to time, so no events get
|
||||||
stuck when there's not enough traffic to fill udp packets fast
|
stuck when there's not enough traffic to fill udp packets fast
|
||||||
@ -62,13 +57,13 @@ void livesync_tell(struct ot_workstruct *ws);
|
|||||||
void livesync_ticker( );
|
void livesync_ticker( );
|
||||||
|
|
||||||
/* Handle an incoming live sync packet */
|
/* Handle an incoming live sync packet */
|
||||||
void handle_livesync(const int64 sock);
|
void handle_livesync( const int64 serversocket );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* If no syncing is required, save calling code from #ifdef
|
/* If no syncing is required, save calling code from #ifdef
|
||||||
constructions */
|
constructions */
|
||||||
#define livesync_deinit()
|
|
||||||
#define livesync_init()
|
#define livesync_init()
|
||||||
#define livesync_ticker()
|
#define livesync_ticker()
|
||||||
#define handle_livesync(a)
|
#define handle_livesync(a)
|
||||||
|
262
ot_mutex.c
262
ot_mutex.c
@ -13,75 +13,125 @@
|
|||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "uint32.h"
|
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_iovec.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_mutex.h"
|
||||||
|
|
||||||
/* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */
|
//#define MTX_DBG( STRING ) fprintf( stderr, STRING )
|
||||||
#define MTX_DBG( STRING )
|
#define MTX_DBG( STRING )
|
||||||
|
|
||||||
/* Our global all torrents list */
|
/* Our global all torrents list */
|
||||||
static ot_vector all_torrents[OT_BUCKET_COUNT];
|
static ot_vector all_torrents[OT_BUCKET_COUNT];
|
||||||
static pthread_mutex_t bucket_mutex[OT_BUCKET_COUNT];
|
|
||||||
static size_t g_torrent_count;
|
|
||||||
|
|
||||||
/* Self pipe from opentracker.c */
|
/* Bucket Magic */
|
||||||
extern int g_self_pipe[2];
|
static int bucket_locklist[ OT_MAX_THREADS ];
|
||||||
|
static int bucket_locklist_count = 0;
|
||||||
|
static pthread_mutex_t bucket_mutex;
|
||||||
|
static pthread_cond_t bucket_being_unlocked;
|
||||||
|
|
||||||
|
static int bucket_check( int bucket ) {
|
||||||
|
/* C should come with auto-i ;) */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* No more space to acquire lock to bucket -- should not happen */
|
||||||
|
if( bucket_locklist_count == OT_MAX_THREADS ) {
|
||||||
|
fprintf( stderr, "More lock requests than mutexes. Consult source code.\n" );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See, if bucket is already locked */
|
||||||
|
for( i=0; i<bucket_locklist_count; ++i )
|
||||||
|
if( bucket_locklist[ i ] == bucket )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bucket_push( int bucket ) {
|
||||||
|
bucket_locklist[ bucket_locklist_count++ ] = bucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bucket_remove( int bucket ) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while( ( i < bucket_locklist_count ) && ( bucket_locklist[ i ] != bucket ) )
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if( i == bucket_locklist_count ) {
|
||||||
|
fprintf( stderr, "Request to unlock bucket that was never locked. Consult source code.\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; i < bucket_locklist_count - 1; ++i )
|
||||||
|
bucket_locklist[ i ] = bucket_locklist[ i + 1 ];
|
||||||
|
|
||||||
|
--bucket_locklist_count;
|
||||||
|
}
|
||||||
|
|
||||||
ot_vector *mutex_bucket_lock( int bucket ) {
|
ot_vector *mutex_bucket_lock( int bucket ) {
|
||||||
pthread_mutex_lock(bucket_mutex + bucket);
|
pthread_mutex_lock( &bucket_mutex );
|
||||||
|
while( bucket_check( bucket ) )
|
||||||
|
pthread_cond_wait( &bucket_being_unlocked, &bucket_mutex );
|
||||||
|
bucket_push( bucket );
|
||||||
|
pthread_mutex_unlock( &bucket_mutex );
|
||||||
return all_torrents + bucket;
|
return all_torrents + bucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash) { return mutex_bucket_lock(uint32_read_big((const char *)hash) >> OT_BUCKET_COUNT_SHIFT); }
|
ot_vector *mutex_bucket_lock_by_hash( ot_hash *hash ) {
|
||||||
|
unsigned char *local_hash = hash[0];
|
||||||
|
int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 );
|
||||||
|
|
||||||
void mutex_bucket_unlock(int bucket, int delta_torrentcount) {
|
/* Can block */
|
||||||
pthread_mutex_unlock(bucket_mutex + bucket);
|
mutex_bucket_lock( bucket );
|
||||||
g_torrent_count += delta_torrentcount;
|
|
||||||
|
return all_torrents + bucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) {
|
void mutex_bucket_unlock( int bucket ) {
|
||||||
mutex_bucket_unlock(uint32_read_big((char *)hash) >> OT_BUCKET_COUNT_SHIFT, delta_torrentcount);
|
pthread_mutex_lock( &bucket_mutex );
|
||||||
|
bucket_remove( bucket );
|
||||||
|
pthread_cond_broadcast( &bucket_being_unlocked );
|
||||||
|
pthread_mutex_unlock( &bucket_mutex );
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mutex_get_torrent_count() { return g_torrent_count; }
|
void mutex_bucket_unlock_by_hash( ot_hash *hash ) {
|
||||||
|
unsigned char *local_hash = hash[0];
|
||||||
|
int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 );
|
||||||
|
mutex_bucket_unlock( bucket );
|
||||||
|
}
|
||||||
|
|
||||||
/* TaskQueue Magic */
|
/* TaskQueue Magic */
|
||||||
|
|
||||||
struct ot_task {
|
struct ot_task {
|
||||||
ot_taskid taskid;
|
ot_taskid taskid;
|
||||||
ot_tasktype tasktype;
|
ot_tasktype tasktype;
|
||||||
int64 sock;
|
int64 socket;
|
||||||
int iovec_entries;
|
int iovec_entries;
|
||||||
struct iovec *iovec;
|
struct iovec *iovec;
|
||||||
struct ot_task *next;
|
struct ot_task *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ot_taskid next_free_taskid = 1;
|
static ot_taskid next_free_taskid = 1;
|
||||||
static struct ot_task *tasklist;
|
static struct ot_task *tasklist = NULL;
|
||||||
static pthread_mutex_t tasklist_mutex;
|
static pthread_mutex_t tasklist_mutex;
|
||||||
static pthread_cond_t tasklist_being_filled;
|
static pthread_cond_t tasklist_being_filled;
|
||||||
|
|
||||||
int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) {
|
int mutex_workqueue_pushtask( int64 socket, ot_tasktype tasktype ) {
|
||||||
struct ot_task ** tmptask, * task;
|
struct ot_task ** tmptask, * task;
|
||||||
|
|
||||||
task = malloc(sizeof(struct ot_task));
|
|
||||||
if (!task)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
task->taskid = 0;
|
|
||||||
task->tasktype = tasktype;
|
|
||||||
task->sock = sock;
|
|
||||||
task->iovec_entries = 0;
|
|
||||||
task->iovec = NULL;
|
|
||||||
task->next = 0;
|
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "pushtask locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushtask locked.\n" );
|
||||||
|
|
||||||
|
task = malloc(sizeof( struct ot_task));
|
||||||
|
if( !task ) {
|
||||||
|
MTX_DBG( "pushtask fail unlocks.\n" );
|
||||||
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushtask fail unlocked.\n" );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip to end of list */
|
/* Skip to end of list */
|
||||||
tmptask = &tasklist;
|
tmptask = &tasklist;
|
||||||
@ -89,35 +139,51 @@ int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) {
|
|||||||
tmptask = &(*tmptask)->next;
|
tmptask = &(*tmptask)->next;
|
||||||
*tmptask = task;
|
*tmptask = task;
|
||||||
|
|
||||||
|
task->taskid = 0;
|
||||||
|
task->tasktype = tasktype;
|
||||||
|
task->socket = socket;
|
||||||
|
task->iovec_entries = 0;
|
||||||
|
task->iovec = NULL;
|
||||||
|
task->next = 0;
|
||||||
|
|
||||||
/* Inform waiting workers and release lock */
|
/* Inform waiting workers and release lock */
|
||||||
|
MTX_DBG( "pushtask broadcasts.\n" );
|
||||||
pthread_cond_broadcast( &tasklist_being_filled );
|
pthread_cond_broadcast( &tasklist_being_filled );
|
||||||
|
MTX_DBG( "pushtask broadcasted, mutex unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushtask end mutex unlocked.\n" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_workqueue_canceltask(int64 sock) {
|
void mutex_workqueue_canceltask( int64 socket ) {
|
||||||
struct ot_task ** task;
|
struct ot_task ** task;
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "canceltask locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "canceltask locked.\n" );
|
||||||
|
|
||||||
for (task = &tasklist; *task; task = &((*task)->next))
|
task = &tasklist;
|
||||||
if ((*task)->sock == sock) {
|
while( *task && ( (*task)->socket != socket ) )
|
||||||
|
*task = (*task)->next;
|
||||||
|
|
||||||
|
if( *task && ( (*task)->socket == socket ) ) {
|
||||||
struct iovec *iovec = (*task)->iovec;
|
struct iovec *iovec = (*task)->iovec;
|
||||||
struct ot_task *ptask = *task;
|
struct ot_task *ptask = *task;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Free task's iovec */
|
/* Free task's iovec */
|
||||||
for( i=0; i<(*task)->iovec_entries; ++i )
|
for( i=0; i<(*task)->iovec_entries; ++i )
|
||||||
free(iovec[i].iov_base);
|
munmap( iovec[i].iov_base , iovec[i].iov_len );
|
||||||
|
|
||||||
*task = (*task)->next;
|
*task = (*task)->next;
|
||||||
free( ptask );
|
free( ptask );
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release lock */
|
/* Release lock */
|
||||||
|
MTX_DBG( "canceltask unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "canceltask unlocked.\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype ) {
|
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype ) {
|
||||||
@ -125,26 +191,33 @@ ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype) {
|
|||||||
ot_taskid taskid = 0;
|
ot_taskid taskid = 0;
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "poptask mutex locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "poptask mutex locked.\n" );
|
||||||
|
|
||||||
while( !taskid ) {
|
while( !taskid ) {
|
||||||
/* Skip to the first unassigned task this worker wants to do */
|
/* Skip to the first unassigned task this worker wants to do */
|
||||||
for (task = tasklist; task; task = task->next)
|
task = tasklist;
|
||||||
if (!task->taskid && (TASK_CLASS_MASK & task->tasktype) == *tasktype) {
|
while( task && ( ( ( TASK_CLASS_MASK & task->tasktype ) != *tasktype ) || task->taskid ) )
|
||||||
|
task = task->next;
|
||||||
|
|
||||||
/* If we found an outstanding task, assign a taskid to it
|
/* If we found an outstanding task, assign a taskid to it
|
||||||
and leave the loop */
|
and leave the loop */
|
||||||
|
if( task ) {
|
||||||
task->taskid = taskid = ++next_free_taskid;
|
task->taskid = taskid = ++next_free_taskid;
|
||||||
*tasktype = task->tasktype;
|
*tasktype = task->tasktype;
|
||||||
break;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until the next task is being fed */
|
/* Wait until the next task is being fed */
|
||||||
if (!taskid)
|
MTX_DBG( "poptask cond waits.\n" );
|
||||||
pthread_cond_wait( &tasklist_being_filled, &tasklist_mutex );
|
pthread_cond_wait( &tasklist_being_filled, &tasklist_mutex );
|
||||||
|
MTX_DBG( "poptask cond waited.\n" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release lock */
|
/* Release lock */
|
||||||
|
MTX_DBG( "poptask end mutex unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "poptask end mutex unlocked.\n" );
|
||||||
|
|
||||||
return taskid;
|
return taskid;
|
||||||
}
|
}
|
||||||
@ -153,120 +226,97 @@ void mutex_workqueue_pushsuccess(ot_taskid taskid) {
|
|||||||
struct ot_task ** task;
|
struct ot_task ** task;
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "pushsuccess locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushsuccess locked.\n" );
|
||||||
|
|
||||||
for (task = &tasklist; *task; task = &((*task)->next))
|
task = &tasklist;
|
||||||
if ((*task)->taskid == taskid) {
|
while( *task && ( (*task)->taskid != taskid ) )
|
||||||
|
*task = (*task)->next;
|
||||||
|
|
||||||
|
if( *task && ( (*task)->taskid == taskid ) ) {
|
||||||
struct ot_task *ptask = *task;
|
struct ot_task *ptask = *task;
|
||||||
*task = (*task)->next;
|
*task = (*task)->next;
|
||||||
free( ptask );
|
free( ptask );
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release lock */
|
/* Release lock */
|
||||||
|
MTX_DBG( "pushsuccess unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushsuccess unlocked.\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovec ) {
|
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovec ) {
|
||||||
struct ot_task * task;
|
struct ot_task * task;
|
||||||
const char byte = 'o';
|
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "pushresult locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushresult locked.\n" );
|
||||||
|
|
||||||
for (task = tasklist; task; task = task->next)
|
task = tasklist;
|
||||||
if (task->taskid == taskid) {
|
while( task && ( task->taskid != taskid ) )
|
||||||
|
task = task->next;
|
||||||
|
|
||||||
|
if( task ) {
|
||||||
task->iovec_entries = iovec_entries;
|
task->iovec_entries = iovec_entries;
|
||||||
task->iovec = iovec;
|
task->iovec = iovec;
|
||||||
task->tasktype = TASK_DONE;
|
task->tasktype = TASK_DONE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release lock */
|
/* Release lock */
|
||||||
|
MTX_DBG( "pushresult unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "pushresult unlocked.\n" );
|
||||||
io_trywrite(g_self_pipe[1], &byte, 1);
|
|
||||||
|
|
||||||
/* Indicate whether the worker has to throw away results */
|
/* Indicate whether the worker has to throw away results */
|
||||||
return task ? 0 : -1;
|
return task ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) {
|
int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovec ) {
|
||||||
struct ot_task *task;
|
|
||||||
const char byte = 'o';
|
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
|
||||||
pthread_mutex_lock(&tasklist_mutex);
|
|
||||||
|
|
||||||
for (task = tasklist; task; task = task->next)
|
|
||||||
if (task->taskid == taskid) {
|
|
||||||
if (iovec) {
|
|
||||||
if (iovec_append(&task->iovec_entries, &task->iovec, iovec))
|
|
||||||
task->tasktype = TASK_DONE_PARTIAL;
|
|
||||||
else
|
|
||||||
task = NULL;
|
|
||||||
} else
|
|
||||||
task->tasktype = TASK_DONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release lock */
|
|
||||||
pthread_mutex_unlock(&tasklist_mutex);
|
|
||||||
|
|
||||||
io_trywrite(g_self_pipe[1], &byte, 1);
|
|
||||||
|
|
||||||
/* Indicate whether the worker has to throw away results */
|
|
||||||
return task ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovec, int *is_partial) {
|
|
||||||
struct ot_task ** task;
|
struct ot_task ** task;
|
||||||
int64 sock = -1;
|
int64 socket = -1;
|
||||||
|
|
||||||
*is_partial = 0;
|
|
||||||
|
|
||||||
/* Want exclusive access to tasklist */
|
/* Want exclusive access to tasklist */
|
||||||
|
MTX_DBG( "popresult locks.\n" );
|
||||||
pthread_mutex_lock( &tasklist_mutex );
|
pthread_mutex_lock( &tasklist_mutex );
|
||||||
|
MTX_DBG( "popresult locked.\n" );
|
||||||
|
|
||||||
for (task = &tasklist; *task; task = &((*task)->next))
|
task = &tasklist;
|
||||||
if (((*task)->tasktype & TASK_CLASS_MASK) == TASK_DONE) {
|
while( *task && ( (*task)->tasktype != TASK_DONE ) )
|
||||||
|
task = &(*task)->next;
|
||||||
|
|
||||||
|
if( *task && ( (*task)->tasktype == TASK_DONE ) ) {
|
||||||
struct ot_task *ptask = *task;
|
struct ot_task *ptask = *task;
|
||||||
*iovec_entries = ptask->iovec_entries;
|
|
||||||
*iovec = ptask->iovec;
|
|
||||||
sock = ptask->sock;
|
|
||||||
|
|
||||||
if ((*task)->tasktype == TASK_DONE) {
|
*iovec_entries = (*task)->iovec_entries;
|
||||||
*task = ptask->next;
|
*iovec = (*task)->iovec;
|
||||||
|
socket = (*task)->socket;
|
||||||
|
|
||||||
|
*task = (*task)->next;
|
||||||
free( ptask );
|
free( ptask );
|
||||||
} else {
|
|
||||||
ptask->iovec_entries = 0;
|
|
||||||
ptask->iovec = NULL;
|
|
||||||
*is_partial = 1;
|
|
||||||
/* Prevent task from showing up immediately again unless new data was added */
|
|
||||||
(*task)->tasktype = TASK_FULLSCRAPE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release lock */
|
/* Release lock */
|
||||||
|
MTX_DBG( "popresult unlocks.\n" );
|
||||||
pthread_mutex_unlock( &tasklist_mutex );
|
pthread_mutex_unlock( &tasklist_mutex );
|
||||||
return sock;
|
MTX_DBG( "popresult unlocked.\n" );
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_init( ) {
|
void mutex_init( ) {
|
||||||
int i;
|
|
||||||
pthread_mutex_init(&tasklist_mutex, NULL);
|
pthread_mutex_init(&tasklist_mutex, NULL);
|
||||||
pthread_cond_init (&tasklist_being_filled, NULL);
|
pthread_cond_init (&tasklist_being_filled, NULL);
|
||||||
for (i = 0; i < OT_BUCKET_COUNT; ++i)
|
pthread_mutex_init(&bucket_mutex, NULL);
|
||||||
pthread_mutex_init(bucket_mutex + i, NULL);
|
pthread_cond_init (&bucket_being_unlocked, NULL);
|
||||||
byte_zero( all_torrents, sizeof( all_torrents ) );
|
byte_zero( all_torrents, sizeof( all_torrents ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_deinit( ) {
|
void mutex_deinit( ) {
|
||||||
int i;
|
pthread_mutex_destroy(&bucket_mutex);
|
||||||
for (i = 0; i < OT_BUCKET_COUNT; ++i)
|
pthread_cond_destroy(&bucket_being_unlocked);
|
||||||
pthread_mutex_destroy(bucket_mutex + i);
|
|
||||||
pthread_mutex_destroy(&tasklist_mutex);
|
pthread_mutex_destroy(&tasklist_mutex);
|
||||||
pthread_cond_destroy(&tasklist_being_filled);
|
pthread_cond_destroy(&tasklist_being_filled);
|
||||||
byte_zero( all_torrents, sizeof( all_torrents ) );
|
byte_zero( all_torrents, sizeof( all_torrents ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_version_mutex_c = "$Source$: $Revision$\n";
|
||||||
|
57
ot_mutex.h
57
ot_mutex.h
@ -3,22 +3,17 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_MUTEX_H__
|
#ifndef __OT_MUTEX_H__
|
||||||
#define OT_MUTEX_H__
|
#define __OT_MUTEX_H__
|
||||||
|
|
||||||
#include <sys/uio.h>
|
void mutex_init( );
|
||||||
#include "trackerlogic.h"
|
void mutex_deinit( );
|
||||||
|
|
||||||
void mutex_init(void);
|
|
||||||
void mutex_deinit(void);
|
|
||||||
|
|
||||||
ot_vector *mutex_bucket_lock( int bucket );
|
ot_vector *mutex_bucket_lock( int bucket );
|
||||||
ot_vector *mutex_bucket_lock_by_hash(ot_hash const hash);
|
ot_vector *mutex_bucket_lock_by_hash( ot_hash *hash );
|
||||||
|
|
||||||
void mutex_bucket_unlock(int bucket, int delta_torrentcount);
|
void mutex_bucket_unlock( int bucket );
|
||||||
void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount);
|
void mutex_bucket_unlock_by_hash( ot_hash *hash );
|
||||||
|
|
||||||
size_t mutex_get_torrent_count(void);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TASK_STATS_CONNS = 0x0001,
|
TASK_STATS_CONNS = 0x0001,
|
||||||
@ -28,39 +23,36 @@ typedef enum {
|
|||||||
TASK_STATS_FULLSCRAPE = 0x0005,
|
TASK_STATS_FULLSCRAPE = 0x0005,
|
||||||
TASK_STATS_TPB = 0x0006,
|
TASK_STATS_TPB = 0x0006,
|
||||||
TASK_STATS_HTTPERRORS = 0x0007,
|
TASK_STATS_HTTPERRORS = 0x0007,
|
||||||
TASK_STATS_VERSION = 0x0008,
|
TASK_STATS_STARTSTOP = 0x0008,
|
||||||
TASK_STATS_BUSY_NETWORKS = 0x0009,
|
TASK_STATS_TORADDREM = 0x0009,
|
||||||
TASK_STATS_RENEW = 0x000a,
|
TASK_STATS_VERSION = 0x000a,
|
||||||
TASK_STATS_SYNCS = 0x000b,
|
TASK_STATS_BUSY_NETWORKS = 0x000b,
|
||||||
TASK_STATS_COMPLETED = 0x000c,
|
TASK_STATS_VECTOR_DEBUG = 0x000c,
|
||||||
TASK_STATS_NUMWANTS = 0x000d,
|
TASK_STATS_RENEW = 0x000d,
|
||||||
|
|
||||||
TASK_STATS = 0x0100, /* Mask */
|
TASK_STATS = 0x0100, /* Mask */
|
||||||
TASK_STATS_TORRENTS = 0x0101,
|
TASK_STATS_TORRENTS = 0x0101,
|
||||||
TASK_STATS_PEERS = 0x0102,
|
TASK_STATS_PEERS = 0x0102,
|
||||||
TASK_STATS_SLASH24S = 0x0103,
|
TASK_STATS_SLASH24S = 0x0103,
|
||||||
TASK_STATS_TOP10 = 0x0104,
|
TASK_STATS_TOP10 = 0x0104,
|
||||||
TASK_STATS_TOP100 = 0x0105,
|
TASK_STATS_MEMORY = 0x0105,
|
||||||
TASK_STATS_EVERYTHING = 0x0106,
|
|
||||||
TASK_STATS_FULLLOG = 0x0107,
|
|
||||||
TASK_STATS_WOODPECKERS = 0x0108,
|
|
||||||
|
|
||||||
TASK_FULLSCRAPE = 0x0200, /* Default mode */
|
TASK_FULLSCRAPE = 0x0200, /* Default mode */
|
||||||
TASK_FULLSCRAPE_TPB_BINARY = 0x0201,
|
TASK_FULLSCRAPE_TPB_BINARY = 0x0201,
|
||||||
TASK_FULLSCRAPE_TPB_ASCII = 0x0202,
|
TASK_FULLSCRAPE_TPB_ASCII = 0x0202,
|
||||||
TASK_FULLSCRAPE_TPB_ASCII_PLUS = 0x0203,
|
TASK_FULLSCRAPE_TPB_URLENCODED = 0x0203,
|
||||||
TASK_FULLSCRAPE_TPB_URLENCODED = 0x0204,
|
|
||||||
TASK_FULLSCRAPE_TRACKERSTATE = 0x0205,
|
|
||||||
|
|
||||||
TASK_DMEM = 0x0300,
|
TASK_CLEAN = 0x0300,
|
||||||
|
|
||||||
|
TASK_SYNC_OUT = 0x0400,
|
||||||
|
TASK_SYNC_IN = 0x0401,
|
||||||
|
|
||||||
|
TASK_DMEM = 0x0500,
|
||||||
|
|
||||||
TASK_DONE = 0x0f00,
|
TASK_DONE = 0x0f00,
|
||||||
TASK_DONE_PARTIAL = 0x0f01,
|
|
||||||
|
|
||||||
TASK_FLAG_GZIP = 0x1000,
|
TASK_FLAG_GZIP = 0x1000,
|
||||||
TASK_FLAG_BZIP2 = 0x2000,
|
TASK_FLAG_BZIP2 = 0x2000,
|
||||||
TASK_FLAG_ZSTD = 0x4000,
|
|
||||||
TASK_FLAG_CHUNKED = 0x8000,
|
|
||||||
|
|
||||||
TASK_TASK_MASK = 0x0fff,
|
TASK_TASK_MASK = 0x0fff,
|
||||||
TASK_CLASS_MASK = 0x0f00,
|
TASK_CLASS_MASK = 0x0f00,
|
||||||
@ -69,12 +61,11 @@ typedef enum {
|
|||||||
|
|
||||||
typedef unsigned long ot_taskid;
|
typedef unsigned long ot_taskid;
|
||||||
|
|
||||||
int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype);
|
int mutex_workqueue_pushtask( int64 socket, ot_tasktype tasktype );
|
||||||
void mutex_workqueue_canceltask(int64 sock);
|
void mutex_workqueue_canceltask( int64 socket );
|
||||||
void mutex_workqueue_pushsuccess( ot_taskid taskid );
|
void mutex_workqueue_pushsuccess( ot_taskid taskid );
|
||||||
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype );
|
ot_taskid mutex_workqueue_poptask( ot_tasktype *tasktype );
|
||||||
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovector );
|
int mutex_workqueue_pushresult( ot_taskid taskid, int iovec_entries, struct iovec *iovector );
|
||||||
int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec);
|
int64 mutex_workqueue_popresult( int *iovec_entries, struct iovec ** iovector );
|
||||||
int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovector, int *is_partial);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
488
ot_rijndael.c
488
ot_rijndael.c
@ -1,488 +0,0 @@
|
|||||||
/**
|
|
||||||
* rijndael-alg-fst.c
|
|
||||||
*
|
|
||||||
* @version 3.0 (December 2000)
|
|
||||||
*
|
|
||||||
* Optimised ANSI C code for the Rijndael cipher (now AES)
|
|
||||||
*
|
|
||||||
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
|
|
||||||
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
|
|
||||||
* @author Paulo Barreto <paulo.barreto@terra.com.br>
|
|
||||||
*
|
|
||||||
* This code is hereby placed in the public domain.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS OR CONTRIBUTORS 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.
|
|
||||||
*/
|
|
||||||
#include "ot_rijndael.h"
|
|
||||||
|
|
||||||
static const uint32_t Te0[256] = {
|
|
||||||
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
|
|
||||||
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
|
|
||||||
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
|
|
||||||
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
|
|
||||||
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
|
|
||||||
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
|
|
||||||
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
|
|
||||||
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
|
|
||||||
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
|
|
||||||
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
|
|
||||||
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
|
|
||||||
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
|
|
||||||
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
|
|
||||||
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
|
|
||||||
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
|
|
||||||
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
|
|
||||||
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
|
|
||||||
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
|
|
||||||
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
|
|
||||||
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
|
|
||||||
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
|
|
||||||
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
|
|
||||||
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
|
|
||||||
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
|
|
||||||
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
|
|
||||||
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
|
|
||||||
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
|
|
||||||
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
|
|
||||||
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
|
|
||||||
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
|
|
||||||
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
|
|
||||||
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
|
|
||||||
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
|
|
||||||
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
|
|
||||||
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
|
|
||||||
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
|
|
||||||
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
|
|
||||||
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
|
|
||||||
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
|
|
||||||
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
|
|
||||||
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
|
|
||||||
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
|
|
||||||
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
|
|
||||||
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
|
|
||||||
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
|
|
||||||
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
|
|
||||||
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
|
|
||||||
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
|
|
||||||
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
|
|
||||||
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
|
|
||||||
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
|
|
||||||
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
|
|
||||||
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
|
|
||||||
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
|
|
||||||
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
|
|
||||||
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
|
|
||||||
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
|
|
||||||
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
|
|
||||||
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
|
|
||||||
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
|
|
||||||
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
|
|
||||||
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
|
|
||||||
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
|
|
||||||
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
|
|
||||||
};
|
|
||||||
static const uint32_t Te1[256] = {
|
|
||||||
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
|
|
||||||
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
|
|
||||||
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
|
|
||||||
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
|
|
||||||
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
|
|
||||||
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
|
|
||||||
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
|
|
||||||
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
|
|
||||||
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
|
|
||||||
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
|
|
||||||
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
|
|
||||||
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
|
|
||||||
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
|
|
||||||
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
|
|
||||||
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
|
|
||||||
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
|
|
||||||
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
|
|
||||||
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
|
|
||||||
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
|
|
||||||
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
|
|
||||||
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
|
|
||||||
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
|
|
||||||
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
|
|
||||||
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
|
|
||||||
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
|
|
||||||
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
|
|
||||||
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
|
|
||||||
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
|
|
||||||
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
|
|
||||||
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
|
|
||||||
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
|
|
||||||
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
|
|
||||||
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
|
|
||||||
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
|
|
||||||
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
|
|
||||||
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
|
|
||||||
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
|
|
||||||
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
|
|
||||||
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
|
|
||||||
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
|
|
||||||
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
|
|
||||||
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
|
|
||||||
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
|
|
||||||
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
|
|
||||||
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
|
|
||||||
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
|
|
||||||
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
|
|
||||||
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
|
|
||||||
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
|
|
||||||
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
|
|
||||||
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
|
|
||||||
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
|
|
||||||
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
|
|
||||||
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
|
|
||||||
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
|
|
||||||
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
|
|
||||||
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
|
|
||||||
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
|
|
||||||
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
|
|
||||||
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
|
|
||||||
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
|
|
||||||
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
|
|
||||||
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
|
|
||||||
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
|
|
||||||
};
|
|
||||||
static const uint32_t Te2[256] = {
|
|
||||||
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
|
|
||||||
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
|
|
||||||
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
|
|
||||||
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
|
|
||||||
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
|
|
||||||
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
|
|
||||||
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
|
|
||||||
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
|
|
||||||
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
|
|
||||||
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
|
|
||||||
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
|
|
||||||
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
|
|
||||||
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
|
|
||||||
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
|
|
||||||
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
|
|
||||||
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
|
|
||||||
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
|
|
||||||
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
|
|
||||||
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
|
|
||||||
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
|
|
||||||
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
|
|
||||||
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
|
|
||||||
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
|
|
||||||
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
|
|
||||||
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
|
|
||||||
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
|
|
||||||
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
|
|
||||||
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
|
|
||||||
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
|
|
||||||
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
|
|
||||||
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
|
|
||||||
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
|
|
||||||
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
|
|
||||||
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
|
|
||||||
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
|
|
||||||
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
|
|
||||||
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
|
|
||||||
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
|
|
||||||
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
|
|
||||||
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
|
|
||||||
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
|
|
||||||
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
|
|
||||||
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
|
|
||||||
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
|
|
||||||
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
|
|
||||||
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
|
|
||||||
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
|
|
||||||
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
|
|
||||||
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
|
|
||||||
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
|
|
||||||
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
|
|
||||||
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
|
|
||||||
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
|
|
||||||
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
|
|
||||||
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
|
|
||||||
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
|
|
||||||
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
|
|
||||||
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
|
|
||||||
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
|
|
||||||
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
|
|
||||||
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
|
|
||||||
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
|
|
||||||
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
|
|
||||||
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
|
|
||||||
};
|
|
||||||
static const uint32_t Te3[256] = {
|
|
||||||
|
|
||||||
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
|
|
||||||
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
|
|
||||||
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
|
|
||||||
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
|
|
||||||
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
|
|
||||||
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
|
|
||||||
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
|
|
||||||
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
|
|
||||||
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
|
|
||||||
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
|
|
||||||
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
|
|
||||||
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
|
|
||||||
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
|
|
||||||
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
|
|
||||||
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
|
|
||||||
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
|
|
||||||
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
|
|
||||||
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
|
|
||||||
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
|
|
||||||
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
|
|
||||||
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
|
|
||||||
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
|
|
||||||
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
|
|
||||||
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
|
|
||||||
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
|
|
||||||
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
|
|
||||||
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
|
|
||||||
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
|
|
||||||
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
|
|
||||||
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
|
|
||||||
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
|
|
||||||
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
|
|
||||||
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
|
|
||||||
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
|
|
||||||
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
|
|
||||||
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
|
|
||||||
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
|
|
||||||
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
|
|
||||||
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
|
|
||||||
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
|
|
||||||
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
|
|
||||||
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
|
|
||||||
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
|
|
||||||
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
|
|
||||||
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
|
|
||||||
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
|
|
||||||
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
|
|
||||||
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
|
|
||||||
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
|
|
||||||
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
|
|
||||||
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
|
|
||||||
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
|
|
||||||
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
|
|
||||||
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
|
|
||||||
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
|
|
||||||
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
|
|
||||||
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
|
|
||||||
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
|
|
||||||
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
|
|
||||||
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
|
|
||||||
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
|
|
||||||
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
|
|
||||||
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
|
|
||||||
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
|
|
||||||
};
|
|
||||||
static const uint32_t Te4[256] = {
|
|
||||||
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
|
|
||||||
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
|
|
||||||
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
|
|
||||||
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
|
|
||||||
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
|
|
||||||
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
|
|
||||||
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
|
|
||||||
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
|
|
||||||
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
|
|
||||||
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
|
|
||||||
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
|
|
||||||
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
|
|
||||||
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
|
|
||||||
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
|
|
||||||
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
|
|
||||||
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
|
|
||||||
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
|
|
||||||
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
|
|
||||||
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
|
|
||||||
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
|
|
||||||
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
|
|
||||||
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
|
|
||||||
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
|
|
||||||
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
|
|
||||||
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
|
|
||||||
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
|
|
||||||
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
|
|
||||||
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
|
|
||||||
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
|
|
||||||
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
|
|
||||||
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
|
|
||||||
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
|
|
||||||
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
|
|
||||||
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
|
|
||||||
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
|
|
||||||
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
|
|
||||||
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
|
|
||||||
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
|
|
||||||
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
|
|
||||||
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
|
|
||||||
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
|
|
||||||
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
|
|
||||||
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
|
|
||||||
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
|
|
||||||
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
|
|
||||||
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
|
|
||||||
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
|
|
||||||
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
|
|
||||||
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
|
|
||||||
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
|
|
||||||
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
|
|
||||||
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
|
|
||||||
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
|
|
||||||
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
|
|
||||||
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
|
|
||||||
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
|
|
||||||
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
|
|
||||||
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
|
|
||||||
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
|
|
||||||
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
|
|
||||||
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
|
|
||||||
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
|
|
||||||
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
|
|
||||||
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
|
|
||||||
};
|
|
||||||
static const uint32_t rcon[] = {
|
|
||||||
0x01000000, 0x02000000, 0x04000000, 0x08000000,
|
|
||||||
0x10000000, 0x20000000, 0x40000000, 0x80000000,
|
|
||||||
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GETU32(pt) (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
|
|
||||||
#define PUTU32(ct, st) { (ct)[0] = (uint8_t)((st) >> 24); (ct)[1] = (uint8_t)((st) >> 16); (ct)[2] = (uint8_t)((st) >> 8); (ct)[3] = (uint8_t)(st); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand the cipher key into the encryption key schedule.
|
|
||||||
*
|
|
||||||
* @return the number of rounds for the given cipher key size.
|
|
||||||
*/
|
|
||||||
int rijndaelKeySetupEnc128(uint32_t rk[44], const uint8_t cipherKey[] ) {
|
|
||||||
int i = 0;
|
|
||||||
uint32_t temp;
|
|
||||||
|
|
||||||
rk[0] = GETU32(cipherKey );
|
|
||||||
rk[1] = GETU32(cipherKey + 4);
|
|
||||||
rk[2] = GETU32(cipherKey + 8);
|
|
||||||
rk[3] = GETU32(cipherKey + 12);
|
|
||||||
for (;;) {
|
|
||||||
temp = rk[3];
|
|
||||||
rk[4] = rk[0] ^
|
|
||||||
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
|
|
||||||
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
|
||||||
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
|
|
||||||
(Te4[(temp >> 24) ] & 0x000000ff) ^
|
|
||||||
rcon[i];
|
|
||||||
rk[5] = rk[1] ^ rk[4];
|
|
||||||
rk[6] = rk[2] ^ rk[5];
|
|
||||||
rk[7] = rk[3] ^ rk[6];
|
|
||||||
if (++i == 10) {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
rk += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rijndaelEncrypt128(const uint32_t rk[44], const uint8_t pt[16], uint8_t ct[16]) {
|
|
||||||
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* map byte array block to cipher state
|
|
||||||
* and add initial round key:
|
|
||||||
*/
|
|
||||||
s0 = GETU32(pt ) ^ rk[0];
|
|
||||||
s1 = GETU32(pt + 4) ^ rk[1];
|
|
||||||
s2 = GETU32(pt + 8) ^ rk[2];
|
|
||||||
s3 = GETU32(pt + 12) ^ rk[3];
|
|
||||||
/* round 1: */
|
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
|
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
|
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
|
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
|
|
||||||
/* round 2: */
|
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
|
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
|
|
||||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
|
|
||||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
|
|
||||||
/* round 3: */
|
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
|
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
|
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
|
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
|
|
||||||
/* round 4: */
|
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
|
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
|
|
||||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
|
|
||||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
|
|
||||||
/* round 5: */
|
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
|
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
|
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
|
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
|
|
||||||
/* round 6: */
|
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
|
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
|
|
||||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
|
|
||||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
|
|
||||||
/* round 7: */
|
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
|
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
|
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
|
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
|
|
||||||
/* round 8: */
|
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
|
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
|
|
||||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
|
|
||||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
|
|
||||||
/* round 9: */
|
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
|
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
|
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
|
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* apply last round and
|
|
||||||
* map cipher state to byte array block:
|
|
||||||
*/
|
|
||||||
s0 =
|
|
||||||
(Te4[(t0 >> 24) ] & 0xff000000) ^
|
|
||||||
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
|
|
||||||
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
|
|
||||||
(Te4[(t3 ) & 0xff] & 0x000000ff) ^
|
|
||||||
rk[40];
|
|
||||||
PUTU32(ct , s0);
|
|
||||||
s1 =
|
|
||||||
(Te4[(t1 >> 24) ] & 0xff000000) ^
|
|
||||||
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
|
|
||||||
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
|
|
||||||
(Te4[(t0 ) & 0xff] & 0x000000ff) ^
|
|
||||||
rk[41];
|
|
||||||
PUTU32(ct + 4, s1);
|
|
||||||
s2 =
|
|
||||||
(Te4[(t2 >> 24) ] & 0xff000000) ^
|
|
||||||
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
|
|
||||||
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
|
|
||||||
(Te4[(t1 ) & 0xff] & 0x000000ff) ^
|
|
||||||
rk[42];
|
|
||||||
PUTU32(ct + 8, s2);
|
|
||||||
s3 =
|
|
||||||
(Te4[(t3 >> 24) ] & 0xff000000) ^
|
|
||||||
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
|
|
||||||
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
|
|
||||||
(Te4[(t2 ) & 0xff] & 0x000000ff) ^
|
|
||||||
rk[43];
|
|
||||||
PUTU32(ct + 12, s3);
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
|
|
||||||
It is considered beerware. Prost. Skol. Cheers or whatever.
|
|
||||||
|
|
||||||
The rijndael implementation was taken from
|
|
||||||
|
|
||||||
http://www.cs.ucdavis.edu/~rogaway/ocb/ocb-ref/rijndael-alg-fst.c
|
|
||||||
|
|
||||||
and modified to work with 128 bits (this is 10 rounds) only.
|
|
||||||
|
|
||||||
$id$ */
|
|
||||||
|
|
||||||
#ifndef OT_RIJNDAEL_H__
|
|
||||||
#define OT_RIJNDAEL_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
int rijndaelKeySetupEnc128(uint32_t rk[44], const uint8_t cipherKey[] );
|
|
||||||
void rijndaelEncrypt128(const uint32_t rk[44], const uint8_t pt[16], uint8_t ct[16]);
|
|
||||||
|
|
||||||
extern const char *g_version_rijndael_c;
|
|
||||||
|
|
||||||
#endif
|
|
961
ot_stats.c
961
ot_stats.c
File diff suppressed because it is too large
Load Diff
29
ot_stats.h
29
ot_stats.h
@ -3,28 +3,24 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_STATS_H__
|
#ifndef __OT_STATS_H__
|
||||||
#define OT_STATS_H__
|
#define __OT_STATS_H__
|
||||||
|
|
||||||
#include "trackerlogic.h"
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EVENT_ACCEPT,
|
EVENT_ACCEPT,
|
||||||
EVENT_READ,
|
EVENT_READ,
|
||||||
EVENT_CONNECT, /* UDP only */
|
EVENT_CONNECT, /* UDP only */
|
||||||
EVENT_ANNOUNCE,
|
EVENT_ANNOUNCE,
|
||||||
EVENT_COMPLETED,
|
|
||||||
EVENT_RENEW,
|
EVENT_RENEW,
|
||||||
EVENT_SYNC,
|
|
||||||
EVENT_SCRAPE,
|
EVENT_SCRAPE,
|
||||||
EVENT_FULLSCRAPE_REQUEST,
|
EVENT_FULLSCRAPE_REQUEST,
|
||||||
EVENT_FULLSCRAPE_REQUEST_GZIP,
|
EVENT_FULLSCRAPE_REQUEST_GZIP,
|
||||||
EVENT_FULLSCRAPE_REQUEST_ZSTD,
|
|
||||||
EVENT_FULLSCRAPE, /* TCP only */
|
EVENT_FULLSCRAPE, /* TCP only */
|
||||||
EVENT_FAILED,
|
EVENT_SYNC_IN_REQUEST,
|
||||||
EVENT_BUCKET_LOCKED,
|
EVENT_SYNC_IN,
|
||||||
EVENT_WOODPECKER,
|
EVENT_SYNC_OUT_REQUEST,
|
||||||
EVENT_CONNID_MISSMATCH
|
EVENT_SYNC_OUT,
|
||||||
|
EVENT_FAILED
|
||||||
} ot_status_event;
|
} ot_status_event;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -32,8 +28,6 @@ enum {
|
|||||||
CODE_HTTPERROR_400,
|
CODE_HTTPERROR_400,
|
||||||
CODE_HTTPERROR_400_PARAM,
|
CODE_HTTPERROR_400_PARAM,
|
||||||
CODE_HTTPERROR_400_COMPACT,
|
CODE_HTTPERROR_400_COMPACT,
|
||||||
CODE_HTTPERROR_402_NOTMODEST,
|
|
||||||
CODE_HTTPERROR_402_PAYMENT_REQUIRED,
|
|
||||||
CODE_HTTPERROR_403_IP,
|
CODE_HTTPERROR_403_IP,
|
||||||
CODE_HTTPERROR_404,
|
CODE_HTTPERROR_404,
|
||||||
CODE_HTTPERROR_500,
|
CODE_HTTPERROR_500,
|
||||||
@ -41,12 +35,11 @@ enum {
|
|||||||
CODE_HTTPERROR_COUNT
|
CODE_HTTPERROR_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data);
|
void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data );
|
||||||
void stats_deliver(int64 sock, int tasktype);
|
void stats_deliver( int64 socket, int tasktype );
|
||||||
void stats_cleanup(void);
|
|
||||||
size_t return_stats_for_tracker( char *reply, int mode, int format );
|
size_t return_stats_for_tracker( char *reply, int mode, int format );
|
||||||
size_t stats_return_tracker_version( char *reply );
|
size_t stats_return_tracker_version( char *reply );
|
||||||
void stats_init(void);
|
void stats_init( );
|
||||||
void stats_deinit(void);
|
void stats_deinit( );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
42
ot_sync.c
42
ot_sync.c
@ -4,24 +4,24 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <pthread.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <pthread.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
|
#include "scan.h"
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "scan.h"
|
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_iovec.h"
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "ot_sync.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_mutex.h"
|
||||||
|
#include "ot_sync.h"
|
||||||
|
#include "ot_stats.h"
|
||||||
|
#include "ot_iovec.h"
|
||||||
|
|
||||||
#ifdef WANT_SYNC_BATCH
|
#ifdef WANT_SYNC_BATCH
|
||||||
|
|
||||||
@ -38,8 +38,7 @@ int add_changeset_to_tracker(uint8_t *data, size_t len) {
|
|||||||
|
|
||||||
/* We do know, that the string is \n terminated, so it cant
|
/* We do know, that the string is \n terminated, so it cant
|
||||||
overflow */
|
overflow */
|
||||||
if (byte_diff(data, 8, "d4:syncd"))
|
if( byte_diff( data, 8, "d4:syncd" ) ) return -1;
|
||||||
return -1;
|
|
||||||
data += 8;
|
data += 8;
|
||||||
|
|
||||||
while( 1 ) {
|
while( 1 ) {
|
||||||
@ -62,8 +61,7 @@ int add_changeset_to_tracker(uint8_t *data, size_t len) {
|
|||||||
|
|
||||||
while( peer_count > 0 ) {
|
while( peer_count > 0 ) {
|
||||||
add_peer_to_torrent( hash, (ot_peer*)data, 1 );
|
add_peer_to_torrent( hash, (ot_peer*)data, 1 );
|
||||||
data += 8;
|
data += 8; peer_count -= 8;
|
||||||
peer_count -= 8;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -86,8 +84,7 @@ static void sync_make(int *iovec_entries, struct iovec **iovector) {
|
|||||||
This works as a low watermark */
|
This works as a low watermark */
|
||||||
re = r + OT_SYNC_CHUNK_SIZE;
|
re = r + OT_SYNC_CHUNK_SIZE;
|
||||||
|
|
||||||
memmove(r, "d4:syncd", 8);
|
memmove( r, "d4:syncd", 8 ); r += 8;
|
||||||
r += 8;
|
|
||||||
|
|
||||||
/* For each bucket... */
|
/* For each bucket... */
|
||||||
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
||||||
@ -114,14 +111,10 @@ static void sync_make(int *iovec_entries, struct iovec **iovector) {
|
|||||||
re = r + OT_SYNC_CHUNK_SIZE;
|
re = r + OT_SYNC_CHUNK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*r++ = '2';
|
*r++ = '2'; *r++ = '0'; *r++ = ':';
|
||||||
*r++ = '0';
|
memmove( r, hash, sizeof( ot_hash ) ); r += sizeof( ot_hash );
|
||||||
*r++ = ':';
|
|
||||||
memmove(r, hash, sizeof(ot_hash));
|
|
||||||
r += sizeof(ot_hash);
|
|
||||||
r += sprintf( r, "%zd:", byte_count );
|
r += sprintf( r, "%zd:", byte_count );
|
||||||
memmove(r, peer_list->changeset.data, byte_count);
|
memmove( r, peer_list->changeset.data, byte_count ); r += byte_count;
|
||||||
r += byte_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All torrents done: release lock on currenct bucket */
|
/* All torrents done: release lock on currenct bucket */
|
||||||
@ -129,8 +122,7 @@ static void sync_make(int *iovec_entries, struct iovec **iovector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Close bencoded sync dictionary */
|
/* Close bencoded sync dictionary */
|
||||||
*r++ = 'e';
|
*r++='e'; *r++='e';
|
||||||
*r++ = 'e';
|
|
||||||
|
|
||||||
/* Release unused memory in current output buffer */
|
/* Release unused memory in current output buffer */
|
||||||
iovec_fixlast( iovec_entries, iovector, r );
|
iovec_fixlast( iovec_entries, iovector, r );
|
||||||
@ -170,3 +162,5 @@ void sync_deliver( int64 socket ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char *g_version_sync_c = "$Source$: $Revision$\n";
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_SYNC_H__
|
#ifndef __OT_SYNC_H__
|
||||||
#define OT_SYNC_H__
|
#define __OT_SYNC_H__
|
||||||
|
|
||||||
#ifdef WANT_SYNC_BATCH
|
#ifdef WANT_SYNC_BATCH
|
||||||
enum { SYNC_IN, SYNC_OUT };
|
enum { SYNC_IN, SYNC_OUT };
|
||||||
|
239
ot_udp.c
239
ot_udp.c
@ -4,233 +4,138 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "io.h"
|
|
||||||
#include "ip6.h"
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_rijndael.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "ot_udp.h"
|
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_udp.h"
|
||||||
|
#include "ot_stats.h"
|
||||||
|
|
||||||
|
static char static_inbuf[8192];
|
||||||
|
static char static_outbuf[8192];
|
||||||
|
|
||||||
#if 0
|
|
||||||
static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
|
static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
|
||||||
#endif
|
|
||||||
static uint32_t g_rijndael_round_key[44] = {0};
|
|
||||||
static uint32_t g_key_of_the_hour[2] = {0};
|
|
||||||
static ot_time g_hour_of_the_key;
|
|
||||||
|
|
||||||
static void udp_generate_rijndael_round_key() {
|
static void udp_make_connectionid( uint32_t * connid, const char * remoteip ) {
|
||||||
uint32_t key[16];
|
/* Touch unused variable */
|
||||||
#ifdef WANT_ARC4RANDOM
|
(void)remoteip;
|
||||||
arc4random_buf(&key[0], sizeof(key));
|
|
||||||
#else
|
|
||||||
key[0] = random();
|
|
||||||
key[1] = random();
|
|
||||||
key[2] = random();
|
|
||||||
key[3] = random();
|
|
||||||
#endif
|
|
||||||
rijndaelKeySetupEnc128(g_rijndael_round_key, (uint8_t *)key);
|
|
||||||
|
|
||||||
#ifdef WANT_ARC4RANDOM
|
/* Use a static secret for now */
|
||||||
g_key_of_the_hour[0] = arc4random();
|
memcpy( connid, g_static_connid, 8 );
|
||||||
#else
|
|
||||||
g_key_of_the_hour[0] = random();
|
|
||||||
#endif
|
|
||||||
g_hour_of_the_key = g_now_minutes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate current and previous connection id for ip */
|
static int udp_test_connectionid( const uint32_t * const connid, const char * remoteip ) {
|
||||||
static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int age) {
|
/* Touch unused variable */
|
||||||
uint32_t plain[4], crypt[4];
|
(void)remoteip;
|
||||||
int i;
|
|
||||||
if (g_now_minutes + 60 > g_hour_of_the_key) {
|
|
||||||
g_hour_of_the_key = g_now_minutes;
|
|
||||||
g_key_of_the_hour[1] = g_key_of_the_hour[0];
|
|
||||||
#ifdef WANT_ARC4RANDOM
|
|
||||||
g_key_of_the_hour[0] = arc4random();
|
|
||||||
#else
|
|
||||||
g_key_of_the_hour[0] = random();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(plain, remoteip, sizeof(plain));
|
/* Test against our static secret */
|
||||||
for (i = 0; i < 4; ++i)
|
return !memcmp( connid, g_static_connid, 8 );
|
||||||
plain[i] ^= g_key_of_the_hour[age];
|
|
||||||
rijndaelEncrypt128(g_rijndael_round_key, (uint8_t *)remoteip, (uint8_t *)crypt);
|
|
||||||
connid[0] = crypt[0] ^ crypt[1];
|
|
||||||
connid[1] = crypt[2] ^ crypt[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
|
/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
|
||||||
int handle_udp6(int64 serversocket, struct ot_workstruct *ws) {
|
void handle_udp4( int64 serversocket ) {
|
||||||
ot_ip6 remoteip;
|
ot_peer peer;
|
||||||
uint32_t *inpacket = (uint32_t *)ws->inbuf;
|
ot_torrent *torrent;
|
||||||
uint32_t *outpacket = (uint32_t *)ws->outbuf;
|
ot_hash *hash = NULL;
|
||||||
uint32_t left, event, scopeid;
|
char remoteip[4];
|
||||||
uint32_t connid[2];
|
uint32_t *inpacket = (uint32_t*)static_inbuf;
|
||||||
uint32_t action;
|
uint32_t *outpacket = (uint32_t*)static_outbuf;
|
||||||
|
uint32_t numwant, left, event;
|
||||||
uint16_t port, remoteport;
|
uint16_t port, remoteport;
|
||||||
size_t byte_count, scrape_count;
|
size_t r, r_out;
|
||||||
|
|
||||||
byte_count = socket_recv6(serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid);
|
r = socket_recv4( serversocket, static_inbuf, sizeof( static_inbuf ), remoteip, &remoteport);
|
||||||
if (!byte_count)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
stats_issue_event(EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip);
|
stats_issue_event( EVENT_ACCEPT, FLAG_UDP, ntohl(*(uint32_t*)remoteip) );
|
||||||
stats_issue_event(EVENT_READ, FLAG_UDP, byte_count);
|
stats_issue_event( EVENT_READ, FLAG_UDP, r );
|
||||||
|
|
||||||
/* Minimum udp tracker packet size, also catches error */
|
/* Minimum udp tracker packet size, also catches error */
|
||||||
if (byte_count < 16)
|
if( r < 16 )
|
||||||
return 1;
|
return;
|
||||||
|
|
||||||
/* Get action to take. Ignore error messages and broken packets */
|
/* fprintf( stderr, "UDP Connection id: %16llX\n", *(uint64_t*)inpacket ); */
|
||||||
action = ntohl(inpacket[2]);
|
|
||||||
if (action > 2)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Generate the connection id we give out and expect to and from
|
switch( ntohl( inpacket[2] ) ) {
|
||||||
the requesting ip address, this prevents udp spoofing */
|
|
||||||
udp_make_connectionid(connid, remoteip, 0);
|
|
||||||
|
|
||||||
/* Initialise hash pointer */
|
|
||||||
ws->hash = NULL;
|
|
||||||
ws->peer_id = NULL;
|
|
||||||
|
|
||||||
/* If action is not 0 (connect), then we expect the derived
|
|
||||||
connection id in first 64 bit */
|
|
||||||
if ((action > 0) && (inpacket[0] != connid[0] || inpacket[1] != connid[1])) {
|
|
||||||
/* If connection id does not match, try the one that was
|
|
||||||
valid in the previous hour. Only if this also does not
|
|
||||||
match, return an error packet */
|
|
||||||
udp_make_connectionid(connid, remoteip, 1);
|
|
||||||
if (inpacket[0] != connid[0] || inpacket[1] != connid[1]) {
|
|
||||||
const size_t s = sizeof("Connection ID missmatch.");
|
|
||||||
outpacket[0] = htonl(3);
|
|
||||||
outpacket[1] = inpacket[3];
|
|
||||||
memcpy(&outpacket[2], "Connection ID missmatch.", s);
|
|
||||||
socket_send6(serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0);
|
|
||||||
stats_issue_event(EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case 0: /* This is a connect action */
|
case 0: /* This is a connect action */
|
||||||
/* look for udp bittorrent magic id */
|
/* look for udp bittorrent magic id */
|
||||||
if( (ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980) )
|
if( (ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980) )
|
||||||
return 1;
|
return;
|
||||||
|
|
||||||
outpacket[0] = 0;
|
outpacket[0] = 0;
|
||||||
outpacket[1] = inpacket[3];
|
outpacket[1] = inpacket[3];
|
||||||
outpacket[2] = connid[0];
|
udp_make_connectionid( outpacket + 2, remoteip );
|
||||||
outpacket[3] = connid[1];
|
|
||||||
|
|
||||||
socket_send6(serversocket, ws->outbuf, 16, remoteip, remoteport, 0);
|
socket_send4( serversocket, static_outbuf, 16, remoteip, remoteport );
|
||||||
stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 );
|
stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 );
|
||||||
break;
|
break;
|
||||||
case 1: /* This is an announce action */
|
case 1: /* This is an announce action */
|
||||||
/* Minimum udp announce packet size */
|
/* Minimum udp announce packet size */
|
||||||
if (byte_count < 98)
|
if( r < 98 )
|
||||||
return 1;
|
return;
|
||||||
|
|
||||||
|
if( !udp_test_connectionid( inpacket, remoteip ))
|
||||||
|
fprintf( stderr, "UDP connect Connection id missmatch.\n" );
|
||||||
|
|
||||||
/* We do only want to know, if it is zero */
|
/* We do only want to know, if it is zero */
|
||||||
left = inpacket[64/4] | inpacket[68/4];
|
left = inpacket[64/4] | inpacket[68/4];
|
||||||
|
|
||||||
event = ntohl(inpacket[80 / 4]);
|
numwant = ntohl( inpacket[92/4] );
|
||||||
port = *(uint16_t *)(((char *)inpacket) + 96);
|
if (numwant > 200) numwant = 200;
|
||||||
ws->hash = (ot_hash *)(((char *)inpacket) + 16);
|
|
||||||
|
|
||||||
OT_SETIP(ws->peer, remoteip);
|
event = ntohl( inpacket[80/4] );
|
||||||
OT_SETPORT(ws->peer, &port);
|
port = *(uint16_t*)( static_inbuf + 96 );
|
||||||
OT_PEERFLAG(ws->peer) = 0;
|
hash = (ot_hash*)( static_inbuf + 16 );
|
||||||
|
|
||||||
|
OT_SETIP( &peer, remoteip );
|
||||||
|
OT_SETPORT( &peer, &port );
|
||||||
|
OT_FLAG( &peer ) = 0;
|
||||||
|
|
||||||
switch( event ) {
|
switch( event ) {
|
||||||
case 1:
|
case 1: OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED; break;
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
|
case 3: OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; break;
|
||||||
break;
|
default: break;
|
||||||
case 3:
|
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !left )
|
if( !left )
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_SEEDING;
|
OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
|
||||||
|
|
||||||
outpacket[0] = htonl( 1 ); /* announce action */
|
outpacket[0] = htonl( 1 ); /* announce action */
|
||||||
outpacket[1] = inpacket[12/4];
|
outpacket[1] = inpacket[12/4];
|
||||||
|
|
||||||
if (OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED) { /* Peer is gone. */
|
if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */
|
||||||
ws->reply = ws->outbuf;
|
r = remove_peer_from_torrent( hash, &peer, static_outbuf, FLAG_UDP );
|
||||||
ws->reply_size = remove_peer_from_torrent(FLAG_UDP, ws);
|
else {
|
||||||
} else {
|
torrent = add_peer_to_torrent( hash, &peer WANT_SYNC_PARAM( 0 ) );
|
||||||
/* Limit amount of peers to OT_MAX_PEERS_UDP */
|
if( !torrent )
|
||||||
uint32_t numwant = ntohl(inpacket[92 / 4]);
|
return; /* XXX maybe send error */
|
||||||
size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6;
|
|
||||||
if (numwant > max_peers)
|
|
||||||
numwant = max_peers;
|
|
||||||
|
|
||||||
ws->reply = ws->outbuf + 8;
|
r = 8 + return_peers_for_torrent( hash, numwant, static_outbuf + 8, FLAG_UDP );
|
||||||
ws->reply_size = 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP, ws, numwant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_send6(serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0);
|
socket_send4( serversocket, static_outbuf, r, remoteip, remoteport );
|
||||||
stats_issue_event(EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size);
|
stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, r );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* This is a scrape action */
|
case 2: /* This is a scrape action */
|
||||||
|
if( !udp_test_connectionid( inpacket, remoteip ))
|
||||||
|
fprintf( stderr, "UDP scrape Connection id missmatch.\n" );
|
||||||
|
|
||||||
outpacket[0] = htonl( 2 ); /* scrape action */
|
outpacket[0] = htonl( 2 ); /* scrape action */
|
||||||
outpacket[1] = inpacket[12/4];
|
outpacket[1] = inpacket[12/4];
|
||||||
|
|
||||||
for (scrape_count = 0; (scrape_count * 20 < byte_count - 16) && (scrape_count <= 74); scrape_count++)
|
for( r_out = 0; ( r_out * 20 < r - 16) && ( r_out <= 74 ); r_out++ )
|
||||||
return_udp_scrape_for_torrent(*(ot_hash *)(((char *)inpacket) + 16 + 20 * scrape_count), ((char *)outpacket) + 8 + 12 * scrape_count);
|
return_udp_scrape_for_torrent( (ot_hash*)( static_inbuf + 16 + 20 * r_out ), static_outbuf + 8 + 12 * r_out );
|
||||||
|
|
||||||
socket_send6(serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0);
|
socket_send4( serversocket, static_outbuf, 8 + 12 * r_out, remoteip, remoteport );
|
||||||
stats_issue_event(EVENT_SCRAPE, FLAG_UDP, scrape_count);
|
stats_issue_event( EVENT_SCRAPE, FLAG_UDP, r );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *udp_worker(void *args) {
|
const char *g_version_udp_c = "$Source$: $Revision$\n";
|
||||||
int64 sock = (int64)args;
|
|
||||||
struct ot_workstruct ws;
|
|
||||||
memset(&ws, 0, sizeof(ws));
|
|
||||||
|
|
||||||
ws.inbuf = malloc(G_INBUF_SIZE);
|
|
||||||
ws.outbuf = malloc(G_OUTBUF_SIZE);
|
|
||||||
#ifdef _DEBUG_HTTPERROR
|
|
||||||
ws.debugbuf = malloc(G_DEBUGBUF_SIZE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (g_opentracker_running)
|
|
||||||
handle_udp6(sock, &ws);
|
|
||||||
|
|
||||||
free(ws.inbuf);
|
|
||||||
free(ws.outbuf);
|
|
||||||
#ifdef _DEBUG_HTTPERROR
|
|
||||||
free(ws.debugbuf);
|
|
||||||
#endif
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void udp_init(int64 sock, unsigned int worker_count) {
|
|
||||||
pthread_t thread_id;
|
|
||||||
if (!g_rijndael_round_key[0])
|
|
||||||
udp_generate_rijndael_round_key();
|
|
||||||
#ifdef _DEBUG
|
|
||||||
fprintf(stderr, " installing %d workers on udp socket %ld\n", worker_count, (unsigned long)sock);
|
|
||||||
#endif
|
|
||||||
while (worker_count--)
|
|
||||||
pthread_create(&thread_id, NULL, udp_worker, (void *)sock);
|
|
||||||
}
|
|
||||||
|
7
ot_udp.h
7
ot_udp.h
@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_UDP_H__
|
#ifndef __OT_UDP_H__
|
||||||
#define OT_UDP_H__
|
#define __OT_UDP_H__
|
||||||
|
|
||||||
void udp_init(int64 sock, unsigned int worker_count);
|
void handle_udp4( int64 serversocket );
|
||||||
int handle_udp6(int64 serversocket, struct ot_workstruct *ws);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
305
ot_vector.c
305
ot_vector.c
@ -4,53 +4,69 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "trackerlogic.h"
|
#include "trackerlogic.h"
|
||||||
|
#include "ot_vector.h"
|
||||||
|
|
||||||
/* Libowfat */
|
#ifdef _DEBUG_VECTOR
|
||||||
#include "uint16.h"
|
#include <stdio.h>
|
||||||
#include "uint32.h"
|
|
||||||
|
|
||||||
static int vector_compare_peer6(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE6); }
|
static uint64_t vector_debug_inc[32];
|
||||||
static int vector_compare_peer4(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE4); }
|
static uint64_t vector_debug_noinc[32];
|
||||||
|
static uint64_t vector_debug_dec[32];
|
||||||
|
static uint64_t vector_debug_nodec[32];
|
||||||
|
static void vector_debug( size_t old_size, ssize_t diff_size, size_t old_space, ssize_t diff_space ) {
|
||||||
|
int x = 0;
|
||||||
|
while( old_space ) { old_space>>=1; ++x; }
|
||||||
|
old_size = old_size;
|
||||||
|
|
||||||
|
if( diff_size == -1 )
|
||||||
|
if( diff_space ) vector_debug_dec[x]++; else vector_debug_nodec[x]++;
|
||||||
|
else
|
||||||
|
if( diff_space ) vector_debug_inc[x]++; else vector_debug_noinc[x]++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vector_info( char * reply ) {
|
||||||
|
char * r = reply;
|
||||||
|
int i;
|
||||||
|
for( i=1; i<28; ++i )
|
||||||
|
r += sprintf( r, " inc % 12d -> % 12d: % 16lld\n", 1<<(i-1), 8<<(i-1), vector_debug_inc[i] );
|
||||||
|
for( i=1; i<28; ++i )
|
||||||
|
r += sprintf( r, "noinc % 12d -> % 12d: % 16lld\n", 1<<(i-1), 1<<(i-1), vector_debug_noinc[i] );
|
||||||
|
for( i=1; i<28; ++i )
|
||||||
|
r += sprintf( r, " dec % 12d -> % 12d: % 16lld\n", 1<<(i-1), 4<<(i-1), vector_debug_dec[i] );
|
||||||
|
for( i=1; i<28; ++i )
|
||||||
|
r += sprintf( r, "nodec % 12d -> % 12d: % 16lld\n", 1<<(i-1), 1<<(i-1), vector_debug_nodec[i] );
|
||||||
|
return r - reply;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This function gives us a binary search that returns a pointer, even if
|
/* This function gives us a binary search that returns a pointer, even if
|
||||||
no exact match is found. In that case it sets exactmatch 0 and gives
|
no exact match is found. In that case it sets exactmatch 0 and gives
|
||||||
calling functions the chance to insert data
|
calling functions the chance to insert data
|
||||||
*/
|
*/
|
||||||
void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch) {
|
void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
|
||||||
size_t interval = member_count;
|
size_t compare_size, int *exactmatch ) {
|
||||||
|
size_t mc = member_count;
|
||||||
|
uint8_t *lookat = ((uint8_t*)base) + member_size * (member_count >> 1);
|
||||||
|
*exactmatch = 1;
|
||||||
|
|
||||||
while (interval) {
|
while( mc ) {
|
||||||
uint8_t *lookat = ((uint8_t *)base) + member_size * (interval / 2);
|
|
||||||
int cmp = memcmp( lookat, key, compare_size);
|
int cmp = memcmp( lookat, key, compare_size);
|
||||||
if (cmp == 0) {
|
if (cmp == 0) return (void *)lookat;
|
||||||
base = lookat;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
base = lookat + member_size;
|
base = (void*)(lookat + member_size);
|
||||||
interval--;
|
--mc;
|
||||||
}
|
}
|
||||||
interval /= 2;
|
mc >>= 1;
|
||||||
|
lookat = ((uint8_t*)base) + member_size * (mc >> 1);
|
||||||
}
|
}
|
||||||
|
*exactmatch = 0;
|
||||||
*exactmatch = interval;
|
return (void*)lookat;
|
||||||
return (void *)base;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, int bucket_count) {
|
|
||||||
unsigned int hash = 5381;
|
|
||||||
uint8_t *p = (uint8_t *)peer;
|
|
||||||
while (compare_size--)
|
|
||||||
hash += (hash << 5) + *(p++);
|
|
||||||
return hash % bucket_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the generic insert operation for our vector type.
|
/* This is the generic insert operation for our vector type.
|
||||||
@ -62,15 +78,17 @@ static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, int bu
|
|||||||
*/
|
*/
|
||||||
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) {
|
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) {
|
||||||
uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch );
|
uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch );
|
||||||
|
#ifdef _DEBUG_VECTOR
|
||||||
|
size_t old_space = vector->space;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (*exactmatch)
|
if( *exactmatch ) return match;
|
||||||
return match;
|
|
||||||
|
|
||||||
if (vector->size + 1 > vector->space) {
|
if( vector->size + 1 >= vector->space ) {
|
||||||
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
|
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
|
||||||
uint8_t *new_data = realloc( vector->data, new_space * member_size );
|
uint8_t *new_data = realloc( vector->data, new_space * member_size );
|
||||||
if (!new_data)
|
if( !new_data ) return NULL;
|
||||||
return NULL;
|
|
||||||
/* Adjust pointer if it moved by realloc */
|
/* Adjust pointer if it moved by realloc */
|
||||||
match = new_data + (match - (uint8_t*)vector->data);
|
match = new_data + (match - (uint8_t*)vector->data);
|
||||||
|
|
||||||
@ -79,206 +97,71 @@ void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, si
|
|||||||
}
|
}
|
||||||
memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match );
|
memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match );
|
||||||
|
|
||||||
vector->size++;
|
#ifdef _DEBUG_VECTOR
|
||||||
return match;
|
vector_debug( vector->size, 1, old_space, vector->space - old_space );
|
||||||
}
|
#endif
|
||||||
|
|
||||||
ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) {
|
|
||||||
ot_peer *match, *end;
|
|
||||||
const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
|
|
||||||
size_t match_to_end;
|
|
||||||
|
|
||||||
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */
|
|
||||||
if (vector->space < vector->size)
|
|
||||||
vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
|
|
||||||
match = binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch);
|
|
||||||
|
|
||||||
if (*exactmatch)
|
|
||||||
return match;
|
|
||||||
|
|
||||||
/* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */
|
|
||||||
end = (ot_peer *)vector->data + vector->size * peer_size;
|
|
||||||
match_to_end = end - match;
|
|
||||||
|
|
||||||
if (vector->size + 1 > vector->space) {
|
|
||||||
ptrdiff_t offset = match - (ot_peer *)vector->data;
|
|
||||||
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
|
|
||||||
ot_peer *new_data = realloc(vector->data, new_space * peer_size);
|
|
||||||
|
|
||||||
if (!new_data)
|
|
||||||
return NULL;
|
|
||||||
/* Adjust pointer if it moved by realloc */
|
|
||||||
match = new_data + offset;
|
|
||||||
|
|
||||||
vector->data = new_data;
|
|
||||||
vector->space = new_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
|
|
||||||
memmove(match + peer_size, match, match_to_end);
|
|
||||||
|
|
||||||
vector->size++;
|
vector->size++;
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the non-generic delete from vector-operation specialized for peers in pools.
|
/* This is the non-generic delete from vector-operation specialized for peers in pools.
|
||||||
|
Set hysteresis == 0 if you expect the vector not to ever grow again.
|
||||||
It returns 0 if no peer was found (and thus not removed)
|
It returns 0 if no peer was found (and thus not removed)
|
||||||
1 if a non-seeding peer was removed
|
1 if a non-seeding peer was removed
|
||||||
2 if a seeding peer was removed
|
2 if a seeding peer was removed
|
||||||
*/
|
*/
|
||||||
int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size) {
|
int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) {
|
||||||
int exactmatch, was_seeder;
|
int exactmatch;
|
||||||
ot_peer *match, *end;
|
size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO;
|
||||||
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
|
ot_peer *end = ((ot_peer*)vector->data) + vector->size;
|
||||||
|
ot_peer *match;
|
||||||
|
#ifdef _DEBUG_VECTOR
|
||||||
|
size_t old_space = vector->space;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!vector->size)
|
if( !vector->size ) return 0;
|
||||||
return 0;
|
match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
|
||||||
|
|
||||||
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */
|
if( !exactmatch ) return 0;
|
||||||
if (vector->space < vector->size)
|
exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
|
||||||
vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
|
memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
|
||||||
|
if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
|
||||||
end = ((ot_peer *)vector->data) + peer_size * vector->size;
|
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
||||||
match = (ot_peer *)binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch);
|
vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
|
||||||
if (!exactmatch)
|
}
|
||||||
return 0;
|
if( !vector->size ) {
|
||||||
|
/* for peer pools its safe to let them go,
|
||||||
was_seeder = (OT_PEERFLAG_D(match, peer_size) & PEER_FLAG_SEEDING) ? 2 : 1;
|
in 999 of 1000 this happens in older pools, that won't ever grow again */
|
||||||
memmove(match, match + peer_size, end - match - peer_size);
|
free( vector->data );
|
||||||
|
vector->data = NULL;
|
||||||
vector->size--;
|
vector->space = 0;
|
||||||
vector_fixup_peers(vector, peer_size);
|
}
|
||||||
return was_seeder;
|
#ifdef _DEBUG_VECTOR
|
||||||
|
vector_debug( vector->size+1, -1, old_space, vector->space - old_space );
|
||||||
|
#endif
|
||||||
|
return exactmatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
|
void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
|
||||||
ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
|
ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
|
||||||
|
#ifdef _DEBUG_VECTOR
|
||||||
|
size_t old_space = vector->space;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!vector->size)
|
if( !vector->size ) return;
|
||||||
return;
|
|
||||||
|
|
||||||
/* If this is being called after a unsuccessful malloc() for peer_list
|
/* If this is being called after a unsuccessful malloc() for peer_list
|
||||||
in add_peer_to_torrent, match->peer_list actually might be NULL */
|
in add_peer_to_torrent, match->peer_list actually might be NULL */
|
||||||
free_peerlist(match->peer_list6);
|
if( match->peer_list) free_peerlist( match->peer_list );
|
||||||
free_peerlist(match->peer_list4);
|
|
||||||
|
|
||||||
memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
|
memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
|
||||||
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
|
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
|
||||||
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
||||||
vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
|
vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
|
||||||
}
|
}
|
||||||
|
#ifdef _DEBUG_VECTOR
|
||||||
|
vector_debug( vector->size+1, -1, old_space, vector->space - old_space );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void vector_clean_list(ot_vector *vector, int num_buckets) {
|
const char *g_version_vector_c = "$Source$: $Revision$\n";
|
||||||
while (num_buckets--)
|
|
||||||
free(vector[num_buckets].data);
|
|
||||||
free(vector);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) {
|
|
||||||
int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
|
|
||||||
ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers;
|
|
||||||
int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
|
|
||||||
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list)) {
|
|
||||||
num_buckets_old = peer_list->peers.size;
|
|
||||||
bucket_list_old = peer_list->peers.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peer_list->peer_count < 255)
|
|
||||||
num_buckets_new = 1;
|
|
||||||
else if (peer_list->peer_count > 8192)
|
|
||||||
num_buckets_new = 64;
|
|
||||||
else if (peer_list->peer_count >= 512 && peer_list->peer_count < 4096)
|
|
||||||
num_buckets_new = 16;
|
|
||||||
else if (peer_list->peer_count < 512 && num_buckets_old <= 16)
|
|
||||||
num_buckets_new = num_buckets_old;
|
|
||||||
else if (peer_list->peer_count < 512)
|
|
||||||
num_buckets_new = 1;
|
|
||||||
else if (peer_list->peer_count < 8192 && num_buckets_old > 1)
|
|
||||||
num_buckets_new = num_buckets_old;
|
|
||||||
else
|
|
||||||
num_buckets_new = 16;
|
|
||||||
|
|
||||||
if (num_buckets_new == num_buckets_old)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Assume near perfect distribution */
|
|
||||||
bucket_list_new = malloc(num_buckets_new * sizeof(ot_vector));
|
|
||||||
if (!bucket_list_new)
|
|
||||||
return;
|
|
||||||
bzero(bucket_list_new, num_buckets_new * sizeof(ot_vector));
|
|
||||||
|
|
||||||
tmp = peer_list->peer_count / num_buckets_new;
|
|
||||||
bucket_size_new = OT_VECTOR_MIN_MEMBERS;
|
|
||||||
while (bucket_size_new < tmp)
|
|
||||||
bucket_size_new *= OT_VECTOR_GROW_RATIO;
|
|
||||||
|
|
||||||
/* preallocate vectors to hold all peers */
|
|
||||||
for (bucket = 0; bucket < num_buckets_new; ++bucket) {
|
|
||||||
bucket_list_new[bucket].space = bucket_size_new;
|
|
||||||
bucket_list_new[bucket].data = malloc(bucket_size_new * peer_size);
|
|
||||||
if (!bucket_list_new[bucket].data)
|
|
||||||
return vector_clean_list(bucket_list_new, num_buckets_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now sort them into the correct bucket */
|
|
||||||
for (bucket = 0; bucket < num_buckets_old; ++bucket) {
|
|
||||||
ot_peer *peers_old = bucket_list_old[bucket].data;
|
|
||||||
int peer_count_old = bucket_list_old[bucket].size;
|
|
||||||
while (peer_count_old--) {
|
|
||||||
ot_vector *bucket_dest = bucket_list_new;
|
|
||||||
if (num_buckets_new > 1)
|
|
||||||
bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new);
|
|
||||||
if (bucket_dest->size + 1 > bucket_dest->space) {
|
|
||||||
void *tmp = realloc(bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space);
|
|
||||||
if (!tmp)
|
|
||||||
return vector_clean_list(bucket_list_new, num_buckets_new);
|
|
||||||
bucket_dest->data = tmp;
|
|
||||||
bucket_dest->space *= OT_VECTOR_GROW_RATIO;
|
|
||||||
}
|
|
||||||
memcpy((ot_peer *)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
|
|
||||||
peers_old += peer_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now sort each bucket to later allow bsearch */
|
|
||||||
for (bucket = 0; bucket < num_buckets_new; ++bucket)
|
|
||||||
qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func);
|
|
||||||
|
|
||||||
/* Everything worked fine. Now link new bucket_list to peer_list */
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list))
|
|
||||||
vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
|
|
||||||
else
|
|
||||||
free(peer_list->peers.data);
|
|
||||||
|
|
||||||
if (num_buckets_new > 1) {
|
|
||||||
peer_list->peers.data = bucket_list_new;
|
|
||||||
peer_list->peers.size = num_buckets_new;
|
|
||||||
peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */
|
|
||||||
} else {
|
|
||||||
peer_list->peers.data = bucket_list_new->data;
|
|
||||||
peer_list->peers.size = bucket_list_new->size;
|
|
||||||
peer_list->peers.space = bucket_list_new->space;
|
|
||||||
free(bucket_list_new);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vector_fixup_peers(ot_vector *vector, size_t peer_size) {
|
|
||||||
int need_fix = 0;
|
|
||||||
|
|
||||||
if (!vector->size) {
|
|
||||||
free(vector->data);
|
|
||||||
vector->data = NULL;
|
|
||||||
vector->space = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) {
|
|
||||||
vector->space /= OT_VECTOR_SHRINK_RATIO;
|
|
||||||
need_fix++;
|
|
||||||
}
|
|
||||||
if (need_fix)
|
|
||||||
vector->data = realloc(vector->data, vector->space * peer_size);
|
|
||||||
}
|
|
||||||
|
20
ot_vector.h
20
ot_vector.h
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_VECTOR_H__
|
#ifndef __OT_VECTOR_H__
|
||||||
#define OT_VECTOR_H__
|
#define __OT_VECTOR_H__
|
||||||
|
|
||||||
/* These defines control vectors behaviour */
|
/* These defines control vectors behaviour */
|
||||||
#define OT_VECTOR_MIN_MEMBERS 2
|
#define OT_VECTOR_MIN_MEMBERS 2
|
||||||
@ -12,25 +12,21 @@
|
|||||||
#define OT_VECTOR_SHRINK_THRESH 4
|
#define OT_VECTOR_SHRINK_THRESH 4
|
||||||
#define OT_VECTOR_SHRINK_RATIO 2
|
#define OT_VECTOR_SHRINK_RATIO 2
|
||||||
|
|
||||||
#define OT_PEER_BUCKET_MINCOUNT 512
|
|
||||||
#define OT_PEER_BUCKET_MAXCOUNT 256
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *data;
|
void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t space;
|
size_t space;
|
||||||
} ot_vector;
|
} ot_vector;
|
||||||
|
|
||||||
void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch);
|
void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
|
||||||
|
size_t compare_size, int *exactmatch );
|
||||||
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch );
|
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch );
|
||||||
ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch);
|
|
||||||
|
|
||||||
int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size);
|
int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis );
|
||||||
void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
|
void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
|
||||||
|
|
||||||
/* For ot_clean.c */
|
#ifdef _DEBUG_VECTOR
|
||||||
void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size);
|
size_t vector_info( char * reply );
|
||||||
void vector_fixup_peers(ot_vector *vector, size_t peer_size);
|
#endif
|
||||||
void vector_clean_list(ot_vector *vector, int num_buckets);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
896
proxy.c
896
proxy.c
@ -1,896 +0,0 @@
|
|||||||
/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
|
|
||||||
It is considered beerware. Prost. Skol. Cheers or whatever.
|
|
||||||
|
|
||||||
$Id$ */
|
|
||||||
|
|
||||||
/* System */
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* Libowfat */
|
|
||||||
#include "byte.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "iob.h"
|
|
||||||
#include "ip6.h"
|
|
||||||
#include "ndelay.h"
|
|
||||||
#include "scan.h"
|
|
||||||
#include "socket.h"
|
|
||||||
|
|
||||||
/* Opentracker */
|
|
||||||
#include "ot_mutex.h"
|
|
||||||
#include "ot_stats.h"
|
|
||||||
#include "ot_vector.h"
|
|
||||||
#include "trackerlogic.h"
|
|
||||||
|
|
||||||
#ifndef WANT_SYNC_LIVE
|
|
||||||
#define WANT_SYNC_LIVE
|
|
||||||
#endif
|
|
||||||
#include "ot_livesync.h"
|
|
||||||
|
|
||||||
ot_ip6 g_serverip;
|
|
||||||
uint16_t g_serverport = 9009;
|
|
||||||
uint32_t g_tracker_id;
|
|
||||||
char groupip_1[4] = {224, 0, 23, 5};
|
|
||||||
int g_self_pipe[2];
|
|
||||||
|
|
||||||
/* If you have more than 10 peers, don't use this proxy
|
|
||||||
Use 20 slots for 10 peers to have room for 10 incoming connection slots
|
|
||||||
*/
|
|
||||||
#define MAX_PEERS 20
|
|
||||||
|
|
||||||
#define LIVESYNC_INCOMING_BUFFSIZE (256 * 256)
|
|
||||||
#define STREAMSYNC_OUTGOING_BUFFSIZE (256 * 256)
|
|
||||||
|
|
||||||
#define LIVESYNC_OUTGOING_BUFFSIZE_PEERS 1480
|
|
||||||
#define LIVESYNC_OUTGOING_WATERMARK_PEERS (sizeof(ot_peer) + sizeof(ot_hash))
|
|
||||||
#define LIVESYNC_MAXDELAY 15 /* seconds */
|
|
||||||
|
|
||||||
/* The amount of time a complete sync cycle should take */
|
|
||||||
#define OT_SYNC_INTERVAL_MINUTES 2
|
|
||||||
|
|
||||||
/* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */
|
|
||||||
#define OT_SYNC_SLEEP (((OT_SYNC_INTERVAL_MINUTES) * 60 * 1000000) / (OT_BUCKET_COUNT))
|
|
||||||
|
|
||||||
enum { OT_SYNC_PEER4, OT_SYNC_PEER6 };
|
|
||||||
enum { FLAG_SERVERSOCKET = 1 };
|
|
||||||
|
|
||||||
/* For incoming packets */
|
|
||||||
static int64 g_socket_in = -1;
|
|
||||||
static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE];
|
|
||||||
|
|
||||||
/* For outgoing packets */
|
|
||||||
static int64 g_socket_out = -1;
|
|
||||||
static uint8_t g_peerbuffer_start[LIVESYNC_OUTGOING_BUFFSIZE_PEERS];
|
|
||||||
static uint8_t *g_peerbuffer_pos;
|
|
||||||
static uint8_t *g_peerbuffer_highwater = g_peerbuffer_start + LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS;
|
|
||||||
static ot_time g_next_packet_time;
|
|
||||||
|
|
||||||
static void *livesync_worker(void *args);
|
|
||||||
static void *streamsync_worker(void *args);
|
|
||||||
static void livesync_proxytell(uint8_t prefix, uint8_t *info_hash, uint8_t *peer);
|
|
||||||
|
|
||||||
void exerr(char *message) {
|
|
||||||
fprintf(stderr, "%s\n", message);
|
|
||||||
exit(111);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) {
|
|
||||||
(void)event;
|
|
||||||
(void)proto;
|
|
||||||
(void)event_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void livesync_bind_mcast(ot_ip6 ip, uint16_t port) {
|
|
||||||
char tmpip[4] = {0, 0, 0, 0};
|
|
||||||
char *v4ip;
|
|
||||||
|
|
||||||
if (!ip6_isv4mapped(ip))
|
|
||||||
exerr("v6 mcast support not yet available.");
|
|
||||||
v4ip = ip + 12;
|
|
||||||
|
|
||||||
if (g_socket_in != -1)
|
|
||||||
exerr("Error: Livesync listen ip specified twice.");
|
|
||||||
|
|
||||||
if ((g_socket_in = socket_udp4()) < 0)
|
|
||||||
exerr("Error: Cant create live sync incoming socket.");
|
|
||||||
ndelay_off(g_socket_in);
|
|
||||||
|
|
||||||
if (socket_bind4_reuse(g_socket_in, tmpip, port) == -1)
|
|
||||||
exerr("Error: Cant bind live sync incoming socket.");
|
|
||||||
|
|
||||||
if (socket_mcjoin4(g_socket_in, groupip_1, v4ip))
|
|
||||||
exerr("Error: Cant make live sync incoming socket join mcast group.");
|
|
||||||
|
|
||||||
if ((g_socket_out = socket_udp4()) < 0)
|
|
||||||
exerr("Error: Cant create live sync outgoing socket.");
|
|
||||||
if (socket_bind4_reuse(g_socket_out, v4ip, port) == -1)
|
|
||||||
exerr("Error: Cant bind live sync outgoing socket.");
|
|
||||||
|
|
||||||
socket_mcttl4(g_socket_out, 1);
|
|
||||||
socket_mcloop4(g_socket_out, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t add_peer_to_torrent_proxy(ot_hash hash, ot_peer *peer, size_t peer_size) {
|
|
||||||
int exactmatch;
|
|
||||||
ot_torrent *torrent;
|
|
||||||
ot_peerlist *peer_list;
|
|
||||||
ot_peer *peer_dest;
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash);
|
|
||||||
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
|
|
||||||
|
|
||||||
torrent = vector_find_or_insert(torrents_list, (void *)hash, sizeof(ot_torrent), compare_size, &exactmatch);
|
|
||||||
if (!torrent)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!exactmatch) {
|
|
||||||
/* Create a new torrent entry, then */
|
|
||||||
memcpy(torrent->hash, hash, sizeof(ot_hash));
|
|
||||||
|
|
||||||
if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
|
|
||||||
vector_remove_torrent(torrents_list, torrent);
|
|
||||||
mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
|
|
||||||
byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
|
|
||||||
}
|
|
||||||
|
|
||||||
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
|
|
||||||
|
|
||||||
/* Check for peer in torrent */
|
|
||||||
peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer, peer_size, &exactmatch);
|
|
||||||
if (!peer_dest) {
|
|
||||||
mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Tell peer that it's fresh */
|
|
||||||
OT_PEERTIME(peer, peer_size) = 0;
|
|
||||||
|
|
||||||
/* If we hadn't had a match create peer there */
|
|
||||||
if (!exactmatch) {
|
|
||||||
peer_list->peer_count++;
|
|
||||||
if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING)
|
|
||||||
peer_list->seed_count++;
|
|
||||||
}
|
|
||||||
memcpy(peer_dest, peer, peer_size);
|
|
||||||
mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t remove_peer_from_torrent_proxy(ot_hash hash, ot_peer *peer, size_t peer_size) {
|
|
||||||
int exactmatch;
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash);
|
|
||||||
ot_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
|
|
||||||
|
|
||||||
if (exactmatch) {
|
|
||||||
ot_peerlist *peer_list = peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
|
|
||||||
switch (vector_remove_peer(&peer_list->peers, peer, peer_size)) {
|
|
||||||
case 2:
|
|
||||||
peer_list->seed_count--; /* Intentional fallthrough */
|
|
||||||
case 1:
|
|
||||||
peer_list->peer_count--; /* Intentional fallthrough */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_peerlist(ot_peerlist *peer_list) {
|
|
||||||
if (peer_list->peers.data) {
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list)) {
|
|
||||||
ot_vector *bucket_list = (ot_vector *)(peer_list->peers.data);
|
|
||||||
|
|
||||||
while (peer_list->peers.size--)
|
|
||||||
free(bucket_list++->data);
|
|
||||||
}
|
|
||||||
free(peer_list->peers.data);
|
|
||||||
}
|
|
||||||
free(peer_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void livesync_handle_peersync(ssize_t datalen, size_t peer_size) {
|
|
||||||
int off = sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
|
|
||||||
fprintf(stderr, ".");
|
|
||||||
|
|
||||||
while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= datalen) {
|
|
||||||
ot_peer *peer = (ot_peer *)(g_inbuffer + off + sizeof(ot_hash));
|
|
||||||
ot_hash *hash = (ot_hash *)(g_inbuffer + off);
|
|
||||||
|
|
||||||
if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_STOPPED)
|
|
||||||
remove_peer_from_torrent_proxy(*hash, peer, peer_size);
|
|
||||||
else
|
|
||||||
add_peer_to_torrent_proxy(*hash, peer, peer_size);
|
|
||||||
|
|
||||||
off += sizeof(ot_hash) + peer_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int usage(char *self) {
|
|
||||||
fprintf(stderr, "Usage: %s -L <livesync_iface_ip> -l <listenip>:<listenport> -c <connectip>:<connectport>\n", self);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
FLAG_OUTGOING = 0x80,
|
|
||||||
|
|
||||||
FLAG_DISCONNECTED = 0x00,
|
|
||||||
FLAG_CONNECTING = 0x01,
|
|
||||||
FLAG_WAITTRACKERID = 0x02,
|
|
||||||
FLAG_CONNECTED = 0x03,
|
|
||||||
|
|
||||||
FLAG_MASK = 0x07
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PROXYPEER_NEEDSCONNECT(flag) ((flag) == FLAG_OUTGOING)
|
|
||||||
#define PROXYPEER_ISCONNECTED(flag) (((flag) & FLAG_MASK) == FLAG_CONNECTED)
|
|
||||||
#define PROXYPEER_SETDISCONNECTED(flag) (flag) = (((flag) & FLAG_OUTGOING) | FLAG_DISCONNECTED)
|
|
||||||
#define PROXYPEER_SETCONNECTING(flag) (flag) = (((flag) & FLAG_OUTGOING) | FLAG_CONNECTING)
|
|
||||||
#define PROXYPEER_SETWAITTRACKERID(flag) (flag) = (((flag) & FLAG_OUTGOING) | FLAG_WAITTRACKERID)
|
|
||||||
#define PROXYPEER_SETCONNECTED(flag) (flag) = (((flag) & FLAG_OUTGOING) | FLAG_CONNECTED)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int state; /* Whether we want to connect, how far our handshake is, etc. */
|
|
||||||
ot_ip6 ip; /* The peer to connect to */
|
|
||||||
uint16_t port; /* The peers port */
|
|
||||||
uint8_t indata[8192 * 16]; /* Any data not processed yet */
|
|
||||||
size_t indata_length; /* Length of unprocessed data */
|
|
||||||
uint32_t tracker_id; /* How the other end greeted */
|
|
||||||
int64 fd; /* A file handle, if connected, <= 0 is disconnected (0 initially, -1 else) */
|
|
||||||
io_batch outdata; /* The iobatch containing our sync data */
|
|
||||||
|
|
||||||
size_t packet_tcount; /* Number of unprocessed torrents in packet we currently receive */
|
|
||||||
uint8_t packet_tprefix; /* Prefix byte for all torrents in current packet */
|
|
||||||
uint8_t packet_type; /* Type of current packet */
|
|
||||||
uint32_t packet_tid; /* Tracker id for current packet */
|
|
||||||
|
|
||||||
} proxy_peer;
|
|
||||||
static void process_indata(proxy_peer *peer);
|
|
||||||
|
|
||||||
void reset_info_block(proxy_peer *peer) {
|
|
||||||
peer->indata_length = 0;
|
|
||||||
peer->tracker_id = 0;
|
|
||||||
peer->fd = -1;
|
|
||||||
peer->packet_tcount = 0;
|
|
||||||
iob_reset(&peer->outdata);
|
|
||||||
PROXYPEER_SETDISCONNECTED(peer->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Number of connections to peers
|
|
||||||
* If a peer's IP is set, we try to reconnect, when the connection drops
|
|
||||||
* If we already have a connected tracker_id in our records for an _incoming_ connection, drop it
|
|
||||||
* Multiple connections to/from the same ip are okay, if tracker_id doesn't match
|
|
||||||
* Reconnect attempts occur only twice a minute
|
|
||||||
*/
|
|
||||||
static int g_connection_count;
|
|
||||||
static ot_time g_connection_reconn;
|
|
||||||
static proxy_peer g_connections[MAX_PEERS];
|
|
||||||
|
|
||||||
static void handle_reconnects(void) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < g_connection_count; ++i)
|
|
||||||
if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) {
|
|
||||||
int64 newfd = socket_tcp6();
|
|
||||||
fprintf(stderr, "(Re)connecting to peer...");
|
|
||||||
if (newfd < 0)
|
|
||||||
continue; /* No socket for you */
|
|
||||||
io_fd(newfd);
|
|
||||||
if (socket_bind6_reuse(newfd, g_serverip, g_serverport, 0)) {
|
|
||||||
io_close(newfd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (socket_connect6(newfd, g_connections[i].ip, g_connections[i].port, 0) == -1 && errno != EINPROGRESS && errno != EWOULDBLOCK) {
|
|
||||||
close(newfd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
io_wantwrite(newfd); /* So we will be informed when it is connected */
|
|
||||||
io_setcookie(newfd, g_connections + i);
|
|
||||||
|
|
||||||
/* Prepare connection info block */
|
|
||||||
reset_info_block(g_connections + i);
|
|
||||||
g_connections[i].fd = newfd;
|
|
||||||
PROXYPEER_SETCONNECTING(g_connections[i].state);
|
|
||||||
}
|
|
||||||
g_connection_reconn = time(NULL) + 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle incoming connection requests, check against whitelist */
|
|
||||||
static void handle_accept(int64 serversocket) {
|
|
||||||
int64 newfd;
|
|
||||||
ot_ip6 ip;
|
|
||||||
uint16 port;
|
|
||||||
|
|
||||||
while ((newfd = socket_accept6(serversocket, ip, &port, NULL)) != -1) {
|
|
||||||
|
|
||||||
/* XXX some access control */
|
|
||||||
|
|
||||||
/* Put fd into a non-blocking mode */
|
|
||||||
io_nonblock(newfd);
|
|
||||||
|
|
||||||
if (!io_fd(newfd))
|
|
||||||
io_close(newfd);
|
|
||||||
else {
|
|
||||||
/* Find a new home for our incoming connection */
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < MAX_PEERS; ++i)
|
|
||||||
if (g_connections[i].state == FLAG_DISCONNECTED)
|
|
||||||
break;
|
|
||||||
if (i == MAX_PEERS) {
|
|
||||||
fprintf(stderr, "No room for incoming connection.");
|
|
||||||
close(newfd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare connection info block */
|
|
||||||
reset_info_block(g_connections + i);
|
|
||||||
PROXYPEER_SETCONNECTING(g_connections[i].state);
|
|
||||||
g_connections[i].port = port;
|
|
||||||
g_connections[i].fd = newfd;
|
|
||||||
|
|
||||||
io_setcookie(newfd, g_connections + i);
|
|
||||||
|
|
||||||
/* We expect the connecting side to begin with its tracker_id */
|
|
||||||
io_wantread(newfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* New sync data on the stream */
|
|
||||||
static void handle_read(int64 peersocket) {
|
|
||||||
int i;
|
|
||||||
int64 datalen;
|
|
||||||
uint32_t tracker_id;
|
|
||||||
proxy_peer *peer = io_getcookie(peersocket);
|
|
||||||
|
|
||||||
if (!peer) {
|
|
||||||
/* Can't happen ;) */
|
|
||||||
io_close(peersocket);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (peer->state & FLAG_MASK) {
|
|
||||||
case FLAG_DISCONNECTED:
|
|
||||||
io_close(peersocket);
|
|
||||||
break; /* Shouldnt happen */
|
|
||||||
case FLAG_CONNECTING:
|
|
||||||
case FLAG_WAITTRACKERID:
|
|
||||||
/* We want at least the first four bytes to come at once, to avoid keeping extra states (for now)
|
|
||||||
This also catches 0 bytes reads == EOF and negative values, denoting connection errors */
|
|
||||||
if (io_tryread(peersocket, (void *)&tracker_id, sizeof(tracker_id)) != sizeof(tracker_id))
|
|
||||||
goto close_socket;
|
|
||||||
|
|
||||||
/* See, if we already have a connection to that peer */
|
|
||||||
for (i = 0; i < MAX_PEERS; ++i)
|
|
||||||
if ((g_connections[i].state & FLAG_MASK) == FLAG_CONNECTED && g_connections[i].tracker_id == tracker_id) {
|
|
||||||
fprintf(stderr, "Peer already connected. Closing connection.\n");
|
|
||||||
goto close_socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Also no need for soliloquy */
|
|
||||||
if (tracker_id == g_tracker_id)
|
|
||||||
goto close_socket;
|
|
||||||
|
|
||||||
/* The new connection is good, send our tracker_id on incoming connections */
|
|
||||||
if (peer->state == FLAG_CONNECTING)
|
|
||||||
if (io_trywrite(peersocket, (void *)&g_tracker_id, sizeof(g_tracker_id)) != sizeof(g_tracker_id))
|
|
||||||
goto close_socket;
|
|
||||||
|
|
||||||
peer->tracker_id = tracker_id;
|
|
||||||
PROXYPEER_SETCONNECTED(peer->state);
|
|
||||||
|
|
||||||
if (peer->state & FLAG_OUTGOING)
|
|
||||||
fprintf(stderr, "succeeded.\n");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "Incoming connection successful.\n");
|
|
||||||
|
|
||||||
break;
|
|
||||||
close_socket:
|
|
||||||
fprintf(stderr, "Handshake incomplete, closing socket\n");
|
|
||||||
io_close(peersocket);
|
|
||||||
reset_info_block(peer);
|
|
||||||
break;
|
|
||||||
case FLAG_CONNECTED:
|
|
||||||
/* Here we acutally expect data from peer
|
|
||||||
indata_length should be less than 20+256*7 bytes, for incomplete torrent entries */
|
|
||||||
datalen = io_tryread(peersocket, (void *)(peer->indata + peer->indata_length), sizeof(peer->indata) - peer->indata_length);
|
|
||||||
if (!datalen || datalen < -1) {
|
|
||||||
fprintf(stderr, "Connection closed by remote peer.\n");
|
|
||||||
io_close(peersocket);
|
|
||||||
reset_info_block(peer);
|
|
||||||
} else if (datalen > 0) {
|
|
||||||
peer->indata_length += datalen;
|
|
||||||
process_indata(peer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can write new sync data to the stream */
|
|
||||||
static void handle_write(int64 peersocket) {
|
|
||||||
proxy_peer *peer = io_getcookie(peersocket);
|
|
||||||
|
|
||||||
if (!peer) {
|
|
||||||
/* Can't happen ;) */
|
|
||||||
io_close(peersocket);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (peer->state & FLAG_MASK) {
|
|
||||||
case FLAG_DISCONNECTED:
|
|
||||||
default: /* Should not happen */
|
|
||||||
io_close(peersocket);
|
|
||||||
break;
|
|
||||||
case FLAG_CONNECTING:
|
|
||||||
/* Ensure that the connection is established and handle connection error */
|
|
||||||
if (peer->state & FLAG_OUTGOING && !socket_connected(peersocket)) {
|
|
||||||
fprintf(stderr, "failed\n");
|
|
||||||
reset_info_block(peer);
|
|
||||||
io_close(peersocket);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (io_trywrite(peersocket, (void *)&g_tracker_id, sizeof(g_tracker_id)) == sizeof(g_tracker_id)) {
|
|
||||||
PROXYPEER_SETWAITTRACKERID(peer->state);
|
|
||||||
io_dontwantwrite(peersocket);
|
|
||||||
io_wantread(peersocket);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Handshake incomplete, closing socket\n");
|
|
||||||
io_close(peersocket);
|
|
||||||
reset_info_block(peer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FLAG_CONNECTED:
|
|
||||||
switch (iob_send(peersocket, &peer->outdata)) {
|
|
||||||
case 0: /* all data sent */
|
|
||||||
io_dontwantwrite(peersocket);
|
|
||||||
break;
|
|
||||||
case -3: /* an error occured */
|
|
||||||
io_close(peersocket);
|
|
||||||
reset_info_block(peer);
|
|
||||||
break;
|
|
||||||
default: /* Normal operation or eagain */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server_mainloop() {
|
|
||||||
int64 sock;
|
|
||||||
|
|
||||||
/* inlined livesync_init() */
|
|
||||||
memset(g_peerbuffer_start, 0, sizeof(g_peerbuffer_start));
|
|
||||||
g_peerbuffer_pos = g_peerbuffer_start;
|
|
||||||
memcpy(g_peerbuffer_pos, &g_tracker_id, sizeof(g_tracker_id));
|
|
||||||
uint32_pack_big((char *)g_peerbuffer_pos + sizeof(g_tracker_id), OT_SYNC_PEER);
|
|
||||||
g_peerbuffer_pos += sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
g_next_packet_time = time(NULL) + LIVESYNC_MAXDELAY;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* See if we need to connect to anyone */
|
|
||||||
if (time(NULL) > g_connection_reconn)
|
|
||||||
handle_reconnects();
|
|
||||||
|
|
||||||
/* Wait for io events until next approx reconn check time */
|
|
||||||
io_waituntil2(30 * 1000);
|
|
||||||
|
|
||||||
/* Loop over readable sockets */
|
|
||||||
while ((sock = io_canread()) != -1) {
|
|
||||||
const void *cookie = io_getcookie(sock);
|
|
||||||
if ((uintptr_t)cookie == FLAG_SERVERSOCKET)
|
|
||||||
handle_accept(sock);
|
|
||||||
else
|
|
||||||
handle_read(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop over writable sockets */
|
|
||||||
while ((sock = io_canwrite()) != -1)
|
|
||||||
handle_write(sock);
|
|
||||||
|
|
||||||
livesync_ticker();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void panic(const char *routine) {
|
|
||||||
fprintf(stderr, "%s: %s\n", routine, strerror(errno));
|
|
||||||
exit(111);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t ot_try_bind(ot_ip6 ip, uint16_t port) {
|
|
||||||
int64 sock = socket_tcp6();
|
|
||||||
|
|
||||||
if (socket_bind6_reuse(sock, ip, port, 0) == -1)
|
|
||||||
panic("socket_bind6_reuse");
|
|
||||||
|
|
||||||
if (socket_listen(sock, SOMAXCONN) == -1)
|
|
||||||
panic("socket_listen");
|
|
||||||
|
|
||||||
if (!io_fd(sock))
|
|
||||||
panic("io_fd");
|
|
||||||
|
|
||||||
io_setcookie(sock, (void *)FLAG_SERVERSOCKET);
|
|
||||||
io_wantread(sock);
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int scan_ip6_port(const char *src, ot_ip6 ip, uint16 *port) {
|
|
||||||
const char *s = src;
|
|
||||||
int off, bracket = 0;
|
|
||||||
while (isspace(*s))
|
|
||||||
++s;
|
|
||||||
if (*s == '[')
|
|
||||||
++s, ++bracket; /* for v6 style notation */
|
|
||||||
if (!(off = scan_ip6(s, ip)))
|
|
||||||
return 0;
|
|
||||||
s += off;
|
|
||||||
if (*s == 0 || isspace(*s))
|
|
||||||
return s - src;
|
|
||||||
if (*s == ']' && bracket)
|
|
||||||
++s;
|
|
||||||
if (!ip6_isv4mapped(ip)) {
|
|
||||||
if ((bracket && *(s) != ':') || (*(s) != '.'))
|
|
||||||
return 0;
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
if (*(s++) != ':')
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!(off = scan_ushort(s, port)))
|
|
||||||
return 0;
|
|
||||||
return off + s - src;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
static pthread_t sync_in_thread_id;
|
|
||||||
static pthread_t sync_out_thread_id;
|
|
||||||
ot_ip6 serverip;
|
|
||||||
uint16_t tmpport;
|
|
||||||
int scanon = 1, lbound = 0, sbound = 0;
|
|
||||||
|
|
||||||
srandom(time(NULL));
|
|
||||||
#ifdef WANT_ARC4RANDOM
|
|
||||||
g_tracker_id = arc4random();
|
|
||||||
#else
|
|
||||||
g_tracker_id = random();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (scanon) {
|
|
||||||
switch (getopt(argc, argv, ":l:c:L:h")) {
|
|
||||||
case -1:
|
|
||||||
scanon = 0;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
tmpport = 0;
|
|
||||||
if (!scan_ip6_port(optarg, serverip, &tmpport) || !tmpport) {
|
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ot_try_bind(serverip, tmpport);
|
|
||||||
++sbound;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
if (g_connection_count > MAX_PEERS / 2)
|
|
||||||
exerr("Connection limit exceeded.\n");
|
|
||||||
tmpport = 0;
|
|
||||||
if (!scan_ip6_port(optarg, g_connections[g_connection_count].ip, &g_connections[g_connection_count].port) || !g_connections[g_connection_count].port) {
|
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
g_connections[g_connection_count++].state = FLAG_OUTGOING;
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
tmpport = 9696;
|
|
||||||
if (!scan_ip6_port(optarg, serverip, &tmpport) || !tmpport) {
|
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
livesync_bind_mcast(serverip, tmpport);
|
|
||||||
++lbound;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case '?':
|
|
||||||
usage(argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lbound)
|
|
||||||
exerr("No livesync port bound.");
|
|
||||||
if (!g_connection_count && !sbound)
|
|
||||||
exerr("No streamsync port bound.");
|
|
||||||
pthread_create(&sync_in_thread_id, NULL, livesync_worker, NULL);
|
|
||||||
pthread_create(&sync_out_thread_id, NULL, streamsync_worker, NULL);
|
|
||||||
|
|
||||||
server_mainloop();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *streamsync_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
while (1) {
|
|
||||||
int bucket;
|
|
||||||
/* For each bucket... */
|
|
||||||
for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
|
|
||||||
/* Get exclusive access to that bucket */
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock(bucket);
|
|
||||||
size_t tor_offset, count_def = 0, count_one = 0, count_two = 0, count_peers = 0;
|
|
||||||
size_t mem, mem_a = 0, mem_b = 0;
|
|
||||||
uint8_t *ptr = 0, *ptr_a, *ptr_b, *ptr_c;
|
|
||||||
|
|
||||||
if (!torrents_list->size)
|
|
||||||
goto unlock_continue;
|
|
||||||
|
|
||||||
/* For each torrent in this bucket.. */
|
|
||||||
for (tor_offset = 0; tor_offset < torrents_list->size; ++tor_offset) {
|
|
||||||
/* Address torrents members */
|
|
||||||
ot_peerlist *peer_list = (((ot_torrent *)(torrents_list->data))[tor_offset]).peer_list;
|
|
||||||
switch (peer_list->peer_count) {
|
|
||||||
case 2:
|
|
||||||
count_two++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
count_one++;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
count_def++;
|
|
||||||
count_peers += peer_list->peer_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Maximal memory requirement: max 3 blocks, max torrents * 20 + max peers * 7 */
|
|
||||||
mem = 3 * (1 + 1 + 2) + (count_one + count_two) * (19 + 1) + count_def * (19 + 8) + (count_one + 2 * count_two + count_peers) * 7;
|
|
||||||
|
|
||||||
fprintf(stderr, "Mem: %zd\n", mem);
|
|
||||||
|
|
||||||
ptr = ptr_a = ptr_b = ptr_c = malloc(mem);
|
|
||||||
if (!ptr)
|
|
||||||
goto unlock_continue;
|
|
||||||
|
|
||||||
if (count_one > 4 || !count_def) {
|
|
||||||
mem_a = 1 + 1 + 2 + count_one * (19 + 7);
|
|
||||||
ptr_b += mem_a;
|
|
||||||
ptr_c += mem_a;
|
|
||||||
ptr_a[0] = 1; /* Offset 0: packet type 1 */
|
|
||||||
ptr_a[1] = (bucket << 8) >> OT_BUCKET_COUNT_BITS; /* Offset 1: the shared prefix */
|
|
||||||
ptr_a[2] = count_one >> 8;
|
|
||||||
ptr_a[3] = count_one & 255;
|
|
||||||
ptr_a += 4;
|
|
||||||
} else
|
|
||||||
count_def += count_one;
|
|
||||||
|
|
||||||
if (count_two > 4 || !count_def) {
|
|
||||||
mem_b = 1 + 1 + 2 + count_two * (19 + 14);
|
|
||||||
ptr_c += mem_b;
|
|
||||||
ptr_b[0] = 2; /* Offset 0: packet type 2 */
|
|
||||||
ptr_b[1] = (bucket << 8) >> OT_BUCKET_COUNT_BITS; /* Offset 1: the shared prefix */
|
|
||||||
ptr_b[2] = count_two >> 8;
|
|
||||||
ptr_b[3] = count_two & 255;
|
|
||||||
ptr_b += 4;
|
|
||||||
} else
|
|
||||||
count_def += count_two;
|
|
||||||
|
|
||||||
if (count_def) {
|
|
||||||
ptr_c[0] = 0; /* Offset 0: packet type 0 */
|
|
||||||
ptr_c[1] = (bucket << 8) >> OT_BUCKET_COUNT_BITS; /* Offset 1: the shared prefix */
|
|
||||||
ptr_c[2] = count_def >> 8;
|
|
||||||
ptr_c[3] = count_def & 255;
|
|
||||||
ptr_c += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For each torrent in this bucket.. */
|
|
||||||
for (tor_offset = 0; tor_offset < torrents_list->size; ++tor_offset) {
|
|
||||||
/* Address torrents members */
|
|
||||||
ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + tor_offset;
|
|
||||||
ot_peerlist *peer_list = torrent->peer_list;
|
|
||||||
ot_peer *peers = (ot_peer *)(peer_list->peers.data);
|
|
||||||
uint8_t **dst;
|
|
||||||
|
|
||||||
/* Determine destination slot */
|
|
||||||
count_peers = peer_list->peer_count;
|
|
||||||
switch (count_peers) {
|
|
||||||
case 0:
|
|
||||||
continue;
|
|
||||||
case 1:
|
|
||||||
dst = mem_a ? &ptr_a : &ptr_c;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
dst = mem_b ? &ptr_b : &ptr_c;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dst = &ptr_c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy tail of info_hash, advance pointer */
|
|
||||||
memcpy(*dst, ((uint8_t *)torrent->hash) + 1, sizeof(ot_hash) - 1);
|
|
||||||
*dst += sizeof(ot_hash) - 1;
|
|
||||||
|
|
||||||
/* Encode peer count */
|
|
||||||
if (dst == &ptr_c)
|
|
||||||
while (count_peers) {
|
|
||||||
if (count_peers <= 0x7f)
|
|
||||||
*(*dst)++ = count_peers;
|
|
||||||
else
|
|
||||||
*(*dst)++ = 0x80 | (count_peers & 0x7f);
|
|
||||||
count_peers >>= 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy peers */
|
|
||||||
count_peers = peer_list->peer_count;
|
|
||||||
while (count_peers--) {
|
|
||||||
memcpy(*dst, peers++, OT_IP_SIZE + 3);
|
|
||||||
*dst += OT_IP_SIZE + 3;
|
|
||||||
}
|
|
||||||
free_peerlist(peer_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(torrents_list->data);
|
|
||||||
memset(torrents_list, 0, sizeof(*torrents_list));
|
|
||||||
unlock_continue:
|
|
||||||
mutex_bucket_unlock(bucket, 0);
|
|
||||||
|
|
||||||
if (ptr) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (ptr_b > ptr_c)
|
|
||||||
ptr_c = ptr_b;
|
|
||||||
if (ptr_a > ptr_c)
|
|
||||||
ptr_c = ptr_a;
|
|
||||||
mem = ptr_c - ptr;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_PEERS; ++i) {
|
|
||||||
if (PROXYPEER_ISCONNECTED(g_connections[i].state)) {
|
|
||||||
void *tmp = malloc(mem);
|
|
||||||
if (tmp) {
|
|
||||||
memcpy(tmp, ptr, mem);
|
|
||||||
iob_addbuf_free(&g_connections[i].outdata, tmp, mem);
|
|
||||||
io_wantwrite(g_connections[i].fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
usleep(OT_SYNC_SLEEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void livesync_issue_peersync() {
|
|
||||||
socket_send4(g_socket_out, (char *)g_peerbuffer_start, g_peerbuffer_pos - g_peerbuffer_start, groupip_1, LIVESYNC_PORT);
|
|
||||||
g_peerbuffer_pos = g_peerbuffer_start + sizeof(g_tracker_id) + sizeof(uint32_t);
|
|
||||||
g_next_packet_time = time(NULL) + LIVESYNC_MAXDELAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void livesync_ticker() {
|
|
||||||
/* livesync_issue_peersync sets g_next_packet_time */
|
|
||||||
if (time(NULL) > g_next_packet_time && g_peerbuffer_pos > g_peerbuffer_start + sizeof(g_tracker_id))
|
|
||||||
livesync_issue_peersync();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void livesync_proxytell(uint8_t prefix, uint8_t *info_hash, uint8_t *peer) {
|
|
||||||
// unsigned int i;
|
|
||||||
|
|
||||||
*g_peerbuffer_pos = prefix;
|
|
||||||
memcpy(g_peerbuffer_pos + 1, info_hash, sizeof(ot_hash) - 1);
|
|
||||||
memcpy(g_peerbuffer_pos + sizeof(ot_hash), peer, sizeof(ot_peer) - 1);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Dump info_hash */
|
|
||||||
for( i=0; i<sizeof(ot_hash); ++i )
|
|
||||||
printf( "%02X", g_peerbuffer_pos[i] );
|
|
||||||
putchar( ':' );
|
|
||||||
#endif
|
|
||||||
g_peerbuffer_pos += sizeof(ot_hash);
|
|
||||||
#if 0
|
|
||||||
printf( "%hhu.%hhu.%hhu.%hhu:%hu (%02X %02X)\n", g_peerbuffer_pos[0], g_peerbuffer_pos[1], g_peerbuffer_pos[2], g_peerbuffer_pos[3],
|
|
||||||
g_peerbuffer_pos[4] | ( g_peerbuffer_pos[5] << 8 ), g_peerbuffer_pos[6], g_peerbuffer_pos[7] );
|
|
||||||
#endif
|
|
||||||
g_peerbuffer_pos += sizeof(ot_peer);
|
|
||||||
|
|
||||||
if (g_peerbuffer_pos >= g_peerbuffer_highwater)
|
|
||||||
livesync_issue_peersync();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void process_indata(proxy_peer *peer) {
|
|
||||||
size_t consumed, peers;
|
|
||||||
uint8_t *data = peer->indata, *hash;
|
|
||||||
uint8_t *dataend = data + peer->indata_length;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* If we're not inside of a packet, make a new one */
|
|
||||||
if (!peer->packet_tcount) {
|
|
||||||
/* Ensure the header is complete or postpone processing */
|
|
||||||
if (data + 4 > dataend)
|
|
||||||
break;
|
|
||||||
peer->packet_type = data[0];
|
|
||||||
peer->packet_tprefix = data[1];
|
|
||||||
peer->packet_tcount = data[2] * 256 + data[3];
|
|
||||||
data += 4;
|
|
||||||
printf("type: %hhu, prefix: %02X, torrentcount: %zd\n", peer->packet_type, peer->packet_tprefix, peer->packet_tcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure size for a minimal torrent block */
|
|
||||||
if (data + sizeof(ot_hash) + OT_IP_SIZE + 3 > dataend)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Advance pointer to peer count or peers */
|
|
||||||
hash = data;
|
|
||||||
data += sizeof(ot_hash) - 1;
|
|
||||||
|
|
||||||
/* Type 0 has peer count encoded before each peers */
|
|
||||||
peers = peer->packet_type;
|
|
||||||
if (!peers) {
|
|
||||||
int shift = 0;
|
|
||||||
do
|
|
||||||
peers |= (0x7f & *data) << (7 * shift);
|
|
||||||
while (*(data++) & 0x80 && shift++ < 6);
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
printf( "peers: %zd\n", peers );
|
|
||||||
#endif
|
|
||||||
/* Ensure enough data being read to hold all peers */
|
|
||||||
if (data + (OT_IP_SIZE + 3) * peers > dataend) {
|
|
||||||
data = hash;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (peers--) {
|
|
||||||
livesync_proxytell(peer->packet_tprefix, hash, data);
|
|
||||||
data += OT_IP_SIZE + 3;
|
|
||||||
}
|
|
||||||
--peer->packet_tcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
consumed = data - peer->indata;
|
|
||||||
memmove(peer->indata, data, peer->indata_length - consumed);
|
|
||||||
peer->indata_length -= consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *livesync_worker(void *args) {
|
|
||||||
(void)args;
|
|
||||||
while (1) {
|
|
||||||
ot_ip6 in_ip;
|
|
||||||
uint16_t in_port;
|
|
||||||
size_t datalen = socket_recv4(g_socket_in, (char *)g_inbuffer, LIVESYNC_INCOMING_BUFFSIZE, 12 + (char *)in_ip, &in_port);
|
|
||||||
|
|
||||||
/* Expect at least tracker id and packet type */
|
|
||||||
if (datalen <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t)))
|
|
||||||
continue;
|
|
||||||
if (!memcmp(g_inbuffer, &g_tracker_id, sizeof(g_tracker_id))) {
|
|
||||||
/* drop packet coming from ourselves */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (uint32_read_big((char *)g_inbuffer + sizeof(g_tracker_id))) {
|
|
||||||
case OT_SYNC_PEER4:
|
|
||||||
livesync_handle_peersync(datalen, OT_PEER_SIZE4);
|
|
||||||
break;
|
|
||||||
case OT_SYNC_PEER6:
|
|
||||||
livesync_handle_peersync(datalen, OT_PEER_SIZE6);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// fprintf( stderr, "Received an unknown live sync packet type %u.\n", uint32_read_big( sizeof( g_tracker_id ) + (char*)g_inbuffer ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -3,14 +3,8 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* Opentracker */
|
|
||||||
#include "scan_urlencoded_query.h"
|
|
||||||
|
|
||||||
/* Libwofat */
|
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
#include "scan_urlencoded_query.h"
|
||||||
/* System */
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Idea is to do a in place replacement or guarantee at least
|
/* Idea is to do a in place replacement or guarantee at least
|
||||||
strlen( string ) bytes in deststring
|
strlen( string ) bytes in deststring
|
||||||
@ -34,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
static const unsigned char is_unreserved[256] = {
|
static const unsigned char is_unreserved[256] = {
|
||||||
8,0,0,0,0,0,0,0,0,0,8,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
8,0,0,0,0,0,0,0,0,0,8,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
8,7,8,8,8,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,7,6,
|
0,7,8,8,8,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,7,6,
|
||||||
4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,7,
|
4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,7,
|
||||||
8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,7,0,
|
8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,7,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
@ -45,13 +39,9 @@ static const unsigned char is_unreserved[256] = {
|
|||||||
|
|
||||||
/* Do a fast nibble to hex representation conversion */
|
/* Do a fast nibble to hex representation conversion */
|
||||||
static unsigned char fromhex(unsigned char x) {
|
static unsigned char fromhex(unsigned char x) {
|
||||||
x -= '0';
|
x-='0'; if( x<=9) return x;
|
||||||
if (x <= 9)
|
x&=~0x20; x-='A'-'0';
|
||||||
return x;
|
if( x<6 ) return x+10;
|
||||||
x &= ~0x20;
|
|
||||||
x -= 'A' - '0';
|
|
||||||
if (x < 6)
|
|
||||||
return x + 10;
|
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,35 +52,15 @@ void scan_urlencoded_skipvalue(char **string) {
|
|||||||
|
|
||||||
/* Since we are asked to skip the 'value', we assume to stop at
|
/* Since we are asked to skip the 'value', we assume to stop at
|
||||||
terminators for a 'value' string position */
|
terminators for a 'value' string position */
|
||||||
while ((f = is_unreserved[*s++]) & SCAN_SEARCHPATH_VALUE)
|
while( ( f = is_unreserved[ *s++ ] ) & SCAN_SEARCHPATH_VALUE );
|
||||||
;
|
|
||||||
|
|
||||||
/* If we stopped at a hard terminator like \0 or \n, make the
|
/* If we stopped at a hard terminator like \0 or \n, make the
|
||||||
next scan_urlencoded_query encounter it again */
|
next scan_urlencoded_query encounter it again */
|
||||||
if (f & SCAN_SEARCHPATH_TERMINATOR)
|
if( f & SCAN_SEARCHPATH_TERMINATOR ) --s;
|
||||||
--s;
|
|
||||||
|
|
||||||
*string = (char*)s;
|
*string = (char*)s;
|
||||||
}
|
}
|
||||||
|
|
||||||
int scan_find_keywords(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags) {
|
|
||||||
char *deststring = *string;
|
|
||||||
ssize_t match_length = scan_urlencoded_query(string, deststring, flags);
|
|
||||||
|
|
||||||
if (match_length < 0)
|
|
||||||
return match_length;
|
|
||||||
if (match_length == 0)
|
|
||||||
return -3;
|
|
||||||
|
|
||||||
while (keywords->key) {
|
|
||||||
if (!strncmp(keywords->key, deststring, match_length) && !keywords->key[match_length])
|
|
||||||
return keywords->value;
|
|
||||||
keywords++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) {
|
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) {
|
||||||
const unsigned char* s=*(const unsigned char**) string;
|
const unsigned char* s=*(const unsigned char**) string;
|
||||||
unsigned char *d = (unsigned char*)deststring;
|
unsigned char *d = (unsigned char*)deststring;
|
||||||
@ -104,10 +74,8 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F
|
|||||||
|
|
||||||
/* When encountering an url escaped character, try to decode */
|
/* When encountering an url escaped character, try to decode */
|
||||||
if( c=='%') {
|
if( c=='%') {
|
||||||
if ((b = fromhex(*s++)) == 0xff)
|
if( ( b = fromhex(*s++) ) == 0xff ) return -1;
|
||||||
return -1;
|
if( ( c = fromhex(*s++) ) == 0xff ) return -1;
|
||||||
if ((c = fromhex(*s++)) == 0xff)
|
|
||||||
return -1;
|
|
||||||
c|=(b<<4);
|
c|=(b<<4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,30 +84,24 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case 0:
|
case 0: case '\r': case '\n': case ' ':
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
case ' ':
|
|
||||||
/* If we started scanning on a hard terminator, indicate we've finished */
|
/* If we started scanning on a hard terminator, indicate we've finished */
|
||||||
if (d == (unsigned char *)deststring)
|
if( d == (unsigned char*)deststring ) return -2;
|
||||||
return -2;
|
|
||||||
|
|
||||||
/* Else make the next call to scan_urlencoded_param encounter it again */
|
/* Else make the next call to scan_urlencoded_param encounter it again */
|
||||||
--s;
|
--s;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
if (flags != SCAN_PATH)
|
/* XXX to help us parse path?param=value?param=value?... sent by µTorrent 1600
|
||||||
return -1;
|
do not return an error but silently terminate
|
||||||
|
if( flags != SCAN_PATH ) return -1; */
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (flags != SCAN_SEARCHPATH_PARAM)
|
if( flags != SCAN_SEARCHPATH_PARAM ) return -1;
|
||||||
return -1;
|
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
if (flags == SCAN_PATH)
|
if( flags == SCAN_PATH ) return -1;
|
||||||
return -1;
|
if( flags == SCAN_SEARCHPATH_PARAM ) --s;
|
||||||
if (flags == SCAN_SEARCHPATH_PARAM)
|
|
||||||
--s;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@ -152,13 +114,27 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F
|
|||||||
ssize_t scan_fixed_int( char *data, size_t len, int *tmp ) {
|
ssize_t scan_fixed_int( char *data, size_t len, int *tmp ) {
|
||||||
int minus = 0;
|
int minus = 0;
|
||||||
*tmp = 0;
|
*tmp = 0;
|
||||||
if (*data == '-')
|
if( *data == '-' ) --len, ++data, ++minus;
|
||||||
--len, ++data, ++minus;
|
while( (len > 0) && (*data >= '0') && (*data <= '9') ) { --len; *tmp = 10**tmp + *data++-'0'; }
|
||||||
while ((len > 0) && (*data >= '0') && (*data <= '9')) {
|
if( minus ) *tmp = -*tmp;
|
||||||
--len;
|
|
||||||
*tmp = 10 * *tmp + *data++ - '0';
|
|
||||||
}
|
|
||||||
if (minus)
|
|
||||||
*tmp = -*tmp;
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t scan_fixed_ip( char *data, size_t len, unsigned char ip[4] ) {
|
||||||
|
int u, i;
|
||||||
|
|
||||||
|
for( i=0; i<4; ++i ) {
|
||||||
|
ssize_t j = scan_fixed_int( data, len, &u );
|
||||||
|
if( j == (ssize_t)len ) return len;
|
||||||
|
ip[i] = u;
|
||||||
|
data += len - j;
|
||||||
|
len = j;
|
||||||
|
if ( i<3 ) {
|
||||||
|
if( !len || *data != '.') return -1;
|
||||||
|
--len; ++data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *g_version_scan_urlencoded_query_c = "$Source$: $Revision$\n";
|
||||||
|
@ -3,15 +3,8 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef SCAN_URLENCODED_QUERY_H__
|
#ifndef __SCAN_URLENCODED_QUERY_H__
|
||||||
#define SCAN_URLENCODED_QUERY_H__
|
#define __SCAN_URLENCODED_QUERY_H__
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *key;
|
|
||||||
int value;
|
|
||||||
} ot_keywords;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCAN_PATH = 1,
|
SCAN_PATH = 1,
|
||||||
@ -26,20 +19,9 @@ typedef enum {
|
|||||||
flags determines, what to parse
|
flags determines, what to parse
|
||||||
returns number of valid converted characters in deststring
|
returns number of valid converted characters in deststring
|
||||||
or -1 for parse error
|
or -1 for parse error
|
||||||
or -2 for terminator found
|
|
||||||
*/
|
*/
|
||||||
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags);
|
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags);
|
||||||
|
|
||||||
/* string in: pointer to source
|
|
||||||
out: pointer to next scan position
|
|
||||||
flags determines, what to parse
|
|
||||||
returns value for matched keyword
|
|
||||||
or -1 for parse error
|
|
||||||
or -2 for terminator found
|
|
||||||
or -3 for no keyword matched
|
|
||||||
*/
|
|
||||||
int scan_find_keywords(const ot_keywords *keywords, char **string, SCAN_SEARCHPATH_FLAG flags);
|
|
||||||
|
|
||||||
/* string in: pointer to value of a param=value pair to skip
|
/* string in: pointer to value of a param=value pair to skip
|
||||||
out: pointer to next scan position on return
|
out: pointer to next scan position on return
|
||||||
*/
|
*/
|
||||||
@ -52,4 +34,11 @@ void scan_urlencoded_skipvalue(char **string);
|
|||||||
*/
|
*/
|
||||||
ssize_t scan_fixed_int( char *data, size_t len, int *number );
|
ssize_t scan_fixed_int( char *data, size_t len, int *number );
|
||||||
|
|
||||||
|
/* data pointer to len chars of string
|
||||||
|
len length of chars in data to parse
|
||||||
|
ip buffer to receive result
|
||||||
|
returns number of bytes not parsed, mostly !=0 means fail
|
||||||
|
*/
|
||||||
|
ssize_t scan_fixed_ip( char *data, size_t len, unsigned char ip[4] );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
request_string="GET /announce?info_hash=0123456789012345678\
|
|
||||||
%$(printf %02X $(( $RANDOM & 0xf )) )\
|
|
||||||
&ip=$(( $RANDOM & 0xf )).$(( $RANDOM & 0xf )).13.16&port=$(( $RANDOM & 0xff )) HTTP/1.0\n"
|
|
||||||
|
|
||||||
echo $request_string
|
|
||||||
# echo
|
|
||||||
echo $request_string | nc 127.0.0.1 6969 >/dev/null
|
|
||||||
# echo
|
|
||||||
|
|
||||||
done
|
|
@ -1,22 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
request_string="GET /announce?info_hash=012345678901234567\
|
|
||||||
$(printf %02X $(( $RANDOM & 0xff )) )\
|
|
||||||
&ip=$(( $RANDOM & 0xff )).17.13.15&port=$(( $RANDOM & 0xff )) HTTP/1.0"
|
|
||||||
|
|
||||||
# echo $request_string
|
|
||||||
# echo
|
|
||||||
printf "%s\n\n" "$request_string" | nc 84.200.61.9 6969 | hexdump -C
|
|
||||||
|
|
||||||
request_string="GET /announce?info_hash=012345678901234567\
|
|
||||||
$(printf %02X $(( $RANDOM & 0xff )) )\
|
|
||||||
&ip=2001:1608:6:27::$(( $RANDOM & 0xff ))&port=$(( $RANDOM & 0xff )) HTTP/1.0"
|
|
||||||
printf "%s\n\n" "$request_string" | nc 2001:1608:6:27::9 6969 | hexdump -C
|
|
||||||
printf "%s\n\n" "$request_string"
|
|
||||||
|
|
||||||
request_string="GET /scrape?info_hash=012345678901234567\
|
|
||||||
$(printf %02X $(( $RANDOM & 0xff )) ) HTTP/1.0"
|
|
||||||
printf "%s\n\n" "$request_string" | nc 2001:1608:6:27::9 6969 | hexdump -C
|
|
||||||
|
|
||||||
done
|
|
670
trackerlogic.c
670
trackerlogic.c
@ -4,382 +4,227 @@
|
|||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
/* System */
|
/* System */
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
/* Libowfat */
|
/* Libowfat */
|
||||||
#include "array.h"
|
#include "scan.h"
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "iob.h"
|
|
||||||
#include "ip6.h"
|
|
||||||
|
|
||||||
/* Opentracker */
|
/* Opentracker */
|
||||||
#include "ot_accesslist.h"
|
#include "trackerlogic.h"
|
||||||
#include "ot_clean.h"
|
|
||||||
#include "ot_fullscrape.h"
|
|
||||||
#include "ot_http.h"
|
|
||||||
#include "ot_livesync.h"
|
|
||||||
#include "ot_mutex.h"
|
#include "ot_mutex.h"
|
||||||
#include "ot_stats.h"
|
#include "ot_stats.h"
|
||||||
#include "ot_vector.h"
|
#include "ot_clean.h"
|
||||||
#include "trackerlogic.h"
|
#include "ot_accesslist.h"
|
||||||
|
#include "ot_fullscrape.h"
|
||||||
/* Forward declaration */
|
#include "ot_sync.h"
|
||||||
size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto);
|
#include "ot_livesync.h"
|
||||||
|
|
||||||
void free_peerlist( ot_peerlist *peer_list ) {
|
void free_peerlist( ot_peerlist *peer_list ) {
|
||||||
if (peer_list->peers.data) {
|
size_t i;
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list))
|
for( i=0; i<OT_POOLS_COUNT; ++i )
|
||||||
vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
|
if( peer_list->peers[i].data )
|
||||||
else
|
free( peer_list->peers[i].data );
|
||||||
free(peer_list->peers.data);
|
#ifdef WANT_SYNC_BATCH
|
||||||
}
|
free( peer_list->changeset.data );
|
||||||
|
#endif
|
||||||
free( peer_list );
|
free( peer_list );
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count) {
|
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) ) {
|
||||||
int exactmatch;
|
int exactmatch;
|
||||||
ot_torrent *torrent;
|
ot_torrent *torrent;
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash);
|
ot_peer *peer_dest;
|
||||||
|
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ), *peer_pool;
|
||||||
|
int base_pool = 0;
|
||||||
|
|
||||||
if (!accesslist_hashisvalid(hash))
|
if( !accesslist_hashisvalid( hash ) ) {
|
||||||
return mutex_bucket_unlock_by_hash(hash, 0);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
if (!torrent || exactmatch)
|
|
||||||
return mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
|
|
||||||
/* Create a new torrent entry, then */
|
|
||||||
byte_zero(torrent, sizeof(ot_torrent));
|
|
||||||
memcpy(torrent->hash, hash, sizeof(ot_hash));
|
|
||||||
|
|
||||||
if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
|
|
||||||
vector_remove_torrent(torrents_list, torrent);
|
|
||||||
return mutex_bucket_unlock_by_hash(hash, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
|
|
||||||
byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
|
|
||||||
torrent->peer_list6->base = base;
|
|
||||||
torrent->peer_list4->base = base;
|
|
||||||
torrent->peer_list6->down_count = down_count;
|
|
||||||
torrent->peer_list4->down_count = down_count;
|
|
||||||
|
|
||||||
return mutex_bucket_unlock_by_hash(hash, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount) {
|
|
||||||
int exactmatch, delta_torrentcount = 0;
|
|
||||||
ot_torrent *torrent;
|
|
||||||
ot_peer *peer_dest;
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
|
|
||||||
ot_peerlist *peer_list;
|
|
||||||
size_t peer_size; /* initialized in next line */
|
|
||||||
ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
|
|
||||||
|
|
||||||
if (!accesslist_hashisvalid(*ws->hash)) {
|
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, 0);
|
|
||||||
if (proto == FLAG_TCP) {
|
|
||||||
const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e";
|
|
||||||
memcpy(ws->reply, invalid_hash, strlen(invalid_hash));
|
|
||||||
return strlen(invalid_hash);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
torrent = vector_find_or_insert(torrents_list, (void *)ws->hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
|
|
||||||
if( !torrent ) {
|
if( !torrent ) {
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, 0);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !exactmatch ) {
|
if( !exactmatch ) {
|
||||||
/* Create a new torrent entry, then */
|
/* Create a new torrent entry, then */
|
||||||
byte_zero(torrent, sizeof(ot_torrent));
|
memmove( &torrent->hash, hash, sizeof( ot_hash ) );
|
||||||
memcpy(torrent->hash, *ws->hash, sizeof(ot_hash));
|
|
||||||
|
|
||||||
if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
|
if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
|
||||||
vector_remove_torrent( torrents_list, torrent );
|
vector_remove_torrent( torrents_list, torrent );
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, 0);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
|
byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
|
||||||
byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
|
|
||||||
delta_torrentcount = 1;
|
|
||||||
} else
|
} else
|
||||||
clean_single_torrent( torrent );
|
clean_single_torrent( torrent );
|
||||||
|
|
||||||
torrent->peer_list6->base = g_now_minutes;
|
/* Timestamp our first pool */
|
||||||
torrent->peer_list4->base = g_now_minutes;
|
torrent->peer_list->base = NOW;
|
||||||
|
|
||||||
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
|
|
||||||
|
|
||||||
/* Check for peer in torrent */
|
|
||||||
peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch);
|
|
||||||
if (!peer_dest) {
|
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell peer that it's fresh */
|
|
||||||
OT_PEERTIME(ws->peer, OT_PEER_SIZE6) = 0;
|
|
||||||
|
|
||||||
/* Sanitize flags: Whoever claims to have completed download, must be a seeder */
|
/* Sanitize flags: Whoever claims to have completed download, must be a seeder */
|
||||||
if ((OT_PEERFLAG(ws->peer) & (PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING)) == PEER_FLAG_COMPLETED)
|
if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
|
||||||
OT_PEERFLAG(ws->peer) ^= PEER_FLAG_COMPLETED;
|
OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED;
|
||||||
|
|
||||||
/* If we hadn't had a match create peer there */
|
|
||||||
if (!exactmatch) {
|
|
||||||
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
|
||||||
if (proto == FLAG_MCA)
|
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_FROM_SYNC;
|
|
||||||
else
|
|
||||||
livesync_tell(ws);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
peer_list->peer_count++;
|
|
||||||
if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) {
|
|
||||||
peer_list->down_count++;
|
|
||||||
stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
|
|
||||||
}
|
|
||||||
if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)
|
|
||||||
peer_list->seed_count++;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
stats_issue_event(EVENT_RENEW, 0, OT_PEERTIME(peer_dest, peer_size));
|
|
||||||
#ifdef WANT_SPOT_WOODPECKER
|
|
||||||
if ((OT_PEERTIME(peer_dest, peer_size) > 0) && (OT_PEERTIME(peer_dest, peer_size) < 20))
|
|
||||||
stats_issue_event(EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer);
|
|
||||||
#endif
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
|
||||||
/* Won't live sync peers that come back too fast. Only exception:
|
|
||||||
fresh "completed" reports */
|
|
||||||
if (proto != FLAG_MCA) {
|
|
||||||
if (OT_PEERTIME(peer_dest, peer_size) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
|
|
||||||
(!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)))
|
|
||||||
livesync_tell(ws);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING))
|
|
||||||
peer_list->seed_count--;
|
|
||||||
if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING))
|
|
||||||
peer_list->seed_count++;
|
|
||||||
if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)) {
|
|
||||||
peer_list->down_count++;
|
|
||||||
stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
|
|
||||||
}
|
|
||||||
if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED)
|
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(peer_dest, peer_src, peer_size);
|
|
||||||
#ifdef WANT_SYNC
|
#ifdef WANT_SYNC
|
||||||
if (proto == FLAG_MCA) {
|
if( from_changeset ) {
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
|
/* Check, whether peer already is in current pool, do nothing if so */
|
||||||
|
peer_pool = &torrent->peer_list->peers[0];
|
||||||
|
binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch );
|
||||||
|
if( exactmatch ) {
|
||||||
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
|
return torrent;
|
||||||
|
}
|
||||||
|
base_pool = 1;
|
||||||
|
if( torrent->peer_list->base < NOW )
|
||||||
|
torrent->peer_list->base = NOW;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
peer_pool = &torrent->peer_list->peers[ base_pool ];
|
||||||
|
peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
|
||||||
|
|
||||||
|
/* If we hadn't had a match in current pool, create peer there and
|
||||||
|
remove it from all older pools */
|
||||||
|
if( !exactmatch ) {
|
||||||
|
int i;
|
||||||
|
memmove( peer_dest, peer, sizeof( ot_peer ) );
|
||||||
|
torrent->peer_list->peer_count++;
|
||||||
|
|
||||||
|
#ifdef WANT_SYNC_LIVE
|
||||||
|
if( !from_changeset )
|
||||||
|
livesync_tell( hash, peer, PEER_FLAG_LEECHING );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED )
|
||||||
|
torrent->peer_list->down_count++;
|
||||||
|
|
||||||
|
if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) {
|
||||||
|
torrent->peer_list->seed_counts[ base_pool ]++;
|
||||||
|
torrent->peer_list->seed_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) {
|
||||||
|
switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) {
|
||||||
|
case 0: continue;
|
||||||
|
case 2: torrent->peer_list->seed_counts[i]--;
|
||||||
|
torrent->peer_list->seed_count--;
|
||||||
|
case 1: default:
|
||||||
|
torrent->peer_list->peer_count--;
|
||||||
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
|
stats_issue_event( EVENT_RENEW, 0, i );
|
||||||
|
return torrent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) {
|
||||||
|
torrent->peer_list->seed_counts[ base_pool ]--;
|
||||||
|
torrent->peer_list->seed_count--;
|
||||||
|
}
|
||||||
|
if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) {
|
||||||
|
torrent->peer_list->seed_counts[ base_pool ]++;
|
||||||
|
torrent->peer_list->seed_count++;
|
||||||
|
}
|
||||||
|
if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) )
|
||||||
|
torrent->peer_list->down_count++;
|
||||||
|
if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED )
|
||||||
|
OT_FLAG( peer ) |= PEER_FLAG_COMPLETED;
|
||||||
|
|
||||||
|
stats_issue_event( EVENT_RENEW, 0, base_pool );
|
||||||
|
memmove( peer_dest, peer, sizeof( ot_peer ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
|
return torrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compiles a list of random peers for a torrent
|
||||||
|
* reply must have enough space to hold 92+6*amount bytes
|
||||||
|
* Selector function can be anything, maybe test for seeds, etc.
|
||||||
|
* RANDOM may return huge values
|
||||||
|
* does not yet check not to return self
|
||||||
|
*/
|
||||||
|
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto ) {
|
||||||
|
char *r = reply;
|
||||||
|
int exactmatch;
|
||||||
|
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
|
||||||
|
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
|
ot_peerlist *peer_list = torrent->peer_list;
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
if( !torrent ) {
|
||||||
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
ws->reply_size = return_peers_for_torrent(ws, torrent, amount, ws->reply, proto);
|
if( peer_list->peer_count < amount )
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
|
amount = peer_list->peer_count;
|
||||||
return ws->reply_size;
|
|
||||||
|
if( proto == FLAG_TCP )
|
||||||
|
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount );
|
||||||
|
else {
|
||||||
|
*(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
|
||||||
|
*(uint32_t*)(r+4) = htonl( peer_list->peer_count );
|
||||||
|
*(uint32_t*)(r+8) = htonl( peer_list->seed_count );
|
||||||
|
r += 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) {
|
if( amount ) {
|
||||||
unsigned int bucket, num_buckets = 1;
|
unsigned int pool_offset, pool_index = 0;;
|
||||||
ot_vector *bucket_list = &peer_list->peers;
|
|
||||||
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
|
|
||||||
size_t result = compare_size * peer_list->peer_count;
|
|
||||||
char *r_end = reply + result;
|
|
||||||
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list)) {
|
|
||||||
num_buckets = bucket_list->size;
|
|
||||||
bucket_list = (ot_vector *)bucket_list->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (bucket = 0; bucket < num_buckets; ++bucket) {
|
|
||||||
ot_peer *peers = bucket_list[bucket].data;
|
|
||||||
size_t peer_count = bucket_list[bucket].size;
|
|
||||||
while (peer_count--) {
|
|
||||||
if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) {
|
|
||||||
r_end -= compare_size;
|
|
||||||
memcpy(r_end, peers, compare_size);
|
|
||||||
} else {
|
|
||||||
memcpy(reply, peers, compare_size);
|
|
||||||
reply += compare_size;
|
|
||||||
}
|
|
||||||
peers += peer_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) {
|
|
||||||
unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
|
|
||||||
ot_vector *bucket_list = &peer_list->peers;
|
|
||||||
unsigned int shifted_pc = peer_list->peer_count;
|
unsigned int shifted_pc = peer_list->peer_count;
|
||||||
unsigned int shifted_step = 0;
|
unsigned int shifted_step = 0;
|
||||||
unsigned int shift = 0;
|
unsigned int shift = 0;
|
||||||
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
|
|
||||||
size_t result = compare_size * amount;
|
|
||||||
char *r_end = reply + result;
|
|
||||||
|
|
||||||
if (OT_PEERLIST_HASBUCKETS(peer_list)) {
|
|
||||||
num_buckets = bucket_list->size;
|
|
||||||
bucket_list = (ot_vector *)bucket_list->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make fixpoint arithmetic as exact as possible */
|
/* Make fixpoint arithmetic as exact as possible */
|
||||||
#define MAXPRECBIT (1<<(8*sizeof(int)-3))
|
#define MAXPRECBIT (1<<(8*sizeof(int)-3))
|
||||||
while (!(shifted_pc & MAXPRECBIT)) {
|
while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; }
|
||||||
shifted_pc <<= 1;
|
|
||||||
shift++;
|
|
||||||
}
|
|
||||||
shifted_step = shifted_pc/amount;
|
shifted_step = shifted_pc/amount;
|
||||||
#undef MAXPRECBIT
|
#undef MAXPRECBIT
|
||||||
|
|
||||||
/* Initialize somewhere in the middle of peers so that
|
/* Initialize somewhere in the middle of peers so that
|
||||||
fixpoint's aliasing doesn't alway miss the same peers */
|
fixpoint's aliasing doesn't alway miss the same peers */
|
||||||
bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
|
pool_offset = random() % peer_list->peer_count;
|
||||||
|
|
||||||
while (amount--) {
|
|
||||||
ot_peer *peer;
|
|
||||||
|
|
||||||
|
for( index = 0; index < amount; ++index ) {
|
||||||
/* This is the aliased, non shifted range, next value may fall into */
|
/* This is the aliased, non shifted range, next value may fall into */
|
||||||
unsigned int diff = (((amount + 1) * shifted_step) >> shift) - ((amount * shifted_step) >> shift);
|
unsigned int diff = ( ( ( index + 1 ) * shifted_step ) >> shift ) -
|
||||||
bucket_offset += 1 + nrand48(ws->rand48_state) % diff;
|
( ( index * shifted_step ) >> shift );
|
||||||
|
pool_offset += 1 + random() % diff;
|
||||||
|
|
||||||
while (bucket_offset >= bucket_list[bucket_index].size) {
|
while( pool_offset >= peer_list->peers[pool_index].size ) {
|
||||||
bucket_offset -= bucket_list[bucket_index].size;
|
pool_offset -= peer_list->peers[pool_index].size;
|
||||||
bucket_index = (bucket_index + 1) % num_buckets;
|
pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT;
|
||||||
}
|
|
||||||
peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
|
|
||||||
if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING) {
|
|
||||||
r_end -= compare_size;
|
|
||||||
memcpy(r_end, peer, compare_size);
|
|
||||||
} else {
|
|
||||||
memcpy(reply, peer, compare_size);
|
|
||||||
reply += compare_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) {
|
memmove( r, ((ot_peer*)peer_list->peers[pool_index].data) + pool_offset, 6 );
|
||||||
char *r = reply;
|
r += 6;
|
||||||
size_t peer_size = peer_size_from_peer6(&ws->peer);
|
|
||||||
ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
|
|
||||||
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
|
|
||||||
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
|
|
||||||
|
|
||||||
if (amount > peer_list->peer_count)
|
|
||||||
amount = peer_list->peer_count;
|
|
||||||
|
|
||||||
*(uint32_t *)(r + 0) = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
|
|
||||||
*(uint32_t *)(r + 4) = htonl(peer_count - seed_count);
|
|
||||||
*(uint32_t *)(r + 8) = htonl(seed_count);
|
|
||||||
r += 12;
|
|
||||||
|
|
||||||
if (amount) {
|
|
||||||
if (amount == peer_list->peer_count)
|
|
||||||
r += return_peers_all(peer_list, peer_size, r);
|
|
||||||
else
|
|
||||||
r += return_peers_selection(ws, peer_list, peer_size, amount, r);
|
|
||||||
}
|
}
|
||||||
return r - reply;
|
|
||||||
}
|
}
|
||||||
|
if( proto == FLAG_TCP )
|
||||||
static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) {
|
|
||||||
char *r = reply;
|
|
||||||
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
|
|
||||||
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
|
|
||||||
size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
|
|
||||||
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - seed_count;
|
|
||||||
|
|
||||||
/* Simple case: amount of peers in both lists is less than requested, here we return all results */
|
|
||||||
size_t amount_v4 = torrent->peer_list4->peer_count;
|
|
||||||
size_t amount_v6 = torrent->peer_list6->peer_count;
|
|
||||||
|
|
||||||
/* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */
|
|
||||||
if (amount_v4 + amount_v6 > amount) {
|
|
||||||
size_t amount_left, percent_v6 = 0, percent_v4 = 0, left_v6, left_v4;
|
|
||||||
const size_t SCALE = 1024;
|
|
||||||
|
|
||||||
/* If possible, fill at least a quarter of peer from each family */
|
|
||||||
if (amount / 4 <= amount_v4)
|
|
||||||
amount_v4 = amount / 4;
|
|
||||||
if (amount / 4 <= amount_v6)
|
|
||||||
amount_v6 = amount / 4;
|
|
||||||
|
|
||||||
/* Fill the rest according to which family's pool provides more peers */
|
|
||||||
amount_left = amount - (amount_v4 + amount_v6);
|
|
||||||
|
|
||||||
left_v4 = torrent->peer_list4->peer_count - amount_v4;
|
|
||||||
left_v6 = torrent->peer_list6->peer_count - amount_v6;
|
|
||||||
|
|
||||||
if (left_v4 + left_v6) {
|
|
||||||
percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6);
|
|
||||||
percent_v6 = (SCALE * left_v6) / (left_v4 + left_v6);
|
|
||||||
}
|
|
||||||
|
|
||||||
amount_v4 += (amount_left * percent_v4) / SCALE;
|
|
||||||
amount_v6 += (amount_left * percent_v6) / SCALE;
|
|
||||||
|
|
||||||
/* Integer division rounding can leave out a peer */
|
|
||||||
if (amount_v4 + amount_v6 < amount && amount_v6 < torrent->peer_list6->peer_count)
|
|
||||||
++amount_v6;
|
|
||||||
if (amount_v4 + amount_v6 < amount && amount_v4 < torrent->peer_list4->peer_count)
|
|
||||||
++amount_v4;
|
|
||||||
}
|
|
||||||
|
|
||||||
r +=
|
|
||||||
sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval / 2);
|
|
||||||
|
|
||||||
if (amount_v4) {
|
|
||||||
r += sprintf(r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
|
|
||||||
if (amount_v4 == torrent->peer_list4->peer_count)
|
|
||||||
r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r);
|
|
||||||
else
|
|
||||||
r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount_v6) {
|
|
||||||
r += sprintf(r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
|
|
||||||
if (amount_v6 == torrent->peer_list6->peer_count)
|
|
||||||
r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r);
|
|
||||||
else
|
|
||||||
r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
*r++ = 'e';
|
*r++ = 'e';
|
||||||
|
|
||||||
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return r - reply;
|
return r - reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compiles a list of random peers for a torrent
|
|
||||||
* Reply must have enough space to hold:
|
|
||||||
* 92 + 6 * amount bytes for TCP/IPv4
|
|
||||||
* 92 + 18 * amount bytes for TCP/IPv6
|
|
||||||
* 12 + 6 * amount bytes for UDP/IPv4
|
|
||||||
* 12 + 18 * amount bytes for UDP/IPv6
|
|
||||||
* Does not yet check not to return self
|
|
||||||
*/
|
|
||||||
size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto) {
|
|
||||||
return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fetches scrape info for a specific torrent */
|
/* Fetches scrape info for a specific torrent */
|
||||||
size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
|
size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
||||||
int exactmatch, delta_torrentcount = 0;
|
int exactmatch;
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
|
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
|
||||||
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
|
|
||||||
@ -391,173 +236,117 @@ size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
|
|||||||
if( clean_single_torrent( torrent ) ) {
|
if( clean_single_torrent( torrent ) ) {
|
||||||
vector_remove_torrent( torrents_list, torrent );
|
vector_remove_torrent( torrents_list, torrent );
|
||||||
memset( reply, 0, 12);
|
memset( reply, 0, 12);
|
||||||
delta_torrentcount = -1;
|
|
||||||
} else {
|
} else {
|
||||||
r[0] = htonl(torrent->peer_list6->seed_count + torrent->peer_list4->seed_count);
|
r[0] = htonl( torrent->peer_list->seed_count );
|
||||||
r[1] = htonl(torrent->peer_list6->down_count + torrent->peer_list4->down_count);
|
r[1] = htonl( torrent->peer_list->down_count );
|
||||||
r[2] = htonl(torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
|
r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_bucket_unlock_by_hash(hash, delta_torrentcount);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetches scrape info for a specific torrent */
|
/* Fetches scrape info for a specific torrent */
|
||||||
size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply) {
|
size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) {
|
||||||
char *r = reply;
|
char *r = reply;
|
||||||
int exactmatch, i;
|
int exactmatch, i;
|
||||||
|
|
||||||
r += sprintf( r, "d5:filesd" );
|
r += sprintf( r, "d5:filesd" );
|
||||||
|
|
||||||
for( i=0; i<amount; ++i ) {
|
for( i=0; i<amount; ++i ) {
|
||||||
int delta_torrentcount = 0;
|
ot_hash *hash = hash_list + i;
|
||||||
ot_hash const *hash = hash_list + i;
|
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(*hash);
|
|
||||||
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
|
|
||||||
if( exactmatch ) {
|
if( exactmatch ) {
|
||||||
if( clean_single_torrent( torrent ) ) {
|
if( clean_single_torrent( torrent ) ) {
|
||||||
vector_remove_torrent( torrents_list, torrent );
|
vector_remove_torrent( torrents_list, torrent );
|
||||||
delta_torrentcount = -1;
|
|
||||||
} else {
|
} else {
|
||||||
*r++ = '2';
|
memmove( r, "20:", 3 ); memmove( r+3, hash, 20 );
|
||||||
*r++ = '0';
|
r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
|
||||||
*r++ = ':';
|
torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23;
|
||||||
memcpy(r, hash, sizeof(ot_hash));
|
|
||||||
r += sizeof(ot_hash);
|
|
||||||
r += sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
|
|
||||||
torrent->peer_list6->down_count + torrent->peer_list4->down_count,
|
|
||||||
torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_bucket_unlock_by_hash(*hash, delta_torrentcount);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
}
|
}
|
||||||
|
|
||||||
*r++ = 'e';
|
*r++ = 'e'; *r++ = 'e';
|
||||||
*r++ = 'e';
|
|
||||||
return r - reply;
|
return r - reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ot_peerlist dummy_list;
|
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ) {
|
||||||
size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
|
|
||||||
int exactmatch;
|
int exactmatch;
|
||||||
ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
|
size_t index;
|
||||||
ot_torrent *torrent = binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
|
ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
|
||||||
ot_peerlist *peer_list = &dummy_list;
|
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||||
size_t peer_size; /* initialized in next line */
|
ot_peerlist *peer_list;
|
||||||
ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
|
|
||||||
size_t peer_count = 0, seed_count = 0;
|
|
||||||
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
#ifdef WANT_SYNC_LIVE
|
||||||
if (proto != FLAG_MCA) {
|
if( proto != FLAG_MCA )
|
||||||
OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
|
livesync_tell( hash, peer, PEER_FLAG_STOPPED );
|
||||||
livesync_tell(ws);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (exactmatch) {
|
if( !exactmatch ) {
|
||||||
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) {
|
|
||||||
case 2:
|
if( proto == FLAG_TCP )
|
||||||
peer_list->seed_count--; /* Intentional fallthrough */
|
return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM );
|
||||||
case 1:
|
|
||||||
peer_list->peer_count--; /* Intentional fallthrough */
|
/* Create fake packet to satisfy parser on the other end */
|
||||||
default:
|
if( proto == FLAG_UDP ) {
|
||||||
break;
|
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
|
||||||
|
((uint32_t*)reply)[3] = ((uint32_t*)reply)[4] = 0;
|
||||||
|
return (size_t)20;
|
||||||
}
|
}
|
||||||
|
|
||||||
peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
|
if( proto == FLAG_MCA )
|
||||||
seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peer_list = torrent->peer_list;
|
||||||
|
for( index = 0; index<OT_POOLS_COUNT; ++index ) {
|
||||||
|
switch( vector_remove_peer( &peer_list->peers[index], peer, index == 0 ) ) {
|
||||||
|
case 0: continue;
|
||||||
|
case 2: peer_list->seed_counts[index]--;
|
||||||
|
peer_list->seed_count--;
|
||||||
|
case 1: default:
|
||||||
|
peer_list->peer_count--;
|
||||||
|
goto exit_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_loop:
|
||||||
|
|
||||||
if( proto == FLAG_TCP ) {
|
if( proto == FLAG_TCP ) {
|
||||||
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
|
size_t reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM );
|
||||||
ws->reply_size = sprintf(ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", seed_count, peer_count - seed_count, erval,
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4);
|
return reply_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle UDP reply */
|
/* Handle UDP reply */
|
||||||
if( proto == FLAG_UDP ) {
|
if( proto == FLAG_UDP ) {
|
||||||
((uint32_t *)ws->reply)[2] = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
|
((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
|
||||||
((uint32_t *)ws->reply)[3] = htonl(peer_count - seed_count);
|
((uint32_t*)reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count );
|
||||||
((uint32_t *)ws->reply)[4] = htonl(seed_count);
|
((uint32_t*)reply)[4] = htonl( peer_list->seed_count);
|
||||||
ws->reply_size = 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_bucket_unlock_by_hash(*ws->hash, 0);
|
mutex_bucket_unlock_by_hash( hash );
|
||||||
return ws->reply_size;
|
return (size_t)20;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) {
|
|
||||||
int bucket;
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
|
|
||||||
ot_vector *torrents_list = mutex_bucket_lock(bucket);
|
|
||||||
ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
|
|
||||||
|
|
||||||
for (j = 0; j < torrents_list->size; ++j)
|
|
||||||
if (for_each(torrents + j, data))
|
|
||||||
break;
|
|
||||||
|
|
||||||
mutex_bucket_unlock(bucket, 0);
|
|
||||||
if (!g_opentracker_running)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) {
|
|
||||||
ot_ip6 *ip = (ot_ip6 *)peer;
|
|
||||||
if (!ip6_isv4mapped(ip)) {
|
|
||||||
*peer_size = OT_PEER_SIZE6;
|
|
||||||
return (ot_peer *)peer;
|
|
||||||
}
|
|
||||||
*peer_size = OT_PEER_SIZE4;
|
|
||||||
return (ot_peer *)(((uint8_t *)peer) + 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t peer_size_from_peer6(ot_peer6 *peer) {
|
|
||||||
ot_ip6 *ip = (ot_ip6 *)peer;
|
|
||||||
if (!ip6_isv4mapped(ip))
|
|
||||||
return OT_PEER_SIZE6;
|
|
||||||
return OT_PEER_SIZE4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _DEBUG_RANDOMTORRENTS
|
|
||||||
void trackerlogic_add_random_torrents(size_t amount) {
|
|
||||||
struct ot_workstruct ws;
|
|
||||||
memset(&ws, 0, sizeof(ws));
|
|
||||||
|
|
||||||
ws.inbuf = malloc(G_INBUF_SIZE);
|
|
||||||
ws.outbuf = malloc(G_OUTBUF_SIZE);
|
|
||||||
ws.reply = ws.outbuf;
|
|
||||||
ws.hash = (ot_hash *)ws.inbuf;
|
|
||||||
|
|
||||||
while (amount--) {
|
|
||||||
arc4random_buf(ws.hash, sizeof(ot_hash));
|
|
||||||
arc4random_buf(&ws.peer, sizeof(ws.peer));
|
|
||||||
|
|
||||||
OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED;
|
|
||||||
|
|
||||||
add_peer_to_torrent_and_return_peers(FLAG_TCP, &ws, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ws.inbuf);
|
|
||||||
free(ws.outbuf);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void exerr( char * message ) {
|
void exerr( char * message ) {
|
||||||
fprintf( stderr, "%s\n", message );
|
fprintf( stderr, "%s\n", message );
|
||||||
exit( 111 );
|
exit( 111 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void trackerlogic_init() {
|
int trackerlogic_init( const char * const serverdir ) {
|
||||||
g_tracker_id = random();
|
if( serverdir && chdir( serverdir ) ) {
|
||||||
|
fprintf( stderr, "Could not chdir() to %s, because %s\n", serverdir, strerror(errno) );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_stats_path)
|
srandom( time(NULL) );
|
||||||
g_stats_path = "stats";
|
g_tracker_id = random();
|
||||||
g_stats_path_len = strlen(g_stats_path);
|
|
||||||
|
|
||||||
/* Initialise background worker threads */
|
/* Initialise background worker threads */
|
||||||
mutex_init( );
|
mutex_init( );
|
||||||
@ -565,34 +354,39 @@ void trackerlogic_init() {
|
|||||||
fullscrape_init( );
|
fullscrape_init( );
|
||||||
accesslist_init( );
|
accesslist_init( );
|
||||||
livesync_init( );
|
livesync_init( );
|
||||||
|
sync_init( );
|
||||||
stats_init( );
|
stats_init( );
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trackerlogic_deinit( void ) {
|
void trackerlogic_deinit( void ) {
|
||||||
int bucket, delta_torrentcount = 0;
|
int bucket;
|
||||||
size_t j;
|
size_t j;
|
||||||
|
|
||||||
|
/* Deinitialise background worker threads */
|
||||||
|
stats_deinit( );
|
||||||
|
sync_deinit( );
|
||||||
|
livesync_init( );
|
||||||
|
accesslist_init( );
|
||||||
|
fullscrape_deinit( );
|
||||||
|
clean_deinit( );
|
||||||
|
|
||||||
/* Free all torrents... */
|
/* Free all torrents... */
|
||||||
for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
|
||||||
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
ot_vector *torrents_list = mutex_bucket_lock( bucket );
|
||||||
if( torrents_list->size ) {
|
if( torrents_list->size ) {
|
||||||
for( j=0; j<torrents_list->size; ++j ) {
|
for( j=0; j<torrents_list->size; ++j ) {
|
||||||
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
|
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
|
||||||
free_peerlist(torrent->peer_list6);
|
free_peerlist( torrent->peer_list );
|
||||||
free_peerlist(torrent->peer_list4);
|
|
||||||
delta_torrentcount -= 1;
|
|
||||||
}
|
}
|
||||||
free( torrents_list->data );
|
free( torrents_list->data );
|
||||||
}
|
}
|
||||||
mutex_bucket_unlock(bucket, delta_torrentcount);
|
mutex_bucket_unlock( bucket );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deinitialise background worker threads */
|
|
||||||
stats_deinit();
|
|
||||||
livesync_deinit();
|
|
||||||
accesslist_deinit();
|
|
||||||
fullscrape_deinit();
|
|
||||||
clean_deinit();
|
|
||||||
/* Release mutexes */
|
/* Release mutexes */
|
||||||
mutex_deinit( );
|
mutex_deinit( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_version_trackerlogic_c = "$Source$: $Revision$\n";
|
||||||
|
172
trackerlogic.h
172
trackerlogic.h
@ -3,38 +3,16 @@
|
|||||||
|
|
||||||
$id$ */
|
$id$ */
|
||||||
|
|
||||||
#ifndef OT_TRACKERLOGIC_H__
|
#ifndef __OT_TRACKERLOGIC_H__
|
||||||
#define OT_TRACKERLOGIC_H__
|
#define __OT_TRACKERLOGIC_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
#if defined(__linux__) && defined(WANT_ARC4RANDOM)
|
|
||||||
#include <bsd/stdlib.h>
|
|
||||||
#endif
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
#define WANT_ARC4RANDOM
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef uint8_t ot_hash[20];
|
typedef uint8_t ot_hash[20];
|
||||||
typedef time_t ot_time;
|
typedef time_t ot_time;
|
||||||
typedef char ot_ip6[16];
|
|
||||||
typedef struct {
|
|
||||||
ot_ip6 address;
|
|
||||||
int bits;
|
|
||||||
} ot_net;
|
|
||||||
/* List of peers should fit in a single UDP packet (around 1200 bytes) */
|
|
||||||
#define OT_MAX_PEERS_UDP6 66
|
|
||||||
#define OT_MAX_PEERS_UDP4 200
|
|
||||||
|
|
||||||
#define OT_IP_SIZE6 16
|
|
||||||
#define OT_IP_SIZE4 4
|
|
||||||
#define OT_PORT_SIZE 2
|
|
||||||
#define OT_FLAG_SIZE 1
|
|
||||||
#define OT_TIME_SIZE 1
|
|
||||||
|
|
||||||
/* Some tracker behaviour tunable */
|
/* Some tracker behaviour tunable */
|
||||||
#define OT_CLIENT_TIMEOUT 30
|
#define OT_CLIENT_TIMEOUT 30
|
||||||
@ -44,82 +22,50 @@ typedef struct {
|
|||||||
#define OT_CLIENT_REQUEST_VARIATION (60*6)
|
#define OT_CLIENT_REQUEST_VARIATION (60*6)
|
||||||
|
|
||||||
#define OT_TORRENT_TIMEOUT_HOURS 24
|
#define OT_TORRENT_TIMEOUT_HOURS 24
|
||||||
#define OT_TORRENT_TIMEOUT (60 * OT_TORRENT_TIMEOUT_HOURS)
|
#define OT_TORRENT_TIMEOUT ((60*60*OT_TORRENT_TIMEOUT_HOURS)/OT_POOLS_TIMEOUT)
|
||||||
|
|
||||||
#define OT_CLIENT_REQUEST_INTERVAL_RANDOM \
|
#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) )
|
||||||
(OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION / 2 + (int)(nrand48(ws->rand48_state) % OT_CLIENT_REQUEST_VARIATION))
|
|
||||||
|
|
||||||
/* If WANT_MODEST_FULLSCRAPES is on, ip addresses may not
|
|
||||||
fullscrape more frequently than this amount in seconds */
|
|
||||||
#define OT_MODEST_PEER_TIMEOUT (60 * 5)
|
|
||||||
|
|
||||||
/* If peers come back before 10 minutes, don't live sync them */
|
|
||||||
#define OT_CLIENT_SYNC_RENEW_BOUNDARY 10
|
|
||||||
|
|
||||||
/* Number of tracker admin ip addresses allowed */
|
|
||||||
#define OT_ADMINIP_MAX 64
|
|
||||||
#define OT_MAX_THREADS 64
|
|
||||||
|
|
||||||
/* Number of minutes after announce before peer is removed */
|
|
||||||
#define OT_PEER_TIMEOUT 45
|
|
||||||
|
|
||||||
/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
|
/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
|
||||||
Sort key is, of course, its hash */
|
Sort key is, of course, its hash */
|
||||||
#define OT_BUCKET_COUNT_BITS 10
|
#define OT_BUCKET_COUNT 1024
|
||||||
|
|
||||||
#define OT_BUCKET_COUNT (1 << OT_BUCKET_COUNT_BITS)
|
/* Number of tracker admin ip addresses allowed */
|
||||||
#define OT_BUCKET_COUNT_SHIFT (32 - OT_BUCKET_COUNT_BITS)
|
#define OT_ADMINIP_MAX 64
|
||||||
|
#define OT_MAX_THREADS 16
|
||||||
|
|
||||||
/* if _DEBUG_RANDOMTORRENTS is set, this is the amount of torrents to create
|
/* This list points to 9 pools of peers each grouped in five-minute-intervals
|
||||||
on startup */
|
thus achieving a timeout of 2700s or 45 minutes
|
||||||
#define RANDOMTORRENTS (1024 * 1024 * 1)
|
These pools are sorted by its binary content */
|
||||||
|
#define OT_POOLS_COUNT 9
|
||||||
|
#define OT_POOLS_TIMEOUT (60*5)
|
||||||
|
|
||||||
/* From opentracker.c */
|
/* From opentracker.c */
|
||||||
extern time_t g_now_seconds;
|
extern time_t g_now;
|
||||||
extern volatile int g_opentracker_running;
|
#define NOW (g_now/OT_POOLS_TIMEOUT)
|
||||||
#define g_now_minutes (g_now_seconds / 60)
|
|
||||||
|
|
||||||
extern uint32_t g_tracker_id;
|
extern uint32_t g_tracker_id;
|
||||||
typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
|
typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA } PROTO_FLAG;
|
||||||
|
|
||||||
#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6) + (OT_PORT_SIZE))
|
typedef struct {
|
||||||
#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4) + (OT_PORT_SIZE))
|
uint8_t data[8];
|
||||||
#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE) - (OT_TIME_SIZE) - (OT_FLAG_SIZE))
|
} ot_peer;
|
||||||
|
|
||||||
#define OT_PEER_SIZE6 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE6))
|
|
||||||
#define OT_PEER_SIZE4 ((OT_TIME_SIZE) + (OT_FLAG_SIZE) + (OT_PEER_COMPARE_SIZE4))
|
|
||||||
|
|
||||||
typedef uint8_t ot_peer; /* Generic pointer to a v6 or v4 peer */
|
|
||||||
typedef uint8_t ot_peer6[OT_PEER_SIZE6];
|
|
||||||
typedef uint8_t ot_peer4[OT_PEER_SIZE4];
|
|
||||||
static const uint8_t PEER_FLAG_SEEDING = 0x80;
|
static const uint8_t PEER_FLAG_SEEDING = 0x80;
|
||||||
static const uint8_t PEER_FLAG_COMPLETED = 0x40;
|
static const uint8_t PEER_FLAG_COMPLETED = 0x40;
|
||||||
static const uint8_t PEER_FLAG_STOPPED = 0x20;
|
static const uint8_t PEER_FLAG_STOPPED = 0x20;
|
||||||
static const uint8_t PEER_FLAG_FROM_SYNC = 0x10;
|
|
||||||
static const uint8_t PEER_FLAG_LEECHING = 0x00;
|
static const uint8_t PEER_FLAG_LEECHING = 0x00;
|
||||||
|
|
||||||
/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */
|
#define OT_SETIP( peer, ip ) memmove((peer),(ip),4);
|
||||||
ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
|
#define OT_SETPORT( peer, port ) memmove(((uint8_t*)peer)+4,(port),2);
|
||||||
size_t peer_size_from_peer6(ot_peer6 *peer);
|
#define OT_FLAG(peer) (((uint8_t*)(peer))[6])
|
||||||
|
|
||||||
/* New style */
|
|
||||||
#define OT_SETIP(peer, ip) memcpy((uint8_t *)(peer), (ip), OT_IP_SIZE6)
|
|
||||||
#define OT_SETPORT(peer, port) memcpy(((uint8_t *)(peer)) + (OT_IP_SIZE6), (port), 2)
|
|
||||||
#define OT_PEERFLAG(peer) (((uint8_t *)(peer))[(OT_IP_SIZE6) + 2])
|
|
||||||
#define OT_PEERFLAG_D(peer, peersize) (((uint8_t *)(peer))[(peersize) - 2])
|
|
||||||
#define OT_PEERTIME(peer, peersize) (((uint8_t *)(peer))[(peersize) - 1])
|
|
||||||
|
|
||||||
#define PEERS_BENCODED6 "6:peers6"
|
|
||||||
#define PEERS_BENCODED4 "5:peers"
|
|
||||||
|
|
||||||
|
#define OT_PEER_COMPARE_SIZE ((size_t)6)
|
||||||
#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
|
#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
|
||||||
|
|
||||||
struct ot_peerlist;
|
struct ot_peerlist;
|
||||||
typedef struct ot_peerlist ot_peerlist;
|
typedef struct ot_peerlist ot_peerlist;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ot_hash hash;
|
ot_hash hash;
|
||||||
ot_peerlist *peer_list6;
|
ot_peerlist *peer_list;
|
||||||
ot_peerlist *peer_list4;
|
|
||||||
} ot_torrent;
|
} ot_torrent;
|
||||||
|
|
||||||
#include "ot_vector.h"
|
#include "ot_vector.h"
|
||||||
@ -129,50 +75,18 @@ struct ot_peerlist {
|
|||||||
size_t seed_count;
|
size_t seed_count;
|
||||||
size_t peer_count;
|
size_t peer_count;
|
||||||
size_t down_count;
|
size_t down_count;
|
||||||
/* normal peers vector or
|
size_t seed_counts[ OT_POOLS_COUNT ];
|
||||||
pointer to ot_vector[32] buckets if data != NULL and space == 0
|
ot_vector peers[ OT_POOLS_COUNT ];
|
||||||
*/
|
#ifdef WANT_SYNC_BATCH
|
||||||
ot_vector peers;
|
ot_vector changeset;
|
||||||
};
|
|
||||||
#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space)
|
|
||||||
|
|
||||||
struct ot_workstruct {
|
|
||||||
/* Thread specific, static */
|
|
||||||
char *inbuf;
|
|
||||||
#define G_INBUF_SIZE 8192
|
|
||||||
char *outbuf;
|
|
||||||
#define G_OUTBUF_SIZE 8192
|
|
||||||
#ifdef _DEBUG_HTTPERROR
|
|
||||||
char *debugbuf;
|
|
||||||
#define G_DEBUGBUF_SIZE 8192
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The peer currently in the working */
|
|
||||||
ot_peer6 peer; /* Can fit v6 and v4 peers */
|
|
||||||
|
|
||||||
/* Pointers into the request buffer */
|
|
||||||
ot_hash *hash;
|
|
||||||
char *peer_id;
|
|
||||||
|
|
||||||
/* HTTP specific, non static */
|
|
||||||
char *request;
|
|
||||||
ssize_t request_size;
|
|
||||||
ssize_t header_size;
|
|
||||||
char *reply;
|
|
||||||
ssize_t reply_size;
|
|
||||||
|
|
||||||
/* Entropy state for rand48 function so that threads don't need to acquire mutexes for
|
|
||||||
global random() or arc4random() state, which causes heavy load on linuxes */
|
|
||||||
uint16_t rand48_state[3];
|
|
||||||
|
|
||||||
int keep_alive;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Exported functions
|
Exported functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WANT_SYNC_LIVE
|
#if defined( WANT_SYNC_BATCH ) || defined( WANT_SYNC_LIVE )
|
||||||
#define WANT_SYNC
|
#define WANT_SYNC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -182,27 +96,15 @@ struct ot_workstruct {
|
|||||||
#define WANT_SYNC_PARAM( param )
|
#define WANT_SYNC_PARAM( param )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WANT_LOG_NETWORKS
|
int trackerlogic_init( const char * const serverdir );
|
||||||
#error Live logging networks disabled at the moment.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void trackerlogic_init(void);
|
|
||||||
void trackerlogic_deinit( void );
|
void trackerlogic_deinit( void );
|
||||||
void exerr( char * message );
|
void exerr( char * message );
|
||||||
|
|
||||||
/* add_peer_to_torrent does only release the torrent bucket if from_sync is set,
|
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) );
|
||||||
otherwise it is released in return_peers_for_torrent */
|
size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto );
|
||||||
size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount);
|
size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto );
|
||||||
size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws);
|
size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply );
|
||||||
size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply);
|
size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply );
|
||||||
size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply);
|
|
||||||
void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count);
|
|
||||||
#ifdef _DEBUG_RANDOMTORRENTS
|
|
||||||
void trackerlogic_add_random_torrents(size_t amount);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* torrent iterator */
|
|
||||||
void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data);
|
|
||||||
|
|
||||||
/* Helper, before it moves to its own object */
|
/* Helper, before it moves to its own object */
|
||||||
void free_peerlist( ot_peerlist *peer_list );
|
void free_peerlist( ot_peerlist *peer_list );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user