import form http://ctorrent_ipv6.sourceforge.net/
This commit is contained in:
commit
01089f65e2
4
AUTHORS
Executable file
4
AUTHORS
Executable file
@ -0,0 +1,4 @@
|
||||
YuHong
|
||||
bsdi@sina.com
|
||||
IPv6 handling:
|
||||
kantacki@o2.pl
|
340
COPYING
Normal file
340
COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
266
Doxyfile
Normal file
266
Doxyfile
Normal file
@ -0,0 +1,266 @@
|
||||
# Doxyfile 1.3.7-KDevelop
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = ctorrent.kdevelop
|
||||
PROJECT_NUMBER = $VERSION$
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH = /usr/home/jake/devel/realrekord-0.9-jr3/
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = /usr/home/jake/devel/ctorrent
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.mm \
|
||||
*.C \
|
||||
*.CC \
|
||||
*.C++ \
|
||||
*.II \
|
||||
*.I++ \
|
||||
*.H \
|
||||
*.HH \
|
||||
*.H++ \
|
||||
*.CS \
|
||||
*.PHP \
|
||||
*.PHP3 \
|
||||
*.M \
|
||||
*.MM \
|
||||
*.C \
|
||||
*.H \
|
||||
*.tlh \
|
||||
*.diff \
|
||||
*.patch \
|
||||
*.moc \
|
||||
*.xpm \
|
||||
*.dox
|
||||
RECURSIVE = yes
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = yes
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE = ctorrent.tag
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
6
INSTALL
Executable file
6
INSTALL
Executable file
@ -0,0 +1,6 @@
|
||||
How to install:
|
||||
|
||||
$ ./configure
|
||||
$ make install
|
||||
$ hash
|
||||
$ ctorrent_ipv6 -h
|
2
Makefile.am
Executable file
2
Makefile.am
Executable file
@ -0,0 +1,2 @@
|
||||
bin_PROGRAMS = ctorrent_ipv6
|
||||
ctorrent_ipv6_SOURCES = bencode.cpp bitfield.cpp btconfig.cpp btcontent.cpp btfiles.cpp btrequest.cpp btstream.cpp bufio.cpp connect_nonb.cpp ctorrent.cpp downloader.cpp httpencode.cpp iplist.cpp peer.cpp peerlist.cpp rate.cpp setnonblock.cpp sigint.cpp tracker.cpp bencode.h bitfield.h btconfig.h btcontent.h btfiles.h btrequest.h btstream.h bufio.h connect_nonb.h def.h downloader.h httpencode.h iplist.h msgencode.h peer.h peerlist.h rate.h setnonblock.h sigint.h tracker.h
|
572
Makefile.in
Normal file
572
Makefile.in
Normal file
@ -0,0 +1,572 @@
|
||||
# Makefile.in generated by automake 1.9.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
top_builddir = .
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
INSTALL = @INSTALL@
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
bin_PROGRAMS = ctorrent_ipv6$(EXEEXT)
|
||||
subdir = .
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
|
||||
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
|
||||
depcomp install-sh missing mkinstalldirs
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno configure.status.lineno
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
|
||||
PROGRAMS = $(bin_PROGRAMS)
|
||||
am_ctorrent_ipv6_OBJECTS = bencode.$(OBJEXT) bitfield.$(OBJEXT) \
|
||||
btconfig.$(OBJEXT) btcontent.$(OBJEXT) btfiles.$(OBJEXT) \
|
||||
btrequest.$(OBJEXT) btstream.$(OBJEXT) bufio.$(OBJEXT) \
|
||||
connect_nonb.$(OBJEXT) ctorrent.$(OBJEXT) downloader.$(OBJEXT) \
|
||||
httpencode.$(OBJEXT) iplist.$(OBJEXT) peer.$(OBJEXT) \
|
||||
peerlist.$(OBJEXT) rate.$(OBJEXT) setnonblock.$(OBJEXT) \
|
||||
sigint.$(OBJEXT) tracker.$(OBJEXT)
|
||||
ctorrent_ipv6_OBJECTS = $(am_ctorrent_ipv6_OBJECTS)
|
||||
ctorrent_ipv6_LDADD = $(LDADD)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
|
||||
-o $@
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(ctorrent_ipv6_SOURCES)
|
||||
DIST_SOURCES = $(ctorrent_ipv6_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d $(distdir) \
|
||||
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr $(distdir); }; }
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMDEP_FALSE = @AMDEP_FALSE@
|
||||
AMDEP_TRUE = @AMDEP_TRUE@
|
||||
AMTAR = @AMTAR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
GREP = @GREP@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
|
||||
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
|
||||
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
|
||||
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build_alias = @build_alias@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host_alias = @host_alias@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
ctorrent_ipv6_SOURCES = bencode.cpp bitfield.cpp btconfig.cpp btcontent.cpp btfiles.cpp btrequest.cpp btstream.cpp bufio.cpp connect_nonb.cpp ctorrent.cpp downloader.cpp httpencode.cpp iplist.cpp peer.cpp peerlist.cpp rate.cpp setnonblock.cpp sigint.cpp tracker.cpp bencode.h bitfield.h btconfig.h btcontent.h btfiles.h btrequest.h btstream.h bufio.h connect_nonb.h def.h downloader.h httpencode.h iplist.h msgencode.h peer.h peerlist.h rate.h setnonblock.h sigint.h tracker.h
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cpp .o .obj
|
||||
am--refresh:
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
|
||||
cd $(srcdir) && $(AUTOMAKE) --gnu \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f stamp-h1; \
|
||||
$(MAKE) stamp-h1; \
|
||||
else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
cd $(top_srcdir) && $(AUTOHEADER)
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
install-binPROGRAMS: $(bin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
|
||||
@list='$(bin_PROGRAMS)'; for p in $$list; do \
|
||||
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
|
||||
if test -f $$p \
|
||||
; then \
|
||||
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
|
||||
echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
|
||||
$(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-binPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(bin_PROGRAMS)'; for p in $$list; do \
|
||||
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
|
||||
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(bindir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-binPROGRAMS:
|
||||
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
|
||||
ctorrent_ipv6$(EXEEXT): $(ctorrent_ipv6_OBJECTS) $(ctorrent_ipv6_DEPENDENCIES)
|
||||
@rm -f ctorrent_ipv6$(EXEEXT)
|
||||
$(CXXLINK) $(ctorrent_ipv6_LDFLAGS) $(ctorrent_ipv6_OBJECTS) $(ctorrent_ipv6_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfield.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/btconfig.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/btcontent.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/btfiles.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/btrequest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/btstream.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufio.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connect_nonb.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctorrent.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/downloader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpencode.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iplist.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peerlist.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rate.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setnonblock.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigint.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracker.Po@am__quote@
|
||||
|
||||
.cpp.o:
|
||||
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||
|
||||
.cpp.obj:
|
||||
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
uninstall-info-am:
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$tags $$unique; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& cd $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) $$here
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
case $$file in \
|
||||
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
|
||||
esac; \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
|
||||
dir="/$$dir"; \
|
||||
$(mkdir_p) "$(distdir)$$dir"; \
|
||||
else \
|
||||
dir=''; \
|
||||
fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
|
||||
fi; \
|
||||
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r $(distdir)
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& cd $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
|
||||
$(am__remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
|
||||
distuninstallcheck:
|
||||
@cd $(distuninstallcheck_dir) \
|
||||
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS) config.h
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(bindir)"; do \
|
||||
test -z "$$dir" || $(mkdir_p) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-exec-am: install-binPROGRAMS
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-man:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-binPROGRAMS uninstall-info-am
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
|
||||
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
|
||||
distclean-compile distclean-generic distclean-hdr \
|
||||
distclean-tags distcleancheck distdir distuninstallcheck dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-binPROGRAMS install-data install-data-am install-exec \
|
||||
install-exec-am install-info install-info-am install-man \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-binPROGRAMS \
|
||||
uninstall-info-am
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
22
NEWS
Normal file
22
NEWS
Normal file
@ -0,0 +1,22 @@
|
||||
Sept 8 2004:
|
||||
Ver 1.3.4
|
||||
=========
|
||||
Changes to tracker.cpp fixes bug in compact peer address acquisition
|
||||
This will speed up download starts using compact tracker protocol
|
||||
|
||||
Addition of peer identifier
|
||||
Peer identifier can be set to any string <= 8 chrs
|
||||
Peer identifier can be set to - to present an anonymous client
|
||||
Peer identifer defaults to -CT1304- where 1304 represents ctorrent-1.3.4
|
||||
|
||||
CTorrent resolves internal domain address if behind firewall
|
||||
|
||||
Ver 1.3.3
|
||||
=========
|
||||
Added compact tracker protocol handling
|
||||
|
||||
Vers < 1.3.3
|
||||
============
|
||||
cache io. modified
|
||||
virtual host. added
|
||||
rate limits. added
|
4
README
Normal file
4
README
Normal file
@ -0,0 +1,4 @@
|
||||
CTorrent
|
||||
=======
|
||||
CTorrent is a BitTorrent Client program written in C/C++ for FreeBSD and Linux.
|
||||
Fast and small are CTorrent`s two strengths.
|
850
aclocal.m4
vendored
Normal file
850
aclocal.m4
vendored
Normal file
@ -0,0 +1,850 @@
|
||||
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
# generated from the m4 files accompanying Automake X.Y.
|
||||
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
|
||||
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION so it can be traced.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.9.6])])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
#
|
||||
# Of course, Automake must honor this variable whenever it calls a
|
||||
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||
# depending on how configure is run. This is pretty annoying, since
|
||||
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||
# source directory, any form will work fine, but in subdirectories a
|
||||
# relative path needs to be adjusted first.
|
||||
#
|
||||
# $ac_aux_dir/missing
|
||||
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||
# $top_srcdir/$ac_aux_dir/missing
|
||||
# fails if $ac_aux_dir is absolute,
|
||||
# fails when called from a subdirectory in a VPATH build with
|
||||
# a relative $ac_aux_dir
|
||||
#
|
||||
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||
# harmless because $srcdir is `.', but things will broke when you
|
||||
# start a VPATH build or use an absolute $srcdir.
|
||||
#
|
||||
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||
# and then we would define $MISSING as
|
||||
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# This will work as long as MISSING is not called from configure, because
|
||||
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||
# However there are other variables, like CC, which are often used in
|
||||
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||
#
|
||||
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||
# configured tree to be moved without reconfiguration.
|
||||
|
||||
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||
[dnl Rely on autoconf to set up CDPATH properly.
|
||||
AC_PREREQ([2.50])dnl
|
||||
# expand $ac_aux_dir to an absolute path
|
||||
am_aux_dir=`cd $ac_aux_dir && pwd`
|
||||
])
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 7
|
||||
|
||||
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||
# -------------------------------------
|
||||
# Define a conditional.
|
||||
AC_DEFUN([AM_CONDITIONAL],
|
||||
[AC_PREREQ(2.52)dnl
|
||||
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||
AC_SUBST([$1_TRUE])
|
||||
AC_SUBST([$1_FALSE])
|
||||
if $2; then
|
||||
$1_TRUE=
|
||||
$1_FALSE='#'
|
||||
else
|
||||
$1_TRUE='#'
|
||||
$1_FALSE=
|
||||
fi
|
||||
AC_CONFIG_COMMANDS_PRE(
|
||||
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8
|
||||
|
||||
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
|
||||
# written in clear, in which case automake, when reading aclocal.m4,
|
||||
# will think it sees a *use*, and therefore will trigger all it's
|
||||
# C support machinery. Also note that it means that autoscan, seeing
|
||||
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
|
||||
|
||||
|
||||
# _AM_DEPENDENCIES(NAME)
|
||||
# ----------------------
|
||||
# See how the compiler implements dependency checking.
|
||||
# NAME is "CC", "CXX", "GCJ", or "OBJC".
|
||||
# We try a few techniques and use that to set a single cache variable.
|
||||
#
|
||||
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
|
||||
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
|
||||
# dependency, and given that the user is not expected to run this macro,
|
||||
# just rely on AC_PROG_CC.
|
||||
AC_DEFUN([_AM_DEPENDENCIES],
|
||||
[AC_REQUIRE([AM_SET_DEPDIR])dnl
|
||||
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
|
||||
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
|
||||
AC_REQUIRE([AM_DEP_TRACK])dnl
|
||||
|
||||
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
|
||||
[$1], CXX, [depcc="$CXX" am_compiler_list=],
|
||||
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
|
||||
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
|
||||
[depcc="$$1" am_compiler_list=])
|
||||
|
||||
AC_CACHE_CHECK([dependency style of $depcc],
|
||||
[am_cv_$1_dependencies_compiler_type],
|
||||
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
|
||||
# We make a subdir and do the tests there. Otherwise we can end up
|
||||
# making bogus files that we don't know about and never remove. For
|
||||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
cp "$am_depcomp" conftest.dir
|
||||
cd conftest.dir
|
||||
# We will build objects and dependencies in a subdirectory because
|
||||
# it helps to detect inapplicable dependency modes. For instance
|
||||
# both Tru64's cc and ICC support -MD to output dependencies as a
|
||||
# side effect of compilation, but ICC will put the dependencies in
|
||||
# the current directory while Tru64 will put them in the object
|
||||
# directory.
|
||||
mkdir sub
|
||||
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
if test "$am_compiler_list" = ""; then
|
||||
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
|
||||
fi
|
||||
for depmode in $am_compiler_list; do
|
||||
# Setup a source with many dependencies, because some compilers
|
||||
# like to wrap large dependency lists on column 80 (with \), and
|
||||
# we should not choose a depcomp mode which is confused by this.
|
||||
#
|
||||
# We need to recreate these files for each test, as the compiler may
|
||||
# overwrite some of them when testing with obscure command lines.
|
||||
# This happens at least with the AIX C compiler.
|
||||
: > sub/conftest.c
|
||||
for i in 1 2 3 4 5 6; do
|
||||
echo '#include "conftst'$i'.h"' >> sub/conftest.c
|
||||
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
|
||||
# Solaris 8's {/usr,}/bin/sh.
|
||||
touch sub/conftst$i.h
|
||||
done
|
||||
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
|
||||
|
||||
case $depmode in
|
||||
nosideeffect)
|
||||
# after this tag, mechanisms are not by side-effect, so they'll
|
||||
# only be used when explicitly requested
|
||||
if test "x$enable_dependency_tracking" = xyes; then
|
||||
continue
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
none) break ;;
|
||||
esac
|
||||
# We check with `-c' and `-o' for the sake of the "dashmstdout"
|
||||
# mode. It turns out that the SunPro C++ compiler does not properly
|
||||
# handle `-M -o', and we need to detect this.
|
||||
if depmode=$depmode \
|
||||
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
|
||||
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
|
||||
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
|
||||
>/dev/null 2>conftest.err &&
|
||||
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
|
||||
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
|
||||
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
|
||||
# icc doesn't choke on unknown options, it will just issue warnings
|
||||
# or remarks (even with -Werror). So we grep stderr for any message
|
||||
# that says an option was ignored or not supported.
|
||||
# When given -MP, icc 7.0 and 7.1 complain thusly:
|
||||
# icc: Command line warning: ignoring option '-M'; no argument required
|
||||
# The diagnosis changed in icc 8.0:
|
||||
# icc: Command line remark: option '-MP' not supported
|
||||
if (grep 'ignoring option' conftest.err ||
|
||||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
|
||||
am_cv_$1_dependencies_compiler_type=$depmode
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
rm -rf conftest.dir
|
||||
else
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
fi
|
||||
])
|
||||
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
|
||||
AM_CONDITIONAL([am__fastdep$1], [
|
||||
test "x$enable_dependency_tracking" != xno \
|
||||
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
|
||||
])
|
||||
|
||||
|
||||
# AM_SET_DEPDIR
|
||||
# -------------
|
||||
# Choose a directory name for dependency files.
|
||||
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
|
||||
AC_DEFUN([AM_SET_DEPDIR],
|
||||
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
|
||||
])
|
||||
|
||||
|
||||
# AM_DEP_TRACK
|
||||
# ------------
|
||||
AC_DEFUN([AM_DEP_TRACK],
|
||||
[AC_ARG_ENABLE(dependency-tracking,
|
||||
[ --disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors])
|
||||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
fi
|
||||
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
AC_SUBST([AMDEPBACKSLASH])
|
||||
])
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
#serial 3
|
||||
|
||||
# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# ------------------------------
|
||||
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[for mf in $CONFIG_FILES; do
|
||||
# Strip MF so we end up with the name of the file.
|
||||
mf=`echo "$mf" | sed -e 's/:.*$//'`
|
||||
# Check whether this is an Automake generated Makefile or not.
|
||||
# We used to match only the files named `Makefile.in', but
|
||||
# some people rename them; so instead we look at the file content.
|
||||
# Grep'ing the first line is not enough: some people post-process
|
||||
# each Makefile.in and add a new line on top of each file to say so.
|
||||
# So let's grep whole file.
|
||||
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
|
||||
dirpart=`AS_DIRNAME("$mf")`
|
||||
else
|
||||
continue
|
||||
fi
|
||||
# Extract the definition of DEPDIR, am__include, and am__quote
|
||||
# from the Makefile without running `make'.
|
||||
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
|
||||
test -z "$DEPDIR" && continue
|
||||
am__include=`sed -n 's/^am__include = //p' < "$mf"`
|
||||
test -z "am__include" && continue
|
||||
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
|
||||
# When using ansi2knr, U may be empty or an underscore; expand it
|
||||
U=`sed -n 's/^U = //p' < "$mf"`
|
||||
# Find all dependency output files, they are included files with
|
||||
# $(DEPDIR) in their names. We invoke sed twice because it is the
|
||||
# simplest approach to changing $(DEPDIR) to its actual value in the
|
||||
# expansion.
|
||||
for file in `sed -n "
|
||||
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
|
||||
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
|
||||
# Make sure the directory exists.
|
||||
test -f "$dirpart/$file" && continue
|
||||
fdir=`AS_DIRNAME(["$file"])`
|
||||
AS_MKDIR_P([$dirpart/$fdir])
|
||||
# echo "creating $dirpart/$file"
|
||||
echo '# dummy' > "$dirpart/$file"
|
||||
done
|
||||
done
|
||||
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
|
||||
|
||||
# AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# -----------------------------
|
||||
# This macro should only be invoked once -- use via AC_REQUIRE.
|
||||
#
|
||||
# This code is only required when automatic dependency tracking
|
||||
# is enabled. FIXME. This creates each `.P' file that we will
|
||||
# need in order to bootstrap the dependency handling code.
|
||||
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AC_CONFIG_COMMANDS([depfiles],
|
||||
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
|
||||
])
|
||||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 12
|
||||
|
||||
# This macro actually does too much. Some checks are only needed if
|
||||
# your package does certain things. But this isn't really a big deal.
|
||||
|
||||
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||
# -----------------------------------------------
|
||||
# The call with PACKAGE and VERSION arguments is the old style
|
||||
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||
# and VERSION should now be passed to AC_INIT and removed from
|
||||
# the call to AM_INIT_AUTOMAKE.
|
||||
# We support both call styles for the transition. After
|
||||
# the next Automake release, Autoconf can make the AC_INIT
|
||||
# arguments mandatory, and then we can depend on a new Autoconf
|
||||
# release and drop the old call support.
|
||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||
[AC_PREREQ([2.58])dnl
|
||||
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||
dnl the ones we care about.
|
||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||
# test to see if srcdir already configured
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`" &&
|
||||
test -f $srcdir/config.status; then
|
||||
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||
fi
|
||||
|
||||
# test whether we have cygpath
|
||||
if test -z "$CYGPATH_W"; then
|
||||
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||
CYGPATH_W='cygpath -w'
|
||||
else
|
||||
CYGPATH_W=echo
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CYGPATH_W])
|
||||
|
||||
# Define the identity of the package.
|
||||
dnl Distinguish between old-style and new-style calls.
|
||||
m4_ifval([$2],
|
||||
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||
AC_SUBST([PACKAGE], [$1])dnl
|
||||
AC_SUBST([VERSION], [$2])],
|
||||
[_AM_SET_OPTIONS([$1])dnl
|
||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||
|
||||
_AM_IF_OPTION([no-define],,
|
||||
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
|
||||
|
||||
# Some tools Automake needs.
|
||||
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOCONF, autoconf)
|
||||
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOHEADER, autoheader)
|
||||
AM_MISSING_PROG(MAKEINFO, makeinfo)
|
||||
AM_PROG_INSTALL_SH
|
||||
AM_PROG_INSTALL_STRIP
|
||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||
[_AM_PROG_TAR([v7])])])
|
||||
_AM_IF_OPTION([no-dependencies],,
|
||||
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||
[_AM_DEPENDENCIES(CC)],
|
||||
[define([AC_PROG_CC],
|
||||
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||
[_AM_DEPENDENCIES(CXX)],
|
||||
[define([AC_PROG_CXX],
|
||||
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
# When config.status generates a header, we must update the stamp-h file.
|
||||
# This file resides in the same directory as the config header
|
||||
# that is generated. The stamp files are numbered to have different names.
|
||||
|
||||
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||
# loop where config.status creates the headers, so we can generate
|
||||
# our stamp files there.
|
||||
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||
[# Compute $1's index in $config_headers.
|
||||
_am_stamp_count=1
|
||||
for _am_header in $config_headers :; do
|
||||
case $_am_header in
|
||||
$1 | $1:* )
|
||||
break ;;
|
||||
* )
|
||||
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||
esac
|
||||
done
|
||||
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
||||
AC_SUBST(install_sh)])
|
||||
|
||||
# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# Check whether the underlying file-system supports filenames
|
||||
# with a leading dot. For instance MS-DOS doesn't.
|
||||
AC_DEFUN([AM_SET_LEADING_DOT],
|
||||
[rm -rf .tst 2>/dev/null
|
||||
mkdir .tst 2>/dev/null
|
||||
if test -d .tst; then
|
||||
am__leading_dot=.
|
||||
else
|
||||
am__leading_dot=_
|
||||
fi
|
||||
rmdir .tst 2>/dev/null
|
||||
AC_SUBST([am__leading_dot])])
|
||||
|
||||
# Check to see how 'make' treats includes. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# AM_MAKE_INCLUDE()
|
||||
# -----------------
|
||||
# Check to see how make treats includes.
|
||||
AC_DEFUN([AM_MAKE_INCLUDE],
|
||||
[am_make=${MAKE-make}
|
||||
cat > confinc << 'END'
|
||||
am__doit:
|
||||
@echo done
|
||||
.PHONY: am__doit
|
||||
END
|
||||
# If we don't find an include directive, just comment out the code.
|
||||
AC_MSG_CHECKING([for style of include used by $am_make])
|
||||
am__include="#"
|
||||
am__quote=
|
||||
_am_result=none
|
||||
# First try GNU make style include.
|
||||
echo "include confinc" > confmf
|
||||
# We grep out `Entering directory' and `Leaving directory'
|
||||
# messages which can occur if `w' ends up in MAKEFLAGS.
|
||||
# In particular we don't look at `^make:' because GNU make might
|
||||
# be invoked under some other name (usually "gmake"), in which
|
||||
# case it prints its new name instead of `make'.
|
||||
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
|
||||
am__include=include
|
||||
am__quote=
|
||||
_am_result=GNU
|
||||
fi
|
||||
# Now try BSD make style include.
|
||||
if test "$am__include" = "#"; then
|
||||
echo '.include "confinc"' > confmf
|
||||
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
|
||||
am__include=.include
|
||||
am__quote="\""
|
||||
_am_result=BSD
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([am__include])
|
||||
AC_SUBST([am__quote])
|
||||
AC_MSG_RESULT([$_am_result])
|
||||
rm -f confinc confmf
|
||||
])
|
||||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||
# ------------------------------
|
||||
AC_DEFUN([AM_MISSING_PROG],
|
||||
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||
$1=${$1-"${am_missing_run}$2"}
|
||||
AC_SUBST($1)])
|
||||
|
||||
|
||||
# AM_MISSING_HAS_RUN
|
||||
# ------------------
|
||||
# Define MISSING if not defined so far and test if it supports --run.
|
||||
# If it does, set am_missing_run to use it, otherwise, to nothing.
|
||||
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# Use eval to expand $SHELL
|
||||
if eval "$MISSING --run true"; then
|
||||
am_missing_run="$MISSING --run "
|
||||
else
|
||||
am_missing_run=
|
||||
AC_MSG_WARN([`missing' script is too old or missing])
|
||||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
|
||||
#
|
||||
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
|
||||
# created by `make install' are always world readable, even if the
|
||||
# installer happens to have an overly restrictive umask (e.g. 077).
|
||||
# This was a mistake. There are at least two reasons why we must not
|
||||
# use `-m 0755':
|
||||
# - it causes special bits like SGID to be ignored,
|
||||
# - it may be too restrictive (some setups expect 775 directories).
|
||||
#
|
||||
# Do not use -m 0755 and let people choose whatever they expect by
|
||||
# setting umask.
|
||||
#
|
||||
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
|
||||
# Some implementations (such as Solaris 8's) are not thread-safe: if a
|
||||
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
|
||||
# concurrently, both version can detect that a/ is missing, but only
|
||||
# one can create it and the other will error out. Consequently we
|
||||
# restrict ourselves to GNU make (using the --version option ensures
|
||||
# this.)
|
||||
AC_DEFUN([AM_PROG_MKDIR_P],
|
||||
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
|
||||
# We used to keeping the `.' as first argument, in order to
|
||||
# allow $(mkdir_p) to be used without argument. As in
|
||||
# $(mkdir_p) $(somedir)
|
||||
# where $(somedir) is conditionally defined. However this is wrong
|
||||
# for two reasons:
|
||||
# 1. if the package is installed by a user who cannot write `.'
|
||||
# make install will fail,
|
||||
# 2. the above comment should most certainly read
|
||||
# $(mkdir_p) $(DESTDIR)$(somedir)
|
||||
# so it does not work when $(somedir) is undefined and
|
||||
# $(DESTDIR) is not.
|
||||
# To support the latter case, we have to write
|
||||
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
|
||||
# so the `.' trick is pointless.
|
||||
mkdir_p='mkdir -p --'
|
||||
else
|
||||
# On NextStep and OpenStep, the `mkdir' command does not
|
||||
# recognize any option. It will interpret all options as
|
||||
# directories to create, and then abort because `.' already
|
||||
# exists.
|
||||
for d in ./-p ./--version;
|
||||
do
|
||||
test -d $d && rmdir $d
|
||||
done
|
||||
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
|
||||
if test -f "$ac_aux_dir/mkinstalldirs"; then
|
||||
mkdir_p='$(mkinstalldirs)'
|
||||
else
|
||||
mkdir_p='$(install_sh) -d'
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([mkdir_p])])
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# ------------------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ----------------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_SANITY_CHECK
|
||||
# ---------------
|
||||
AC_DEFUN([AM_SANITY_CHECK],
|
||||
[AC_MSG_CHECKING([whether build environment is sane])
|
||||
# Just in case
|
||||
sleep 1
|
||||
echo timestamp > conftest.file
|
||||
# Do `set' in a subshell so we don't clobber the current shell's
|
||||
# arguments. Must try -L first in case configure is actually a
|
||||
# symlink; some systems play weird games with the mod time of symlinks
|
||||
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||
# directory).
|
||||
if (
|
||||
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
|
||||
if test "$[*]" = "X"; then
|
||||
# -L didn't work.
|
||||
set X `ls -t $srcdir/configure conftest.file`
|
||||
fi
|
||||
rm -f conftest.file
|
||||
if test "$[*]" != "X $srcdir/configure conftest.file" \
|
||||
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
|
||||
|
||||
# If neither matched, then we have a broken ls. This can happen
|
||||
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||
# broken ls alias from the environment. This has actually
|
||||
# happened. Such a system could not be considered "sane".
|
||||
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||
alias in your environment])
|
||||
fi
|
||||
|
||||
test "$[2]" = conftest.file
|
||||
)
|
||||
then
|
||||
# Ok.
|
||||
:
|
||||
else
|
||||
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||
Check your system clock])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
# specify the program used to strip binaries. This is especially
|
||||
# annoying in cross-compiling environments, where the build's strip
|
||||
# is unlikely to handle the host's binaries.
|
||||
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||
# always use install-sh in `make install-strip', and initialize
|
||||
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
# Installed binaries are usually stripped using `strip' when the user
|
||||
# run `make install-strip'. However `strip' might not be the right
|
||||
# tool to use in cross-compilation environments, therefore Automake
|
||||
# will honor the `STRIP' environment variable to overrule this program.
|
||||
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
|
||||
if test "$cross_compiling" != no; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||
fi
|
||||
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# _AM_PROG_TAR(FORMAT)
|
||||
# --------------------
|
||||
# Check how to create a tarball in format FORMAT.
|
||||
# FORMAT should be one of `v7', `ustar', or `pax'.
|
||||
#
|
||||
# Substitute a variable $(am__tar) that is a command
|
||||
# writing to stdout a FORMAT-tarball containing the directory
|
||||
# $tardir.
|
||||
# tardir=directory && $(am__tar) > result.tar
|
||||
#
|
||||
# Substitute a variable $(am__untar) that extract such
|
||||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility.
|
||||
AM_MISSING_PROG([AMTAR], [tar])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
# Loop over all known methods to create a tar archive until one works.
|
||||
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||
# Do not fold the above two line into one, because Tru64 sh and
|
||||
# Solaris sh will not grok spaces in the rhs of `-'.
|
||||
for _am_tool in $_am_tools
|
||||
do
|
||||
case $_am_tool in
|
||||
gnutar)
|
||||
for _am_tar in tar gnutar gtar;
|
||||
do
|
||||
AM_RUN_LOG([$_am_tar --version]) && break
|
||||
done
|
||||
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||
am__untar="$_am_tar -xf -"
|
||||
;;
|
||||
plaintar)
|
||||
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||
# ustar tarball either.
|
||||
(tar --version) >/dev/null 2>&1 && continue
|
||||
am__tar='tar chf - "$$tardir"'
|
||||
am__tar_='tar chf - "$tardir"'
|
||||
am__untar='tar xf -'
|
||||
;;
|
||||
pax)
|
||||
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||
am__untar='pax -r'
|
||||
;;
|
||||
cpio)
|
||||
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||
am__untar='cpio -i -H $1 -d'
|
||||
;;
|
||||
none)
|
||||
am__tar=false
|
||||
am__tar_=false
|
||||
am__untar=false
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the value was cached, stop now. We just wanted to have am__tar
|
||||
# and am__untar set.
|
||||
test -n "${am_cv_prog_tar_$1}" && break
|
||||
|
||||
# tar/untar a dummy directory, and stop if the command works
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
echo GrepMe > conftest.dir/file
|
||||
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||
rm -rf conftest.dir
|
||||
if test -s conftest.tar; then
|
||||
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||
fi
|
||||
done
|
||||
rm -rf conftest.dir
|
||||
|
||||
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||
AC_SUBST([am__tar])
|
||||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
241
bencode.cpp
Normal file
241
bencode.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "./def.h"
|
||||
#include "bencode.h"
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static const char* next_key(const char *keylist)
|
||||
{
|
||||
for(;*keylist && *keylist != KEY_SP; keylist++);
|
||||
if(*keylist) keylist++;
|
||||
return keylist;
|
||||
}
|
||||
|
||||
static size_t compare_key(const char *key,size_t keylen,const char *keylist)
|
||||
{
|
||||
for(;keylen && *keylist && *key==*keylist;keylen--,key++,keylist++) ;
|
||||
if(!keylen) if(*keylist && *keylist!=KEY_SP) return 1;
|
||||
return keylen;
|
||||
}
|
||||
|
||||
size_t buf_int(const char *b,size_t len,char beginchar,char endchar,size_t *pi)
|
||||
{
|
||||
const char *p = b;
|
||||
const char *psave;
|
||||
|
||||
if(2 > len) return 0; /* buffer too small */
|
||||
|
||||
if( beginchar ){
|
||||
if(*p != beginchar) return 0;
|
||||
p++; len--;
|
||||
}
|
||||
|
||||
for(psave = p; len && isdigit(*p); p++,len--) ;
|
||||
|
||||
if(!len || MAX_INT_SIZ < (p - psave) || *p != endchar) return 0;
|
||||
|
||||
if( pi ){
|
||||
if( beginchar ) *pi = (size_t)strtol(b + 1,(char**) 0,10);
|
||||
else *pi=(size_t)strtol(b,(char**) 0,10);
|
||||
}
|
||||
return (size_t)( p - b + 1 );
|
||||
}
|
||||
|
||||
size_t buf_str(const char *b,size_t len,const char **pstr,size_t* slen)
|
||||
{
|
||||
size_t rl,sl;
|
||||
|
||||
rl = buf_int(b,len,0,':',&sl);
|
||||
|
||||
if( !rl ) return 0;
|
||||
|
||||
if(len < rl + sl) return 0;
|
||||
if(pstr) *pstr = b + rl;
|
||||
if(slen) *slen = sl;
|
||||
|
||||
return( rl + sl );
|
||||
}
|
||||
|
||||
size_t decode_int(const char *b,size_t len)
|
||||
{
|
||||
return(buf_int(b,len,'i','e',(size_t*) 0));
|
||||
}
|
||||
|
||||
size_t decode_str(const char *b,size_t len)
|
||||
{
|
||||
return (buf_str(b,len,(const char**) 0,(size_t*) 0));
|
||||
}
|
||||
|
||||
size_t decode_dict(const char *b,size_t len,const char *keylist)
|
||||
{
|
||||
size_t rl,dl,nl;
|
||||
const char *pkey;
|
||||
dl = 0;
|
||||
if(2 > len || *b != 'd') return 0;
|
||||
|
||||
dl++; len--;
|
||||
for(;len && *(b + dl) != 'e';){
|
||||
rl = buf_str(b + dl,len,&pkey,&nl);
|
||||
|
||||
if( !rl || KEYNAME_SIZ < nl) return 0;
|
||||
dl += rl;
|
||||
len -= rl;
|
||||
|
||||
if(keylist && compare_key(pkey,nl,keylist) == 0){
|
||||
pkey = next_key(keylist);
|
||||
if(! *pkey ) return dl;
|
||||
rl = decode_dict(b + dl,len, pkey);
|
||||
if( !rl ) return 0;
|
||||
return dl + rl;
|
||||
}
|
||||
|
||||
rl = decode_rev(b + dl,len,(const char*) 0);
|
||||
if( !rl ) return 0;
|
||||
|
||||
dl += rl;len -= rl;
|
||||
}
|
||||
if( !len || keylist) return 0;
|
||||
return dl + 1; /* add the last char 'e' */
|
||||
}
|
||||
|
||||
size_t decode_list(const char *b,size_t len,const char *keylist)
|
||||
{
|
||||
size_t ll,rl;
|
||||
ll = 0;
|
||||
if(2 > len || *b != 'l') return 0;
|
||||
len--; ll++;
|
||||
for(;len && *(b + ll) != 'e';){
|
||||
rl = decode_rev(b + ll,len,keylist);
|
||||
if( !rl ) return 0;
|
||||
|
||||
ll += rl; len -= rl;
|
||||
}
|
||||
if( !len ) return 0;
|
||||
return ll + 1; /* add last char 'e' */
|
||||
}
|
||||
|
||||
size_t decode_rev(const char *b,size_t len,const char *keylist)
|
||||
{
|
||||
if( !b ) return 0;
|
||||
switch( *b ){
|
||||
case 'i': return decode_int(b,len);
|
||||
case 'd': return decode_dict(b,len,keylist);
|
||||
case 'l': return decode_list(b,len,keylist);
|
||||
default: return decode_str(b,len);
|
||||
}
|
||||
}
|
||||
|
||||
size_t decode_query(const char *b,size_t len,const char *keylist,const char **ps,size_t *pi,int method)
|
||||
{
|
||||
size_t pos;
|
||||
char kl[KEYNAME_LISTSIZ];
|
||||
strcpy(kl,keylist);
|
||||
pos = decode_rev(b, len, kl);
|
||||
if( !pos ) return 0;
|
||||
switch(method){
|
||||
case QUERY_STR: return(buf_str(b + pos,len - pos, ps, pi));
|
||||
case QUERY_INT: return(buf_int(b + pos,len - pos, 'i', 'e', pi));
|
||||
case QUERY_POS:
|
||||
if(pi) *pi = decode_rev(b + pos, len - pos, (const char*) 0);
|
||||
return pos;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t bencode_buf(const char *buf,size_t len,FILE *fp)
|
||||
{
|
||||
char slen[MAX_INT_SIZ];
|
||||
char *b;
|
||||
if( MAX_INT_SIZ <= snprintf(slen, MAX_INT_SIZ, "%u:", len) ) return 0;
|
||||
if( fwrite( slen, strlen(slen), 1, fp) != 1) return 0;
|
||||
b = new char[len + strlen(slen)];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) return 0;
|
||||
#endif
|
||||
if( fwrite(buf, len, 1, fp) != 1 ){ delete []b; return 0;}
|
||||
delete []b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t bencode_str(const char *str, FILE *fp)
|
||||
{
|
||||
return bencode_buf(str, strlen(str), fp);
|
||||
}
|
||||
|
||||
size_t bencode_int(const int integer, FILE *fp)
|
||||
{
|
||||
char buf[MAX_INT_SIZ];
|
||||
if( EOF == fputc('i', fp)) return 0;
|
||||
if( MAX_INT_SIZ <= snprintf(buf, MAX_INT_SIZ, "%u", integer) )
|
||||
return 0;
|
||||
if( fwrite(buf, strlen(buf), 1, fp) != 1 ) return 0;
|
||||
return ( EOF == fputc('e', fp)) ? 0: 1;
|
||||
}
|
||||
|
||||
size_t bencode_begin_dict(FILE *fp)
|
||||
{
|
||||
return (EOF == fputc('d',fp)) ? 0 : 1;
|
||||
}
|
||||
|
||||
size_t bencode_begin_list(FILE *fp)
|
||||
{
|
||||
return (EOF == fputc('l',fp)) ? 0 : 1;
|
||||
}
|
||||
|
||||
size_t bencode_end_dict_list(FILE *fp)
|
||||
{
|
||||
return (EOF == fputc('e',fp)) ? 0 : 1;
|
||||
}
|
||||
|
||||
size_t bencode_path2list(const char *pathname, FILE *fp)
|
||||
{
|
||||
char *pn;
|
||||
const char *p = pathname;
|
||||
|
||||
if( bencode_begin_list(fp) != 1 ) return 0;
|
||||
|
||||
for(; *p;){
|
||||
pn = strchr(p, PATH_SP);
|
||||
if( pn ){
|
||||
if( bencode_buf(p, pn - p, fp) != 1) return 0;
|
||||
p = pn + 1;
|
||||
}else{
|
||||
if( bencode_str(p, fp) != 1) return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bencode_end_dict_list(fp);
|
||||
}
|
||||
|
||||
size_t decode_list2path(const char *b, size_t n, char *pathname)
|
||||
{
|
||||
const char *pb = b;
|
||||
const char *s = (char *) 0;
|
||||
size_t r,q;
|
||||
|
||||
if( 'l' != *pb ) return 0;
|
||||
pb++;
|
||||
n--;
|
||||
if( !n ) return 0;
|
||||
for(; n;){
|
||||
if(!(r = buf_str(pb, n, &s, &q)) ) return 0;
|
||||
memcpy(pathname, s, q);
|
||||
pathname += q;
|
||||
pb += r; n -= r;
|
||||
if( 'e' != *pb ){*pathname = PATH_SP, pathname++;} else break;
|
||||
}
|
||||
*pathname = '\0';
|
||||
return (pb - b + 1);
|
||||
}
|
34
bencode.h
Normal file
34
bencode.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef BENCODE_H
|
||||
#define BENCODE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define KEY_SP '|' //the keyname list's delimiters
|
||||
#define KEYNAME_SIZ 32
|
||||
#define KEYNAME_LISTSIZ 256
|
||||
|
||||
#define MAX_INT_SIZ 64
|
||||
|
||||
#define QUERY_STR 0
|
||||
#define QUERY_INT 1
|
||||
#define QUERY_POS 2
|
||||
|
||||
size_t buf_int(const char *b,size_t len,char beginchar,char endchar,size_t *pi);
|
||||
size_t buf_str(const char *b,size_t len,const char **pstr,size_t* slen);
|
||||
size_t decode_int(const char *b,size_t len);
|
||||
size_t decode_str(const char *b,size_t len);
|
||||
size_t decode_dict(const char *b,size_t len,const char *keylist);
|
||||
size_t decode_list(const char *b,size_t len,const char *keylist);
|
||||
size_t decode_rev(const char *b,size_t len,const char *keylist);
|
||||
size_t decode_query(const char *b,size_t len,const char *keylist,const char **ps,size_t *pi,int method);
|
||||
size_t decode_list2path(const char *b, size_t n, char *pathname);
|
||||
size_t bencode_buf(const char *str,size_t len,FILE *fp);
|
||||
size_t bencode_str(const char *str, FILE *fp);
|
||||
size_t bencode_int(const int integer, FILE *fp);
|
||||
size_t bencode_begin_dict(FILE *fp);
|
||||
size_t bencode_begin_list(FILE *fp);
|
||||
size_t bencode_end_dict_list(FILE *fp);
|
||||
size_t bencode_path2list(const char *pathname, FILE *fp);
|
||||
|
||||
#endif
|
302
bitfield.cpp
Normal file
302
bitfield.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#include "bitfield.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <io.h>
|
||||
#include <memory.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const unsigned char BIT_HEX[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
|
||||
|
||||
#define _isset(idx) (b[(idx) / 8 ] & BIT_HEX[(idx) % 8])
|
||||
#define _isempty() (nset == 0)
|
||||
#define _isempty_sp(sp) ((sp).nset == 0)
|
||||
#define _isfull() (nset >= nbits)
|
||||
#define _isfull_sp(sp) ((sp).nset >= nbits)
|
||||
|
||||
size_t BitField::nbytes = 0;
|
||||
size_t BitField::nbits = 0;
|
||||
|
||||
BitField::BitField()
|
||||
{
|
||||
b = new unsigned char[nbytes];
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
|
||||
memset(b, 0, nbytes);
|
||||
nset = 0;
|
||||
}
|
||||
|
||||
BitField::BitField(size_t npcs)
|
||||
{
|
||||
nbits = npcs;
|
||||
nbytes = nbits / 8;
|
||||
if( nbits % 8 ) nbytes++;
|
||||
|
||||
b = new unsigned char[nbytes];
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
|
||||
memset(b, 0, nbytes);
|
||||
nset = 0;
|
||||
}
|
||||
|
||||
BitField::BitField(const BitField &bf)
|
||||
{
|
||||
nset = bf.nset;
|
||||
if( _isfull_sp(bf) ) b = (unsigned char *) 0;
|
||||
else{
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
memcpy(b, bf.b, nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::SetReferBuffer(char *buf)
|
||||
{
|
||||
if( !b ){
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
}
|
||||
memcpy((char*)b,buf,nbytes);
|
||||
_recalc();
|
||||
}
|
||||
|
||||
void BitField::SetAll()
|
||||
{
|
||||
if( b ){
|
||||
delete []b;
|
||||
b = (unsigned char*) 0;
|
||||
}
|
||||
nset = nbits;
|
||||
}
|
||||
|
||||
int BitField::IsSet(size_t idx) const
|
||||
{
|
||||
if( idx >= nbits ) return 0;
|
||||
return _isfull() ? 1 : _isset(idx);
|
||||
}
|
||||
|
||||
void BitField::Set(size_t idx)
|
||||
{
|
||||
if(idx >= nbits) return;
|
||||
|
||||
if( !_isfull() && !_isset(idx) ){
|
||||
b[idx / 8] |= BIT_HEX[idx % 8];
|
||||
nset++;
|
||||
if( _isfull() && b){ delete []b; b = (unsigned char*) 0;}
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::UnSet(size_t idx)
|
||||
{
|
||||
if( idx >= nbits ) return;
|
||||
|
||||
if( _isfull() ){
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
_setall(b);
|
||||
b[idx / 8] &= (~BIT_HEX[idx % 8]);
|
||||
nset = nbits - 1;
|
||||
}else{
|
||||
if( _isset(idx) ){
|
||||
b[idx / 8] &= (~BIT_HEX[idx % 8]);
|
||||
nset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::Invert()
|
||||
{
|
||||
if( _isempty() ){
|
||||
if(b){
|
||||
delete []b;
|
||||
b = (unsigned char*) 0;
|
||||
}
|
||||
nset = nbits;
|
||||
}else if( _isfull() ){
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
memset(b, 0, nbytes);
|
||||
nset = 0;
|
||||
}else{
|
||||
size_t i = 0;
|
||||
size_t s = nset;
|
||||
for( ; i < nbytes - 1; i++ ) b[i] = ~b[i];
|
||||
|
||||
if( nbits % nbytes ){
|
||||
for( i = 8 * (nbytes - 1); i < nbits; i++ ) if( _isset(i) ) UnSet(i); else Set(i);
|
||||
}else
|
||||
b[nbytes - 1] = ~b[nbytes - 1];
|
||||
|
||||
nset = nbits - s;
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::Comb(const BitField &bf)
|
||||
{
|
||||
size_t i;
|
||||
if( _isfull() || _isfull_sp(bf) ){
|
||||
SetAll();
|
||||
}else{
|
||||
for(i = 0; i < nbytes; i++) b[i] |= bf.b[i];
|
||||
_recalc();
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::Except(const BitField &bf)
|
||||
{
|
||||
size_t i;
|
||||
char c;
|
||||
if( bf.nset != 0 ){
|
||||
if( nset >= nbits ){
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
_setall(b);
|
||||
}
|
||||
for(i = 0; i < nbytes; i++){
|
||||
c = b[i];
|
||||
b[i] ^= bf.b[i];
|
||||
b[i] &= c;
|
||||
}
|
||||
_recalc();
|
||||
}
|
||||
}
|
||||
|
||||
size_t BitField::Random() const
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
if( _isfull() ) idx = rand() % nbits;
|
||||
else{
|
||||
size_t i;
|
||||
i = rand() % nset + 1;
|
||||
for(idx = 0; idx < nbits && i; idx++)
|
||||
if( _isset(idx) ) i--;
|
||||
idx--;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
void BitField::_recalc()
|
||||
{
|
||||
// ÖØмÆËã nset µÄÖµ
|
||||
size_t i;
|
||||
for(nset = 0, i = 0; i < nbits; i++) if( _isset(i) ) nset++;
|
||||
if( _isfull() && b){ delete []b; b = (unsigned char*) 0;}
|
||||
}
|
||||
|
||||
void BitField::operator=(const BitField &bf)
|
||||
{
|
||||
nset = bf.nset;
|
||||
if( _isfull_sp(bf) ){
|
||||
if( b ) { delete []b; b = (unsigned char*) 0; }
|
||||
}else{
|
||||
if( !b ){
|
||||
b = new unsigned char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
}
|
||||
memcpy(b, bf.b, nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
void BitField::WriteToBuffer(char *buf)
|
||||
{
|
||||
if(_isfull())
|
||||
_setall((unsigned char*)buf);
|
||||
else
|
||||
memcpy(buf,(char*)b,nbytes);
|
||||
}
|
||||
|
||||
void BitField::_setall(unsigned char *buf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(buf,0xFF,nbytes - 1);
|
||||
|
||||
if( nbits % nbytes ){
|
||||
for(i = 8 * (nbytes - 1); i < nbits; i++)
|
||||
buf[i / 8] |= BIT_HEX[i % 8];
|
||||
}else
|
||||
buf[nbytes - 1] = (unsigned char) 0xFF;
|
||||
}
|
||||
|
||||
int BitField::SetReferFile(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
struct stat sb;
|
||||
char *bitbuf = (char*) 0;
|
||||
|
||||
if(stat(fname, &sb) < 0) return -1;
|
||||
if( sb.st_size != nbytes ) return -1;
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if( !fp ) return -1;
|
||||
|
||||
bitbuf = new char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !bitbuf ) goto fclose_err;
|
||||
#endif
|
||||
|
||||
if( fread(bitbuf, nbytes, 1, fp) != 1 ) goto fclose_err;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
SetReferBuffer(bitbuf);
|
||||
|
||||
delete []bitbuf;
|
||||
return 0;
|
||||
fclose_err:
|
||||
if( bitbuf ) delete []bitbuf;
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BitField::WriteToFile(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
char *bitbuf = (char*) 0;
|
||||
|
||||
fp = fopen(fname, "w");
|
||||
if( !fp ) return -1;
|
||||
|
||||
bitbuf = new char[nbytes];
|
||||
#ifndef WINDOWS
|
||||
if( !bitbuf ) goto fclose_err;
|
||||
#endif
|
||||
|
||||
WriteToBuffer(bitbuf);
|
||||
|
||||
if( fwrite(bitbuf, nbytes, 1, fp) != 1 ) goto fclose_err;
|
||||
|
||||
delete []bitbuf;
|
||||
fclose(fp);
|
||||
return 0;
|
||||
fclose_err:
|
||||
if( bitbuf ) delete []bitbuf;
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
50
bitfield.h
Normal file
50
bitfield.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef BITFIELD_H
|
||||
#define BITFIELD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
class BitField
|
||||
{
|
||||
private:
|
||||
static size_t nbits;
|
||||
static size_t nbytes;
|
||||
|
||||
unsigned char *b;
|
||||
size_t nset;
|
||||
|
||||
inline void _recalc();
|
||||
inline void _setall(unsigned char* buf);
|
||||
|
||||
public:
|
||||
BitField();
|
||||
BitField(size_t n_bits);
|
||||
BitField(const BitField &bf);
|
||||
~BitField(){ if(b) delete []b; }
|
||||
|
||||
void operator=(const BitField &bf);
|
||||
|
||||
void SetAll();
|
||||
void SetReferBuffer(char *buf);
|
||||
void Set(size_t idx);
|
||||
void UnSet(size_t idx);
|
||||
|
||||
int IsSet(size_t idx) const;
|
||||
int IsFull() const { return (nset >= nbits) ? 1 : 0; }
|
||||
int IsEmpty() const { return (nset == 0) ? 1 : 0; }
|
||||
|
||||
size_t Count() const { return nset;}
|
||||
size_t NBytes() const { return nbytes; }
|
||||
size_t NBits() const { return nbits; }
|
||||
size_t Random() const;
|
||||
|
||||
void Comb(const BitField &bf);
|
||||
void Except(const BitField &bf);
|
||||
void Invert();
|
||||
|
||||
int WriteToFile(const char *fname);
|
||||
int SetReferFile(const char *fname);
|
||||
|
||||
void WriteToBuffer(char *buf);
|
||||
};
|
||||
|
||||
#endif
|
30
btconfig.cpp
Normal file
30
btconfig.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
size_t cfg_req_slice_size = 32768;
|
||||
|
||||
size_t cfg_cache_size = 16;
|
||||
|
||||
size_t cfg_max_peers = 100;
|
||||
size_t cfg_min_peers = 40;
|
||||
|
||||
int cfg_listen_port = 0;
|
||||
int cfg_max_listen_port = 2706;
|
||||
int cfg_min_listen_port = 2106;
|
||||
|
||||
int cfg_max_bandwidth = -1;
|
||||
|
||||
time_t cfg_seed_hours = 72;
|
||||
|
||||
// arguments global value
|
||||
char *arg_metainfo_file = (char*) 0;
|
||||
char *arg_bitfield_file = (char*) 0;
|
||||
char *arg_save_as = (char*) 0;
|
||||
char *arg_user_agent = (char*) 0;
|
||||
|
||||
unsigned char arg_flg_force_seed_mode = 0;
|
||||
unsigned char arg_flg_check_only = 0;
|
||||
unsigned char arg_flg_exam_only = 0;
|
||||
unsigned char arg_flg_make_torrent = 0;
|
||||
|
||||
size_t arg_piece_length = 262144;
|
||||
char *arg_announce = (char*) 0;
|
39
btconfig.h
Normal file
39
btconfig.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef BTCONFIG_H
|
||||
#define BTCONFIG_H
|
||||
|
||||
extern size_t cfg_req_slice_size;
|
||||
|
||||
#define MAX_METAINFO_FILESIZ 4194304
|
||||
#define cfg_max_slice_size 131072
|
||||
#define cfg_req_queue_length 64
|
||||
#define MAX_PF_LEN 8
|
||||
#define PEER_ID_LEN 20
|
||||
#define PEER_PFX "-C61304-"
|
||||
|
||||
extern size_t cfg_cache_size;
|
||||
|
||||
extern size_t cfg_max_peers;
|
||||
extern size_t cfg_min_peers;
|
||||
|
||||
extern int cfg_listen_port;
|
||||
extern int cfg_max_listen_port;
|
||||
extern int cfg_min_listen_port;
|
||||
|
||||
extern time_t cfg_seed_hours;
|
||||
|
||||
extern int cfg_max_bandwidth;
|
||||
|
||||
// arguments global value
|
||||
extern char *arg_metainfo_file;
|
||||
extern char *arg_bitfield_file;
|
||||
extern char *arg_save_as;
|
||||
extern char *arg_user_agent;
|
||||
|
||||
extern unsigned char arg_flg_force_seed_mode;
|
||||
extern unsigned char arg_flg_check_only;
|
||||
extern unsigned char arg_flg_exam_only;
|
||||
extern unsigned char arg_flg_make_torrent;
|
||||
|
||||
extern size_t arg_piece_length;
|
||||
extern char *arg_announce;
|
||||
#endif
|
607
btcontent.cpp
Normal file
607
btcontent.cpp
Normal file
@ -0,0 +1,607 @@
|
||||
#include "btcontent.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <memory.h>
|
||||
// include windows sha1 header here.
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "btconfig.h"
|
||||
#include "bencode.h"
|
||||
#include "peer.h"
|
||||
#include "httpencode.h"
|
||||
|
||||
#define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),QUERY_STR)
|
||||
#define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),QUERY_INT)
|
||||
#define meta_pos(keylist) decode_query(b,flen,(keylist),(const char**) 0,(size_t*) 0,QUERY_POS)
|
||||
|
||||
#define CACHE_FIT(ca,roff,rlen) \
|
||||
(max_u_int64_t((ca)->bc_off,(roff)) <= \
|
||||
min_u_int64_t(((ca)->bc_off + (ca)->bc_len - 1),(roff + rlen - 1)))
|
||||
|
||||
#define MAX_OPEN_FILES 20
|
||||
|
||||
btContent BTCONTENT;
|
||||
|
||||
static void Sha1(char *ptr,size_t len,unsigned char *dm)
|
||||
{
|
||||
#ifdef WINDOWS
|
||||
;
|
||||
#else
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context,(unsigned char*)ptr,len);
|
||||
SHA1_Final(dm,&context);
|
||||
#endif
|
||||
}
|
||||
|
||||
btContent::btContent()
|
||||
{
|
||||
m_announce = global_piece_buffer = (char*) 0;
|
||||
m_hash_table = (unsigned char *) 0;
|
||||
pBF = (BitField*) 0;
|
||||
m_create_date = m_seed_timestamp = (time_t) 0;
|
||||
time(&m_start_timestamp);
|
||||
m_cache = (BTCACHE*) 0;
|
||||
m_cache_size = m_cache_used = 0;
|
||||
}
|
||||
|
||||
int btContent::CreateMetainfoFile(const char *mifn)
|
||||
{
|
||||
FILE *fp;
|
||||
fp = fopen(mifn, "r");
|
||||
if( fp ){
|
||||
fprintf(stderr,"error, file %s already exist.\n",mifn);
|
||||
return -1;
|
||||
}else if( ENOENT != errno ){
|
||||
fprintf(stderr,"error, couldn't create %s.\n",mifn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopen(mifn, "w");
|
||||
|
||||
if( !fp ){
|
||||
fprintf(stderr,"error, open %s failed. %s\n",mifn, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if( bencode_begin_dict(fp) != 1 ) goto err;
|
||||
|
||||
// announce
|
||||
if( bencode_str("announce", fp) != 1 ) goto err;
|
||||
if( bencode_str(m_announce, fp) !=1 ) goto err;
|
||||
// create date
|
||||
if( bencode_str("creation date", fp) != 1) goto err;
|
||||
if( bencode_int(m_create_date, fp) != 1 ) goto err;
|
||||
|
||||
// info dict
|
||||
if( bencode_str("info", fp) != 1) goto err;
|
||||
if( bencode_begin_dict(fp) != 1 ) goto err;
|
||||
|
||||
if( m_btfiles.FillMetaInfo(fp) != 1 ) goto err;
|
||||
|
||||
// piece length
|
||||
if( bencode_str("piece length", fp) != 1 ) goto err;
|
||||
if( bencode_int(m_piece_length, fp) != 1 ) goto err;
|
||||
|
||||
// hash table;
|
||||
if( bencode_str("pieces", fp) != 1) goto err;
|
||||
if( bencode_buf((const char*) m_hash_table, m_hashtable_length, fp) != 1 ) goto err;
|
||||
|
||||
if( bencode_end_dict_list(fp) != 1 ) goto err; // end info
|
||||
if( bencode_end_dict_list(fp) != 1 ) goto err; // end torrent
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
err:
|
||||
if( fp ) fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int btContent::InitialFromFS(const char *pathname, char *ann_url, size_t piece_length)
|
||||
{
|
||||
size_t n, percent;
|
||||
|
||||
// piece length
|
||||
m_piece_length = piece_length;
|
||||
if( m_piece_length % 65536 ){
|
||||
m_piece_length /= 65536;
|
||||
m_piece_length *= 65536;
|
||||
}
|
||||
|
||||
if( !m_piece_length || m_piece_length > cfg_req_queue_length * cfg_req_slice_size )
|
||||
m_piece_length = 262144;
|
||||
|
||||
m_announce = ann_url;
|
||||
m_create_date = time((time_t*) 0);
|
||||
|
||||
if(m_btfiles.BuildFromFS(pathname) < 0) return -1;
|
||||
|
||||
global_piece_buffer = new char[m_piece_length];
|
||||
#ifndef WINDOWS
|
||||
if( !global_piece_buffer ) return -1;
|
||||
#endif
|
||||
|
||||
// n pieces
|
||||
m_npieces = m_btfiles.GetTotalLength() / m_piece_length;
|
||||
if( m_btfiles.GetTotalLength() % m_piece_length ) m_npieces++;
|
||||
|
||||
// create hash table.
|
||||
m_hashtable_length = m_npieces * 20;
|
||||
m_hash_table = new unsigned char[m_hashtable_length];
|
||||
#ifndef WINDOWS
|
||||
if( !m_hash_table ) return -1;
|
||||
#endif
|
||||
|
||||
percent = m_npieces / 100;
|
||||
if( !percent ) percent = 1;
|
||||
|
||||
for( n = 0; n < m_npieces; n++){
|
||||
if( GetHashValue(n, m_hash_table + n * 20) < 0) return -1;
|
||||
if( 0 == n % percent ){
|
||||
printf("\rCreate hash table: %u/%u", n, m_npieces);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
printf("Complete.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btContent::PrintOut()
|
||||
{
|
||||
printf("META INFO\n");
|
||||
printf("Announce: %s\n",m_announce);
|
||||
if( m_create_date ) printf("Created On: %s",ctime(&m_create_date));
|
||||
printf("Piece length: %u\n\n",m_piece_length);
|
||||
m_btfiles.PrintOut();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btContent::InitialFromMI(const char *metainfo_fname,const char *saveas)
|
||||
{
|
||||
#define ERR_RETURN() {if(b) delete []b; return -1;}
|
||||
unsigned char *ptr = m_shake_buffer;
|
||||
char *b;
|
||||
const char *s;
|
||||
size_t flen, q, r;
|
||||
|
||||
b = _file2mem(metainfo_fname,&flen);
|
||||
if ( !b ) return -1;
|
||||
|
||||
// announce
|
||||
if( !meta_str("announce",&s,&r) ) ERR_RETURN();
|
||||
if( r > MAXPATHLEN ) ERR_RETURN();
|
||||
m_announce = new char [r + 1];
|
||||
memcpy(m_announce, s, r);
|
||||
m_announce[r] = '\0';
|
||||
|
||||
// infohash
|
||||
if( !(r = meta_pos("info")) ) ERR_RETURN();
|
||||
if( !(q = decode_dict(b + r, flen - r, (char *) 0)) ) ERR_RETURN();
|
||||
Sha1(b + r, q, m_shake_buffer + 28);
|
||||
|
||||
if( meta_int("creation date",&r)) m_create_date = (time_t) r;
|
||||
|
||||
// hash table
|
||||
if( !meta_str("info|pieces",&s,&m_hashtable_length) ||
|
||||
m_hashtable_length % 20 != 0) ERR_RETURN();
|
||||
|
||||
m_hash_table = new unsigned char[m_hashtable_length];
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !m_hash_table ) ERR_RETURN();
|
||||
#endif
|
||||
memcpy(m_hash_table, s, m_hashtable_length);
|
||||
|
||||
if(!meta_int("info|piece length",&m_piece_length)) ERR_RETURN();
|
||||
m_npieces = m_hashtable_length / 20;
|
||||
|
||||
if( m_piece_length > cfg_max_slice_size * cfg_req_queue_length ){
|
||||
fprintf(stderr,"error, piece length too long[%u]. please recompile CTorrent with a larger cfg_max_slice_size in <btconfig.h>.\n", m_piece_length);
|
||||
ERR_RETURN();
|
||||
}
|
||||
|
||||
if( m_piece_length < cfg_req_slice_size )
|
||||
cfg_req_slice_size = m_piece_length;
|
||||
else{
|
||||
for( ;(m_piece_length / cfg_req_slice_size) >= cfg_req_queue_length; ){
|
||||
cfg_req_slice_size *= 2;
|
||||
if( cfg_req_slice_size > cfg_max_slice_size ) ERR_RETURN();
|
||||
}
|
||||
}
|
||||
|
||||
if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN();
|
||||
|
||||
delete []b;
|
||||
PrintOut();
|
||||
|
||||
if( arg_flg_exam_only ) return 0;
|
||||
|
||||
if( ( r = m_btfiles.CreateFiles() ) < 0) ERR_RETURN();
|
||||
|
||||
global_piece_buffer = new char[m_piece_length];
|
||||
#ifndef WINDOWS
|
||||
if( !global_piece_buffer ) ERR_RETURN();
|
||||
#endif
|
||||
|
||||
pBF = new BitField(m_npieces);
|
||||
#ifndef WINDOWS
|
||||
if( !pBF ) ERR_RETURN();
|
||||
#endif
|
||||
|
||||
m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
|
||||
if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
|
||||
if( m_left_bytes != m_npieces ) ERR_RETURN();
|
||||
|
||||
m_left_bytes = m_btfiles.GetTotalLength();
|
||||
|
||||
if( arg_bitfield_file ){
|
||||
|
||||
if( !arg_flg_check_only ){
|
||||
if( pBF->SetReferFile(arg_bitfield_file) >= 0){
|
||||
size_t idx;
|
||||
r = 0;
|
||||
for( idx = 0; idx < m_npieces; idx++ )
|
||||
if( pBF->IsSet(idx) ) m_left_bytes -= GetPieceLength(idx);
|
||||
}
|
||||
else{
|
||||
fprintf(stderr,"warn, couldn't set bit field refer file %s.\n",arg_bitfield_file);
|
||||
}
|
||||
}
|
||||
|
||||
if( r ) CheckExist();
|
||||
|
||||
}else if( arg_flg_force_seed_mode ){
|
||||
pBF->SetAll();
|
||||
m_left_bytes = 0;
|
||||
}else if( r ){
|
||||
CheckExist();
|
||||
}
|
||||
|
||||
printf("Already/Total: %u/%u\n",pBF->Count(),m_npieces);
|
||||
|
||||
if( arg_flg_check_only ){
|
||||
if( arg_bitfield_file ) pBF->WriteToFile(arg_bitfield_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CacheConfigure();
|
||||
|
||||
*ptr = (unsigned char) 19; ptr++; // protocol string length
|
||||
memcpy(ptr,"BitTorrent protocol",19); ptr += 19; // protocol string
|
||||
memset(ptr,0,8); // reserved set zero.
|
||||
|
||||
{ // peer id
|
||||
char *sptr = arg_user_agent;
|
||||
char *dptr = (char *)m_shake_buffer + 48;
|
||||
char *eptr = dptr + PEER_ID_LEN;
|
||||
while (*sptr) *dptr++ = *sptr++;
|
||||
while (dptr < eptr) *dptr++ = (unsigned char)random();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
btContent::~btContent()
|
||||
{
|
||||
if(m_hash_table) delete []m_hash_table;
|
||||
if(m_announce) delete []m_announce;
|
||||
if(global_piece_buffer) delete []global_piece_buffer;
|
||||
if(pBF) delete pBF;
|
||||
}
|
||||
|
||||
void btContent::_Set_InfoHash(unsigned char buf[20])
|
||||
{
|
||||
memcpy(m_shake_buffer + 28, buf, 20);
|
||||
}
|
||||
|
||||
ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len)
|
||||
{
|
||||
u_int64_t offset = idx * m_piece_length + off;
|
||||
|
||||
if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0);
|
||||
else{
|
||||
size_t len2;
|
||||
int flg_rescan;
|
||||
BTCACHE *p = m_cache;
|
||||
|
||||
for( ; p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len); p = p->bc_next) ;
|
||||
|
||||
for( ; len && p && CACHE_FIT(p, offset, len);){
|
||||
flg_rescan = 0;
|
||||
if( offset < p->bc_off ){
|
||||
len2 = p->bc_off - offset;
|
||||
if( CacheIO(buf, offset, len2, 0) < 0) return -1;
|
||||
flg_rescan = 1;
|
||||
}else if( offset > p->bc_off ){
|
||||
len2 = p->bc_off + p->bc_len - offset;
|
||||
if( len2 > len ) len2 = len;
|
||||
memcpy(buf, p->bc_buf + offset - p->bc_off, len2);
|
||||
}else{
|
||||
len2 = (len > p->bc_len) ? p->bc_len : len;
|
||||
memcpy(buf, p->bc_buf, len2);
|
||||
}
|
||||
|
||||
buf += len2;
|
||||
offset += len2;
|
||||
len -= len2;
|
||||
|
||||
if( len ){
|
||||
if( flg_rescan ){
|
||||
for( p = m_cache;
|
||||
p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len);
|
||||
p = p->bc_next) ;
|
||||
}else{
|
||||
time(&p->bc_last_timestamp);
|
||||
p = p->bc_next;
|
||||
}
|
||||
}
|
||||
}// end for;
|
||||
|
||||
if( len ) return CacheIO(buf, offset, len, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btContent::CacheClean()
|
||||
{
|
||||
BTCACHE *p, *pp, *prm, *prmp;
|
||||
|
||||
again:
|
||||
pp = prm = prmp = (BTCACHE*) 0;
|
||||
for( p = m_cache; p; p = p->bc_next){
|
||||
if( !p->bc_f_flush ){
|
||||
if( !prm || prm->bc_last_timestamp > p->bc_last_timestamp){ prm = p; prmp = pp;}
|
||||
}
|
||||
pp = p;
|
||||
}
|
||||
|
||||
if( !prm ){
|
||||
if( m_cache_used ) { FlushCache(); goto again; }
|
||||
else return;
|
||||
}
|
||||
|
||||
if( prmp ) prmp->bc_next = prm->bc_next; else m_cache = prm->bc_next;
|
||||
|
||||
m_cache_used -= prm->bc_len;
|
||||
|
||||
delete []prm->bc_buf;
|
||||
delete prm;
|
||||
}
|
||||
|
||||
void btContent::CacheConfigure()
|
||||
{
|
||||
if( cfg_cache_size ){
|
||||
if( cfg_cache_size > 128 ) cfg_cache_size = 128;
|
||||
|
||||
m_cache_size = cfg_cache_size * 1024 * 1024;
|
||||
|
||||
if( m_cache_size < 4 * m_piece_length ) m_cache_size = 4 * m_piece_length;
|
||||
}
|
||||
}
|
||||
|
||||
void btContent::FlushCache()
|
||||
{
|
||||
BTCACHE *p = m_cache;
|
||||
for( ; p; p = p->bc_next)
|
||||
if( p->bc_f_flush ){
|
||||
p->bc_f_flush = 0;
|
||||
if(m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0)
|
||||
fprintf(stderr,"warn, write file failed while flush cache.\n");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
|
||||
{
|
||||
u_int64_t offset = (u_int64_t)(idx * m_piece_length + off);
|
||||
|
||||
if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);
|
||||
else{
|
||||
size_t len2;
|
||||
int flg_rescan;
|
||||
BTCACHE *p;
|
||||
|
||||
for(p = m_cache ; p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len); p = p->bc_next) ;
|
||||
|
||||
for( ; len && p && CACHE_FIT(p, offset, len);){
|
||||
flg_rescan = 0;
|
||||
if( offset < p->bc_off ){
|
||||
len2 = p->bc_off - offset;
|
||||
if( CacheIO(buf, offset, len2, 1) < 0) return -1;
|
||||
flg_rescan = 1;
|
||||
}else if( offset > p->bc_off ){
|
||||
len2 = p->bc_off + p->bc_len - offset;
|
||||
if( len2 > len ) len2 = len;
|
||||
memcpy(p->bc_buf + offset - p->bc_off, buf, len2);
|
||||
p->bc_f_flush = 1;
|
||||
}else{
|
||||
len2 = (len > p->bc_len) ? p->bc_len : len;
|
||||
memcpy(p->bc_buf, buf, len2);
|
||||
p->bc_f_flush = 1;
|
||||
}
|
||||
|
||||
buf += len2;
|
||||
offset += len2;
|
||||
len -= len2;
|
||||
|
||||
if( len ){
|
||||
if( flg_rescan ){
|
||||
for( p = m_cache; p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len); p = p->bc_next) ;
|
||||
}else{
|
||||
time(&p->bc_last_timestamp);
|
||||
p = p->bc_next;
|
||||
}
|
||||
}
|
||||
}// end for;
|
||||
|
||||
if( len ) return CacheIO(buf, offset, len, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t btContent::CacheIO(char *buf, u_int64_t off, size_t len, int method)
|
||||
{
|
||||
BTCACHE *p;
|
||||
BTCACHE *pp = (BTCACHE*) 0;
|
||||
BTCACHE *pnew = (BTCACHE*) 0;
|
||||
|
||||
for( ; m_cache_size < (m_cache_used + len); ) CacheClean();
|
||||
|
||||
if( 0 == method && m_btfiles.IO(buf, off, len, method) < 0) return -1;
|
||||
|
||||
pnew = new BTCACHE;
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !pnew )
|
||||
return method ? m_btfiles.IO(buf, off, len, method) : 0;
|
||||
#endif
|
||||
|
||||
pnew->bc_buf = new char[len];
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !(pnew->bc_buf) ){
|
||||
delete pnew;
|
||||
return method ? m_btfiles.IO(buf, off, len, method) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(pnew->bc_buf, buf, len);
|
||||
pnew->bc_off = off;
|
||||
pnew->bc_len = len;
|
||||
pnew->bc_f_flush = method;
|
||||
m_cache_used += len;
|
||||
time(&pnew->bc_last_timestamp);
|
||||
|
||||
// find insert point.
|
||||
for(p = m_cache; p && off > p->bc_off; pp = p, p = pp->bc_next) ;
|
||||
|
||||
pnew->bc_next = p;
|
||||
|
||||
if( pp ) pp->bc_next = pnew; else m_cache = pnew;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t btContent::ReadPiece(char *buf,size_t idx)
|
||||
{
|
||||
return ReadSlice(buf, idx, 0, GetPieceLength(idx));
|
||||
}
|
||||
|
||||
size_t btContent::GetPieceLength(size_t idx)
|
||||
{
|
||||
return (idx == m_btfiles.GetTotalLength() / m_piece_length) ?
|
||||
(size_t)(m_btfiles.GetTotalLength() % m_piece_length)
|
||||
:m_piece_length;
|
||||
}
|
||||
|
||||
int btContent::CheckExist()
|
||||
{
|
||||
size_t idx = 0;
|
||||
size_t percent = GetNPieces() / 100;
|
||||
unsigned char md[20];
|
||||
|
||||
if( !percent ) percent = 1;
|
||||
|
||||
for( ; idx < m_npieces; idx++){
|
||||
if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){
|
||||
m_left_bytes -= GetPieceLength(idx);
|
||||
pBF->Set(idx);
|
||||
}
|
||||
if(idx % percent == 0){
|
||||
printf("\rCheck exist: %d/%d",idx,pBF->NBits());
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
printf(" Complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* btContent::_file2mem(const char *fname, size_t *psiz)
|
||||
{
|
||||
char *b = (char*) 0;
|
||||
struct stat sb;
|
||||
FILE* fp;
|
||||
fp = fopen(fname,"r");
|
||||
if( !fp ){
|
||||
fprintf(stderr,"error, open %s failed. %s\n",fname,strerror(errno));
|
||||
return (char*) 0;
|
||||
}
|
||||
|
||||
if(stat(fname,&sb) < 0){
|
||||
fprintf(stderr,"error, stat %s failed, %s\n",fname,strerror(errno));
|
||||
return (char*) 0;
|
||||
}
|
||||
|
||||
if( sb.st_size > MAX_METAINFO_FILESIZ ){
|
||||
fprintf(stderr,"error, %s is really a metainfo file???\n",fname);
|
||||
return (char*) 0;
|
||||
}
|
||||
|
||||
b = new char[sb.st_size];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) return (char*) 0;
|
||||
#endif
|
||||
|
||||
if(fread(b, sb.st_size, 1, fp) != 1){
|
||||
if( ferror(fp) ){
|
||||
delete []b;
|
||||
return (char*) 0;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if(psiz) *psiz = sb.st_size;
|
||||
return b;
|
||||
}
|
||||
|
||||
int btContent::APieceComplete(size_t idx)
|
||||
{
|
||||
unsigned char md[20];
|
||||
if(pBF->IsSet(idx)) return 1;
|
||||
if( GetHashValue(idx, md) < 0 ) return -1;
|
||||
|
||||
if( memcmp(md,(m_hash_table + idx * 20), 20) != 0){
|
||||
fprintf(stderr,"warn,piece %d hash check failed.\n",idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pBF->Set(idx);
|
||||
m_left_bytes -= GetPieceLength(idx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int btContent::GetHashValue(size_t idx,unsigned char *md)
|
||||
{
|
||||
if( ReadPiece(global_piece_buffer,idx) < 0) return -1;
|
||||
Sha1(global_piece_buffer,GetPieceLength(idx),md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btContent::SeedTimeout(const time_t *pnow)
|
||||
{
|
||||
if( pBF->IsFull() ){
|
||||
if( !m_seed_timestamp ){
|
||||
Self.ResetDLTimer();
|
||||
Self.ResetULTimer();
|
||||
ReleaseHashTable();
|
||||
m_seed_timestamp = *pnow;
|
||||
FlushCache();
|
||||
printf("\nDownload complete.\n");
|
||||
printf("Total time used: %lu minutes.\n",(*pnow - m_start_timestamp) / 60);
|
||||
printf("Seed for other %lu hours.\n\n", cfg_seed_hours);
|
||||
}
|
||||
if( (*pnow - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
100
btcontent.h
Normal file
100
btcontent.h
Normal file
@ -0,0 +1,100 @@
|
||||
#ifndef BTCONTENT_H
|
||||
#define BTCONTENT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bitfield.h"
|
||||
#include "btfiles.h"
|
||||
|
||||
typedef struct _btcache{
|
||||
u_int64_t bc_off;
|
||||
size_t bc_len;
|
||||
|
||||
unsigned char bc_f_flush:1;
|
||||
unsigned char bc_f_reserved:7;
|
||||
|
||||
time_t bc_last_timestamp;
|
||||
|
||||
char *bc_buf;
|
||||
|
||||
struct _btcache *bc_next;
|
||||
}BTCACHE;
|
||||
|
||||
class btContent
|
||||
{
|
||||
//METAINFO³ÉÔ±
|
||||
char *m_announce;
|
||||
unsigned char *m_hash_table;
|
||||
unsigned char m_shake_buffer[68];
|
||||
|
||||
size_t m_hashtable_length;
|
||||
size_t m_piece_length;
|
||||
size_t m_npieces;
|
||||
time_t m_create_date, m_seed_timestamp, m_start_timestamp;
|
||||
|
||||
u_int64_t m_left_bytes;
|
||||
btFiles m_btfiles;
|
||||
|
||||
BTCACHE *m_cache;
|
||||
size_t m_cache_size, m_cache_used;
|
||||
|
||||
void _Set_InfoHash(unsigned char buf[20]);
|
||||
char* _file2mem(const char *fname, size_t *psiz);
|
||||
|
||||
void ReleaseHashTable(){
|
||||
if(m_hash_table){
|
||||
delete []m_hash_table;
|
||||
m_hash_table = (unsigned char*) 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CheckExist();
|
||||
void CacheConfigure();
|
||||
void CacheClean();
|
||||
u_int64_t max_u_int64_t(u_int64_t a,u_int64_t b) { return (a > b) ? a : b; }
|
||||
u_int64_t min_u_int64_t(u_int64_t a,u_int64_t b) { return (a > b) ? b : a; }
|
||||
ssize_t CacheIO(char *buf, u_int64_t off, size_t len, int method);
|
||||
|
||||
public:
|
||||
BitField *pBF;
|
||||
char *global_piece_buffer;
|
||||
|
||||
btContent();
|
||||
~btContent();
|
||||
|
||||
void FlushCache();
|
||||
|
||||
int CreateMetainfoFile(const char *mifn);
|
||||
int InitialFromFS(const char *pathname, char *ann_url, size_t piece_length);
|
||||
int InitialFromMI(const char *metainfo_fname,const char *saveas);
|
||||
|
||||
char* GetAnnounce() { return m_announce;}
|
||||
|
||||
unsigned char* GetShakeBuffer() {return m_shake_buffer;}
|
||||
unsigned char* GetInfoHash() {return (m_shake_buffer + 28);}
|
||||
unsigned char* GetPeerId() {return (m_shake_buffer + 48); }
|
||||
|
||||
size_t GetPieceLength(size_t idx);
|
||||
size_t GetPieceLength() const { return m_piece_length; }
|
||||
size_t GetNPieces() const { return m_npieces; }
|
||||
|
||||
u_int64_t GetTotalFilesLength() const { return m_btfiles.GetTotalLength(); }
|
||||
u_int64_t GetLeftBytes() const { return m_left_bytes; }
|
||||
|
||||
int APieceComplete(size_t idx);
|
||||
int GetHashValue(size_t idx,unsigned char *md);
|
||||
|
||||
ssize_t ReadSlice(char *buf,size_t idx,size_t off,size_t len);
|
||||
ssize_t WriteSlice(char *buf,size_t idx,size_t off,size_t len);
|
||||
ssize_t ReadPiece(char *buf,size_t idx);
|
||||
|
||||
int PrintOut();
|
||||
int SeedTimeout(const time_t *pnow);
|
||||
};
|
||||
|
||||
extern btContent BTCONTENT;
|
||||
|
||||
#endif
|
490
btfiles.cpp
Normal file
490
btfiles.cpp
Normal file
@ -0,0 +1,490 @@
|
||||
#include "btfiles.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <io.h>
|
||||
#include <memory.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/param.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bencode.h"
|
||||
|
||||
#define MAX_OPEN_FILES 20
|
||||
|
||||
btFiles::btFiles()
|
||||
{
|
||||
m_btfhead = (BTFILE*) 0;
|
||||
m_total_files_length = 0;
|
||||
m_total_opened = 0;
|
||||
m_flag_automanage = 0;
|
||||
m_directory = (char*)0;
|
||||
}
|
||||
|
||||
btFiles::~btFiles()
|
||||
{
|
||||
_btf_destroy();
|
||||
}
|
||||
|
||||
BTFILE* btFiles::_new_bfnode()
|
||||
{
|
||||
BTFILE *pnew = new BTFILE;
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !pnew ) return (BTFILE*) 0;
|
||||
#endif
|
||||
|
||||
pnew->bf_flag_opened = 0;
|
||||
pnew->bf_flag_need = 0;
|
||||
|
||||
pnew->bf_filename = (char*) 0;
|
||||
pnew->bf_fp = (FILE*) 0;
|
||||
pnew->bf_length = 0;
|
||||
|
||||
pnew->bf_last_timestamp = (time_t) 0;
|
||||
pnew->bf_next = (BTFILE*) 0;
|
||||
return pnew;
|
||||
}
|
||||
|
||||
int btFiles::_btf_open(BTFILE *pbf)
|
||||
{
|
||||
char fn[MAXPATHLEN];
|
||||
|
||||
if(m_flag_automanage && (m_total_opened >= MAX_OPEN_FILES)){ // close any files.
|
||||
BTFILE *pbf_n,*pbf_close;
|
||||
pbf_close = (BTFILE *) 0;
|
||||
for(pbf_n = m_btfhead; pbf_n ; pbf_n = pbf_n->bf_next){
|
||||
if(!pbf_n->bf_flag_opened) continue; // file not been opened.
|
||||
if( !pbf_close || pbf_n->bf_last_timestamp < pbf_close->bf_last_timestamp)
|
||||
pbf_close = pbf_n;
|
||||
}
|
||||
if(!pbf_close || fclose(pbf_close->bf_fp) < 0) return -1;
|
||||
pbf_close->bf_flag_opened = 0;
|
||||
m_total_opened--;
|
||||
}
|
||||
|
||||
if( m_directory ){
|
||||
if( MAXPATHLEN <= snprintf(fn, MAXPATHLEN, "%s%c%s", m_directory, PATH_SP, pbf->bf_filename) )
|
||||
return -1;
|
||||
}else{
|
||||
strcpy(fn, pbf->bf_filename);
|
||||
}
|
||||
|
||||
if( !(pbf->bf_fp = fopen(fn,"r+")) ) return -1;
|
||||
|
||||
pbf->bf_flag_opened = 1;
|
||||
m_total_opened++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t btFiles::IO(char *buf, u_int64_t off, size_t len, const int iotype)
|
||||
{
|
||||
u_int64_t n = 0;
|
||||
size_t pos,nio;
|
||||
BTFILE *pbf = m_btfhead;
|
||||
|
||||
if( ( off + (u_int64_t)len ) > m_total_files_length) return -1;
|
||||
|
||||
for(; pbf; pbf = pbf->bf_next){
|
||||
n += (u_int64_t) pbf->bf_length;
|
||||
if(n > off) break;
|
||||
}
|
||||
|
||||
if( !pbf ) return -1;
|
||||
|
||||
pos = (size_t) (off - (n - pbf->bf_length));
|
||||
|
||||
for(; len ;){
|
||||
if( !pbf->bf_flag_opened ){
|
||||
if( _btf_open(pbf) < 0 ) return -1;
|
||||
}
|
||||
|
||||
if( m_flag_automanage ) time(&pbf->bf_last_timestamp);
|
||||
|
||||
if( fseek(pbf->bf_fp,(long) pos,SEEK_SET) < 0) return -1;
|
||||
|
||||
nio = (len < pbf->bf_length - pos) ? len : (pbf->bf_length - pos);
|
||||
|
||||
if(0 == iotype){
|
||||
if( 1 != fread(buf,nio,1,pbf->bf_fp) ) return -1;
|
||||
}else{
|
||||
if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ) return -1;
|
||||
}
|
||||
|
||||
len -= nio;
|
||||
buf += nio;
|
||||
|
||||
if( len ){
|
||||
pbf = pbf->bf_next;
|
||||
if( !pbf ) return -1;
|
||||
pos = 0;
|
||||
}
|
||||
} // end for
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btFiles::_btf_destroy()
|
||||
{
|
||||
BTFILE *pbf,*pbf_next;
|
||||
for(pbf = m_btfhead; pbf;){
|
||||
pbf_next = pbf->bf_next;
|
||||
if( pbf->bf_fp ) fclose( pbf->bf_fp );
|
||||
if( pbf->bf_filename ) delete []pbf->bf_filename;
|
||||
delete pbf;
|
||||
pbf = pbf_next;
|
||||
}
|
||||
m_btfhead = (BTFILE*) 0;
|
||||
m_total_files_length = (u_int64_t) 0;
|
||||
m_total_opened = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btFiles::_btf_ftruncate(int fd,size_t length)
|
||||
{
|
||||
#ifdef WINDOWS
|
||||
char c = (char)0;
|
||||
if(lseek(fd,length - 1, SEEK_SET) < 0 ) return -1;
|
||||
return write(fd, &c, 1);
|
||||
#else
|
||||
return ftruncate(fd,length);
|
||||
#endif
|
||||
}
|
||||
|
||||
int btFiles::_btf_recurses_directory(const char *cur_path, BTFILE* lastnode)
|
||||
{
|
||||
char full_cur[MAXPATHLEN];
|
||||
char fn[MAXPATHLEN];
|
||||
struct stat sb;
|
||||
struct dirent *dirp;
|
||||
DIR *dp;
|
||||
BTFILE *pbf;
|
||||
|
||||
if( !getwd(full_cur) ) return -1;
|
||||
|
||||
if( cur_path ){
|
||||
strcpy(fn, full_cur);
|
||||
if( MAXPATHLEN <= snprintf(full_cur, MAXPATHLEN, "%s%c%s", fn, PATH_SP, cur_path))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (DIR*) 0 == (dp = opendir(full_cur))){
|
||||
fprintf(stderr,"error, open directory %s failed, %s\n",cur_path,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while( (struct dirent*) 0 != (dirp = readdir(dp)) ){
|
||||
|
||||
if( 0 == strcmp(dirp->d_name, ".") ||
|
||||
0 == strcmp(dirp->d_name, "..") ) continue;
|
||||
|
||||
if( cur_path ){
|
||||
if(MAXPATHLEN < snprintf(fn, MAXPATHLEN, "%s%c%s", cur_path, PATH_SP, dirp->d_name)){
|
||||
fprintf(stderr,"error, pathname too long\n");
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
strcpy(fn, dirp->d_name);
|
||||
}
|
||||
|
||||
if( stat(fn, &sb) < 0 ){
|
||||
fprintf(stderr,"error, stat %s failed, %s\n",fn,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( S_IFREG & sb.st_mode ){
|
||||
|
||||
pbf = _new_bfnode();
|
||||
#ifndef WINDOWS
|
||||
if( !pbf ) return -1;
|
||||
#endif
|
||||
pbf->bf_filename = new char[strlen(fn) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !pbf->bf_filename ){ closedir(dp); return -1;}
|
||||
#endif
|
||||
strcpy(pbf->bf_filename, fn);
|
||||
|
||||
pbf->bf_length = sb.st_size;
|
||||
m_total_files_length += sb.st_size;
|
||||
|
||||
if( lastnode ) lastnode->bf_next = pbf; else m_btfhead = pbf;
|
||||
|
||||
lastnode = pbf;
|
||||
|
||||
}else if( S_IFDIR & sb.st_mode ){
|
||||
if(_btf_recurses_directory(fn, lastnode) < 0){closedir(dp); return -1;}
|
||||
}else{
|
||||
fprintf(stderr,"error, %s is not a directory or regular file.\n",fn);
|
||||
closedir(dp);
|
||||
return -1;
|
||||
}
|
||||
} // end while
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btFiles::_btf_creat_by_path(const char *pathname, size_t file_length)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd;
|
||||
char *p,*pnext,last = 0;
|
||||
char sp[MAXPATHLEN];
|
||||
|
||||
strcpy(sp,pathname);
|
||||
|
||||
pnext = sp;
|
||||
if(PATH_SP == *pnext) pnext++;
|
||||
|
||||
for(; !last; ){
|
||||
for(p = pnext; *p && PATH_SP != *p; p++) ;
|
||||
if( !*p ) last = 1;
|
||||
if(last && PATH_SP == *p){ last = 0; break;}
|
||||
*p = '\0';
|
||||
if(stat(sp,&sb) < 0){
|
||||
if( ENOENT == errno ){
|
||||
if( !last ){
|
||||
#ifdef WINDOWS
|
||||
if(mkdir(sp) < 0) break;
|
||||
#else
|
||||
if(mkdir(sp,0755) < 0) break;
|
||||
#endif
|
||||
}else{
|
||||
if((fd = creat(sp,0644)) < 0) { last = 0; break; }
|
||||
if(file_length && _btf_ftruncate(fd, file_length) < 0){close(fd); last = 0; break;}
|
||||
close(fd);
|
||||
}
|
||||
}else{last = 0; break;}
|
||||
}
|
||||
if( !last ){ *p = PATH_SP; pnext = p + 1;}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
int btFiles::BuildFromFS(const char *pathname)
|
||||
{
|
||||
struct stat sb;
|
||||
BTFILE *pbf = (BTFILE*) 0;
|
||||
|
||||
if( stat(pathname, &sb) < 0 ){
|
||||
fprintf(stderr,"error, stat file %s failed, %s\n",pathname,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( S_IFREG & sb.st_mode ){
|
||||
pbf = _new_bfnode();
|
||||
#ifndef WINDOWS
|
||||
if( !pbf ) return -1;
|
||||
#endif
|
||||
pbf->bf_length = m_total_files_length = sb.st_size;
|
||||
pbf->bf_filename = new char[strlen(pathname) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !pbf->bf_filename ) return -1;
|
||||
#endif
|
||||
strcpy(pbf->bf_filename, pathname);
|
||||
m_btfhead = pbf;
|
||||
}else if( S_IFDIR & sb.st_mode ){
|
||||
char wd[MAXPATHLEN];
|
||||
if( !getwd(wd) ) return -1;
|
||||
m_directory = new char[strlen(pathname) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !m_directory ) return -1;
|
||||
#endif
|
||||
strcpy(m_directory, pathname);
|
||||
|
||||
if(chdir(m_directory) < 0){
|
||||
fprintf(stderr,"error, change work directory to %s failed, %s",m_directory, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(_btf_recurses_directory((const char*)0, (BTFILE*) 0) < 0) return -1;
|
||||
if( chdir(wd) < 0) return -1;
|
||||
}else{
|
||||
fprintf(stderr,"error, %s is not a directory or regular file.\n",pathname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
const char *s, *p;
|
||||
size_t r,q,n;
|
||||
if( !decode_query(metabuf, metabuf_len, "info|name",&s,&q,QUERY_STR) ||
|
||||
MAXPATHLEN <= q) return -1;
|
||||
|
||||
memcpy(path, s, q);
|
||||
path[q] = '\0';
|
||||
|
||||
r = decode_query(metabuf,metabuf_len,"info|files",(const char**) 0, &q,QUERY_POS);
|
||||
|
||||
if( r ){
|
||||
BTFILE *pbf_last = (BTFILE*) 0;
|
||||
BTFILE *pbf = (BTFILE*) 0;
|
||||
size_t dl;
|
||||
if( decode_query(metabuf,metabuf_len,"info|length",
|
||||
(const char**) 0,(size_t*) 0,QUERY_INT) )
|
||||
return -1;
|
||||
|
||||
if( saveas ){
|
||||
m_directory = new char[strlen(saveas) + 1];
|
||||
#ifndef WINDOWS
|
||||
if(!m_directory) return -1;
|
||||
#endif
|
||||
strcpy(m_directory,saveas);
|
||||
}else{
|
||||
m_directory = new char[strlen(path) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !m_directory) return -1;
|
||||
#endif
|
||||
strcpy(m_directory,path);
|
||||
}
|
||||
|
||||
/* now r saved the pos of files list. q saved list length */
|
||||
p = metabuf + r + 1;
|
||||
q--;
|
||||
for(; q && 'e' != *p; p += dl, q -= dl){
|
||||
if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1;
|
||||
if( !decode_query(p, dl, "length", (const char**) 0,
|
||||
&r,QUERY_INT) ) return -1;
|
||||
pbf = _new_bfnode();
|
||||
#ifndef WINDOWS
|
||||
if( !pbf ) return -1;
|
||||
#endif
|
||||
pbf->bf_length = r;
|
||||
m_total_files_length += r;
|
||||
r = decode_query(p, dl, "path", (const char **) 0, &n,QUERY_POS);
|
||||
if( !r ) return -1;
|
||||
if(!decode_list2path(p + r, n, path)) return -1;
|
||||
pbf->bf_filename = new char[strlen(path) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !pbf->bf_filename ) return -1;
|
||||
#endif
|
||||
strcpy(pbf->bf_filename, path);
|
||||
if(pbf_last) pbf_last->bf_next = pbf; else m_btfhead = pbf;
|
||||
pbf_last = pbf;
|
||||
}
|
||||
}else{
|
||||
if( !decode_query(metabuf,metabuf_len,"info|length",
|
||||
(const char**) 0,(size_t*) &q,QUERY_INT) )
|
||||
return -1;
|
||||
m_btfhead = _new_bfnode();
|
||||
#ifndef WINDOWS
|
||||
if( !m_btfhead) return -1;
|
||||
#endif
|
||||
m_btfhead->bf_length = m_total_files_length = q;
|
||||
if( saveas ){
|
||||
m_btfhead->bf_filename = new char[strlen(saveas) + 1];
|
||||
#ifndef WINDOWS
|
||||
if(!m_btfhead->bf_filename ) return -1;
|
||||
#endif
|
||||
strcpy(m_btfhead->bf_filename, saveas);
|
||||
}else{
|
||||
m_btfhead->bf_filename = new char[strlen(path) + 1];
|
||||
#ifndef WINDOWS
|
||||
if(!m_btfhead->bf_filename ) return -1;
|
||||
#endif
|
||||
strcpy(m_btfhead->bf_filename, path);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btFiles::CreateFiles()
|
||||
{
|
||||
int check_exist = 0;
|
||||
char fn[MAXPATHLEN];
|
||||
BTFILE *pbt = m_btfhead;
|
||||
struct stat sb;
|
||||
|
||||
for(; pbt; pbt = pbt->bf_next){
|
||||
if( m_directory ){
|
||||
if( MAXPATHLEN <= snprintf(fn, MAXPATHLEN, "%s%c%s", m_directory, PATH_SP, pbt->bf_filename) )
|
||||
return -1;
|
||||
}else{
|
||||
strcpy(fn, pbt->bf_filename);
|
||||
}
|
||||
|
||||
if(stat(fn ,&sb) < 0){
|
||||
if(ENOENT == errno){
|
||||
if( !_btf_creat_by_path(fn,pbt->bf_length)){
|
||||
fprintf(stderr,"error, create file %s failed.\n",fn);
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
fprintf(stderr,"error, couldn't create file %s\n", fn);
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
if( !check_exist) check_exist = 1;
|
||||
if( !(S_IFREG & sb.st_mode) ){
|
||||
fprintf(stderr,"error, file %s not a regular file.\n", fn);
|
||||
return -1;
|
||||
}
|
||||
if(sb.st_size != pbt->bf_length){
|
||||
fprintf(stderr,"error, file %s 's size not match. must be %u\n",
|
||||
fn, pbt->bf_length);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} //end for
|
||||
return check_exist;
|
||||
}
|
||||
|
||||
void btFiles::PrintOut()
|
||||
{
|
||||
BTFILE *p = m_btfhead;
|
||||
size_t id = 1;
|
||||
printf("FILES INFO\n");
|
||||
if(m_directory) printf("Directory: %s\n",m_directory);
|
||||
for( ; p ; p = p->bf_next ){
|
||||
printf("<%d> %c%s [%u]\n",id++,
|
||||
m_directory ? '\t': ' ',p->bf_filename, p->bf_length);
|
||||
}
|
||||
printf("Total: %lu MB\n\n",(unsigned long)(m_total_files_length / 1024 / 1024));
|
||||
}
|
||||
|
||||
size_t btFiles::FillMetaInfo(FILE* fp)
|
||||
{
|
||||
BTFILE *p;
|
||||
if( m_directory ){
|
||||
// multi files
|
||||
if( bencode_str("files", fp) != 1 ) return 0;
|
||||
|
||||
if( bencode_begin_list(fp) != 1) return 0;
|
||||
|
||||
for( p = m_btfhead; p; p = p->bf_next){
|
||||
if( bencode_begin_dict(fp) != 1) return 0;
|
||||
|
||||
if( bencode_str("length", fp) != 1 ) return 0;
|
||||
if( bencode_int(p->bf_length, fp) != 1) return 0;
|
||||
|
||||
if( bencode_str("path", fp) != 1) return 0;
|
||||
if( bencode_path2list(p->bf_filename, fp) != 1 ) return 0;
|
||||
|
||||
if( bencode_end_dict_list(fp) != 1) return 0;
|
||||
}
|
||||
|
||||
if(bencode_end_dict_list(fp) != 1 ) return 0;
|
||||
|
||||
if(bencode_str("name", fp) != 1) return 0;
|
||||
return bencode_str(m_directory, fp);
|
||||
|
||||
}else{
|
||||
if( bencode_str("length", fp) != 1 ) return 0;
|
||||
if( bencode_int(m_btfhead->bf_length, fp) != 1) return 0;
|
||||
|
||||
if( bencode_str("name", fp) != 1 ) return 0;
|
||||
return bencode_str(m_btfhead->bf_filename, fp);
|
||||
}
|
||||
return 1;
|
||||
}
|
61
btfiles.h
Normal file
61
btfiles.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef BTFILES_H
|
||||
#define BTFILES_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include "./def.h"
|
||||
|
||||
typedef struct _btfile{
|
||||
char *bf_filename; // full path of file.
|
||||
size_t bf_length; //single file length limits to 4 GB
|
||||
FILE *bf_fp;
|
||||
|
||||
time_t bf_last_timestamp; // last io timestamp.
|
||||
|
||||
size_t bf_completed; // already downloaded length
|
||||
|
||||
unsigned char bf_flag_opened:1;
|
||||
unsigned char bf_flag_need:1;
|
||||
unsigned char bf_reserved:6;
|
||||
|
||||
struct _btfile *bf_next;
|
||||
}BTFILE;
|
||||
|
||||
|
||||
class btFiles
|
||||
{
|
||||
private:
|
||||
|
||||
BTFILE *m_btfhead;
|
||||
char *m_directory;
|
||||
u_int64_t m_total_files_length;
|
||||
size_t m_total_opened; // already opened
|
||||
|
||||
u_int8_t m_flag_automanage:1;
|
||||
u_int8_t m_flag_reserved:7; // current version not implement
|
||||
|
||||
BTFILE* _new_bfnode();
|
||||
int _btf_open(BTFILE *sbf_p);
|
||||
int _btf_ftruncate(int fd,size_t length);
|
||||
int _btf_creat_by_path(const char *pathname, size_t file_length);
|
||||
int _btf_destroy();
|
||||
int _btf_recurses_directory(const char *cur_path, BTFILE *lastnode);
|
||||
|
||||
public:
|
||||
int CreateFiles();
|
||||
|
||||
btFiles();
|
||||
~btFiles();
|
||||
|
||||
int BuildFromFS(const char *pathname);
|
||||
int BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas);
|
||||
|
||||
u_int64_t GetTotalLength() const { return m_total_files_length; }
|
||||
ssize_t IO(char *buf, u_int64_t off, size_t len, const int iotype);
|
||||
size_t FillMetaInfo(FILE* fp);
|
||||
#ifndef WINDOWS
|
||||
void PrintOut();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
233
btrequest.cpp
Normal file
233
btrequest.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "btrequest.h"
|
||||
#include "btcontent.h"
|
||||
#include "btconfig.h"
|
||||
|
||||
|
||||
static void _empty_slice_list(PSLICE *ps_head)
|
||||
{
|
||||
PSLICE p;
|
||||
for(; *ps_head;){
|
||||
p = (*ps_head)->next;
|
||||
delete (*ps_head);
|
||||
*ps_head = p;
|
||||
}
|
||||
}
|
||||
|
||||
RequestQueue::~RequestQueue()
|
||||
{
|
||||
if( rq_head ) _empty_slice_list(&rq_head);
|
||||
}
|
||||
|
||||
RequestQueue::RequestQueue()
|
||||
{
|
||||
rq_head = (PSLICE) 0;
|
||||
}
|
||||
|
||||
void RequestQueue::Empty()
|
||||
{
|
||||
if(rq_head) _empty_slice_list(&rq_head);
|
||||
}
|
||||
|
||||
void RequestQueue::SetHead(PSLICE ps)
|
||||
{
|
||||
if( rq_head ) _empty_slice_list(&rq_head);
|
||||
rq_head = ps;
|
||||
}
|
||||
|
||||
void RequestQueue::operator=(RequestQueue &rq)
|
||||
{
|
||||
if( rq_head ) _empty_slice_list(&rq_head);
|
||||
rq_head = rq.rq_head;
|
||||
rq.rq_head = (PSLICE) 0;
|
||||
}
|
||||
|
||||
int RequestQueue::Add(size_t idx,size_t off,size_t len)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
PSLICE n = rq_head;
|
||||
PSLICE u = (PSLICE) 0;
|
||||
|
||||
for( ; n ; u = n,n = u->next) cnt++; // move to end
|
||||
|
||||
if( cnt >= cfg_req_queue_length ) return -1; // already full
|
||||
|
||||
n = new SLICE;
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !n ) return -1;
|
||||
#endif
|
||||
|
||||
n->next = (PSLICE) 0;
|
||||
n->index = idx;
|
||||
n->offset = off;
|
||||
n->length = len;
|
||||
|
||||
if( u ) u->next = n; else rq_head = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RequestQueue::Remove(size_t idx,size_t off,size_t len)
|
||||
{
|
||||
PSLICE n = rq_head;
|
||||
PSLICE u = (PSLICE) 0;
|
||||
|
||||
for( ; n ; u = n, n = u->next){
|
||||
if(n->index == idx && n->offset == off && n->length == len ) break;
|
||||
}
|
||||
|
||||
if( !n ) return -1; /* not found */
|
||||
|
||||
if( u ) u->next = n->next; else rq_head = n->next;
|
||||
delete n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RequestQueue::Pop(size_t *pidx,size_t *poff,size_t *plen)
|
||||
{
|
||||
PSLICE n;
|
||||
|
||||
if( !rq_head ) return -1;
|
||||
|
||||
n = rq_head->next;
|
||||
|
||||
if(pidx) *pidx = rq_head->index;
|
||||
if(poff) *poff = rq_head->offset;
|
||||
if(plen) *plen = rq_head->length;
|
||||
|
||||
delete rq_head;
|
||||
|
||||
rq_head = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RequestQueue::Peek(size_t *pidx,size_t *poff,size_t *plen) const
|
||||
{
|
||||
if( !rq_head ) return -1;
|
||||
|
||||
if(pidx) *pidx = rq_head->index;
|
||||
if(poff) *poff = rq_head->offset;
|
||||
if(plen) *plen = rq_head->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RequestQueue::CreateWithIdx(size_t idx)
|
||||
{
|
||||
size_t i,off,len,ns;
|
||||
|
||||
if( rq_head ) _empty_slice_list(&rq_head);
|
||||
|
||||
ns = NSlices(idx);
|
||||
|
||||
for( i = off = 0; i < ns; i++){
|
||||
len = Slice_Length(idx,i);
|
||||
if( Add(idx,off,len) < 0) return -1;
|
||||
off += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t RequestQueue::Slice_Length(size_t idx,size_t sidx) const
|
||||
{
|
||||
size_t plen = BTCONTENT.GetPieceLength(idx);
|
||||
|
||||
return (sidx == ( plen / cfg_req_slice_size)) ?
|
||||
(plen % cfg_req_slice_size) :
|
||||
cfg_req_slice_size;
|
||||
}
|
||||
|
||||
size_t RequestQueue::NSlices(size_t idx) const
|
||||
{
|
||||
size_t r,n;
|
||||
r = BTCONTENT.GetPieceLength(idx);
|
||||
n = r / cfg_req_slice_size;
|
||||
return ( r % cfg_req_slice_size ) ? n + 1 : n;
|
||||
}
|
||||
|
||||
int RequestQueue::IsValidRequest(size_t idx,size_t off,size_t len)
|
||||
{
|
||||
return ( idx < BTCONTENT.GetNPieces() &&
|
||||
len &&
|
||||
(off + len) <= BTCONTENT.GetPieceLength(idx) &&
|
||||
len <= cfg_max_slice_size) ?
|
||||
1 : 0;
|
||||
}
|
||||
|
||||
// ****************************** PendingQueue ******************************
|
||||
|
||||
PendingQueue PENDINGQUEUE;
|
||||
|
||||
PendingQueue::PendingQueue()
|
||||
{
|
||||
int i = 0;
|
||||
for(; i < PENDING_QUEUE_SIZE; i++) pending_array[i] = (PSLICE) 0;
|
||||
pq_count = 0;
|
||||
}
|
||||
|
||||
PendingQueue::~PendingQueue()
|
||||
{
|
||||
if(pq_count) Empty();
|
||||
}
|
||||
|
||||
void PendingQueue::Empty()
|
||||
{
|
||||
int i = 0;
|
||||
for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++)
|
||||
if( pending_array[i] != (PSLICE) 0 ){
|
||||
_empty_slice_list(&(pending_array[i]));
|
||||
pq_count--;
|
||||
}
|
||||
}
|
||||
|
||||
int PendingQueue::Exist(size_t idx)
|
||||
{
|
||||
int i = 0;
|
||||
for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++)
|
||||
if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PendingQueue::Pending(RequestQueue *prq)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if( pq_count >= PENDING_QUEUE_SIZE ){
|
||||
prq->Empty();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for( ; i < PENDING_QUEUE_SIZE; i++)
|
||||
if(pending_array[i] == (PSLICE) 0){
|
||||
pending_array[i] = prq->GetHead();
|
||||
prq->Release();
|
||||
pq_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PendingQueue::ReAssign(RequestQueue *prq, BitField &bf)
|
||||
{
|
||||
int i = 0;
|
||||
size_t sc = pq_count;
|
||||
for( ; i < PENDING_QUEUE_SIZE && sc; i++){
|
||||
if( pending_array[i] != (PSLICE) 0){
|
||||
sc--;
|
||||
if( bf.IsSet(pending_array[i]->index) ){
|
||||
prq->SetHead(pending_array[i]);
|
||||
pending_array[i] = (PSLICE) 0;
|
||||
pq_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
67
btrequest.h
Normal file
67
btrequest.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef SLICE_H
|
||||
#define SLICE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "btcontent.h"
|
||||
#include "bitfield.h"
|
||||
|
||||
typedef struct _slice{
|
||||
size_t index;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
struct _slice *next;
|
||||
}SLICE,*PSLICE;
|
||||
|
||||
class RequestQueue
|
||||
{
|
||||
private:
|
||||
PSLICE rq_head;
|
||||
public:
|
||||
|
||||
RequestQueue();
|
||||
~RequestQueue();
|
||||
|
||||
void Empty();
|
||||
|
||||
void SetHead(PSLICE ps);
|
||||
PSLICE GetHead() const { return rq_head; }
|
||||
size_t GetRequestIdx(){ return rq_head ? rq_head->index : BTCONTENT.GetNPieces(); }
|
||||
size_t GetRequestLen(){ return rq_head ? rq_head->length : 0; }
|
||||
void Release(){ rq_head = (PSLICE) 0; }
|
||||
int IsValidRequest(size_t idx,size_t off,size_t len);
|
||||
|
||||
void operator=(RequestQueue &rq);
|
||||
|
||||
int IsEmpty() const { return rq_head ? 0 : 1; }
|
||||
|
||||
int Add(size_t idx,size_t off,size_t len);
|
||||
int Remove(size_t idx,size_t off,size_t len);
|
||||
|
||||
int Pop(size_t *pidx,size_t *poff,size_t *plen);
|
||||
int Peek(size_t *pidx,size_t *poff,size_t *plen) const;
|
||||
|
||||
int CreateWithIdx(size_t idx);
|
||||
size_t NSlices(size_t idx) const;
|
||||
size_t Slice_Length(size_t idx,size_t sidx) const;
|
||||
};
|
||||
|
||||
#define PENDING_QUEUE_SIZE 100
|
||||
|
||||
class PendingQueue
|
||||
{
|
||||
private:
|
||||
PSLICE pending_array[PENDING_QUEUE_SIZE];
|
||||
size_t pq_count;
|
||||
|
||||
public:
|
||||
PendingQueue();
|
||||
~PendingQueue();
|
||||
void Empty();
|
||||
int Pending(RequestQueue *prq);
|
||||
int ReAssign(RequestQueue *prq, BitField &bf);
|
||||
int Exist(size_t idx);
|
||||
};
|
||||
|
||||
extern PendingQueue PENDINGQUEUE;
|
||||
|
||||
#endif
|
117
btstream.cpp
Normal file
117
btstream.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <arpa/inet.h>
|
||||
#include "btstream.h"
|
||||
#include "msgencode.h"
|
||||
#include "btconfig.h"
|
||||
|
||||
ssize_t btStream::Flush()
|
||||
{
|
||||
return out_buffer.FlushOut(sock);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_State(unsigned char state)
|
||||
{
|
||||
char msg[H_BASE_LEN + 4];
|
||||
*(size_t*)msg = htonl(H_BASE_LEN);
|
||||
msg[4] = (char)state;
|
||||
return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Have(size_t idx)
|
||||
{
|
||||
char msg[H_HAVE_LEN + 4];
|
||||
size_t *p = (size_t*)msg;
|
||||
|
||||
*p = htonl(H_HAVE_LEN);
|
||||
msg[4] = (char)M_HAVE;
|
||||
p = (size_t*)(msg + 5);
|
||||
*p = htonl(idx);
|
||||
|
||||
return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Bitfield(char *bit_buf,size_t len)
|
||||
{
|
||||
size_t q = htonl(len + 1);
|
||||
unsigned char t = M_BITFIELD;
|
||||
ssize_t r = out_buffer.Put(sock,(char*)&q,4);
|
||||
if(r < 0) return r;
|
||||
r = out_buffer.Put(sock,(char*)&t,1);
|
||||
if(r < 0) return r;
|
||||
return out_buffer.PutFlush(sock,bit_buf,len);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len)
|
||||
{
|
||||
char msg[H_CANCEL_LEN + 4];
|
||||
size_t *p = (size_t*)msg;
|
||||
|
||||
*p = htonl(H_CANCEL_LEN);
|
||||
msg[4] = M_CANCEL;
|
||||
p = (size_t*)(msg + 5);
|
||||
*p = htonl(idx); p++;
|
||||
*p = htonl(off); p++;
|
||||
*p = htonl(len);
|
||||
return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Piece(size_t idx,size_t off,char *piece_buf,size_t len)
|
||||
{
|
||||
size_t q = htonl(len + H_PIECE_LEN);
|
||||
unsigned char t = M_PIECE;
|
||||
ssize_t r;
|
||||
|
||||
idx = htonl(idx);
|
||||
off = htonl(off);
|
||||
if( (r = out_buffer.Put(sock,(char*)&q,4)) < 0 ) return r;
|
||||
if( (r = out_buffer.Put(sock,(char*)&t,1)) < 0 ) return r;
|
||||
if( (r = out_buffer.Put(sock,(char*)&idx,4)) < 0) return r;
|
||||
if( (r = out_buffer.Put(sock,(char*)&off,4)) < 0) return r;
|
||||
return out_buffer.PutFlush(sock,piece_buf,len);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len)
|
||||
{
|
||||
char msg[H_REQUEST_LEN + 4];
|
||||
size_t *p = (size_t*) msg;
|
||||
|
||||
*p = htonl(H_REQUEST_LEN);
|
||||
msg[4] = (char)M_REQUEST;
|
||||
p = (size_t*)(msg + 5);
|
||||
*p = htonl(idx); p++;
|
||||
*p = htonl(off); p++;
|
||||
*p = htonl(len);
|
||||
return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Keepalive()
|
||||
{
|
||||
size_t i = 0;
|
||||
return out_buffer.PutFlush(sock,(char*)&i,4);
|
||||
}
|
||||
|
||||
int btStream::HaveMessage()
|
||||
{
|
||||
// if message arrived.
|
||||
size_t r;
|
||||
if( 4 <= in_buffer.Count() ){
|
||||
r = ntohl(*(size_t*)in_buffer.BasePointer());
|
||||
if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long
|
||||
if( (r + 4) <= in_buffer.Count() ) return 1;
|
||||
}
|
||||
return 0; //no message arrived
|
||||
}
|
||||
|
||||
ssize_t btStream::Feed()
|
||||
{
|
||||
return in_buffer.FeedIn(sock);
|
||||
}
|
||||
|
||||
ssize_t btStream::PickMessage()
|
||||
{
|
||||
return in_buffer.PickUp( ntohl((*(int*)in_buffer.BasePointer())) + 4);
|
||||
}
|
||||
|
||||
ssize_t btStream::Send_Buffer(char *buf, size_t len)
|
||||
{
|
||||
return out_buffer.PutFlush(sock,buf,len);
|
||||
}
|
53
btstream.h
Normal file
53
btstream.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef BTSTREAM_H
|
||||
#define BTSTREAM_H
|
||||
|
||||
#include "./def.h"
|
||||
#include "./bufio.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include "Winsock2.h"
|
||||
#else
|
||||
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
class btStream
|
||||
{
|
||||
private:
|
||||
SOCKET sock;
|
||||
|
||||
public:
|
||||
BufIo in_buffer;
|
||||
BufIo out_buffer;
|
||||
|
||||
btStream() { sock = INVALID_SOCKET ;}
|
||||
~btStream() {if( INVALID_SOCKET != sock) CLOSE_SOCKET(sock);}
|
||||
|
||||
|
||||
SOCKET GetSocket() {return sock;}
|
||||
void SetSocket(SOCKET sk){ sock = sk; }
|
||||
|
||||
void Close(){
|
||||
if( INVALID_SOCKET != sock ){ CLOSE_SOCKET(sock); sock = INVALID_SOCKET;}
|
||||
in_buffer.Close();
|
||||
out_buffer.Close();
|
||||
}
|
||||
|
||||
ssize_t PickMessage(); //移除接收缓存中的一条消息
|
||||
ssize_t Feed();
|
||||
|
||||
int HaveMessage(); // 返回值 1: 缓存中有消息 0: 暂无消息 -1: 失败
|
||||
|
||||
ssize_t Send_Keepalive();
|
||||
ssize_t Send_State(unsigned char state);
|
||||
ssize_t Send_Have(size_t idx);
|
||||
ssize_t Send_Piece(size_t idx,size_t off,char *piece_buf,size_t len);
|
||||
ssize_t Send_Bitfield(char *bit_buf,size_t len);
|
||||
ssize_t Send_Request(size_t idx,size_t off,size_t len);
|
||||
ssize_t Send_Cancel(size_t idx,size_t off,size_t len);
|
||||
ssize_t Send_Buffer(char *buf,size_t len);
|
||||
|
||||
ssize_t Flush();
|
||||
};
|
||||
|
||||
#endif
|
166
bufio.cpp
Normal file
166
bufio.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "./bufio.h"
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "btrequest.h"
|
||||
|
||||
#define DEF_BUF_SIZ 36864 /* 36 KB */
|
||||
#define INCREAST_SIZ 32768 /* 32 KB */
|
||||
#define MAX_BUF_SIZ 135168 /* 132 KB */
|
||||
|
||||
#define _left_buffer_size (n - p)
|
||||
|
||||
BufIo::BufIo()
|
||||
{
|
||||
f_socket_remote_closed = 0;
|
||||
b = new char[DEF_BUF_SIZ];
|
||||
#ifndef WINDOWS
|
||||
if( !b ) throw 9;
|
||||
#endif
|
||||
p = 0;
|
||||
n = DEF_BUF_SIZ;
|
||||
}
|
||||
|
||||
ssize_t BufIo::_realloc_buffer()
|
||||
{
|
||||
char *tbuf;
|
||||
|
||||
if( ( n + INCREAST_SIZ ) >= MAX_BUF_SIZ ) return -1; // buffer too long
|
||||
|
||||
tbuf = new char[n + INCREAST_SIZ];
|
||||
#ifndef WINDOWS
|
||||
if( !tbuf ) return -1;
|
||||
#endif
|
||||
|
||||
if(p) memcpy(tbuf, b, p);
|
||||
delete []b;
|
||||
b = tbuf;
|
||||
n += INCREAST_SIZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// retval
|
||||
// successful return bytes sended. otherwise -1;
|
||||
ssize_t BufIo::_SEND(SOCKET sk, char *buf, size_t len)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t t = 0;
|
||||
for(; len;){
|
||||
r = SEND(sk,buf,len);
|
||||
if(r < 0){
|
||||
#ifndef WINDOWS
|
||||
if(errno == EINTR) continue;
|
||||
#endif
|
||||
return (EWOULDBLOCK == errno) ? (ssize_t)t : -1;
|
||||
}else if( 0 == r ){
|
||||
return t; // no possible???
|
||||
}else{
|
||||
buf += r;
|
||||
len -= r;
|
||||
t += r;
|
||||
}
|
||||
}
|
||||
return (ssize_t)t;
|
||||
}
|
||||
|
||||
ssize_t BufIo::_RECV(SOCKET sk, char *buf,size_t len)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t t = 0;
|
||||
for(; len;){
|
||||
r = RECV(sk,(char*)buf,len);
|
||||
if(r < 0){
|
||||
#ifndef WINDOWS
|
||||
if(errno == EINTR) continue;
|
||||
#endif
|
||||
return (EWOULDBLOCK == errno) ? (ssize_t)t : -1;
|
||||
}else if( 0 == r ){
|
||||
f_socket_remote_closed = 1;
|
||||
return t; //connection closed by remote.
|
||||
}else{
|
||||
buf += r;
|
||||
len -= r;
|
||||
t += r;
|
||||
}
|
||||
}
|
||||
return (ssize_t)t;
|
||||
}
|
||||
|
||||
ssize_t BufIo::Put(SOCKET sk, char *buf,size_t len)
|
||||
{
|
||||
ssize_t r;
|
||||
if( _left_buffer_size < len ){ //no enough space
|
||||
r = FlushOut(sk);
|
||||
if( r < 0 ) return r;
|
||||
for( ; _left_buffer_size < len; ) // still no enough space
|
||||
if(_realloc_buffer() < 0) return -3;
|
||||
}
|
||||
memcpy(b + p, buf, len);
|
||||
p += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufIo::FeedIn(SOCKET sk)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
if(!_left_buffer_size)
|
||||
if(_realloc_buffer() < 0) return (ssize_t) -2;
|
||||
|
||||
r = _RECV(sk, b + p, _left_buffer_size);
|
||||
if( r < 0 ) return -1;
|
||||
else{
|
||||
if( r ) p += r;
|
||||
if( f_socket_remote_closed ) return -2; // connection closed by remote
|
||||
}
|
||||
return (ssize_t) p;
|
||||
}
|
||||
|
||||
ssize_t BufIo::PutFlush(SOCKET sk, char *buf,size_t len)
|
||||
{
|
||||
if( _left_buffer_size < len && p){
|
||||
if( FlushOut(sk) < 0) return -1;
|
||||
}
|
||||
|
||||
for(; _left_buffer_size < len; )
|
||||
if( _realloc_buffer() < 0) return -3;
|
||||
|
||||
memcpy(b + p, buf, len);
|
||||
p += len;
|
||||
return FlushOut(sk);
|
||||
}
|
||||
|
||||
// retval
|
||||
// >= 0 left bytes in buffer
|
||||
// < 0 failed
|
||||
ssize_t BufIo::FlushOut(SOCKET sk)
|
||||
{
|
||||
ssize_t r;
|
||||
if( !p ) return 0; // no data to be send
|
||||
|
||||
r = _SEND(sk,b,p);
|
||||
if( r < 0 ) return r;
|
||||
else if( r > 0){
|
||||
p -= r;
|
||||
if( p ) memmove(b, b + r, p);
|
||||
}
|
||||
return (ssize_t)p;
|
||||
}
|
||||
|
||||
ssize_t BufIo::PickUp(size_t len)
|
||||
{
|
||||
if( p < len ) return -1;
|
||||
p -= len;
|
||||
if( p ) memmove(b, b + len, p);
|
||||
return 0;
|
||||
}
|
50
bufio.h
Normal file
50
bufio.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef BUFIO_H
|
||||
#define BUFIO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "def.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
#endif
|
||||
|
||||
class BufIo
|
||||
{
|
||||
private:
|
||||
char *b;
|
||||
size_t p;
|
||||
size_t n;
|
||||
|
||||
int f_socket_remote_closed;
|
||||
|
||||
ssize_t _realloc_buffer();
|
||||
ssize_t _SEND(SOCKET socket,char *buf,size_t len);
|
||||
ssize_t _RECV(SOCKET socket,char *buf,size_t len);
|
||||
|
||||
public:
|
||||
BufIo();
|
||||
~BufIo() { if(b){ delete []b; b = (char*) 0;} }
|
||||
|
||||
|
||||
void Reset(){ p = 0; f_socket_remote_closed = 0;}
|
||||
|
||||
void Close(){
|
||||
if( b ){ delete []b; b = (char*) 0; }
|
||||
p = n = 0;
|
||||
}
|
||||
|
||||
size_t Count() const { return p; } //缓存中现有字节数
|
||||
size_t LeftSize() const { return (n - p); }
|
||||
|
||||
ssize_t PickUp(size_t len); //移除缓存中前len个字节
|
||||
|
||||
ssize_t FeedIn(SOCKET sk); //从sk读数据到缓存直到暂时无数据可读或缓冲区满
|
||||
ssize_t FlushOut(SOCKET sk); //将缓存中数据写到socket
|
||||
ssize_t Put(SOCKET sk,char *buf,size_t len); //将buf内容添加到缓存
|
||||
ssize_t PutFlush(SOCKET sk,char *buf,size_t len);
|
||||
|
||||
char *BasePointer(){ return b; }
|
||||
char *CurrentPointer() { return ( b + p); }
|
||||
};
|
||||
|
||||
#endif
|
186
config.h.in
Normal file
186
config.h.in
Normal file
@ -0,0 +1,186 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname2' function. */
|
||||
#undef HAVE_GETHOSTBYNAME2
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the `getwd' function. */
|
||||
#undef HAVE_GETWD
|
||||
|
||||
/* Define to 1 if you have the `inet_ntop' function. */
|
||||
#undef HAVE_INET_NTOP
|
||||
|
||||
/* Define to 1 if you have the `inet_pton' function. */
|
||||
#undef HAVE_INET_PTON
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `crypt' library (-lcrypt). */
|
||||
#undef HAVE_LIBCRYPT
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `md' library (-lmd). */
|
||||
#undef HAVE_LIBMD
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
#undef HAVE_LIBSSL
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the `memchr' function. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#undef HAVE_MKDIR
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <ssl/sha.h> header file. */
|
||||
#undef HAVE_SSL_SHA_H
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#undef HAVE_STRNCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strnstr' function. */
|
||||
#undef HAVE_STRNSTR
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#undef HAVE_STRTOL
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
37
configure.ac
Executable file
37
configure.ac
Executable file
@ -0,0 +1,37 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT([CTorrent_ipv6], [devel], [kantacki@o2.pl])
|
||||
AM_INIT_AUTOMAKE(ctorrent_ipv6,devel)
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
||||
AC_CONFIG_SRCDIR([ctorrent.cpp])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([ssl],[SHA1_Init],,
|
||||
[AC_CHECK_LIB([crypt],[SHA1_Init],,
|
||||
[AC_CHECK_LIB([crypto],[SHA1_Init],,
|
||||
[AC_CHECK_LIB([md],[SHA1_Init],,
|
||||
[AC_MSG_ERROR([error, Please install OpenSSL first!])])])])])
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h memory.h netdb.h netinet/in.h stdlib.h string.h sys/param.h sys/socket.h sys/time.h unistd.h ssl/sha.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
# Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_STAT
|
||||
AC_CHECK_FUNCS([ftruncate gethostbyname2 gettimeofday getwd inet_ntop inet_pton memchr memmove memset mkdir select socket strchr strerror strncasecmp strstr strtol strnstr])
|
||||
|
||||
AC_OUTPUT(Makefile)
|
17
connect_nonb.cpp
Normal file
17
connect_nonb.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "connect_nonb.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
//
|
||||
// >0
|
||||
// -1
|
||||
// -2
|
||||
int connect_nonb(SOCKET sk,struct sockaddr* psa)
|
||||
{
|
||||
int r;
|
||||
r = connect(sk,psa,sizeof(struct sockaddr_in6));
|
||||
if(r < 0 && errno == EINPROGRESS) r = -2;
|
||||
return r;
|
||||
}
|
15
connect_nonb.h
Normal file
15
connect_nonb.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef CONNECT_NONB_H
|
||||
#define CONNECT_NONB_H
|
||||
|
||||
#include "./def.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
int connect_nonb(SOCKET sk,struct sockaddr *psa);
|
||||
|
||||
#endif
|
242
ctorrent.cpp
Normal file
242
ctorrent.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "./def.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "btconfig.h"
|
||||
#include "btcontent.h"
|
||||
#include "downloader.h"
|
||||
#include "peerlist.h"
|
||||
#include "tracker.h"
|
||||
|
||||
#include "./config.h"
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include "sigint.h"
|
||||
#endif
|
||||
|
||||
void usage();
|
||||
int param_check(int argc, char **argv);
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrzevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void Random_init()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,(struct timezone*) 0);
|
||||
unsigned int seed = tv.tv_usec + tv.tv_sec + getpid();
|
||||
return srandom(seed);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
Random_init();
|
||||
arg_user_agent = new char[MAX_PF_LEN];
|
||||
strcpy(arg_user_agent,PEER_PFX);
|
||||
|
||||
if( argc < 2 || param_check(argc,argv) < 0 ){
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if( arg_flg_make_torrent ){
|
||||
if( !arg_announce ){ fprintf(stderr,"please use -u to specify a announce url!\n"); exit(1);}
|
||||
if( !arg_save_as ){ fprintf(stderr,"please use -s to specify a metainfo file name!\n"); exit(1);}
|
||||
if( BTCONTENT.InitialFromFS(arg_metainfo_file, arg_announce, arg_piece_length) < 0 ||
|
||||
BTCONTENT.CreateMetainfoFile(arg_save_as) < 0){
|
||||
fprintf(stderr,"create metainfo failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("create metainfo file %s successful.\n", arg_save_as);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if( BTCONTENT.InitialFromMI(arg_metainfo_file, arg_save_as) < 0){
|
||||
fprintf(stderr,"error,initial meta info failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if( !arg_flg_exam_only && !arg_flg_check_only){
|
||||
if(WORLD.Initial_ListenPort() < 0){
|
||||
fprintf(stderr,"warn, you couldn't accept connection.\n");
|
||||
}else
|
||||
printf("Listen on: %d\n",cfg_listen_port);
|
||||
|
||||
Tracker.Initial();
|
||||
|
||||
signal(SIGPIPE,SIG_IGN);
|
||||
signal(SIGINT,sigint_catch);
|
||||
Downloader();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int param_check(int argc, char **argv)
|
||||
{
|
||||
int c, l;
|
||||
while ( ( c = getopt(argc,argv,"b:B:cC:e:fl:M:m:P:p:s:tu:xhH")) != -1)
|
||||
switch( c ){
|
||||
case 'b':
|
||||
arg_bitfield_file = new char[strlen(optarg) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !arg_bitfield_file ) return -1;
|
||||
#endif
|
||||
strcpy(arg_bitfield_file, optarg);
|
||||
break;
|
||||
|
||||
case 'p': // listen on Port XXXX
|
||||
cfg_listen_port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 's': // Save as FILE/DIR NAME
|
||||
if( arg_save_as ) return -1;
|
||||
arg_save_as = new char[strlen(optarg) + 1];
|
||||
#ifndef WINDOWS
|
||||
if( !arg_save_as ) return -1;
|
||||
#endif
|
||||
strcpy(arg_save_as,optarg);
|
||||
break;
|
||||
|
||||
case 'e': // Exit while complete
|
||||
cfg_seed_hours = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'c': // Check exist only
|
||||
arg_flg_check_only = 1;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
cfg_cache_size = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'M': // Max peers
|
||||
cfg_max_peers = atoi(optarg);
|
||||
if( cfg_max_peers > 1000 ||
|
||||
cfg_max_peers < 20){
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': // Min peers
|
||||
cfg_min_peers = atoi(optarg);
|
||||
if( cfg_min_peers > 1000 ||
|
||||
cfg_min_peers < 20){
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f': // force seed mode, skip sha1 check when startup.
|
||||
arg_flg_force_seed_mode = 1;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
cfg_max_bandwidth = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
l = strlen(optarg);
|
||||
if (l > MAX_PF_LEN) {printf("-P arg must be 8 or less characters\n"); exit(1);}
|
||||
if (l == 1 && *optarg == '-') *arg_user_agent = (char) 0;
|
||||
else strcpy(arg_user_agent,optarg);
|
||||
break;
|
||||
|
||||
// BELLOW OPTIONS USED FOR CREATE TORRENT.
|
||||
case 'u': // Announce url
|
||||
if( arg_announce ) return -1;
|
||||
arg_announce = new char[strlen(optarg) + 1];
|
||||
strcpy(arg_announce, optarg);
|
||||
break;
|
||||
|
||||
case 't': // make Torrent
|
||||
arg_flg_make_torrent = 1;
|
||||
break;
|
||||
|
||||
case 'l': // piece Length (default 262144)
|
||||
arg_piece_length = atoi(optarg);
|
||||
if( arg_piece_length < 65536 ||
|
||||
arg_piece_length > 1310720 ){
|
||||
// warn message:
|
||||
// piece length range is 65536 =>> 1310720
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
arg_flg_exam_only = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'H':
|
||||
default:
|
||||
//unknow option.
|
||||
return -1;
|
||||
}
|
||||
|
||||
argc -= optind; argv += optind;
|
||||
if( cfg_min_peers >= cfg_max_peers ) cfg_min_peers = cfg_max_peers - 1;
|
||||
if( argc != 1 ) return -1;
|
||||
arg_metainfo_file = new char[strlen(*argv) + 1];
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !arg_metainfo_file ) return -1;
|
||||
#endif
|
||||
strcpy(arg_metainfo_file, *argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
fprintf(stderr,"%s Copyright: YuHong(992126018601033)",PACKAGE_STRING);
|
||||
fprintf(stderr,"\nIPv6 handling made by Lukasz Kalamlacki:\n");
|
||||
fprintf(stderr,"\nWARNING: THERE IS NO WARRANTY FOR CTorrent_ipv6. USE AT YOUR OWN RISK!!!\n");
|
||||
fprintf(stderr,"\nGeneric Options:\n");
|
||||
fprintf(stderr,"-h/-H\t\tShow this message.\n");
|
||||
fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n");
|
||||
fprintf(stderr,"-c\t\tCheck exist only. don't download.\n");
|
||||
fprintf(stderr,"\nDownload Options:\n");
|
||||
fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n");
|
||||
fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n");
|
||||
fprintf(stderr,"-s save_as\tSave file/directory/metainfo as... \n");
|
||||
fprintf(stderr,"-C cache_size\tCache size,unit MB. (default 16MB)\n");
|
||||
fprintf(stderr,"-f\t\tForce seed mode. skip hash check at startup.\n");
|
||||
fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n");
|
||||
fprintf(stderr,"-M max_peers\tMax peers count.\n");
|
||||
fprintf(stderr,"-m min_peers\tMin peers count.\n");
|
||||
fprintf(stderr,"-B rate\t\tMax bandwidth (unit KB/s)\n");
|
||||
fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n");
|
||||
fprintf(stderr,"\nMake metainfo(torrent) file Options:\n");
|
||||
fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n");
|
||||
fprintf(stderr,"-u url\t\tTracker's url.\n");
|
||||
fprintf(stderr,"\t\tIf you want use IPv6 address, use it in format like in this example:\n");
|
||||
fprintf(stderr,"\t\thttp://[fec0::1]:80/announce.php , address is fec0::1 , port is 80\n");
|
||||
fprintf(stderr,"-l piece_len\tPiece length.(default 262144)\n");
|
||||
fprintf(stderr,"\neg.\n");
|
||||
fprintf(stderr,"hong> ctorrent -s new_filename -e 12 -C 32 -p 6881 eg.torrent\n\n");
|
||||
fprintf(stderr,"home page: http://ctorrent_ipv6.sourceforge.net/\n");
|
||||
fprintf(stderr,"bug report: %s\n\n",PACKAGE_BUGREPORT);
|
||||
}
|
45
def.h
Normal file
45
def.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef DEF_H
|
||||
#define DEF_H
|
||||
|
||||
#include "./config.h"
|
||||
|
||||
#ifdef WINDOWS //if Windows ********************
|
||||
typedef int ssize_t;
|
||||
typedef int socklen_t;
|
||||
typedef unsigned __int64 u_int64_t;
|
||||
typedef unsigned __int8 u_int8_t;
|
||||
|
||||
#define PATH_SP '\\'
|
||||
#define MAXPATHLEN 1024
|
||||
#define MAXHOSTNAMELEN 256
|
||||
|
||||
//#define mkdir(path,mode) _mkdir((path))
|
||||
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#define ioctl ioctlsocket
|
||||
|
||||
#define RECV(fd,buf,len) recv((fd),(buf),(len),0)
|
||||
#define SEND(fd,buf,len) send((fd),(buf),(len),0)
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define CLOSE_SOCKET(sk) closesocket((sk))
|
||||
|
||||
#else // if *Nix *****************************
|
||||
|
||||
#define CLOSE_SOCKET(sk) close((sk))
|
||||
|
||||
#ifndef SOCKET
|
||||
typedef int SOCKET;
|
||||
#endif
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
|
||||
#define PATH_SP '/'
|
||||
#define RECV(fd,buf,len) read((fd),(buf),(len))
|
||||
#define SEND(fd,buf,len) write((fd),(buf),(len))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
411
depcomp
Executable file
411
depcomp
Executable file
@ -0,0 +1,411 @@
|
||||
#! /bin/sh
|
||||
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
# Copyright 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# `libtool' can also be set to `yes' or `no'.
|
||||
|
||||
depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say).
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> $depfile
|
||||
echo >> $depfile
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> $depfile
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. This file always lives in the current directory.
|
||||
# Also, the AIX compiler puts `$object:' at the start of each line;
|
||||
# $object doesn't have directory information.
|
||||
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
|
||||
tmpdepfile="$stripped.u"
|
||||
outname="$stripped.o"
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
"$@" -M
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 AIX compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
|
||||
tmpdepfile1="$object.d"
|
||||
tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'`
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile1"; then
|
||||
tmpdepfile="$tmpdepfile1"
|
||||
else
|
||||
tmpdepfile="$tmpdepfile2"
|
||||
fi
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a space and a tab in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*) # this is libtool, let us make it quiet
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case "$arg" in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
# X makedepend
|
||||
(
|
||||
shift
|
||||
cleared=no
|
||||
for arg in "$@"; do
|
||||
case $cleared in no)
|
||||
set ""; shift
|
||||
cleared=yes
|
||||
esac
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
-*)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
esac
|
||||
done
|
||||
obj_suffix="`echo $object | sed 's/^.*\././'`"
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tail +3 "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" -E |
|
||||
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||
sed '$ s: \\$::' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" -E |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
52
downloader.cpp
Normal file
52
downloader.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <winsock2.h>
|
||||
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "peerlist.h"
|
||||
#include "tracker.h"
|
||||
#include "btcontent.h"
|
||||
|
||||
void Downloader()
|
||||
{
|
||||
int nfds,maxfd,r;
|
||||
struct timeval timeout;
|
||||
time_t now;
|
||||
fd_set rfd;
|
||||
fd_set wfd;
|
||||
|
||||
for(;;){
|
||||
time(&now);
|
||||
if( BTCONTENT.SeedTimeout(&now) ) break;
|
||||
|
||||
FD_ZERO(&rfd); FD_ZERO(&wfd);
|
||||
maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd);
|
||||
r = WORLD.FillFDSET(&now,&rfd,&wfd);
|
||||
if( r > maxfd ) maxfd = r;
|
||||
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
nfds = select(maxfd + 1,&rfd,&wfd,(fd_set*) 0,&timeout);
|
||||
|
||||
if(nfds > 0){
|
||||
if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds);
|
||||
if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds);
|
||||
}
|
||||
}/* end for(;;) */
|
||||
}
|
6
downloader.h
Normal file
6
downloader.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef DOWNLOADER_H
|
||||
#define DOWNLOADER_H
|
||||
|
||||
void Downloader();
|
||||
|
||||
#endif
|
186
httpencode.cpp
Normal file
186
httpencode.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "./def.h"
|
||||
#include "./httpencode.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./config.h"
|
||||
|
||||
#ifndef HAVE_STRNSTR
|
||||
|
||||
/* FUNCTION PROGRAMER: Siberiaic Sang */
|
||||
static char* strnstr(const char *haystack,const char *needle,size_t haystacklen)
|
||||
{
|
||||
char *p;
|
||||
ssize_t plen;
|
||||
ssize_t len = strlen(needle);
|
||||
|
||||
if (*needle == '\0')
|
||||
return (char*) haystack;
|
||||
|
||||
plen = haystacklen;
|
||||
for (p = (char*) haystack; p != (char*) 0; p = (char*)memchr(p + 1, *needle, plen-1)) {
|
||||
plen = haystacklen - (p - haystack);
|
||||
|
||||
if (plen < len) return (char*) 0;
|
||||
|
||||
if (strncmp(p, needle, len) == 0)
|
||||
return (p);
|
||||
}
|
||||
return (char*) 0;
|
||||
}
|
||||
#endif
|
||||
/* ************************************************** */
|
||||
|
||||
static void url_encode_char(char *b,char c)
|
||||
{
|
||||
char HEX_TABLE[] = "0123456789ABCDEF";
|
||||
b[0] = '%';
|
||||
b[1] = HEX_TABLE[(c >> 4) & 0x0F];
|
||||
b[2] = HEX_TABLE[c & 0x0F];
|
||||
}
|
||||
|
||||
char* Http_url_encode(char *s,char *b,size_t n)
|
||||
{
|
||||
size_t r,i;
|
||||
for(r = 0,i = 0 ; i < n; i++){
|
||||
if( isalpha(b[i]) || isdigit(b[i]) ){
|
||||
s[r] = b[i];
|
||||
r++;
|
||||
}else{
|
||||
url_encode_char(s + r, b[i]);
|
||||
r += 3;
|
||||
}
|
||||
}
|
||||
s[r] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//ipv6 support available
|
||||
int Http_url_analyse(char *url,char *host,int *port,char *path)
|
||||
{
|
||||
char *p;
|
||||
int r;
|
||||
*port = 80; /* default port 80 */
|
||||
p = strstr(url,"://");
|
||||
if( !p )
|
||||
p = url;
|
||||
else
|
||||
p += 3;
|
||||
/* host */
|
||||
if(*p == '[') {
|
||||
// tracker's ipv6 address
|
||||
p++;
|
||||
for(; *p && (isalnum(*p) || *p == ':' ); p++, host++)
|
||||
*host = *p;
|
||||
if( *p != ']') return -1;
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
// hostname in dns
|
||||
for(; *p && (isalnum(*p) || *p == '.' || *p == '-'); p++, host++)
|
||||
*host = *p;
|
||||
}
|
||||
*host = '\0';
|
||||
|
||||
if( *p == ':' ){
|
||||
/* port */
|
||||
p++;
|
||||
for( r = 0; p[r] >= '0' && p[r] <= '9' && r < 6; r++) ;
|
||||
|
||||
if( !r ) return -1;
|
||||
*port = atoi(p);
|
||||
if(*port > 65536) return -1;
|
||||
p += r;
|
||||
}
|
||||
|
||||
/* path */
|
||||
if( *p != '/' ) return -1;
|
||||
for( ; *p && *p != '?'; p++,path++) *path = *p;
|
||||
*path = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Http_split(char *b,size_t n,char **pd,size_t *dlen)
|
||||
{
|
||||
char *p;
|
||||
size_t addtion, hlen;
|
||||
|
||||
addtion = 2; hlen = 0;
|
||||
|
||||
if( n < 16 ) return 0;
|
||||
|
||||
if(strncasecmp(b,"HTTP/",5) != 0){
|
||||
return 0;
|
||||
/* message without http header */
|
||||
//*pd = b;
|
||||
//*dlen = n;
|
||||
}else{
|
||||
p = strnstr(b,"\n\n",n);
|
||||
if( !p ){ p = strnstr(b,"\r\n\r\n",n); if(p) addtion = 4;}
|
||||
|
||||
if( p ){
|
||||
hlen = p - b;
|
||||
*pd = ( p + addtion );
|
||||
*dlen = n - hlen - addtion;
|
||||
}else{
|
||||
hlen = n;
|
||||
*pd = (char*) 0;
|
||||
*dlen = 0;
|
||||
}
|
||||
}
|
||||
return hlen;
|
||||
}
|
||||
|
||||
int Http_reponse_code(char *b,size_t n)
|
||||
{
|
||||
int r = -1;
|
||||
|
||||
for(; n && *b != ' ' && *b != '\n'; b++,n--) ;
|
||||
if( !n || *b != ' ') r = -1;
|
||||
else{
|
||||
r = atoi(b);
|
||||
if( r < 100 || r > 600 ) r = -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int Http_get_header(char *b,int n,char *header,char *v)
|
||||
{
|
||||
char *e,h[64];
|
||||
int r,header_len;
|
||||
|
||||
strcpy(h,header);
|
||||
strcat(h,": ");
|
||||
header_len = strlen(h);
|
||||
|
||||
/* remove status line. */
|
||||
e = strchr(b,'\n');
|
||||
if( !e ) return -1;
|
||||
e++;
|
||||
n -= (e - b);
|
||||
b = e;
|
||||
|
||||
for(; n >= 0; ){
|
||||
e = strchr(b,'\n');
|
||||
if( !e ) r = n; /* last line */
|
||||
else{r = e - b ; r++;}
|
||||
|
||||
if( r > header_len ){
|
||||
if( strncasecmp(b, h, header_len) == 0){
|
||||
/* header founded */
|
||||
b += header_len;
|
||||
for(; *b != '\n'; v++,b++) *v = *b;
|
||||
*v = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
b += r;
|
||||
n -= r;
|
||||
} /* end for */
|
||||
return -1;
|
||||
}
|
19
httpencode.h
Normal file
19
httpencode.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef HTTPENCODE_H
|
||||
#define HTTPENCODE_H
|
||||
|
||||
#define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d"
|
||||
|
||||
// compact unsupported by ipv6 trackers
|
||||
//#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0"
|
||||
//#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0"
|
||||
|
||||
#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s HTTP/1.0"
|
||||
#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d HTTP/1.0"
|
||||
|
||||
char* Http_url_encode(char *s,char *b,size_t n);
|
||||
int Http_url_analyse(char *url,char *host,int *port,char *path);
|
||||
size_t Http_split(char *b,size_t n,char **pd,size_t *dlen);
|
||||
int Http_reponse_code(char *b,size_t n);
|
||||
int Http_get_header(char *b,int n,char *header,char *v);
|
||||
|
||||
#endif
|
251
install-sh
Executable file
251
install-sh
Executable file
@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
47
iplist.cpp
Normal file
47
iplist.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <string.h>
|
||||
#include "iplist.h"
|
||||
|
||||
IpList IPQUEUE;
|
||||
|
||||
void IpList::_Emtpy()
|
||||
{
|
||||
IPLIST *node = ipl_head;
|
||||
for(; ipl_head;){
|
||||
node = ipl_head;
|
||||
delete ipl_head;
|
||||
ipl_head = node->next;
|
||||
}
|
||||
count = 0;
|
||||
}
|
||||
|
||||
int IpList::Add(const struct sockaddr_in6 *psin)
|
||||
{
|
||||
IPLIST *node = ipl_head;
|
||||
for(; node; node = node->next)
|
||||
if(memcmp(psin, &node->address, sizeof(struct sockaddr_in6)) == 0) break;
|
||||
|
||||
if( node ) return -1;
|
||||
// if not exist;
|
||||
node = new IPLIST;
|
||||
#ifndef WINDOWS
|
||||
if( !node ) return -1;
|
||||
#endif
|
||||
count++;
|
||||
memcpy(&node->address,psin,sizeof(struct sockaddr_in6));
|
||||
node->next = ipl_head;
|
||||
ipl_head = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IpList::Pop(struct sockaddr_in6 *psin)
|
||||
{
|
||||
IPLIST *node = (IPLIST*) 0;
|
||||
if(!ipl_head) return -1;
|
||||
node = ipl_head;
|
||||
ipl_head = ipl_head->next;
|
||||
|
||||
count--;
|
||||
memcpy(psin, &node->address, sizeof(struct sockaddr_in6));
|
||||
delete node;
|
||||
return 0;
|
||||
}
|
35
iplist.h
Normal file
35
iplist.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef IPLIST_H
|
||||
#define IPLIST_H
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
typedef struct _iplist{
|
||||
struct sockaddr_in6 address;
|
||||
struct _iplist *next;
|
||||
}IPLIST;
|
||||
|
||||
class IpList
|
||||
{
|
||||
private:
|
||||
IPLIST *ipl_head;
|
||||
size_t count;
|
||||
void _Emtpy();
|
||||
public:
|
||||
IpList() { ipl_head = (IPLIST*)0; count = 0;}
|
||||
~IpList() { if(ipl_head) _Emtpy(); }
|
||||
int Add(const struct sockaddr_in6* psin);
|
||||
int Pop(struct sockaddr_in6* psin);
|
||||
int IsEmpty() { return count ? 0 : 1; }
|
||||
};
|
||||
|
||||
extern IpList IPQUEUE;
|
||||
#endif
|
283
missing
Executable file
283
missing
Executable file
@ -0,0 +1,283 @@
|
||||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
|
||||
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run=:
|
||||
|
||||
# In the cases where this matters, `missing' is being run in the
|
||||
# srcdir already.
|
||||
if test -f configure.ac; then
|
||||
configure_ac=configure.ac
|
||||
else
|
||||
configure_ac=configure.in
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
--run)
|
||||
# Try to run requested program, and just exit if it succeeds.
|
||||
run=
|
||||
shift
|
||||
"$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# If it does not exist, or fails to run (possibly an outdated version),
|
||||
# try to emulate it.
|
||||
case "$1" in
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||
error status if there is no known handling for PROGRAM.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
--run try to run the given command, and emulate it if it fails
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal touch file \`aclocal.m4'
|
||||
autoconf touch file \`configure'
|
||||
autoheader touch file \`config.h.in'
|
||||
automake touch all \`Makefile.in' files
|
||||
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
flex create \`lex.yy.c', if possible, from existing .c
|
||||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing 0.3 - GNU automake"
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: Unknown \`$1' option"
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aclocal)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||
any GNU archive site."
|
||||
touch aclocal.m4
|
||||
;;
|
||||
|
||||
autoconf)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`${configure_ac}'. You might want to install the
|
||||
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||
archive site."
|
||||
touch configure
|
||||
;;
|
||||
|
||||
autoheader)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||
from any GNU archive site."
|
||||
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||
test -z "$files" && files="config.h"
|
||||
touch_files=
|
||||
for f in $files; do
|
||||
case "$f" in
|
||||
*:*) touch_files="$touch_files "`echo "$f" |
|
||||
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||
*) touch_files="$touch_files $f.in";;
|
||||
esac
|
||||
done
|
||||
touch $touch_files
|
||||
;;
|
||||
|
||||
automake)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||
You might want to install the \`Automake' and \`Perl' packages.
|
||||
Grab them from any GNU archive site."
|
||||
find . -type f -name Makefile.am -print |
|
||||
sed 's/\.am$/.in/' |
|
||||
while read f; do touch "$f"; done
|
||||
;;
|
||||
|
||||
bison|yacc)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.y' file. You may need the \`Bison' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if [ $# -ne 1 ]; then
|
||||
eval LASTARG="\${$#}"
|
||||
case "$LASTARG" in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" y.tab.c
|
||||
fi
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" y.tab.h
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ ! -f y.tab.h ]; then
|
||||
echo >y.tab.h
|
||||
fi
|
||||
if [ ! -f y.tab.c ]; then
|
||||
echo 'main() { return 0; }' >y.tab.c
|
||||
fi
|
||||
;;
|
||||
|
||||
lex|flex)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.l' file. You may need the \`Flex' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if [ $# -ne 1 ]; then
|
||||
eval LASTARG="\${$#}"
|
||||
case "$LASTARG" in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" lex.yy.c
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ ! -f lex.yy.c ]; then
|
||||
echo 'main() { return 0; }' >lex.yy.c
|
||||
fi
|
||||
;;
|
||||
|
||||
help2man)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a dependency of a manual page. You may need the
|
||||
\`Help2man' package in order for those modifications to take
|
||||
effect. You can get \`Help2man' from any GNU archive site."
|
||||
|
||||
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||
if test -z "$file"; then
|
||||
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
|
||||
fi
|
||||
if [ -f "$file" ]; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo ".ab help2man is required to generate this page"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
makeinfo)
|
||||
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
|
||||
# We have makeinfo, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||
indirectly affecting the aspect of the manual. The spurious
|
||||
call might also be the consequence of using a buggy \`make' (AIX,
|
||||
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||
the \`GNU make' package. Grab either from any GNU archive site."
|
||||
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||
if test -z "$file"; then
|
||||
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
|
||||
fi
|
||||
touch $file
|
||||
;;
|
||||
|
||||
tar)
|
||||
shift
|
||||
if test -n "$run"; then
|
||||
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We have already tried tar in the generic part.
|
||||
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||
# messages.
|
||||
if (gnutar --version > /dev/null 2>&1); then
|
||||
gnutar ${1+"$@"} && exit 0
|
||||
fi
|
||||
if (gtar --version > /dev/null 2>&1); then
|
||||
gtar ${1+"$@"} && exit 0
|
||||
fi
|
||||
firstarg="$1"
|
||||
if shift; then
|
||||
case "$firstarg" in
|
||||
*o*)
|
||||
firstarg=`echo "$firstarg" | sed s/o//`
|
||||
tar "$firstarg" ${1+"$@"} && exit 0
|
||||
;;
|
||||
esac
|
||||
case "$firstarg" in
|
||||
*h*)
|
||||
firstarg=`echo "$firstarg" | sed s/h//`
|
||||
tar "$firstarg" ${1+"$@"} && exit 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||
You may want to install GNU tar or Free paxutils, or check the
|
||||
command line arguments."
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and you do not seem to have it handy on your
|
||||
system. You might have modified some files without having the
|
||||
proper tools for further handling them. Check the \`README' file,
|
||||
it often tells you about the needed prerequirements for installing
|
||||
this package. You may also peek at any GNU archive site, in case
|
||||
some other package would contain this missing \`$1' program."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
40
mkinstalldirs
Executable file
40
mkinstalldirs
Executable file
@ -0,0 +1,40 @@
|
||||
#! /bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# Created: 1993-05-16
|
||||
# Public domain
|
||||
|
||||
# $Id: mkinstalldirs,v 1.8 2004/01/30 17:52:32 yuhong Exp $
|
||||
|
||||
errstatus=0
|
||||
|
||||
for file
|
||||
do
|
||||
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||
shift
|
||||
|
||||
pathcomp=
|
||||
for d
|
||||
do
|
||||
pathcomp="$pathcomp$d"
|
||||
case "$pathcomp" in
|
||||
-* ) pathcomp=./$pathcomp ;;
|
||||
esac
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
echo "mkdir $pathcomp"
|
||||
|
||||
mkdir "$pathcomp" || lasterr=$?
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
errstatus=$lasterr
|
||||
fi
|
||||
fi
|
||||
|
||||
pathcomp="$pathcomp/"
|
||||
done
|
||||
done
|
||||
|
||||
exit $errstatus
|
||||
|
||||
# mkinstalldirs ends here
|
21
msgencode.h
Normal file
21
msgencode.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef MSGENCODE_H
|
||||
#define MSGENCODE_H
|
||||
|
||||
#define M_CHOKE (unsigned char) 0
|
||||
#define M_UNCHOKE (unsigned char) 1
|
||||
#define M_INTERESTED (unsigned char) 2
|
||||
#define M_NOT_INTERESTED (unsigned char) 3
|
||||
#define M_HAVE (unsigned char) 4
|
||||
#define M_BITFIELD (unsigned char) 5
|
||||
#define M_REQUEST (unsigned char) 6
|
||||
#define M_PIECE (unsigned char) 7
|
||||
#define M_CANCEL (unsigned char) 8
|
||||
|
||||
#define H_BASE_LEN 1 /* int_siz + chr_siz */
|
||||
|
||||
#define H_HAVE_LEN 5 /* chr_siz + int_siz */
|
||||
#define H_PIECE_LEN 9 /* chr_siz + int_siz*2 */
|
||||
#define H_REQUEST_LEN 13 /* chr_siz + int_siz*3 */
|
||||
#define H_CANCEL_LEN 13 /* chr_siz + int_siz*3 */
|
||||
|
||||
#endif
|
482
peer.cpp
Normal file
482
peer.cpp
Normal file
@ -0,0 +1,482 @@
|
||||
#include "peer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./btcontent.h"
|
||||
#include "./msgencode.h"
|
||||
#include "./peerlist.h"
|
||||
#include "./btconfig.h"
|
||||
|
||||
btBasic Self;
|
||||
|
||||
void btBasic::SetIp(struct sockaddr_in6 addr)
|
||||
{
|
||||
memcpy(&m_sin.sin6_addr,&addr.sin6_addr,sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
void btBasic::SetAddress(struct sockaddr_in6 addr)
|
||||
{
|
||||
memcpy(&m_sin,&addr,sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
int btBasic::IpEquiv(struct sockaddr_in6 addr)
|
||||
{
|
||||
// fprintf(stdout,"IpEquiv: %s <=> ", inet_ntoa(m_sin.sin_addr));
|
||||
// fprintf(stdout,"%s\n", inet_ntoa(addr.sin_addr));
|
||||
return (memcmp(&m_sin.sin6_addr,&addr.sin6_addr,sizeof(struct in6_addr)) == 0) ?
|
||||
1 : 0;
|
||||
}
|
||||
|
||||
int btPeer::Need_Local_Data()
|
||||
{
|
||||
if( m_state.remote_interested && !bitfield.IsFull()){
|
||||
|
||||
if( BTCONTENT.pBF->IsFull() ) return 1; // i am seed
|
||||
|
||||
BitField tmpBitfield = *BTCONTENT.pBF;
|
||||
tmpBitfield.Except(bitfield);
|
||||
return tmpBitfield.IsEmpty() ? 0 : 1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btPeer::Need_Remote_Data()
|
||||
{
|
||||
if( BTCONTENT.pBF->IsFull()) return 0;
|
||||
else if( bitfield.IsFull() ) return 1;
|
||||
else{
|
||||
BitField tmpBitfield = bitfield;
|
||||
tmpBitfield.Except(*BTCONTENT.pBF);
|
||||
return tmpBitfield.IsEmpty() ? 0 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
btPeer::btPeer()
|
||||
{
|
||||
m_f_keepalive = 0;
|
||||
m_status = P_CONNECTING;
|
||||
m_unchoke_timestamp = (time_t) 0;
|
||||
time(&m_last_timestamp);
|
||||
m_state.remote_choked = m_state.local_choked = 1;
|
||||
m_state.remote_interested = m_state.local_interested = 0;
|
||||
|
||||
m_err_count = 0;
|
||||
m_cached_idx = BTCONTENT.GetNPieces();
|
||||
}
|
||||
|
||||
int btPeer::SetLocal(unsigned char s)
|
||||
{
|
||||
switch(s){
|
||||
case M_CHOKE:
|
||||
if( m_state.local_choked ) return 0;
|
||||
m_state.local_choked = 1;
|
||||
break;
|
||||
case M_UNCHOKE:
|
||||
if( !reponse_q.IsEmpty() ) StartULTimer();
|
||||
if( !m_state.local_choked ) return 0;
|
||||
time(&m_unchoke_timestamp);
|
||||
m_state.local_choked = 0;
|
||||
break;
|
||||
case M_INTERESTED:
|
||||
if( m_state.local_interested ) return 0;
|
||||
m_state.local_interested = 1;
|
||||
break;
|
||||
case M_NOT_INTERESTED:
|
||||
if( !m_state.local_interested ) return 0;
|
||||
m_state.local_interested = 0;
|
||||
break;
|
||||
default:
|
||||
return -1; // BUG ???
|
||||
}
|
||||
return stream.Send_State(s);
|
||||
}
|
||||
|
||||
int btPeer::RequestPiece()
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
PENDINGQUEUE.ReAssign(&request_q,bitfield);
|
||||
|
||||
if( !request_q.IsEmpty() ) return SendRequest();
|
||||
|
||||
if( m_cached_idx < BTCONTENT.GetNPieces() ){
|
||||
idx = m_cached_idx;
|
||||
m_cached_idx = BTCONTENT.GetNPieces();
|
||||
if( !BTCONTENT.pBF->IsSet(idx) &&
|
||||
!PENDINGQUEUE.Exist(idx) &&
|
||||
!WORLD.AlreadyRequested(idx) ){
|
||||
return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
|
||||
}
|
||||
}else{
|
||||
BitField tmpBitField;
|
||||
if( bitfield.IsFull() ){
|
||||
tmpBitField = *BTCONTENT.pBF;
|
||||
tmpBitField.Invert();
|
||||
}else{
|
||||
tmpBitField = bitfield;
|
||||
tmpBitField.Except(*BTCONTENT.pBF);
|
||||
}
|
||||
|
||||
if( !tmpBitField.IsEmpty() ){
|
||||
WORLD.CheckBitField(tmpBitField);
|
||||
if(tmpBitField.IsEmpty()){
|
||||
|
||||
btPeer *peer = WORLD.Who_Can_Abandon(this);
|
||||
if(peer){
|
||||
peer->StopDLTimer();
|
||||
request_q = peer->request_q;
|
||||
|
||||
if(peer->CancelRequest(request_q.GetHead()) < 0 ||
|
||||
peer->RequestCheck() < 0){
|
||||
peer->CloseConnection();
|
||||
}
|
||||
|
||||
return SendRequest();
|
||||
}
|
||||
|
||||
}else{
|
||||
idx = tmpBitField.Random();
|
||||
return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btPeer::MsgDeliver()
|
||||
{
|
||||
size_t r,idx,off,len;
|
||||
|
||||
char *msgbuf = stream.in_buffer.BasePointer();
|
||||
|
||||
r = ntohl(*(size_t*) msgbuf);
|
||||
|
||||
if( 0 == r ){
|
||||
time(&m_last_timestamp);
|
||||
if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1;
|
||||
m_f_keepalive = 0;
|
||||
return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0;
|
||||
}else{
|
||||
switch(msgbuf[4]){
|
||||
case M_CHOKE:
|
||||
if(H_BASE_LEN != r){ return -1;}
|
||||
m_state.remote_choked = 1;
|
||||
StopDLTimer();
|
||||
if( !request_q.IsEmpty()){
|
||||
PSLICE ps = request_q.GetHead();
|
||||
PENDINGQUEUE.Pending(&request_q);
|
||||
if( CancelRequest(ps) < 0) return -1;
|
||||
}
|
||||
return 0;
|
||||
case M_UNCHOKE:
|
||||
if(H_BASE_LEN != r){return -1;}
|
||||
m_state.remote_choked = 0;
|
||||
return RequestCheck();
|
||||
|
||||
case M_INTERESTED:
|
||||
if(H_BASE_LEN != r){return -1;}
|
||||
m_state.remote_interested = 1;
|
||||
break;
|
||||
|
||||
case M_NOT_INTERESTED:
|
||||
if(r != H_BASE_LEN){return -1;}
|
||||
|
||||
m_state.remote_interested = 0;
|
||||
StopULTimer();
|
||||
|
||||
/* remove peer's reponse queue */
|
||||
if( !reponse_q.IsEmpty()) reponse_q.Empty();
|
||||
return 0;
|
||||
case M_HAVE:
|
||||
if(H_HAVE_LEN != r){return -1;}
|
||||
|
||||
idx = ntohl(*(size_t*) (msgbuf + 5));
|
||||
|
||||
if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1;
|
||||
|
||||
bitfield.Set(idx);
|
||||
|
||||
if( bitfield.IsFull() && BTCONTENT.pBF->IsFull() ){ return -2; }
|
||||
|
||||
if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx;
|
||||
|
||||
return ( !m_state.remote_choked && request_q.IsEmpty() ) ? RequestCheck() : 0;
|
||||
|
||||
case M_REQUEST:
|
||||
if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; }
|
||||
|
||||
idx = ntohl(*(size_t*)(msgbuf + 5));
|
||||
|
||||
if( !BTCONTENT.pBF->IsSet(idx) ) return -1;
|
||||
|
||||
off = ntohl(*(size_t*)(msgbuf + 9));
|
||||
len = ntohl(*(size_t*)(msgbuf + 13));
|
||||
|
||||
if( !reponse_q.IsValidRequest(idx, off, len) ) return -1;
|
||||
|
||||
return reponse_q.Add(idx, off, len);
|
||||
|
||||
case M_PIECE:
|
||||
if( request_q.IsEmpty() || !m_state.local_interested){
|
||||
m_err_count++;
|
||||
return 0;
|
||||
}
|
||||
return PieceDeliver(r);
|
||||
|
||||
case M_BITFIELD:
|
||||
if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1;
|
||||
bitfield.SetReferBuffer(msgbuf + 5);
|
||||
if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2;
|
||||
return 0;
|
||||
|
||||
case M_CANCEL:
|
||||
if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1;
|
||||
|
||||
idx = ntohl(*(size_t*)(msgbuf + 5));
|
||||
off = ntohl(*(size_t*)(msgbuf + 9));
|
||||
len = ntohl(*(size_t*)(msgbuf + 13));
|
||||
if( reponse_q.Remove(idx,off,len) < 0 ){
|
||||
m_err_count++;
|
||||
return 0;
|
||||
}
|
||||
if( reponse_q.IsEmpty() ) StopULTimer();
|
||||
return 0;
|
||||
default:
|
||||
return -1; // unknow message type
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btPeer::ReponseSlice()
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
reponse_q.Peek((size_t*) 0,(size_t*) 0, &len);
|
||||
|
||||
if(len && stream.out_buffer.LeftSize() <= (len + 13 + 3 * 1024))
|
||||
stream.Flush();
|
||||
|
||||
if(len && stream.out_buffer.LeftSize() > (len + 13 + 3 * 1024)){
|
||||
size_t idx,off;
|
||||
reponse_q.Pop(&idx,&off,(size_t *) 0);
|
||||
|
||||
if(BTCONTENT.ReadSlice(BTCONTENT.global_piece_buffer,idx,off,len) != 0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
Self.DataSended(len);
|
||||
DataSended(len);
|
||||
return stream.Send_Piece(idx,off,BTCONTENT.global_piece_buffer,len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btPeer::SendRequest()
|
||||
{
|
||||
PSLICE ps = request_q.GetHead();
|
||||
for( ; ps ; ps = ps->next )
|
||||
if(stream.Send_Request(ps->index,ps->offset,ps->length) < 0){ return -1; }
|
||||
|
||||
return stream.Flush();
|
||||
}
|
||||
|
||||
int btPeer::CancelRequest(PSLICE ps)
|
||||
{
|
||||
for( ; ps; ps = ps->next){
|
||||
if(stream.Send_Cancel(ps->index,ps->offset,ps->length) < 0)
|
||||
return -1;
|
||||
}
|
||||
return stream.Flush();
|
||||
}
|
||||
|
||||
int btPeer::ReportComplete(size_t idx)
|
||||
{
|
||||
if( BTCONTENT.APieceComplete(idx) ){
|
||||
WORLD.Tell_World_I_Have(idx);
|
||||
if( BTCONTENT.pBF->IsFull() ){
|
||||
ResetDLTimer();
|
||||
WORLD.CloseAllConnectionToSeed();
|
||||
}
|
||||
}else
|
||||
m_err_count++;
|
||||
return (P_FAILED == m_status) ? -1 : RequestCheck();
|
||||
}
|
||||
|
||||
int btPeer::PieceDeliver(size_t mlen)
|
||||
{
|
||||
size_t idx,off,len;
|
||||
char *msgbuf = stream.in_buffer.BasePointer();
|
||||
|
||||
idx = ntohl(*(size_t*) (msgbuf + 5));
|
||||
off = ntohl(*(size_t*) (msgbuf + 9));
|
||||
len = mlen - 9;
|
||||
|
||||
if( request_q.Remove(idx,off,len) < 0 ){
|
||||
m_err_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(BTCONTENT.WriteSlice((char*)(msgbuf + 13),idx,off,len) < 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
Self.StartDLTimer();
|
||||
Self.DataRecved(len);
|
||||
DataRecved(len);
|
||||
|
||||
/* if piece download complete. */
|
||||
return request_q.IsEmpty() ? ReportComplete(idx) : 0;
|
||||
}
|
||||
|
||||
int btPeer::RequestCheck()
|
||||
{
|
||||
if( BandWidthLimit() ) return 0;
|
||||
|
||||
if( BTCONTENT.pBF->IsFull() ){
|
||||
if( bitfield.IsFull() ){ return -1; }
|
||||
return SetLocal(M_NOT_INTERESTED);
|
||||
}
|
||||
|
||||
if( Need_Remote_Data() ){
|
||||
if(!m_state.local_interested && SetLocal(M_INTERESTED) < 0) return -1;
|
||||
if(request_q.IsEmpty() && !m_state.remote_choked){
|
||||
if( RequestPiece() < 0 ) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!request_q.IsEmpty()) StartDLTimer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btPeer::CloseConnection()
|
||||
{
|
||||
if( P_FAILED != m_status ){
|
||||
m_status = P_FAILED;
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
int btPeer::HandShake()
|
||||
{
|
||||
ssize_t r = stream.Feed();
|
||||
if( r < 0 ) return -1;
|
||||
else if( r < 68 ){
|
||||
if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),r) != 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ) return -1;
|
||||
|
||||
// ignore peer id verify
|
||||
if( !BTCONTENT.pBF->IsEmpty()){
|
||||
char *bf = new char[BTCONTENT.pBF->NBytes()];
|
||||
#ifndef WINDOWS
|
||||
if(!bf) return -1;
|
||||
#endif
|
||||
BTCONTENT.pBF->WriteToBuffer(bf);
|
||||
r = stream.Send_Bitfield(bf,BTCONTENT.pBF->NBytes());
|
||||
delete []bf;
|
||||
}
|
||||
|
||||
if( r >= 0){
|
||||
if( stream.in_buffer.PickUp(68) < 0 ) return -1;
|
||||
m_status = P_SUCCESS;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int btPeer::Send_ShakeInfo()
|
||||
{
|
||||
return stream.Send_Buffer((char*)BTCONTENT.GetShakeBuffer(),68);
|
||||
}
|
||||
|
||||
int btPeer::BandWidthLimit()
|
||||
{
|
||||
if( cfg_max_bandwidth <= 0 ) return 0;
|
||||
return ((Self.RateDL() + Self.RateUL()*2) / 1024 >= cfg_max_bandwidth) ?
|
||||
1:0;
|
||||
}
|
||||
|
||||
int btPeer::NeedWrite()
|
||||
{
|
||||
int yn = 0;
|
||||
if( stream.out_buffer.Count() || // data need send in buffer.
|
||||
(!reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimit()) ||
|
||||
P_CONNECTING == m_status ) // peer is connecting
|
||||
yn = 1;
|
||||
return yn;
|
||||
}
|
||||
|
||||
int btPeer::CouldReponseSlice()
|
||||
{
|
||||
if(!m_state.local_choked &&
|
||||
(stream.out_buffer.LeftSize() > reponse_q.GetRequestLen() + 4 * 1024 ))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btPeer::AreYouOK()
|
||||
{
|
||||
m_f_keepalive = 1;
|
||||
return stream.Send_Keepalive();
|
||||
}
|
||||
|
||||
int btPeer::RecvModule()
|
||||
{
|
||||
int f_peer_closed = 0;
|
||||
ssize_t r;
|
||||
|
||||
if ( 64 < m_err_count ) return -1;
|
||||
|
||||
r = stream.Feed();
|
||||
|
||||
if( r < 0 && r != -2 )
|
||||
return -1;
|
||||
else if ( r == -2 )
|
||||
f_peer_closed = 1;
|
||||
|
||||
r = stream.HaveMessage();
|
||||
for( ; r;){
|
||||
if( r < 0 ) return -1;
|
||||
if(MsgDeliver() < 0 || stream.PickMessage() < 0) return -1;
|
||||
r = stream.HaveMessage();
|
||||
}
|
||||
return f_peer_closed ? -1 : 0;
|
||||
}
|
||||
|
||||
int btPeer::SendModule()
|
||||
{
|
||||
if( stream.out_buffer.Count() && stream.Flush() < 0) return -1;
|
||||
|
||||
if(! reponse_q.IsEmpty() && CouldReponseSlice() ) {
|
||||
StartULTimer();
|
||||
Self.StartULTimer();
|
||||
}
|
||||
|
||||
for(; !reponse_q.IsEmpty() && CouldReponseSlice(); )
|
||||
if( ReponseSlice() < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btPeer::dump()
|
||||
{
|
||||
struct sockaddr_in6 sin;
|
||||
char buforek[256];
|
||||
|
||||
GetAddress(&sin);
|
||||
|
||||
|
||||
printf("%s: %d -> %d:%d %lud:%lud\n", inet_ntop(AF_INET6, &sin.sin6_addr, buforek, sizeof(buforek) ),
|
||||
bitfield.Count(),
|
||||
Is_Remote_UnChoked() ? 1 : 0,
|
||||
request_q.IsEmpty() ? 0 : 1,
|
||||
(unsigned long)TotalDL(),
|
||||
(unsigned long)TotalUL());
|
||||
}
|
||||
|
142
peer.h
Normal file
142
peer.h
Normal file
@ -0,0 +1,142 @@
|
||||
#ifndef PEER_H
|
||||
#define PEER_H
|
||||
|
||||
#include "./def.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "btrequest.h"
|
||||
#include "btstream.h"
|
||||
#include "bitfield.h"
|
||||
#include "rate.h"
|
||||
|
||||
#define P_CONNECTING (unsigned char) 0 // connecting
|
||||
#define P_HANDSHAKE (unsigned char) 1 // handshaking
|
||||
#define P_SUCCESS (unsigned char) 2 // successful
|
||||
#define P_FAILED (unsigned char) 3 // failed
|
||||
|
||||
typedef struct _btstatus{
|
||||
unsigned char remote_choked:1;
|
||||
unsigned char remote_interested:1;
|
||||
unsigned char local_choked:1;
|
||||
unsigned char local_interested:1;
|
||||
|
||||
unsigned char reserved:4; /* unused */
|
||||
}BTSTATUS;
|
||||
|
||||
class btBasic
|
||||
{
|
||||
private:
|
||||
Rate rate_dl;
|
||||
Rate rate_ul;
|
||||
public:
|
||||
struct sockaddr_in6 m_sin;
|
||||
|
||||
//IP地址相关函数
|
||||
int IpEquiv(struct sockaddr_in6 addr);
|
||||
void SetIp(struct sockaddr_in6 addr);
|
||||
void SetAddress(struct sockaddr_in6 addr);
|
||||
void GetAddress(struct sockaddr_in6 *psin) const {
|
||||
memcpy(psin,&m_sin,sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
// 速率相关函数
|
||||
Rate GetDLRate() const { return rate_dl; }
|
||||
Rate GetULRate() const { return rate_ul; }
|
||||
|
||||
u_int64_t TotalDL() const { return rate_dl.Count(); }
|
||||
u_int64_t TotalUL() const { return rate_ul.Count(); }
|
||||
|
||||
void DataRecved(size_t nby) { rate_dl.CountAdd(nby); }
|
||||
void DataSended(size_t nby) { rate_ul.CountAdd(nby); }
|
||||
|
||||
size_t RateDL() const { return rate_dl.RateMeasure(); }
|
||||
size_t RateUL() const { return rate_ul.RateMeasure();}
|
||||
|
||||
void StartDLTimer() { rate_dl.StartTimer(); }
|
||||
void StartULTimer() { rate_ul.StartTimer(); }
|
||||
void StopDLTimer() { rate_dl.StopTimer(); }
|
||||
void StopULTimer() { rate_ul.StopTimer(); }
|
||||
void ResetDLTimer() { rate_dl.Reset(); }
|
||||
void ResetULTimer() { rate_ul.Reset(); }
|
||||
};
|
||||
|
||||
class btPeer:public btBasic
|
||||
{
|
||||
private:
|
||||
time_t m_last_timestamp, m_unchoke_timestamp;
|
||||
|
||||
unsigned char m_f_keepalive:1;
|
||||
unsigned char m_status:4;
|
||||
unsigned char m_reserved:3;
|
||||
|
||||
BTSTATUS m_state;
|
||||
|
||||
size_t m_cached_idx;
|
||||
size_t m_err_count;
|
||||
|
||||
int PieceDeliver(size_t mlen);
|
||||
int ReportComplete(size_t idx);
|
||||
int RequestCheck();
|
||||
int SendRequest();
|
||||
int CancelRequest(PSLICE ps);
|
||||
int ReponseSlice();
|
||||
int RequestPiece();
|
||||
int MsgDeliver();
|
||||
int CouldReponseSlice();
|
||||
|
||||
int BandWidthLimit();
|
||||
public:
|
||||
BitField bitfield;
|
||||
btStream stream;
|
||||
RequestQueue request_q;
|
||||
RequestQueue reponse_q;
|
||||
|
||||
btPeer();
|
||||
|
||||
int RecvModule();
|
||||
int SendModule();
|
||||
|
||||
time_t SetLastTimestamp() { return time(&m_last_timestamp); }
|
||||
time_t GetLastTimestamp() const { return m_last_timestamp; }
|
||||
time_t SetLastUnchokeTime() { return time(&m_unchoke_timestamp); }
|
||||
time_t GetLastUnchokeTime() const { return m_unchoke_timestamp; }
|
||||
|
||||
int Is_Remote_Interested() const { return m_state.remote_interested ? 1 : 0; }
|
||||
int Is_Remote_UnChoked() const { return m_state.remote_choked ? 0 : 1; }
|
||||
int Is_Local_Interested() const { return m_state.local_interested ? 1 : 0;}
|
||||
int Is_Local_UnChoked() const { return m_state.local_choked ? 0 : 1; }
|
||||
int SetLocal(unsigned char s);
|
||||
|
||||
|
||||
void SetStatus(unsigned char s){ m_status = s; }
|
||||
unsigned char GetStatus() const { return m_status; }
|
||||
int NeedWrite();
|
||||
|
||||
|
||||
void CloseConnection();
|
||||
|
||||
|
||||
int AreYouOK();
|
||||
int Send_ShakeInfo();
|
||||
int HandShake();
|
||||
|
||||
int Need_Remote_Data();
|
||||
int Need_Local_Data();
|
||||
|
||||
void dump();
|
||||
};
|
||||
|
||||
extern btBasic Self;
|
||||
|
||||
#endif
|
573
peerlist.cpp
Normal file
573
peerlist.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "peerlist.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "btconfig.h"
|
||||
#include "connect_nonb.h"
|
||||
#include "setnonblock.h"
|
||||
#include "btcontent.h"
|
||||
#include "msgencode.h"
|
||||
|
||||
#include "iplist.h"
|
||||
#include "tracker.h"
|
||||
|
||||
|
||||
#define MAX_UNCHOKE 3
|
||||
#define UNCHOKE_INTERVAL 10
|
||||
|
||||
#define KEEPALIVE_INTERVAL 117
|
||||
|
||||
#define LISTEN_PORT_MAX 2706
|
||||
#define LISTEN_PORT_MIN 2106
|
||||
|
||||
#define PEER_IS_SUCCESS(peer) (P_SUCCESS == (peer)->GetStatus())
|
||||
#define PEER_IS_FAILED(peer) (P_FAILED == (peer)->GetStatus())
|
||||
#define NEED_MORE_PEERS() (m_peers_count < cfg_max_peers)
|
||||
|
||||
const char LIVE_CHAR[4] = {'-', '\\','|','/'};
|
||||
|
||||
PeerList WORLD;
|
||||
|
||||
PeerList::PeerList()
|
||||
{
|
||||
m_unchoke_check_timestamp =
|
||||
m_keepalive_check_timestamp = time((time_t*) 0);
|
||||
|
||||
m_head = (PEERNODE*) 0;
|
||||
m_listen_sock = INVALID_SOCKET;
|
||||
m_peers_count = 0;
|
||||
m_live_idx = 0;
|
||||
}
|
||||
|
||||
PeerList::~PeerList()
|
||||
{
|
||||
PEERNODE *p,*pnext;
|
||||
for(p = m_head; p ; ){
|
||||
pnext = p->next;
|
||||
delete p->peer;
|
||||
delete p;
|
||||
p = pnext;
|
||||
}
|
||||
}
|
||||
|
||||
int PeerList::IsEmpty() const
|
||||
{
|
||||
return m_peers_count ? 0 : 1;
|
||||
}
|
||||
|
||||
void PeerList::Sort()
|
||||
{
|
||||
PEERNODE *newhead = (PEERNODE*) 0;
|
||||
PEERNODE *p, *pp, *spn;
|
||||
|
||||
if( m_peers_count < 10 ) return;
|
||||
|
||||
for(; m_head;){
|
||||
pp = (PEERNODE*) 0;
|
||||
for(p = newhead; p && m_head->click < p->click; pp = p, p = p->next) ;
|
||||
|
||||
spn = m_head->next;
|
||||
m_head->next = p;
|
||||
if( pp ) pp->next = m_head; else newhead = m_head;
|
||||
m_head = spn;
|
||||
}
|
||||
m_head = newhead;
|
||||
}
|
||||
|
||||
void PeerList::CloseAll()
|
||||
{
|
||||
PEERNODE *p;
|
||||
for(p = m_head; p;){
|
||||
m_head = p->next;
|
||||
delete (p->peer);
|
||||
delete p;
|
||||
p = m_head;
|
||||
}
|
||||
}
|
||||
|
||||
int PeerList::NewPeer(struct sockaddr_in6 addr, SOCKET sk)
|
||||
{
|
||||
PEERNODE *p;
|
||||
btPeer *peer = (btPeer*) 0;
|
||||
int r;
|
||||
|
||||
if( m_peers_count >= cfg_max_peers ){
|
||||
if( INVALID_SOCKET != sk ) CLOSE_SOCKET(sk);
|
||||
return -4;
|
||||
}
|
||||
|
||||
if( Self.IpEquiv(addr) ){
|
||||
if(INVALID_SOCKET != sk) CLOSE_SOCKET(sk); return -3;} // myself
|
||||
|
||||
for(p = m_head; p; p = p->next){
|
||||
if(PEER_IS_FAILED(p->peer)) continue;
|
||||
if( p->peer->IpEquiv(addr)){ // already exist.
|
||||
if( INVALID_SOCKET != sk) CLOSE_SOCKET(sk);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
if( INVALID_SOCKET == sk ){
|
||||
if( INVALID_SOCKET == (sk = socket(PF_INET6,SOCK_STREAM,0)) ) return -1;
|
||||
|
||||
if( setfd_nonblock(sk) < 0) goto err;
|
||||
|
||||
if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1;
|
||||
|
||||
peer = new btPeer;
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !peer ) goto err;
|
||||
#endif
|
||||
|
||||
peer->SetAddress(addr);
|
||||
peer->stream.SetSocket(sk);
|
||||
peer->SetStatus( (-2 == r) ? P_CONNECTING : P_HANDSHAKE );
|
||||
|
||||
}else{
|
||||
if( setfd_nonblock(sk) < 0) goto err;
|
||||
|
||||
peer = new btPeer;
|
||||
|
||||
#ifndef WINDOWS
|
||||
if( !peer ) goto err;
|
||||
#endif
|
||||
|
||||
peer->SetAddress(addr);
|
||||
peer->stream.SetSocket(sk);
|
||||
peer->SetStatus(P_HANDSHAKE);
|
||||
}
|
||||
|
||||
if( P_HANDSHAKE == peer->GetStatus() )
|
||||
if( peer->Send_ShakeInfo() != 0 ) { delete peer; return -1; }
|
||||
|
||||
p = new PEERNODE;
|
||||
#ifndef WINDOWS
|
||||
if( !p ){ delete peer; return -1;}
|
||||
#endif
|
||||
m_peers_count++;
|
||||
|
||||
p->peer = peer;
|
||||
p->click = 0;
|
||||
|
||||
p->next = m_head;
|
||||
m_head = p;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
CLOSE_SOCKET(sk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PeerList::FillFDSET(const time_t *pnow,fd_set *rfdp,fd_set *wfdp)
|
||||
{
|
||||
PEERNODE *p;
|
||||
PEERNODE *pp = (PEERNODE*) 0;
|
||||
int f_keepalive_check = 0;
|
||||
int f_unchoke_check = 0;
|
||||
int maxfd = -1;
|
||||
int i = 0;
|
||||
SOCKET sk = INVALID_SOCKET;
|
||||
struct sockaddr_in6 addr;
|
||||
btPeer * UNCHOKER[MAX_UNCHOKE + 1];
|
||||
|
||||
for( ;NEED_MORE_PEERS() && !IPQUEUE.IsEmpty(); ){
|
||||
if(IPQUEUE.Pop(&addr) < 0) break;
|
||||
if(NewPeer(addr,INVALID_SOCKET) == -4) break;
|
||||
}
|
||||
|
||||
// show status line.
|
||||
if( m_pre_dlrate.TimeUsed(pnow) ){
|
||||
printf("\r ");
|
||||
printf("\r%c %u,[%u/%u/%u],%u,%u | %u,%u E:%u",
|
||||
LIVE_CHAR[m_live_idx],
|
||||
m_peers_count,
|
||||
BTCONTENT.pBF->Count(),
|
||||
BTCONTENT.pBF->NBits(),
|
||||
Pieces_I_Can_Get(),
|
||||
Self.RateDL(), Self.RateUL(),
|
||||
m_pre_dlrate.RateMeasure(Self.GetDLRate()),
|
||||
m_pre_ulrate.RateMeasure(Self.GetULRate()),
|
||||
Tracker.GetRefuseClick());
|
||||
fflush(stdout);
|
||||
m_pre_dlrate = Self.GetDLRate();
|
||||
m_pre_ulrate = Self.GetULRate();
|
||||
m_live_idx++;
|
||||
}
|
||||
|
||||
if(KEEPALIVE_INTERVAL <= (*pnow - m_keepalive_check_timestamp)){
|
||||
m_keepalive_check_timestamp = *pnow;
|
||||
f_keepalive_check = 1;
|
||||
}
|
||||
|
||||
if(UNCHOKE_INTERVAL <= (*pnow - m_unchoke_check_timestamp)){
|
||||
|
||||
m_unchoke_check_timestamp = *pnow;
|
||||
f_unchoke_check = 1;
|
||||
|
||||
Sort();
|
||||
}
|
||||
|
||||
if( f_unchoke_check ) memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
|
||||
|
||||
for(p = m_head; p;){
|
||||
if( PEER_IS_FAILED(p->peer)){
|
||||
if( pp ) pp->next = p->next; else m_head = p->next;
|
||||
delete p->peer;
|
||||
delete p;
|
||||
m_peers_count--;
|
||||
if( pp ) p = pp->next; else p = m_head;
|
||||
continue;
|
||||
}else{
|
||||
if( f_keepalive_check ){
|
||||
|
||||
if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){
|
||||
p->peer->CloseConnection();
|
||||
goto skip_continue;
|
||||
}
|
||||
|
||||
if(PEER_IS_SUCCESS(p->peer) &&
|
||||
KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) &&
|
||||
p->peer->AreYouOK() < 0){
|
||||
p->peer->CloseConnection();
|
||||
goto skip_continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( f_unchoke_check ){
|
||||
|
||||
if(PEER_IS_SUCCESS(p->peer) && p->peer->Need_Local_Data()){
|
||||
|
||||
if((time_t) 0 == p->peer->GetLastUnchokeTime()){
|
||||
if(p->peer->SetLocal(M_UNCHOKE) < 0){
|
||||
p->peer->CloseConnection();
|
||||
goto skip_continue;
|
||||
}
|
||||
}else
|
||||
UnChokeCheck(p->peer, UNCHOKER);
|
||||
}
|
||||
}
|
||||
|
||||
sk = p->peer->stream.GetSocket();
|
||||
if(maxfd < sk) maxfd = sk;
|
||||
FD_SET(sk,rfdp);
|
||||
|
||||
if( p->peer->NeedWrite() ) FD_SET(sk,wfdp);
|
||||
skip_continue:
|
||||
pp = p;
|
||||
p = p->next;
|
||||
}
|
||||
} // end for
|
||||
|
||||
|
||||
if( INVALID_SOCKET != m_listen_sock && m_peers_count < cfg_max_peers){
|
||||
FD_SET(m_listen_sock, rfdp);
|
||||
if( maxfd < m_listen_sock ) maxfd = m_listen_sock;
|
||||
}
|
||||
|
||||
if( f_unchoke_check ){
|
||||
for( i = 0; i < MAX_UNCHOKE + 1; i++){
|
||||
|
||||
if( (btPeer*) 0 == UNCHOKER[i]) break;
|
||||
|
||||
if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;
|
||||
|
||||
if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){
|
||||
UNCHOKER[i]->CloseConnection();
|
||||
continue;
|
||||
}
|
||||
|
||||
sk = UNCHOKER[i]->stream.GetSocket();
|
||||
|
||||
if(!FD_ISSET(sk,wfdp) && UNCHOKER[i]->NeedWrite()){
|
||||
FD_SET(sk,wfdp);
|
||||
if( maxfd < sk) maxfd = sk;
|
||||
}
|
||||
} // end for
|
||||
}
|
||||
|
||||
return maxfd;
|
||||
}
|
||||
|
||||
btPeer* PeerList::Who_Can_Abandon(btPeer *proposer)
|
||||
{
|
||||
PEERNODE *p;
|
||||
btPeer *peer = (btPeer*) 0;
|
||||
for(p = m_head; p; p = p->next){
|
||||
if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer ||
|
||||
p->peer->request_q.IsEmpty() ) continue;
|
||||
|
||||
if(proposer->bitfield.IsSet(p->peer->request_q.GetRequestIdx())){
|
||||
if(!peer){
|
||||
if( p->peer->RateDL() < proposer->RateDL() ) peer = p->peer;
|
||||
}else{
|
||||
if( p->peer->RateDL() < peer->RateDL() ) peer = p->peer;
|
||||
}
|
||||
}
|
||||
}//end for
|
||||
return peer;
|
||||
}
|
||||
|
||||
void PeerList::Tell_World_I_Have(size_t idx)
|
||||
{
|
||||
PEERNODE *p;
|
||||
int f_seed = 0;
|
||||
|
||||
if ( BTCONTENT.pBF->IsFull() ) f_seed = 1;
|
||||
|
||||
for( p = m_head; p; p = p->next){
|
||||
|
||||
if( !PEER_IS_SUCCESS(p->peer) ) continue;
|
||||
|
||||
if( p->peer->stream.Send_Have(idx) < 0)
|
||||
p->peer->CloseConnection();
|
||||
|
||||
if( f_seed ){
|
||||
if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty();
|
||||
if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection();
|
||||
}
|
||||
|
||||
} // end for
|
||||
}
|
||||
|
||||
int PeerList::Accepter()
|
||||
{
|
||||
SOCKET newsk;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_in6 addr;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
newsk = accept(m_listen_sock,(struct sockaddr*) &addr,&addrlen);
|
||||
|
||||
if( INVALID_SOCKET == newsk ) return -1;
|
||||
|
||||
if( AF_INET6 != addr.sin6_family || addrlen != sizeof(struct sockaddr_in6)) {
|
||||
CLOSE_SOCKET(newsk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return NewPeer(addr,newsk);
|
||||
}
|
||||
|
||||
int PeerList::Initial_ListenPort()
|
||||
{
|
||||
int r = 0;
|
||||
struct sockaddr_in6 lis_addr;
|
||||
memset(&lis_addr,0, sizeof(sockaddr_in6));
|
||||
memcpy(&lis_addr.sin6_addr, &in6addr_any, sizeof(struct in6_addr) );
|
||||
|
||||
m_listen_sock = socket(PF_INET6,SOCK_STREAM,0);
|
||||
|
||||
if( INVALID_SOCKET == m_listen_sock ) return -1;
|
||||
|
||||
if(cfg_listen_port && cfg_listen_port != LISTEN_PORT_MAX){
|
||||
lis_addr.sin6_port = htons(cfg_listen_port);
|
||||
if(bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in6)) == 0)
|
||||
r = 1;
|
||||
else
|
||||
fprintf(stderr,"warn,couldn't bind on specified port: %d\n",cfg_listen_port);
|
||||
}
|
||||
|
||||
if( !r ){
|
||||
r = -1;
|
||||
cfg_listen_port = cfg_max_listen_port;
|
||||
for( ; r != 0; ){
|
||||
lis_addr.sin6_port = htons(cfg_listen_port);
|
||||
r = bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in6));
|
||||
if(r != 0){
|
||||
cfg_listen_port--;
|
||||
if(cfg_listen_port < cfg_min_listen_port){
|
||||
CLOSE_SOCKET(m_listen_sock);
|
||||
fprintf(stderr,"error,couldn't bind port from %d to %d.\n",
|
||||
cfg_min_listen_port,cfg_max_listen_port);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} /* end for(; r != 0;) */
|
||||
}
|
||||
|
||||
if(listen(m_listen_sock,5) == -1){
|
||||
CLOSE_SOCKET(m_listen_sock);
|
||||
fprintf(stderr,"error, couldn't listen on port %d.\n",cfg_listen_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( setfd_nonblock(m_listen_sock) < 0){
|
||||
CLOSE_SOCKET(m_listen_sock);
|
||||
fprintf(stderr,"error, couldn't set socket to nonblock mode.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t PeerList::Pieces_I_Can_Get()
|
||||
{
|
||||
PEERNODE *p;
|
||||
BitField tmpBitField = *BTCONTENT.pBF;
|
||||
|
||||
if( tmpBitField.IsFull() ) return BTCONTENT.GetNPieces();
|
||||
|
||||
for( p = m_head; p && !tmpBitField.IsFull(); p = p->next){
|
||||
if( !PEER_IS_SUCCESS(p->peer) ) continue;
|
||||
tmpBitField.Comb(p->peer->bitfield);
|
||||
}
|
||||
return tmpBitField.Count();
|
||||
}
|
||||
|
||||
int PeerList::AlreadyRequested(size_t idx)
|
||||
{
|
||||
PEERNODE *p;
|
||||
for(p = m_head; p; p = p->next){
|
||||
if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty()) continue;
|
||||
if( idx == p->peer->request_q.GetRequestIdx() ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PeerList::CheckBitField(BitField &bf)
|
||||
{
|
||||
PEERNODE *p;
|
||||
for(p = m_head; p ; p = p->next){
|
||||
if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty()) continue;
|
||||
bf.UnSet(p->peer->request_q.GetRequestIdx());
|
||||
}
|
||||
}
|
||||
|
||||
void PeerList::PrintOut()
|
||||
{
|
||||
PEERNODE *p = m_head;
|
||||
struct sockaddr_in6 sin;
|
||||
printf("\nPEER LIST\n");
|
||||
for( ; p ; p = p->next){
|
||||
if(PEER_IS_FAILED(p->peer)) continue;
|
||||
p->peer->dump();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerList::AnyPeerReady(fd_set *rfdp, fd_set *wfdp, int *nready)
|
||||
{
|
||||
PEERNODE *p,*p2;
|
||||
btPeer *peer;
|
||||
SOCKET sk;
|
||||
|
||||
if( FD_ISSET(m_listen_sock, rfdp)){
|
||||
FD_CLR(m_listen_sock,rfdp);
|
||||
(*nready)--;
|
||||
Accepter();
|
||||
}
|
||||
|
||||
for(p = m_head; p && *nready ; p = p->next){
|
||||
if( PEER_IS_FAILED(p->peer) ) continue;
|
||||
|
||||
peer = p->peer;
|
||||
sk = peer->stream.GetSocket();
|
||||
|
||||
if( P_CONNECTING == peer->GetStatus()){
|
||||
if(FD_ISSET(sk,wfdp)){
|
||||
(*nready)--;
|
||||
FD_CLR(sk,wfdp);
|
||||
|
||||
if(FD_ISSET(sk,rfdp)){ // connect failed.
|
||||
FD_CLR(sk,rfdp);
|
||||
peer->CloseConnection();
|
||||
}else{
|
||||
if(peer->Send_ShakeInfo() < 0){
|
||||
peer->CloseConnection();
|
||||
}
|
||||
else
|
||||
peer->SetStatus(P_HANDSHAKE);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(FD_ISSET(sk,rfdp)){
|
||||
p->click++;
|
||||
if( !(p->click) )
|
||||
for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
|
||||
|
||||
(*nready)--;
|
||||
FD_CLR(sk,rfdp);
|
||||
if(peer->GetStatus() == P_HANDSHAKE){
|
||||
if( peer->HandShake() < 0 ) peer->CloseConnection();
|
||||
}else{
|
||||
if( peer->RecvModule() < 0 ) peer->CloseConnection();
|
||||
}
|
||||
}else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
|
||||
p->click++;
|
||||
if( !(p->click) )
|
||||
for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
|
||||
|
||||
(*nready)--;
|
||||
FD_CLR(sk,wfdp);
|
||||
if( peer->SendModule() < 0 ) peer->CloseConnection();
|
||||
}
|
||||
}
|
||||
}// end for
|
||||
}
|
||||
|
||||
void PeerList::CloseAllConnectionToSeed()
|
||||
{
|
||||
PEERNODE *p = m_head;
|
||||
for( ; p; p = p->next)
|
||||
if(p->peer->bitfield.IsFull()) p->peer->CloseConnection();
|
||||
}
|
||||
|
||||
void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[])
|
||||
{
|
||||
int i = 0;
|
||||
int cancel_idx = 0;
|
||||
btPeer *loster = (btPeer*) 0;
|
||||
int f_seed = BTCONTENT.pBF->IsFull();
|
||||
|
||||
for( cancel_idx = i = 0; i < MAX_UNCHOKE; i++ ){
|
||||
if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){ // ÓпÕλ
|
||||
cancel_idx = i;
|
||||
break;
|
||||
}else{
|
||||
if(cancel_idx == i) continue;
|
||||
|
||||
if(f_seed){
|
||||
// compare upload rate.
|
||||
if(peer_array[cancel_idx]->RateUL() > peer_array[i]->RateUL())
|
||||
cancel_idx = i;
|
||||
}else{
|
||||
// compare download rate.
|
||||
if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL())
|
||||
cancel_idx = i;
|
||||
}
|
||||
}
|
||||
} // end for
|
||||
|
||||
if( (btPeer*) 0 != peer_array[cancel_idx] && PEER_IS_SUCCESS(peer_array[cancel_idx]) ){
|
||||
if(f_seed){
|
||||
if(peer->RateUL() > peer_array[cancel_idx]->RateUL()){
|
||||
loster = peer_array[cancel_idx];
|
||||
peer_array[cancel_idx] = peer;
|
||||
}else
|
||||
loster = peer;
|
||||
}else{
|
||||
if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){
|
||||
loster = peer_array[cancel_idx];
|
||||
peer_array[cancel_idx] = peer;
|
||||
}else
|
||||
loster = peer;
|
||||
}
|
||||
|
||||
// opt unchoke
|
||||
if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) )
|
||||
peer_array[MAX_UNCHOKE] = loster;
|
||||
else{
|
||||
if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime())
|
||||
peer_array[MAX_UNCHOKE] = loster;
|
||||
else{
|
||||
if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
|
||||
}
|
||||
}
|
||||
}else //else if((btPeer*) 0 != peer_array[cancel_idx].....
|
||||
peer_array[cancel_idx] = peer;
|
||||
}
|
60
peerlist.h
Normal file
60
peerlist.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef PEERLIST_H
|
||||
#define PEERLIST_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "./def.h"
|
||||
#include "./peer.h"
|
||||
#include "./rate.h"
|
||||
|
||||
typedef struct _peernode{
|
||||
btPeer *peer;
|
||||
size_t click;
|
||||
struct _peernode *next;
|
||||
}PEERNODE;
|
||||
|
||||
class PeerList
|
||||
{
|
||||
private:
|
||||
SOCKET m_listen_sock;
|
||||
PEERNODE *m_head;
|
||||
size_t m_peers_count;
|
||||
time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp;
|
||||
|
||||
unsigned char m_live_idx:2;
|
||||
unsigned char m_reserved:6;
|
||||
|
||||
Rate m_pre_dlrate, m_pre_ulrate;
|
||||
|
||||
int Accepter();
|
||||
void Sort();
|
||||
void UnChokeCheck(btPeer* peer,btPeer *peer_array[]);
|
||||
|
||||
public:
|
||||
PeerList();
|
||||
~PeerList();
|
||||
|
||||
size_t TotalPeers() const { return m_peers_count; }
|
||||
int Initial_ListenPort();
|
||||
|
||||
int IsEmpty() const;
|
||||
|
||||
void PrintOut();
|
||||
|
||||
int NewPeer(struct sockaddr_in6 addr, SOCKET sk);
|
||||
|
||||
void CloseAllConnectionToSeed();
|
||||
void CloseAll();
|
||||
|
||||
int FillFDSET(const time_t *pnow, fd_set *rfd, fd_set *wfd);
|
||||
void AnyPeerReady(fd_set *rfdp,fd_set *wfdp,int *nready);
|
||||
|
||||
void Tell_World_I_Have(size_t idx);
|
||||
btPeer* Who_Can_Abandon(btPeer *proposer);
|
||||
void CheckBitField(BitField &bf);
|
||||
int AlreadyRequested(size_t idx);
|
||||
size_t Pieces_I_Can_Get();
|
||||
};
|
||||
|
||||
extern PeerList WORLD;
|
||||
|
||||
#endif
|
45
rate.cpp
Normal file
45
rate.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "rate.h"
|
||||
|
||||
void Rate::StartTimer()
|
||||
{
|
||||
if( !m_last_timestamp ) time(&m_last_timestamp);
|
||||
}
|
||||
|
||||
void Rate::StopTimer()
|
||||
{
|
||||
if( !m_last_timestamp ){
|
||||
m_total_timeused += (time((time_t*) 0) - m_last_timestamp);
|
||||
m_last_timestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Rate::CountAdd(size_t nbytes)
|
||||
{
|
||||
m_count_bytes += nbytes;
|
||||
}
|
||||
|
||||
void Rate::operator=(const Rate &ra)
|
||||
{
|
||||
m_last_timestamp = time((time_t*) 0);
|
||||
m_count_bytes = ra.m_count_bytes;
|
||||
}
|
||||
|
||||
size_t Rate::RateMeasure() const
|
||||
{
|
||||
time_t timeused = m_total_timeused;
|
||||
if( m_last_timestamp ) timeused += (time((time_t*) 0) - m_last_timestamp);
|
||||
if( timeused < 1 ) timeused = 1;
|
||||
return (size_t)(m_count_bytes / timeused);
|
||||
}
|
||||
|
||||
size_t Rate::RateMeasure(const Rate &ra_to) const
|
||||
{
|
||||
time_t timeused = time((time_t*) 0) - m_last_timestamp;
|
||||
if( timeused < 1 ) timeused = 1;
|
||||
return (size_t)((ra_to.m_count_bytes - m_count_bytes) / timeused);
|
||||
}
|
||||
|
||||
time_t Rate::TimeUsed(const time_t *pnow) const
|
||||
{
|
||||
return (*pnow - m_last_timestamp);
|
||||
}
|
26
rate.h
Normal file
26
rate.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef RATE_H
|
||||
#define RATE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include "def.h"
|
||||
|
||||
class Rate{
|
||||
private:
|
||||
time_t m_last_timestamp;
|
||||
time_t m_total_timeused;
|
||||
u_int64_t m_count_bytes;
|
||||
public:
|
||||
Rate(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0; }
|
||||
void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0;}
|
||||
void StartTimer();
|
||||
void StopTimer();
|
||||
void CountAdd(size_t nbytes);
|
||||
void operator=(const Rate &ra);
|
||||
u_int64_t Count() const { return m_count_bytes; }
|
||||
size_t RateMeasure() const;
|
||||
size_t RateMeasure(const Rate &ra) const;
|
||||
time_t TimeUsed(const time_t *pnow) const;
|
||||
};
|
||||
|
||||
#endif
|
25
setnonblock.cpp
Normal file
25
setnonblock.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "./setnonblock.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
int setfd_nonblock(SOCKET socket)
|
||||
{
|
||||
unsigned long val = 1;
|
||||
return ioctl(socket,FIONBIO,&val);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int setfd_nonblock(SOCKET socket)
|
||||
{
|
||||
int f_old;
|
||||
f_old = fcntl(socket,F_GETFL,0);
|
||||
if( f_old < 0 ) return -1;
|
||||
f_old |= O_NONBLOCK;
|
||||
return (fcntl(socket,F_SETFL,f_old));
|
||||
}
|
||||
|
||||
#endif
|
15
setnonblock.h
Normal file
15
setnonblock.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef SETNONBLOCK_H
|
||||
#define SETNONBLOCK_H
|
||||
|
||||
#include "./def.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
int setfd_nonblock(SOCKET socket);
|
||||
|
||||
#endif
|
21
sigint.cpp
Normal file
21
sigint.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef WINDOWS
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "btcontent.h"
|
||||
#include "peerlist.h"
|
||||
#include "btconfig.h"
|
||||
|
||||
void sigint_catch(int sig_no)
|
||||
{
|
||||
if(SIGINT == sig_no){
|
||||
if( cfg_cache_size ) BTCONTENT.FlushCache();
|
||||
if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
|
||||
WORLD.CloseAll();
|
||||
signal(SIGINT,SIG_DFL);
|
||||
raise(SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
8
sigint.h
Normal file
8
sigint.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef SIGINT_H
|
||||
#define SIGINT_H
|
||||
|
||||
#ifndef WINDOWS
|
||||
void sigint_catch(int sig_no);
|
||||
#endif
|
||||
|
||||
#endif
|
1
stamp-h.in
Normal file
1
stamp-h.in
Normal file
@ -0,0 +1 @@
|
||||
timestamp
|
434
tracker.cpp
Normal file
434
tracker.cpp
Normal file
@ -0,0 +1,434 @@
|
||||
#include "tracker.h"
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "peerlist.h"
|
||||
#include "httpencode.h"
|
||||
#include "bencode.h"
|
||||
#include "setnonblock.h"
|
||||
#include "connect_nonb.h"
|
||||
#include "btcontent.h"
|
||||
#include "iplist.h"
|
||||
|
||||
#include "btconfig.h"
|
||||
|
||||
btTracker Tracker;
|
||||
|
||||
btTracker::btTracker()
|
||||
{
|
||||
memset(m_host,0,MAXHOSTNAMELEN);
|
||||
memset(m_path,0,MAXPATHLEN);
|
||||
|
||||
m_sock = INVALID_SOCKET;
|
||||
m_port = 80;
|
||||
m_status = T_FREE;
|
||||
m_f_started = m_f_stoped = m_f_pause = 0;
|
||||
m_interval = 15;
|
||||
|
||||
m_connect_refuse_click = 0;
|
||||
m_last_timestamp = (time_t) 0;
|
||||
}
|
||||
|
||||
btTracker::~btTracker()
|
||||
{
|
||||
if( m_sock != INVALID_SOCKET) CLOSE_SOCKET(m_sock);
|
||||
}
|
||||
|
||||
void btTracker::Reset(time_t new_interval)
|
||||
{
|
||||
if(new_interval) m_interval = new_interval;
|
||||
|
||||
if( INVALID_SOCKET != m_sock ){
|
||||
CLOSE_SOCKET(m_sock);
|
||||
m_sock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
m_reponse_buffer.Reset();
|
||||
time(&m_last_timestamp);
|
||||
m_status = T_FREE;
|
||||
}
|
||||
|
||||
int btTracker:: _IPsin(char *h, int p, struct sockaddr_in6 *psin)
|
||||
{
|
||||
psin->sin6_family = AF_INET6;
|
||||
psin->sin6_port = htons(p);
|
||||
return (inet_pton(AF_INET6, h, &psin->sin6_addr ) != 1) ? -1 : 0;
|
||||
}
|
||||
|
||||
int btTracker:: _s2sin(char *h,int p,struct sockaddr_in6 *psin)
|
||||
{
|
||||
psin->sin6_family = AF_INET6;
|
||||
psin->sin6_port = htons(p);
|
||||
if( h ){
|
||||
if( inet_pton(AF_INET6, h, &psin->sin6_addr ) != 1 ){
|
||||
struct hostent *ph = gethostbyname2(h,AF_INET6);
|
||||
if( !ph || ph->h_addrtype != AF_INET6){
|
||||
memset(psin,0,sizeof(struct sockaddr_in6));
|
||||
return -1;
|
||||
}
|
||||
memcpy(&psin->sin6_addr,ph->h_addr_list[0],sizeof(struct in6_addr));
|
||||
}
|
||||
}else
|
||||
memcpy(&psin->sin6_addr, &in6addr_any, sizeof(struct in6_addr) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// do modyfikacji (lista perow inaczej przesy³ana)
|
||||
int btTracker::_UpdatePeerList(char *buf,size_t bufsiz)
|
||||
{
|
||||
char tmphost[MAXHOSTNAMELEN];
|
||||
const char *ps;
|
||||
size_t i,pos,tmpport;
|
||||
size_t cnt = 0;
|
||||
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
if( decode_query(buf,bufsiz,"failure reason",&ps,&i,QUERY_STR) ){
|
||||
char failreason[1024];
|
||||
if( i < 1024 ){
|
||||
memcpy(failreason, ps, i);
|
||||
failreason[i] = '\0';
|
||||
}else{
|
||||
memcpy(failreason, ps, 1000);
|
||||
failreason[1000] = '\0';
|
||||
strcat(failreason,"...");
|
||||
}
|
||||
fprintf(stderr,"TRACKER FAILURE REASON: %s\n",failreason);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!decode_query(buf,bufsiz,"interval",(const char**) 0,&i,QUERY_INT)){return -1;}
|
||||
|
||||
if(m_interval != (time_t)i) m_interval = (time_t)i;
|
||||
|
||||
pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
|
||||
|
||||
if( !pos ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(4 > bufsiz - pos){return -1; } // peers list ̫С
|
||||
|
||||
buf += (pos + 1); bufsiz -= (pos + 1);
|
||||
|
||||
ps = buf-1; // bankowo do modyfikacji, sprawdzic dane od trakera, lista perrów !! z ipv4 do ipv6
|
||||
if (*ps != 'l') { // binary peers section if not 'l'
|
||||
addr.sin6_family = AF_INET6;
|
||||
i = 0;
|
||||
while (*ps != ':' ) i = i * 10 + (*ps++ - '0'); // konwersja liszby string na inta=a
|
||||
i /= 18; // z 6 zmieniono na 18, ipv6 adres to jest 16bajtow + 2 bajty na port // ile adresów ip w binarce
|
||||
ps++;
|
||||
while (i-- > 0) {
|
||||
// if peer is not us
|
||||
if(memcmp(&Self.m_sin.sin6_addr,ps,sizeof(struct in6_addr))) {
|
||||
memcpy(&addr.sin6_addr,ps,sizeof(struct in6_addr));
|
||||
memcpy(&addr.sin6_port,ps+sizeof(struct in6_addr),sizeof(unsigned short));
|
||||
cnt++;
|
||||
IPQUEUE.Add(&addr);
|
||||
}
|
||||
ps += 18;
|
||||
}
|
||||
}
|
||||
else
|
||||
for( ;bufsiz && *buf!='e'; buf += pos, bufsiz -= pos ){
|
||||
pos = decode_dict(buf,bufsiz,(char*) 0);
|
||||
if(!pos) break;
|
||||
if(!decode_query(buf,pos,"ip",&ps,&i,QUERY_STR) || MAXHOSTNAMELEN < i) continue;
|
||||
memcpy(tmphost,ps,i); tmphost[i] = '\0';
|
||||
|
||||
if(!decode_query(buf,pos,"port",(const char**) 0,&tmpport,QUERY_INT)) continue;
|
||||
|
||||
if(!decode_query(buf,pos,"peer id",&ps,&i,QUERY_STR) && i != 20 ) continue;
|
||||
|
||||
if(_IPsin(tmphost,tmpport,&addr) < 0){
|
||||
fprintf(stderr,"warn, detected invalid ip address %s.\n",tmphost);
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !Self.IpEquiv(addr) ){
|
||||
cnt++;
|
||||
IPQUEUE.Add(&addr);
|
||||
}
|
||||
}
|
||||
|
||||
if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btTracker::CheckReponse()
|
||||
{
|
||||
#define MAX_LINE_SIZ 32
|
||||
char *pdata;
|
||||
ssize_t r;
|
||||
size_t q, hlen, dlen;
|
||||
|
||||
r = m_reponse_buffer.FeedIn(m_sock);
|
||||
|
||||
if( r > 0 ) return 0;
|
||||
|
||||
q = m_reponse_buffer.Count();
|
||||
|
||||
Reset( (-1 == r) ? 15 : 0 );
|
||||
|
||||
if( !q ){
|
||||
int error = 0;
|
||||
socklen_t n = sizeof(error);
|
||||
if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
|
||||
error != 0 ){
|
||||
fprintf(stderr,"warn, received nothing from tracker! %s\n",strerror(error));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
hlen = Http_split(m_reponse_buffer.BasePointer(), q, &pdata,&dlen);
|
||||
|
||||
if( !hlen ){
|
||||
fprintf(stderr,"warn, tracker reponse invalid. No html header found.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = Http_reponse_code(m_reponse_buffer.BasePointer(),hlen);
|
||||
if ( r != 200 ){
|
||||
if( r == 301 || r == 302 ){
|
||||
char redirect[MAXPATHLEN],ih_buf[20 * 3 + 1],pi_buf[20 * 3 + 1],tmppath[MAXPATHLEN];
|
||||
if( Http_get_header(m_reponse_buffer.BasePointer(), hlen, "Location", redirect) < 0 )
|
||||
return -1;
|
||||
|
||||
if( Http_url_analyse(redirect,m_host,&m_port,m_path) < 0){
|
||||
fprintf(stderr,"warn, tracker redirect to an invalid url %s!\n", redirect);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(tmppath,m_path);
|
||||
|
||||
if(MAXPATHLEN < snprintf(m_path,MAXPATHLEN,REQ_URL_P1_FMT,
|
||||
tmppath,
|
||||
Http_url_encode(ih_buf, (char*)BTCONTENT.GetInfoHash(), 20),
|
||||
Http_url_encode(pi_buf, (char*)BTCONTENT.GetPeerId(), 20),
|
||||
cfg_listen_port)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Connect();
|
||||
}else if( r >= 400 ){
|
||||
fprintf(stderr,"\nTracker reponse code >= 400 !!! The file is not registered on this tracker, or it may have been removed. IF YOU SEE THIS MESSAGE FOR A LONG TIME AND DOWNLOAD DOESN'T BEGIN, RECOMMEND YOU STOP NOW!!!\n");
|
||||
fprintf(stderr,"\nTracker reponse data DUMP:\n");
|
||||
if( pdata && dlen ) write(STDERR_FILENO, pdata, dlen);
|
||||
fprintf(stderr,"\n== DUMP OVER==\n");
|
||||
return -1;
|
||||
}else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !pdata ) return 0;
|
||||
|
||||
if( !m_f_started ) m_f_started = 1;
|
||||
m_connect_refuse_click = 0;
|
||||
|
||||
return _UpdatePeerList(pdata,dlen);
|
||||
}
|
||||
|
||||
int btTracker::Initial()
|
||||
{
|
||||
char ih_buf[20 * 3 + 1],pi_buf[20 * 3 + 1],tmppath[MAXPATHLEN];
|
||||
|
||||
if(Http_url_analyse(BTCONTENT.GetAnnounce(),m_host,&m_port,m_path) < 0){
|
||||
fprintf(stderr,"error, invalid tracker url format!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(tmppath,m_path);
|
||||
|
||||
if(MAXPATHLEN < snprintf((char*)m_path,MAXPATHLEN,REQ_URL_P1_FMT,
|
||||
tmppath,
|
||||
Http_url_encode(ih_buf,(char*)BTCONTENT.GetInfoHash(),20),
|
||||
Http_url_encode(pi_buf,(char*)BTCONTENT.GetPeerId(),20),
|
||||
cfg_listen_port)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get local ip address */
|
||||
// 1st: if behind firewall, this only gets local side
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in6);
|
||||
if(getsockname(m_sock,(struct sockaddr*)&addr,&addrlen) == 0)
|
||||
Self.SetIp(addr);
|
||||
}
|
||||
// 2nd: better to use addr of our domain
|
||||
{
|
||||
struct hostent *h;
|
||||
char hostname[128];
|
||||
char *hostdots[2]={0,0}, *hdptr=hostname;
|
||||
|
||||
if (gethostname(hostname, 128) == -1) return -1;
|
||||
// printf("%s\n", hostname);
|
||||
while(*hdptr) if(*hdptr++ == '.') {
|
||||
hostdots[0] = hostdots[1];
|
||||
hostdots[1] = hdptr;
|
||||
}
|
||||
if (hostdots[0] == 0) return -1;
|
||||
// printf("%s\n", hostdots[0]);
|
||||
if ((h = gethostbyname2(hostdots[0],AF_INET6)) == NULL) return -1;
|
||||
//printf("Host domain : %s\n", h->h_name);
|
||||
//printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));
|
||||
memcpy(&Self.m_sin.sin6_addr,h->h_addr,sizeof(struct in6_addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btTracker::Connect()
|
||||
{
|
||||
ssize_t r;
|
||||
time(&m_last_timestamp);
|
||||
|
||||
if(_s2sin(m_host,m_port,&m_sin) < 0) {
|
||||
fprintf(stderr,"warn, get tracker's ip address failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_sock = socket(AF_INET6,SOCK_STREAM,0);
|
||||
if(INVALID_SOCKET == m_sock) return -1;
|
||||
|
||||
if(setfd_nonblock(m_sock) < 0) {CLOSE_SOCKET(m_sock); return -1; }
|
||||
|
||||
r = connect_nonb(m_sock,(struct sockaddr*)&m_sin);
|
||||
|
||||
if( r == -1 ){ CLOSE_SOCKET(m_sock); return -1;}
|
||||
else if( r == -2 ) m_status = T_CONNECTING;
|
||||
else{
|
||||
if( 0 == SendRequest()) m_status = T_READY;
|
||||
else{ CLOSE_SOCKET(m_sock); return -1;}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btTracker::SendRequest()
|
||||
{
|
||||
char *event,*str_event[] = {"started","stopped","completed" };
|
||||
char REQ_BUFFER[MAXPATHLEN];
|
||||
socklen_t addrlen;
|
||||
|
||||
struct sockaddr_in6 addr;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
|
||||
/* get local ip address */
|
||||
if(getsockname(m_sock,(struct sockaddr*)&addr,&addrlen) < 0){ return -1;}
|
||||
|
||||
//jc Self.SetIp(addr);
|
||||
// fprintf(stdout,"Old Set Self:");
|
||||
// fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr));
|
||||
|
||||
if( m_f_stoped ) /* stopped */
|
||||
event = str_event[1];
|
||||
else if( BTCONTENT.pBF->IsFull()) /* download complete */
|
||||
event = str_event[2];
|
||||
else if( m_f_started ) /* interval */
|
||||
event = (char*) 0;
|
||||
else
|
||||
event = str_event[0]; /* started */
|
||||
|
||||
if(event){
|
||||
if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
|
||||
m_path,
|
||||
(size_t)Self.TotalUL(),
|
||||
(size_t)Self.TotalDL(),
|
||||
(size_t)BTCONTENT.GetLeftBytes(),
|
||||
event)){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
|
||||
m_path,
|
||||
(size_t)Self.TotalUL(),
|
||||
(size_t)Self.TotalDL(),
|
||||
(size_t)BTCONTENT.GetLeftBytes()
|
||||
)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(_IPsin(m_host, m_port, &addr) < 0){
|
||||
char REQ_HOST[MAXHOSTNAMELEN];
|
||||
if(MAXHOSTNAMELEN < snprintf(REQ_HOST,MAXHOSTNAMELEN,"\r\nHost: %s",m_host)) return -1;
|
||||
strcat(REQ_BUFFER, REQ_HOST);
|
||||
}
|
||||
|
||||
strcat(REQ_BUFFER,"\r\n\r\n");
|
||||
// hc
|
||||
//fprintf(stderr,"SendRequest: %s\n", REQ_BUFFER);
|
||||
|
||||
if( 0 != m_reponse_buffer.PutFlush(m_sock,REQ_BUFFER,strlen((char*)REQ_BUFFER))){
|
||||
fprintf(stderr,"warn, send request to tracker failed. %s\n",strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btTracker::IntervalCheck(const time_t *pnow, fd_set *rfdp, fd_set *wfdp)
|
||||
{
|
||||
/* tracker communication */
|
||||
if( T_FREE == m_status ){
|
||||
if((*pnow - m_last_timestamp >= m_interval) &&
|
||||
(cfg_min_peers > WORLD.TotalPeers())){
|
||||
|
||||
if(Connect() < 0){ Reset(15); return -1; }
|
||||
|
||||
if( m_status == T_CONNECTING ){
|
||||
FD_SET(m_sock, rfdp);
|
||||
FD_SET(m_sock, wfdp);
|
||||
}else{
|
||||
FD_SET(m_sock, rfdp);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( m_status == T_CONNECTING ){
|
||||
FD_SET(m_sock, rfdp);
|
||||
FD_SET(m_sock, wfdp);
|
||||
}else{
|
||||
FD_SET(m_sock, rfdp);
|
||||
}
|
||||
}
|
||||
return m_sock;
|
||||
}
|
||||
|
||||
int btTracker::SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds)
|
||||
{
|
||||
if( T_FREE == m_status ) return 0;
|
||||
|
||||
if( T_CONNECTING == m_status &&
|
||||
(FD_ISSET(m_sock, wfdp) || FD_ISSET(m_sock,wfdp)) ){
|
||||
int error = 0;
|
||||
socklen_t n = sizeof(error);
|
||||
(*nfds)--;
|
||||
FD_CLR(m_sock, wfdp);
|
||||
if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
|
||||
error != 0 ){
|
||||
if( ECONNREFUSED != error )
|
||||
fprintf(stderr,"warn, connect to tracker failed. %s\n",strerror(error));
|
||||
else
|
||||
m_connect_refuse_click++;
|
||||
Reset(15);
|
||||
return -1;
|
||||
}else{
|
||||
if( SendRequest() == 0 ) m_status = T_READY;
|
||||
else { Reset(15); return -1; }
|
||||
}
|
||||
}else if(FD_ISSET(m_sock, rfdp) ){
|
||||
(*nfds)--;
|
||||
FD_CLR(m_sock,rfdp);
|
||||
CheckReponse();
|
||||
}
|
||||
return 0;
|
||||
}
|
80
tracker.h
Normal file
80
tracker.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef TRACKER_H
|
||||
#define TRACKER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "./def.h"
|
||||
#include "./bufio.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Winsock2.h>
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#define T_FREE 0
|
||||
#define T_CONNECTING 1
|
||||
#define T_READY 2
|
||||
|
||||
class btTracker
|
||||
{
|
||||
private:
|
||||
char m_host[MAXHOSTNAMELEN];
|
||||
char m_path[MAXPATHLEN];
|
||||
int m_port;
|
||||
|
||||
struct sockaddr_in6 m_sin;
|
||||
|
||||
unsigned char m_status:2;
|
||||
unsigned char m_f_started:1;
|
||||
unsigned char m_f_stoped:1;
|
||||
|
||||
unsigned char m_f_pause:1;
|
||||
unsigned char m_f_reserved:3;
|
||||
|
||||
|
||||
time_t m_interval; // 与Tracker通信的时间间隔
|
||||
time_t m_last_timestamp; // 最后一次成功与Tracker通信的时间
|
||||
size_t m_connect_refuse_click;
|
||||
|
||||
SOCKET m_sock;
|
||||
BufIo m_reponse_buffer;
|
||||
|
||||
int _IPsin(char *h, int p, struct sockaddr_in6 *psin);
|
||||
int _s2sin(char *h,int p,struct sockaddr_in6 *psin);
|
||||
int _UpdatePeerList(char *buf,size_t bufsiz);
|
||||
|
||||
public:
|
||||
btTracker();
|
||||
~btTracker();
|
||||
|
||||
int Initial();
|
||||
|
||||
void Reset(time_t new_interval);
|
||||
|
||||
unsigned char GetStatus() { return m_status;}
|
||||
void SetStatus(unsigned char s) { m_status = s; }
|
||||
|
||||
SOCKET GetSocket() { return m_sock; }
|
||||
|
||||
void SetPause() { m_f_pause = 1; }
|
||||
void ClearPause() { m_f_pause = 0; }
|
||||
|
||||
int Connect();
|
||||
int SendRequest();
|
||||
int CheckReponse();
|
||||
int IntervalCheck(const time_t *pnow,fd_set* rfdp, fd_set *wfdp);
|
||||
int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds);
|
||||
|
||||
size_t GetRefuseClick() const { return m_connect_refuse_click; }
|
||||
};
|
||||
|
||||
extern btTracker Tracker;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user