First git commit.
This commit is contained in:
commit
ac56e7a5b9
6
AUTHORS
Normal file
6
AUTHORS
Normal file
@ -0,0 +1,6 @@
|
||||
Authors of uHub
|
||||
===============
|
||||
|
||||
Jan Vidar Krey, Design and implementation
|
||||
|
||||
|
38
BUGS
Normal file
38
BUGS
Normal file
@ -0,0 +1,38 @@
|
||||
GENERIC:
|
||||
|
||||
- BUG: SID allocator needs work for supporting the overflow case (1 million connections).
|
||||
|
||||
- BUG: A passive client with no 'I4' (or 'I6') flag set,
|
||||
cannot set it at any later point.
|
||||
I4,I6,U4,U6 cannot be updated!
|
||||
|
||||
- BUG?
|
||||
No IQUI to disconnected user if they are disconnected by the hub.
|
||||
Only peers receive that, but the disconnected user will receive a STA
|
||||
(status) message.
|
||||
The ADC spec is unclear on this point.
|
||||
|
||||
- Some very rare abort or crashes.
|
||||
Window hub just stop without actually crashing.
|
||||
Seem to be some weird memory race conditions also.
|
||||
|
||||
- Exceeding send queue by just joining. Need to use dynamic send queue
|
||||
based on number of clients.
|
||||
|
||||
- A memory leak in hub_handle_info() -> update_user_info() -> adc_msg_copy().
|
||||
|
||||
- Get rid of list.c, use TAILQ instead!
|
||||
|
||||
Feature enhancements:
|
||||
- No support for changing nick names.
|
||||
|
||||
Todo:
|
||||
* Commands
|
||||
* !kick_nick <nick>
|
||||
* !kick_cid <cid>
|
||||
* !kick_ip <ip>
|
||||
* !reload
|
||||
* !stats
|
||||
* +myip
|
||||
* !help
|
||||
|
674
COPYING
Normal file
674
COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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 Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
120
ChangeLog
Normal file
120
ChangeLog
Normal file
@ -0,0 +1,120 @@
|
||||
0.2.5-3487:
|
||||
- Fixed out of memory situations, used when uhub operates on a limited heap.
|
||||
- Code cleanups, reduced heap memory footprint.
|
||||
- Fixed bug throwing users out due to exessive send queue when logging into a large hub.
|
||||
- Added some simple hub commands (!stats, !uptime, !version, !help, etc).
|
||||
|
||||
|
||||
0.2.4-3470:
|
||||
- Added option chat_is_privileged, which makes chat for privileged users only.
|
||||
- Started working on hub commands.
|
||||
- Fixed a double free() related crash / abort.
|
||||
- Fixed several send() -> EPIPE related crashes.
|
||||
|
||||
|
||||
0.2.3-3429:
|
||||
- Fixed one crash bug (jump to NULL).
|
||||
- Fixed IPv6 dual stack issues on Winsock, but needs Vista or later to compile.
|
||||
- Disable IPv6 if dual stack is not supported (WinXP with IPv6).
|
||||
- Fixed bind issue for IPv4 addresses.
|
||||
- Made sure no chat message could have PM context flag, unless set by the hub.
|
||||
- Ignore empty INF update messages.
|
||||
|
||||
|
||||
0.2.2-3393:
|
||||
- Fixed a crash related to hub login.
|
||||
- Added some fixes for older versions of libevent
|
||||
- Added option to log messages through syslog.
|
||||
- Added low bandwidth mode for really big hubs.
|
||||
- Started writing a benchmark tool for the hub.
|
||||
- Fix bug: reload configuration reset uptime.
|
||||
- Experimental support for NetBSD 3.1.
|
||||
|
||||
|
||||
0.2.1-3321:
|
||||
- Added more robust configuration file parsing.
|
||||
- Use defaults if config file is not found, unless a file is specified.
|
||||
- Added user class super user (above operator, below admin).
|
||||
- Added NAT override for clients behind the same NAT as the hub.
|
||||
- Fixed a bug summarizing shared size and files for the PING extension.
|
||||
- Fixed bugs related to hub limits.
|
||||
|
||||
|
||||
0.2.0-3293:
|
||||
- Fixed multiple crash bugs.
|
||||
- Fully compatible with ADC/1.0.
|
||||
- Protocol extensions: 'TIGR' and 'PING'
|
||||
- Added support for configuring min/max share size, slots, concurrent hubs, not very well tested.
|
||||
- Made all status message strings configurable.
|
||||
- Various BSD issues fixed. Should perform equally well as Linux.
|
||||
- Allow ignored configuration options (used when deprecating configuration options).
|
||||
- Added command line options for checking configuration.
|
||||
- A windows port is more or less done (MinGW)
|
||||
- Lots of new auto tests added.
|
||||
|
||||
|
||||
0.1.6-2608:
|
||||
- Changes required for the ADC/0.14 specification.
|
||||
- Stability fixes.
|
||||
- Win32 fixes, it compiles and runs, but not quite ported yet.
|
||||
- Added CMAKE files, which can be used instead of GNU make.
|
||||
- Made sure all messages are terminated when created.
|
||||
- Use length of messages, instead of strlen() to determine them.
|
||||
- Added more asserts for messages. Spotted a few errors as a result of that.
|
||||
- Added support for more sophisticated memory allocation debugging.
|
||||
|
||||
|
||||
0.1.5-2462
|
||||
- Fixed double free (crash).
|
||||
- Fixed password challenge/response coding error (crash).
|
||||
- Changes required for the new ADC/0.13 specification.
|
||||
- Fixed IPv6 netmask matching (banning)
|
||||
- Added UDP server, needed for auto-configure extension (AUT0)
|
||||
- Send 'ping' messages periodically if nothing heard from clients.
|
||||
- Print IP when client disconnects.
|
||||
- Lots of automatic testcases added, fix many bugs in the process.
|
||||
- GCC 2.95 compile fixes.
|
||||
|
||||
|
||||
0.1.4-2301:
|
||||
- uHub now requires and utilizes libevent. This allows for greater code
|
||||
portability, and less code complexity.
|
||||
- Various FreeBSD/OpenBSD/NetBSD fixes have been applied.
|
||||
- Can now log files other than stderr.
|
||||
- Added several automatic testcases.
|
||||
- The application should now be much more stable, and never consume much CPU.
|
||||
- Fixed several small annoying bugs.
|
||||
|
||||
|
||||
0.1.3-2147:
|
||||
- Changed license to GPL3
|
||||
- Fixed several crashes
|
||||
- Major code cleanups
|
||||
- Refactored event handling
|
||||
- Log file format change (minor)
|
||||
- Automatic regression testing of code base (via exotic).
|
||||
- Memory handling debug infrastructure.
|
||||
|
||||
|
||||
0.1.2-2020:
|
||||
- Fix infinite loops
|
||||
- Don't log users leaving unless they are logged in.
|
||||
- Fix private messages in chat only hubs.
|
||||
- Operators/admins override chat only hub settings.
|
||||
- Fix client/server protocol support negotiation handling
|
||||
- IP banning should now work (IPv6 is not tested yet).
|
||||
|
||||
|
||||
0.1.1-1956:
|
||||
- Fixed memory leaks in ACL handling
|
||||
- Prevent unneeded malloc's in command handling when buffers are big enough.
|
||||
- Code cleanups and more doxygen style comments added.
|
||||
- Fixed crashes and infinite loops
|
||||
- FreeBSD compile fixes
|
||||
- Timestamp log messages.
|
||||
- Log network/bandwidth statistics
|
||||
|
||||
|
||||
0.1.0-1840:
|
||||
- First public release
|
||||
|
245
GNUmakefile
Normal file
245
GNUmakefile
Normal file
@ -0,0 +1,245 @@
|
||||
##
|
||||
## Makefile for uhub (Use GNU make)
|
||||
## Copyright (C) 2007-2008, Jan Vidar Krey <janvidar@extatic.org>
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
LD := $(CC)
|
||||
MV := mv
|
||||
RANLIB := ranlib
|
||||
CFLAGS += -pipe -Wall
|
||||
USE_PCH ?= YES
|
||||
USE_SSL ?= NO
|
||||
USE_BIGENDIAN ?= AUTO
|
||||
BITS ?= AUTO
|
||||
SILENT ?= YES
|
||||
LDLIBS += -levent
|
||||
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
WINDOWS ?= YES
|
||||
endif
|
||||
|
||||
ifeq ($(WINDOWS),YES)
|
||||
USE_BIGENDIAN := NO
|
||||
LDLIBS += -lws2_32
|
||||
UHUB_CONF_DIR ?= c:/uhub/
|
||||
UHUB_PREFIX ?= c:/uhub/
|
||||
CFLAGS += -mno-cygwin
|
||||
LDFLAGS += -mno-cygwin
|
||||
BIN_EXT ?= .exe
|
||||
else
|
||||
UHUB_CONF_DIR ?= /etc/uhub
|
||||
UHUB_PREFIX ?= /usr/local
|
||||
CFLAGS += -I/usr/local/include
|
||||
LDFLAGS += -L/usr/local/lib
|
||||
BIN_EXT ?=
|
||||
endif
|
||||
|
||||
ifeq ($(SILENT),YES)
|
||||
MSG_CC=@echo " CC:" $(notdir $^) &&
|
||||
MSG_PCH=@echo " PCH:" $(notdir $@) &&
|
||||
MSG_LD=@echo " LD:" $(notdir $@) &&
|
||||
MSG_AR=@echo " AR:" $(notdir $@) &&
|
||||
else
|
||||
MSG_CC=
|
||||
MSG_PCH=
|
||||
MSG_LD=
|
||||
MSG_AR=
|
||||
endif
|
||||
|
||||
|
||||
CFLAGS += -I/source/libevent
|
||||
LDFLAGS += -L/source/libevent
|
||||
|
||||
-include release_setup.mk
|
||||
ifeq ($(RELEASE),YES)
|
||||
CFLAGS += -Os -DNDEBUG -fstack-protector-all
|
||||
else
|
||||
CFLAGS += -g -DDEBUG -fstack-protector-all
|
||||
endif
|
||||
|
||||
ifeq ($(PROFILING),YES)
|
||||
CFLAGS += -pg
|
||||
LDFLAGS += -pg
|
||||
endif
|
||||
|
||||
ifeq ($(FUNCTRACE),YES)
|
||||
CFLAGS += -finstrument-functions
|
||||
CFLAGS += -DDEBUG_FUNCTION_TRACE
|
||||
endif
|
||||
|
||||
ifeq ($(USE_PCH),YES)
|
||||
PCHSRC=src/uhub.h
|
||||
PCH=src/uhub.h.gch
|
||||
else
|
||||
PCH=
|
||||
endif
|
||||
|
||||
ifneq ($(BITS), AUTO)
|
||||
ifeq ($(BITS), 64)
|
||||
CFLAGS += -m64
|
||||
LDFLAGS += -m64
|
||||
else
|
||||
ifeq ($(BITS), 32)
|
||||
CFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_BIGENDIAN),AUTO)
|
||||
ifeq ($(shell perl -e 'print pack("L", 0x554E4958)'),UNIX)
|
||||
CFLAGS += -DARCH_BIGENDIAN
|
||||
endif
|
||||
else
|
||||
ifeq ($(USE_BIGENDIAN),YES)
|
||||
CFLAGS += -DARCH_BIGENDIAN
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_SSL),YES)
|
||||
CFLAGS += -DSSL_SUPPORT
|
||||
LDLIBS += -lssl
|
||||
endif
|
||||
|
||||
ifneq ($(LIBEVENT_PATH),)
|
||||
CFLAGS += -I$(LIBEVENT_PATH)
|
||||
LDFLAGS += -L$(LIBEVENT_PATH)
|
||||
endif
|
||||
|
||||
# Sources
|
||||
libuhub_SOURCES := \
|
||||
src/auth.c \
|
||||
src/commands.c \
|
||||
src/config.c \
|
||||
src/eventqueue.c \
|
||||
src/hubevent.c \
|
||||
src/hub.c \
|
||||
src/inf.c \
|
||||
src/ipcalc.c \
|
||||
src/list.c \
|
||||
src/log.c \
|
||||
src/memory.c \
|
||||
src/message.c \
|
||||
src/misc.c \
|
||||
src/netevent.c \
|
||||
src/network.c \
|
||||
src/route.c \
|
||||
src/sid.c \
|
||||
src/tiger.c \
|
||||
src/user.c \
|
||||
src/usermanager.c
|
||||
|
||||
uhub_SOURCES := src/main.c
|
||||
|
||||
adcrush_SOURCES := src/adcrush.c
|
||||
|
||||
uhub_HEADERS := \
|
||||
src/adcconst.h \
|
||||
src/auth.h \
|
||||
src/config.h \
|
||||
src/eventid.h \
|
||||
src/eventqueue.h \
|
||||
src/hubevent.h \
|
||||
src/hub.h \
|
||||
src/inf.h \
|
||||
src/ipcalc.h \
|
||||
src/list.h \
|
||||
src/log.h \
|
||||
src/memory.h \
|
||||
src/message.h \
|
||||
src/misc.h \
|
||||
src/netevent.h \
|
||||
src/network.h \
|
||||
src/route.h \
|
||||
src/sid.h \
|
||||
src/tiger.h \
|
||||
src/uhub.h \
|
||||
src/user.h \
|
||||
src/usermanager.h
|
||||
|
||||
autotest_SOURCES := \
|
||||
autotest/test_message.tcc \
|
||||
autotest/test_list.tcc \
|
||||
autotest/test_memory.tcc \
|
||||
autotest/test_ipfilter.tcc \
|
||||
autotest/test_inf.tcc \
|
||||
autotest/test_hub.tcc \
|
||||
autotest/test_misc.tcc \
|
||||
autotest/test_tiger.tcc \
|
||||
autotest/test_eventqueue.tcc
|
||||
|
||||
autotest_OBJECTS = autotest.o
|
||||
|
||||
# Source to objects
|
||||
libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o)
|
||||
uhub_OBJECTS := $(uhub_SOURCES:.c=.o)
|
||||
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o)
|
||||
|
||||
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS)
|
||||
|
||||
LIBUHUB=libuhub.a
|
||||
uhub_BINARY=uhub$(BIN_EXT)
|
||||
adcrush_BINARY=adcrush$(BIN_EXT)
|
||||
autotest_BINARY=autotest/test$(BIN_EXT)
|
||||
|
||||
%.o: %.c
|
||||
$(MSG_CC) $(CC) -c $(CFLAGS) -o $@.tmp $^ && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
all: $(uhub_BINARY) $(PCH)
|
||||
|
||||
$(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
$(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
$(LIBUHUB): $(libuhub_OBJECTS)
|
||||
$(MSG_AR) $(AR) rc $@.tmp $^ && \
|
||||
$(RANLIB) $@.tmp && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
ifeq ($(USE_PCH),YES)
|
||||
$(PCH): $(uhub_HEADERS)
|
||||
$(MSG_PCH) $(CC) $(CFLAGS) -o $@.tmp $(PCHSRC) && \
|
||||
$(MV) $@.tmp $@
|
||||
endif
|
||||
|
||||
$(autotest_OBJECTS): autotest.c
|
||||
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@.tmp $< && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
$(autotest_BINARY): $(autotest_OBJECTS) $(LIBUHUB)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $^ $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
autotest: $(autotest_BINARY)
|
||||
@./$(autotest_BINARY) -s -f
|
||||
|
||||
ifeq ($(WINDOWS),YES)
|
||||
install:
|
||||
@echo "Cannot install automatically on windows."
|
||||
else
|
||||
install: $(uhub_BINARY)
|
||||
@echo Copying $(uhub_BINARY) to $(UHUB_PREFIX)/bin/
|
||||
@cp $(uhub_BINARY) $(UHUB_PREFIX)/bin/
|
||||
@if [ ! -d $(UHUB_CONF_DIR) ]; then echo Creating $(UHUB_CONF_DIR); mkdir -p $(UHUB_CONF_DIR); fi
|
||||
@if [ ! -f $(UHUB_CONF_DIR)/uhub.conf ]; then cp doc/uhub.conf $(UHUB_CONF_DIR); fi
|
||||
@if [ ! -f $(UHUB_CONF_DIR)/users.conf ]; then cp doc/users.conf $(UHUB_CONF_DIR); fi
|
||||
@touch $(UHUB_CONF_DIR)/motd
|
||||
@echo done.
|
||||
endif
|
||||
|
||||
dist-clean:
|
||||
@rm -rf $(all_OBJECTS) $(PCH) *~ core
|
||||
|
||||
clean:
|
||||
@rm -rf $(libuhub_OBJECTS) $(PCH) *~ core $(uhub_BINARY) $(LIBUHUB) $(all_OBJECTS) && \
|
||||
echo Clean as a whistle
|
||||
|
||||
-include release_targets.mk
|
||||
|
66
README
Normal file
66
README
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
Welcome and thanks for downloading uHub.
|
||||
See the COPYING file for licensing details (GPLv3).
|
||||
|
||||
|
||||
SUPPORTED PLATFORMS AND PREREQUISITES
|
||||
|
||||
Getting started should be fairly straight forward if you are
|
||||
on Linux, BSD or MacOSX.
|
||||
|
||||
In any case you will need GNU make for compiling uHub.
|
||||
The makefiles depends on Perl for autodetect the endianess of the
|
||||
host system, but this can be worked around by specifying
|
||||
BIGENDIAN=YES or NO as a parameter for make (default is AUTO).
|
||||
|
||||
uHub requires libevent to be installed, you can download libevent
|
||||
from http://monkey.org/~provos/libevent/ if you do not already
|
||||
have it.
|
||||
|
||||
On Windows you will need MinGW in order to compile, and you might
|
||||
have to use (make CC=gcc).
|
||||
|
||||
|
||||
COMPILING
|
||||
|
||||
- run "make"
|
||||
|
||||
Make sure you have GNU make. On some systems, such as FreeBSD,
|
||||
you have to run "gmake" instead of the traditional BSD make.
|
||||
|
||||
|
||||
INSTALLING
|
||||
|
||||
Either run "make install", or:
|
||||
|
||||
- create the directory /etc/uhub
|
||||
- copy ./doc/uhub.conf to /etc/uhub
|
||||
- copy ./doc/users.conf to /etc/uhub
|
||||
|
||||
You should now be able to start the hub (using: ./uhub).
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
|
||||
To see help, use ./uhub -h
|
||||
|
||||
The default configuration file is fairly straight forward
|
||||
and will explain roughly what all the different configuration
|
||||
directive does.
|
||||
|
||||
When you have reconfigured the hub, you don't have to restart
|
||||
it, but rather send a 'HUP' signal to the server, and it will
|
||||
reload the configuration files, user database and message
|
||||
of the day (motd).
|
||||
|
||||
Use: "kill -HUP {pid of uhub}", or "killall -HUP uhub".
|
||||
|
||||
|
||||
REPORTING PROBLEMS
|
||||
|
||||
Send bugs reports, questions, feature requests, etc. to our
|
||||
e-mail address: < uhub (at) extatic (dot) org >
|
||||
|
||||
However, see the file 'BUGS' for a list of known bugs.
|
||||
|
||||
|
89
autotest/test_eventqueue.tcc
Normal file
89
autotest/test_eventqueue.tcc
Normal file
@ -0,0 +1,89 @@
|
||||
#include <uhub.h>
|
||||
|
||||
static struct event_queue* eq;
|
||||
static int eq_val;
|
||||
struct event* libevent_handle;
|
||||
|
||||
static void eq_callback(void* callback_data, struct event_data* event_data)
|
||||
{
|
||||
eq_val += event_data->id;
|
||||
}
|
||||
|
||||
EXO_TEST(eventqueue_init_1, {
|
||||
eq = 0;
|
||||
eq_val = 0;
|
||||
return event_queue_initialize(&eq, eq_callback, &eq_val) == 0 && event_queue_size(eq) == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_init_2, {
|
||||
/* hack */
|
||||
libevent_handle = eq->event;
|
||||
eq->event = 0;
|
||||
return eq->callback_data == &eq_val && eq->callback == eq_callback && eq->q1 && eq->q2 && !eq->locked;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_post_1, {
|
||||
struct event_data message;
|
||||
message.id = 0x1001;
|
||||
message.ptr = &message;
|
||||
message.flags = message.id * 2;
|
||||
event_queue_post(eq, &message);
|
||||
return event_queue_size(eq) == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_process_1, {
|
||||
event_queue_process(eq);
|
||||
return eq_val == 0x1001;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_size_1, {
|
||||
eq_val = 0;
|
||||
return event_queue_size(eq) == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_post_2, {
|
||||
struct event_data message;
|
||||
message.id = 0x1002;
|
||||
message.ptr = &message;
|
||||
message.flags = message.id * 2;
|
||||
event_queue_post(eq, &message);
|
||||
return event_queue_size(eq) == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_size_2, {
|
||||
eq_val = 0;
|
||||
return event_queue_size(eq) == 1;
|
||||
});
|
||||
|
||||
|
||||
EXO_TEST(eventqueue_post_3, {
|
||||
struct event_data message;
|
||||
message.id = 0x1003;
|
||||
message.ptr = &message;
|
||||
message.flags = message.id * 2;
|
||||
event_queue_post(eq, &message);
|
||||
return event_queue_size(eq) == 2;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_size_3, {
|
||||
eq_val = 0;
|
||||
return event_queue_size(eq) == 2;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_process_2, {
|
||||
event_queue_process(eq);
|
||||
return eq_val == 0x2005;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_size_4, {
|
||||
eq_val = 0;
|
||||
return event_queue_size(eq) == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(eventqueue_shutdown_1, {
|
||||
eq->event = libevent_handle;
|
||||
event_queue_shutdown(eq);
|
||||
return 1;
|
||||
});
|
||||
|
||||
|
71
autotest/test_hub.tcc
Normal file
71
autotest/test_hub.tcc
Normal file
@ -0,0 +1,71 @@
|
||||
#include <uhub.h>
|
||||
|
||||
static struct hub_config g_config;
|
||||
static struct acl_handle g_acl;
|
||||
static struct hub_info* g_hub;
|
||||
|
||||
/*
|
||||
static void create_test_user()
|
||||
{
|
||||
if (g_user)
|
||||
return;
|
||||
|
||||
g_user = (struct user*) malloc(sizeof(struct user));
|
||||
memset(g_user, 0, sizeof(struct user));
|
||||
memcpy(g_user->id.nick, "exotic-tester", 13);
|
||||
g_user->sid = 1;
|
||||
}
|
||||
*/
|
||||
|
||||
EXO_TEST(hub_net_startup, {
|
||||
return (net_initialize() != -1);
|
||||
});
|
||||
|
||||
EXO_TEST(hub_config_initialize, {
|
||||
config_defaults(&g_config);
|
||||
return 1;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_acl_initialize, {
|
||||
return (acl_initialize(&g_config, &g_acl) != -1);
|
||||
});
|
||||
|
||||
EXO_TEST(hub_service_initialize, {
|
||||
g_hub = hub_start_service(&g_config);
|
||||
return g_hub ? 1 : 0;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_variables_startup, {
|
||||
hub_set_variables(g_hub, &g_acl);
|
||||
return 1;
|
||||
});
|
||||
|
||||
/*** HUB IS OPERATIONAL HERE! ***/
|
||||
|
||||
EXO_TEST(hub_variables_shutdown, {
|
||||
hub_free_variables(g_hub);
|
||||
return 1;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_acl_shutdown, {
|
||||
acl_shutdown(&g_acl);
|
||||
return 1;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_config_shutdown, {
|
||||
free_config(&g_config);
|
||||
return 1;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_service_shutdown, {
|
||||
if (g_hub)
|
||||
{
|
||||
hub_shutdown_service(g_hub);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
EXO_TEST(hub_net_shutdown, {
|
||||
return (net_shutdown() != -1);
|
||||
});
|
155
autotest/test_inf.tcc
Normal file
155
autotest/test_inf.tcc
Normal file
@ -0,0 +1,155 @@
|
||||
#include <uhub.h>
|
||||
|
||||
#define USER_CID "GNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI"
|
||||
#define USER_PID "3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y"
|
||||
#define USER_NICK "Friend"
|
||||
#define USER_SID "AAAB"
|
||||
|
||||
static struct user* inf_user = 0;
|
||||
static struct hub_info* inf_hub = 0;
|
||||
|
||||
extern int hub_handle_info_login(struct user* user, struct adc_message* cmd);
|
||||
|
||||
static void inf_create_hub()
|
||||
{
|
||||
inf_hub = (struct hub_info*) hub_malloc_zero(sizeof(struct hub_info));
|
||||
inf_hub->users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
|
||||
inf_hub->users->list = list_create();
|
||||
inf_hub->users->free_sid = 1;
|
||||
|
||||
inf_hub->acl = (struct acl_handle*) hub_malloc_zero(sizeof(struct acl_handle));
|
||||
inf_hub->config = (struct hub_config*) hub_malloc_zero(sizeof(struct hub_config));
|
||||
|
||||
config_defaults(inf_hub->config);
|
||||
acl_initialize(inf_hub->config, inf_hub->acl);
|
||||
}
|
||||
|
||||
static void inf_destroy_hub()
|
||||
{
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
|
||||
static void inf_create_user()
|
||||
{
|
||||
if (inf_user) return;
|
||||
inf_user = (struct user*) hub_malloc_zero(sizeof(struct user));
|
||||
inf_user->id.sid = 1;
|
||||
inf_user->sd = -1;
|
||||
inf_user->hub = inf_hub;
|
||||
inf_user->limits.upload_slots = 1;
|
||||
}
|
||||
|
||||
static void inf_destroy_user()
|
||||
{
|
||||
if (!inf_user) return;
|
||||
hub_free(inf_user);
|
||||
inf_user = 0;
|
||||
}
|
||||
|
||||
EXO_TEST(inf_create_setup,
|
||||
{
|
||||
inf_create_hub();
|
||||
inf_create_user();
|
||||
return (inf_user && inf_hub);
|
||||
});
|
||||
|
||||
|
||||
|
||||
#define CHECK_INF(MSG, EXPECT) \
|
||||
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
|
||||
int ok = hub_handle_info_login(inf_user, msg); \
|
||||
adc_msg_free(msg); \
|
||||
if (ok != EXPECT) \
|
||||
printf("Expected %d, got %d\n", EXPECT, ok); \
|
||||
return ok == EXPECT;
|
||||
|
||||
|
||||
EXO_TEST(inf_ok_1, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", 0); });
|
||||
|
||||
/* check CID abuse */
|
||||
EXO_TEST(inf_cid_1, { CHECK_INF("BINF AAAB NIFriend PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_missing); });
|
||||
EXO_TEST(inf_cid_2, { CHECK_INF("BINF AAAB NIFriend IDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); });
|
||||
EXO_TEST(inf_cid_3, { CHECK_INF("BINF AAAB NIFriend IDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); });
|
||||
EXO_TEST(inf_cid_4, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2R PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); }); /* cid 1 byte short */
|
||||
EXO_TEST(inf_cid_5, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RX PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); }); /* cid 1 byte longer */
|
||||
EXO_TEST(inf_cid_6, { CHECK_INF("BINF AAAB NIFriend IDA PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); });
|
||||
EXO_TEST(inf_cid_7, { CHECK_INF("BINF AAAB NIFriend IDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_cid_invalid); }); /* multi */
|
||||
EXO_TEST(inf_cid_8, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y IDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n", status_msg_inf_error_cid_invalid); });
|
||||
EXO_TEST(inf_cid_9, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI\n", status_msg_inf_error_cid_invalid); });
|
||||
|
||||
/* equivalent to the pid versions */
|
||||
EXO_TEST(inf_pid_1, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI\n", status_msg_inf_error_pid_missing); }); /* pid missing */
|
||||
EXO_TEST(inf_pid_2, { CHECK_INF("BINF AAAB NIFriend ID3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y PDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n", status_msg_inf_error_cid_invalid); }); /* variant of inf_cid_2 */
|
||||
EXO_TEST(inf_pid_3, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", status_msg_inf_error_pid_invalid); }); /* pid invalid */
|
||||
EXO_TEST(inf_pid_4, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7\n", status_msg_inf_error_pid_invalid); }); /* pid 1 byte short */
|
||||
EXO_TEST(inf_pid_5, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7YX\n", status_msg_inf_error_pid_invalid); }); /* pid 1 byte longer */
|
||||
EXO_TEST(inf_pid_6, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PDA\n", status_msg_inf_error_pid_invalid); }); /* very short pid */
|
||||
EXO_TEST(inf_pid_7, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y PDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n", status_msg_inf_error_pid_invalid); });
|
||||
EXO_TEST(inf_pid_8, { CHECK_INF("BINF AAAB NIFriend PDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_pid_invalid); });
|
||||
EXO_TEST(inf_pid_9, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_pid_invalid); });
|
||||
|
||||
/* check nickname abuse */
|
||||
EXO_TEST(inf_nick_01, { CHECK_INF("BINF AAAB IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_missing); });
|
||||
EXO_TEST(inf_nick_02, { CHECK_INF("BINF AAAB NI IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_short); });
|
||||
EXO_TEST(inf_nick_03, { CHECK_INF("BINF AAAB NIa IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_short); });
|
||||
EXO_TEST(inf_nick_04, { CHECK_INF("BINF AAAB NIabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_long); });
|
||||
EXO_TEST(inf_nick_05, { CHECK_INF("BINF AAAB NI\\sabc IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_spaces); });
|
||||
EXO_TEST(inf_nick_06, { CHECK_INF("BINF AAAB NIa\\sc IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", 0); });
|
||||
EXO_TEST(inf_nick_07, { CHECK_INF("BINF AAAB NIa\tc IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_bad_chars); });
|
||||
EXO_TEST(inf_nick_08, { CHECK_INF("BINF AAAB NIa\\nc IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_bad_chars); });
|
||||
EXO_TEST(inf_nick_09, { CHECK_INF("BINF AAAB NIabc NIdef IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_multiple); });
|
||||
EXO_TEST(inf_nick_10, {
|
||||
const char* line = "BINF AAAB IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n";
|
||||
char nick[10];
|
||||
nick[0] = 0xf7; nick[1] = 0x80; nick[2] = 0x7f; nick[3] = 0x81; nick[4] = 0x98; nick[5] = 0x00;
|
||||
struct adc_message* msg = adc_msg_parse_verify(inf_user, line, strlen(line));
|
||||
|
||||
adc_msg_add_named_argument(msg, "NI", nick);
|
||||
int ok = hub_handle_info_login(inf_user, msg);
|
||||
adc_msg_free(msg);
|
||||
if (ok != status_msg_inf_error_nick_not_utf8)
|
||||
printf("Expected %d, got %d\n", status_msg_inf_error_nick_not_utf8, ok);
|
||||
return ok == status_msg_inf_error_nick_not_utf8;
|
||||
});
|
||||
|
||||
/* check limits for slots and share */
|
||||
EXO_TEST(inf_limits_1, { inf_hub->config->limit_min_slots = 1; CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y SL0\n", status_msg_user_slots_low); });
|
||||
EXO_TEST(inf_limits_2, { inf_hub->config->limit_max_slots = 5; CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y SL99\n", status_msg_user_slots_high); });
|
||||
EXO_TEST(inf_limits_3, { inf_hub->config->limit_min_share = 100; CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y SS104857599\n", status_msg_user_share_size_low); });
|
||||
EXO_TEST(inf_limits_4, { inf_hub->config->limit_max_share = 500; CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y SS524288001\n", status_msg_user_share_size_high); });
|
||||
|
||||
/* setup for check limits for hubs */
|
||||
EXO_TEST(inf_limit_hubs_setup,
|
||||
{
|
||||
inf_hub->config->limit_min_slots = 0;
|
||||
inf_hub->config->limit_max_slots = 0;
|
||||
inf_hub->config->limit_max_share = 0;
|
||||
inf_hub->config->limit_min_share = 0;
|
||||
inf_hub->config->limit_max_hubs_user = 10;
|
||||
inf_hub->config->limit_max_hubs_reg = 10;
|
||||
inf_hub->config->limit_max_hubs_op = 10;
|
||||
inf_hub->config->limit_min_hubs_user = 2;
|
||||
inf_hub->config->limit_min_hubs_reg = 2;
|
||||
inf_hub->config->limit_min_hubs_op = 2;
|
||||
inf_hub->config->limit_max_hubs = 25;
|
||||
|
||||
return 1;
|
||||
} );
|
||||
|
||||
|
||||
EXO_TEST(inf_limit_hubs_1, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HN15\n", status_msg_user_hub_limit_high); });
|
||||
EXO_TEST(inf_limit_hubs_2, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HN1\n", status_msg_user_hub_limit_low); });
|
||||
EXO_TEST(inf_limit_hubs_3, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HO15\n", status_msg_user_hub_limit_high); });
|
||||
EXO_TEST(inf_limit_hubs_4, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HO1\n", status_msg_user_hub_limit_low); });
|
||||
EXO_TEST(inf_limit_hubs_5, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HR15\n", status_msg_user_hub_limit_high); });
|
||||
EXO_TEST(inf_limit_hubs_6, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HR1\n", status_msg_user_hub_limit_low); });
|
||||
EXO_TEST(inf_limit_hubs_7, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y HN15 HR15 HO15\n", status_msg_user_hub_limit_high); });
|
||||
|
||||
|
||||
EXO_TEST(inf_destroy_setup,
|
||||
{
|
||||
inf_destroy_user();
|
||||
inf_destroy_hub();
|
||||
return 1;
|
||||
});
|
599
autotest/test_ipfilter.tcc
Normal file
599
autotest/test_ipfilter.tcc
Normal file
@ -0,0 +1,599 @@
|
||||
#include <uhub.h>
|
||||
|
||||
static int ipv6 = 0;
|
||||
|
||||
static struct ip_addr_encap ip4_a;
|
||||
static struct ip_addr_encap ip4_b;
|
||||
static struct ip_addr_encap ip4_c;
|
||||
static struct ip_addr_encap ip6_a;
|
||||
static struct ip_addr_encap ip6_b;
|
||||
static struct ip_addr_encap ip6_c;
|
||||
static struct ip_addr_encap mask;
|
||||
static struct ip_ban_record ban6;
|
||||
static struct ip_ban_record ban4;
|
||||
|
||||
EXO_TEST(prepare_network, {
|
||||
return net_initialize() == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(check_ipv6, {
|
||||
ipv6 = net_is_ipv6_supported();
|
||||
return ipv6 != -1;
|
||||
});
|
||||
|
||||
EXO_TEST(create_addresses_1, {
|
||||
return
|
||||
ip_convert_to_binary("192.168.0.0", &ip4_a) &&
|
||||
ip_convert_to_binary("192.168.255.255", &ip4_b) &&
|
||||
ip_convert_to_binary("192.168.0.1", &ip4_c);
|
||||
});
|
||||
|
||||
EXO_TEST(create_addresses_2, {
|
||||
return
|
||||
ip_convert_to_binary("2001::201:2ff:fefa:0", &ip6_a) &&
|
||||
ip_convert_to_binary("2001::201:2ff:fefa:ffff", &ip6_b) &&
|
||||
ip_convert_to_binary("2001::201:2ff:fefa:fffe", &ip6_c);
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_1, {
|
||||
return ip_is_valid_ipv4("127.0.0.1");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_2, {
|
||||
return ip_is_valid_ipv4("10.18.1.178");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_3, {
|
||||
return ip_is_valid_ipv4("10.18.1.178");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_4, {
|
||||
return ip_is_valid_ipv4("224.0.0.1");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_5, {
|
||||
return !ip_is_valid_ipv4("224.0.0.");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_6, {
|
||||
return !ip_is_valid_ipv4("invalid");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_7, {
|
||||
return !ip_is_valid_ipv4("localhost");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_8, {
|
||||
return !ip_is_valid_ipv4("123.45.67.890");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv4_9, {
|
||||
return !ip_is_valid_ipv4("777.777.777.777");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv6_1, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_is_valid_ipv6("::");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv6_2, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_is_valid_ipv6("::1");
|
||||
});
|
||||
|
||||
EXO_TEST(ip_is_valid_ipv6_3, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_is_valid_ipv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_1, {
|
||||
return ip_compare(&ip4_a, &ip4_b) < 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_2, {
|
||||
return ip_compare(&ip4_a, &ip4_c) < 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_3, {
|
||||
return ip_compare(&ip4_b, &ip4_c) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_4, {
|
||||
return ip_compare(&ip4_b, &ip4_a) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_5, {
|
||||
return ip_compare(&ip4_c, &ip4_a) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_compare_6, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip4_c, &ip4_c) == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_1, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_a, &ip6_b) < 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_2, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_a, &ip6_c) < 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_3, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_b, &ip6_c) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_4, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_b, &ip6_a) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_5, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_c, &ip6_a) > 0;
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_compare_6, {
|
||||
if (!ipv6) return 1;
|
||||
return ip_compare(&ip6_c, &ip6_c) == 0;
|
||||
});
|
||||
|
||||
static int compare_str(const char* s1, const char* s2)
|
||||
{
|
||||
int ok = strcmp(s1, s2);
|
||||
#ifdef DEBUG_TESTS
|
||||
if (ok)
|
||||
{
|
||||
printf("compare_str fail: s1='%s', s2='%s'\n", s1, s2);
|
||||
}
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
#define LMASK4(bits) !ip_mask_create_left (AF_INET, bits, &mask)
|
||||
#define LMASK6(bits) (ipv6 ? !ip_mask_create_left (AF_INET6, bits, &mask) : 1)
|
||||
#define RMASK4(bits) !ip_mask_create_right(AF_INET, bits, &mask)
|
||||
#define RMASK6(bits) (ipv6 ? !ip_mask_create_right(AF_INET6, bits, &mask) : 1)
|
||||
#define CHECK4(expect) !compare_str(ip_convert_to_string(&mask), expect)
|
||||
#define CHECK6(expect) (ipv6 ? !compare_str(ip_convert_to_string(&mask), expect) : 1)
|
||||
|
||||
/* Check IPv4 masks */
|
||||
EXO_TEST(ipv4_lmask_create_0, { return LMASK4( 0) && CHECK4("0.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_1, { return LMASK4( 1) && CHECK4("128.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_2, { return LMASK4( 2) && CHECK4("192.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_3, { return LMASK4( 3) && CHECK4("224.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_4, { return LMASK4( 4) && CHECK4("240.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_5, { return LMASK4( 5) && CHECK4("248.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_6, { return LMASK4( 6) && CHECK4("252.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_7, { return LMASK4( 7) && CHECK4("254.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_8, { return LMASK4( 8) && CHECK4("255.0.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_9, { return LMASK4( 9) && CHECK4("255.128.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_10, { return LMASK4(10) && CHECK4("255.192.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_11, { return LMASK4(11) && CHECK4("255.224.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_12, { return LMASK4(12) && CHECK4("255.240.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_13, { return LMASK4(13) && CHECK4("255.248.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_14, { return LMASK4(14) && CHECK4("255.252.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_15, { return LMASK4(15) && CHECK4("255.254.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_16, { return LMASK4(16) && CHECK4("255.255.0.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_17, { return LMASK4(17) && CHECK4("255.255.128.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_18, { return LMASK4(18) && CHECK4("255.255.192.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_19, { return LMASK4(19) && CHECK4("255.255.224.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_20, { return LMASK4(20) && CHECK4("255.255.240.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_21, { return LMASK4(21) && CHECK4("255.255.248.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_22, { return LMASK4(22) && CHECK4("255.255.252.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_23, { return LMASK4(23) && CHECK4("255.255.254.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_24, { return LMASK4(24) && CHECK4("255.255.255.0"); });
|
||||
EXO_TEST(ipv4_lmask_create_25, { return LMASK4(25) && CHECK4("255.255.255.128"); });
|
||||
EXO_TEST(ipv4_lmask_create_26, { return LMASK4(26) && CHECK4("255.255.255.192"); });
|
||||
EXO_TEST(ipv4_lmask_create_27, { return LMASK4(27) && CHECK4("255.255.255.224"); });
|
||||
EXO_TEST(ipv4_lmask_create_28, { return LMASK4(28) && CHECK4("255.255.255.240"); });
|
||||
EXO_TEST(ipv4_lmask_create_29, { return LMASK4(29) && CHECK4("255.255.255.248"); });
|
||||
EXO_TEST(ipv4_lmask_create_30, { return LMASK4(30) && CHECK4("255.255.255.252"); });
|
||||
EXO_TEST(ipv4_lmask_create_31, { return LMASK4(31) && CHECK4("255.255.255.254"); });
|
||||
EXO_TEST(ipv4_lmask_create_32, { return LMASK4(32) && CHECK4("255.255.255.255"); });
|
||||
|
||||
/* Check IPv4 right to left mask */
|
||||
EXO_TEST(ipv4_rmask_create_0, { return RMASK4( 0) && CHECK4("0.0.0.0"); });
|
||||
EXO_TEST(ipv4_rmask_create_1, { return RMASK4( 1) && CHECK4("0.0.0.1"); });
|
||||
EXO_TEST(ipv4_rmask_create_2, { return RMASK4( 2) && CHECK4("0.0.0.3"); });
|
||||
EXO_TEST(ipv4_rmask_create_3, { return RMASK4( 3) && CHECK4("0.0.0.7"); });
|
||||
EXO_TEST(ipv4_rmask_create_4, { return RMASK4( 4) && CHECK4("0.0.0.15"); });
|
||||
EXO_TEST(ipv4_rmask_create_5, { return RMASK4( 5) && CHECK4("0.0.0.31"); });
|
||||
EXO_TEST(ipv4_rmask_create_6, { return RMASK4( 6) && CHECK4("0.0.0.63"); });
|
||||
EXO_TEST(ipv4_rmask_create_7, { return RMASK4( 7) && CHECK4("0.0.0.127"); });
|
||||
EXO_TEST(ipv4_rmask_create_8, { return RMASK4( 8) && CHECK4("0.0.0.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_9, { return RMASK4( 9) && CHECK4("0.0.1.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_10, { return RMASK4(10) && CHECK4("0.0.3.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_11, { return RMASK4(11) && CHECK4("0.0.7.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_12, { return RMASK4(12) && CHECK4("0.0.15.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_13, { return RMASK4(13) && CHECK4("0.0.31.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_14, { return RMASK4(14) && CHECK4("0.0.63.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_15, { return RMASK4(15) && CHECK4("0.0.127.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_16, { return RMASK4(16) && CHECK4("0.0.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_17, { return RMASK4(17) && CHECK4("0.1.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_18, { return RMASK4(18) && CHECK4("0.3.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_19, { return RMASK4(19) && CHECK4("0.7.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_20, { return RMASK4(20) && CHECK4("0.15.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_21, { return RMASK4(21) && CHECK4("0.31.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_22, { return RMASK4(22) && CHECK4("0.63.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_23, { return RMASK4(23) && CHECK4("0.127.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_24, { return RMASK4(24) && CHECK4("0.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_25, { return RMASK4(25) && CHECK4("1.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_26, { return RMASK4(26) && CHECK4("3.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_27, { return RMASK4(27) && CHECK4("7.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_28, { return RMASK4(28) && CHECK4("15.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_29, { return RMASK4(29) && CHECK4("31.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_30, { return RMASK4(30) && CHECK4("63.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_31, { return RMASK4(31) && CHECK4("127.255.255.255"); });
|
||||
EXO_TEST(ipv4_rmask_create_32, { return RMASK4(32) && CHECK4("255.255.255.255"); });
|
||||
|
||||
|
||||
/* Check IPv6 masks */
|
||||
EXO_TEST(ip6_lmask_create_0, { return LMASK6( 0) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_lmask_create_1, { return LMASK6( 1) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"); });
|
||||
EXO_TEST(ip6_lmask_create_2, { return LMASK6( 2) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"); });
|
||||
EXO_TEST(ip6_lmask_create_3, { return LMASK6( 3) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"); });
|
||||
EXO_TEST(ip6_lmask_create_4, { return LMASK6( 4) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"); });
|
||||
EXO_TEST(ip6_lmask_create_5, { return LMASK6( 5) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0"); });
|
||||
EXO_TEST(ip6_lmask_create_6, { return LMASK6( 6) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0"); });
|
||||
EXO_TEST(ip6_lmask_create_7, { return LMASK6( 7) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80"); });
|
||||
EXO_TEST(ip6_lmask_create_8, { return LMASK6( 8) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00"); });
|
||||
EXO_TEST(ip6_lmask_create_9, { return LMASK6( 9) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00"); });
|
||||
EXO_TEST(ip6_lmask_create_10, { return LMASK6( 10) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00"); });
|
||||
EXO_TEST(ip6_lmask_create_11, { return LMASK6( 11) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800"); });
|
||||
EXO_TEST(ip6_lmask_create_12, { return LMASK6( 12) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000"); });
|
||||
EXO_TEST(ip6_lmask_create_13, { return LMASK6( 13) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000"); });
|
||||
EXO_TEST(ip6_lmask_create_14, { return LMASK6( 14) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000"); });
|
||||
EXO_TEST(ip6_lmask_create_15, { return LMASK6( 15) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000"); });
|
||||
EXO_TEST(ip6_lmask_create_16, { return LMASK6( 16) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff::")); });
|
||||
EXO_TEST(ip6_lmask_create_17, { return LMASK6( 17) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fffe:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fffe::")); });
|
||||
EXO_TEST(ip6_lmask_create_18, { return LMASK6( 18) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fffc:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fffc::")); });
|
||||
EXO_TEST(ip6_lmask_create_19, { return LMASK6( 19) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fff8:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fff8::")); });
|
||||
EXO_TEST(ip6_lmask_create_20, { return LMASK6( 20) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fff0:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fff0::")); });
|
||||
EXO_TEST(ip6_lmask_create_21, { return LMASK6( 21) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffe0::")); });
|
||||
EXO_TEST(ip6_lmask_create_22, { return LMASK6( 22) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffc0::")); });
|
||||
EXO_TEST(ip6_lmask_create_23, { return LMASK6( 23) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ff80:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ff80::")); });
|
||||
EXO_TEST(ip6_lmask_create_24, { return LMASK6( 24) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ff00:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ff00::")); });
|
||||
EXO_TEST(ip6_lmask_create_25, { return LMASK6( 25) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fe00:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fe00::")); });
|
||||
EXO_TEST(ip6_lmask_create_26, { return LMASK6( 26) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fc00:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:fc00::")); });
|
||||
EXO_TEST(ip6_lmask_create_27, { return LMASK6( 27) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:f800:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:f800::")); });
|
||||
EXO_TEST(ip6_lmask_create_28, { return LMASK6( 28) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:f000:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:f000::")); });
|
||||
EXO_TEST(ip6_lmask_create_29, { return LMASK6( 29) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:e000:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:e000::")); });
|
||||
EXO_TEST(ip6_lmask_create_30, { return LMASK6( 30) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:c000:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:c000::")); });
|
||||
EXO_TEST(ip6_lmask_create_31, { return LMASK6( 31) && (CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:8000:0") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:8000::")); });
|
||||
EXO_TEST(ip6_lmask_create_32, { return LMASK6( 32) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_33, { return LMASK6( 33) && CHECK6("ffff:ffff:ffff:ffff:ffff:fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_34, { return LMASK6( 34) && CHECK6("ffff:ffff:ffff:ffff:ffff:fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_35, { return LMASK6( 35) && CHECK6("ffff:ffff:ffff:ffff:ffff:fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_36, { return LMASK6( 36) && CHECK6("ffff:ffff:ffff:ffff:ffff:fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_37, { return LMASK6( 37) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_38, { return LMASK6( 38) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_39, { return LMASK6( 39) && CHECK6("ffff:ffff:ffff:ffff:ffff:ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_40, { return LMASK6( 40) && CHECK6("ffff:ffff:ffff:ffff:ffff:ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_41, { return LMASK6( 41) && CHECK6("ffff:ffff:ffff:ffff:ffff:fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_42, { return LMASK6( 42) && CHECK6("ffff:ffff:ffff:ffff:ffff:fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_43, { return LMASK6( 43) && CHECK6("ffff:ffff:ffff:ffff:ffff:f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_44, { return LMASK6( 44) && CHECK6("ffff:ffff:ffff:ffff:ffff:f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_45, { return LMASK6( 45) && CHECK6("ffff:ffff:ffff:ffff:ffff:e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_46, { return LMASK6( 46) && CHECK6("ffff:ffff:ffff:ffff:ffff:c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_47, { return LMASK6( 47) && CHECK6("ffff:ffff:ffff:ffff:ffff:8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_48, { return LMASK6( 48) && CHECK6("ffff:ffff:ffff:ffff:ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_49, { return LMASK6( 49) && CHECK6("ffff:ffff:ffff:ffff:fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_50, { return LMASK6( 50) && CHECK6("ffff:ffff:ffff:ffff:fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_51, { return LMASK6( 51) && CHECK6("ffff:ffff:ffff:ffff:fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_52, { return LMASK6( 52) && CHECK6("ffff:ffff:ffff:ffff:fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_53, { return LMASK6( 53) && CHECK6("ffff:ffff:ffff:ffff:ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_54, { return LMASK6( 54) && CHECK6("ffff:ffff:ffff:ffff:ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_55, { return LMASK6( 55) && CHECK6("ffff:ffff:ffff:ffff:ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_56, { return LMASK6( 56) && CHECK6("ffff:ffff:ffff:ffff:ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_57, { return LMASK6( 57) && CHECK6("ffff:ffff:ffff:ffff:fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_58, { return LMASK6( 58) && CHECK6("ffff:ffff:ffff:ffff:fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_59, { return LMASK6( 59) && CHECK6("ffff:ffff:ffff:ffff:f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_60, { return LMASK6( 60) && CHECK6("ffff:ffff:ffff:ffff:f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_61, { return LMASK6( 61) && CHECK6("ffff:ffff:ffff:ffff:e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_62, { return LMASK6( 62) && CHECK6("ffff:ffff:ffff:ffff:c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_63, { return LMASK6( 63) && CHECK6("ffff:ffff:ffff:ffff:8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_64, { return LMASK6( 64) && CHECK6("ffff:ffff:ffff:ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_65, { return LMASK6( 65) && CHECK6("ffff:ffff:ffff:fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_66, { return LMASK6( 66) && CHECK6("ffff:ffff:ffff:fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_67, { return LMASK6( 67) && CHECK6("ffff:ffff:ffff:fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_68, { return LMASK6( 68) && CHECK6("ffff:ffff:ffff:fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_69, { return LMASK6( 69) && CHECK6("ffff:ffff:ffff:ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_70, { return LMASK6( 70) && CHECK6("ffff:ffff:ffff:ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_71, { return LMASK6( 71) && CHECK6("ffff:ffff:ffff:ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_72, { return LMASK6( 72) && CHECK6("ffff:ffff:ffff:ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_73, { return LMASK6( 73) && CHECK6("ffff:ffff:ffff:fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_74, { return LMASK6( 74) && CHECK6("ffff:ffff:ffff:fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_75, { return LMASK6( 75) && CHECK6("ffff:ffff:ffff:f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_76, { return LMASK6( 76) && CHECK6("ffff:ffff:ffff:f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_77, { return LMASK6( 77) && CHECK6("ffff:ffff:ffff:e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_78, { return LMASK6( 78) && CHECK6("ffff:ffff:ffff:c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_79, { return LMASK6( 79) && CHECK6("ffff:ffff:ffff:8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_80, { return LMASK6( 80) && CHECK6("ffff:ffff:ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_81, { return LMASK6( 81) && CHECK6("ffff:ffff:fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_82, { return LMASK6( 82) && CHECK6("ffff:ffff:fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_83, { return LMASK6( 83) && CHECK6("ffff:ffff:fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_84, { return LMASK6( 84) && CHECK6("ffff:ffff:fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_85, { return LMASK6( 85) && CHECK6("ffff:ffff:ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_86, { return LMASK6( 86) && CHECK6("ffff:ffff:ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_87, { return LMASK6( 87) && CHECK6("ffff:ffff:ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_88, { return LMASK6( 88) && CHECK6("ffff:ffff:ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_89, { return LMASK6( 89) && CHECK6("ffff:ffff:fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_90, { return LMASK6( 90) && CHECK6("ffff:ffff:fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_91, { return LMASK6( 91) && CHECK6("ffff:ffff:f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_92, { return LMASK6( 92) && CHECK6("ffff:ffff:f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_93, { return LMASK6( 93) && CHECK6("ffff:ffff:e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_94, { return LMASK6( 94) && CHECK6("ffff:ffff:c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_95, { return LMASK6( 95) && CHECK6("ffff:ffff:8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_96, { return LMASK6( 96) && CHECK6("ffff:ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_97, { return LMASK6( 97) && CHECK6("ffff:fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_98, { return LMASK6( 98) && CHECK6("ffff:fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_99, { return LMASK6( 99) && CHECK6("ffff:fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_100, { return LMASK6(100) && CHECK6("ffff:fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_101, { return LMASK6(101) && CHECK6("ffff:ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_102, { return LMASK6(102) && CHECK6("ffff:ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_103, { return LMASK6(103) && CHECK6("ffff:ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_104, { return LMASK6(104) && CHECK6("ffff:ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_105, { return LMASK6(105) && CHECK6("ffff:fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_106, { return LMASK6(106) && CHECK6("ffff:fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_107, { return LMASK6(107) && CHECK6("ffff:f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_108, { return LMASK6(108) && CHECK6("ffff:f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_109, { return LMASK6(109) && CHECK6("ffff:e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_110, { return LMASK6(110) && CHECK6("ffff:c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_111, { return LMASK6(111) && CHECK6("ffff:8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_112, { return LMASK6(112) && CHECK6("ffff::"); });
|
||||
EXO_TEST(ip6_lmask_create_113, { return LMASK6(113) && CHECK6("fffe::"); });
|
||||
EXO_TEST(ip6_lmask_create_114, { return LMASK6(114) && CHECK6("fffc::"); });
|
||||
EXO_TEST(ip6_lmask_create_115, { return LMASK6(115) && CHECK6("fff8::"); });
|
||||
EXO_TEST(ip6_lmask_create_116, { return LMASK6(116) && CHECK6("fff0::"); });
|
||||
EXO_TEST(ip6_lmask_create_117, { return LMASK6(117) && CHECK6("ffe0::"); });
|
||||
EXO_TEST(ip6_lmask_create_118, { return LMASK6(118) && CHECK6("ffc0::"); });
|
||||
EXO_TEST(ip6_lmask_create_119, { return LMASK6(119) && CHECK6("ff80::"); });
|
||||
EXO_TEST(ip6_lmask_create_120, { return LMASK6(120) && CHECK6("ff00::"); });
|
||||
EXO_TEST(ip6_lmask_create_121, { return LMASK6(121) && CHECK6("fe00::"); });
|
||||
EXO_TEST(ip6_lmask_create_122, { return LMASK6(122) && CHECK6("fc00::"); });
|
||||
EXO_TEST(ip6_lmask_create_123, { return LMASK6(123) && CHECK6("f800::"); });
|
||||
EXO_TEST(ip6_lmask_create_124, { return LMASK6(124) && CHECK6("f000::"); });
|
||||
EXO_TEST(ip6_lmask_create_125, { return LMASK6(125) && CHECK6("e000::"); });
|
||||
EXO_TEST(ip6_lmask_create_126, { return LMASK6(126) && CHECK6("c000::"); });
|
||||
EXO_TEST(ip6_lmask_create_127, { return LMASK6(127) && CHECK6("8000::"); });
|
||||
EXO_TEST(ip6_lmask_create_128, { return LMASK6(128) && CHECK6("::"); });
|
||||
|
||||
/* Check IPv6 right to left masks */
|
||||
EXO_TEST(ip6_rmask_create_0, { return RMASK6( 0) && CHECK6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_1, { return RMASK6( 1) && CHECK6("7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_2, { return RMASK6( 2) && CHECK6("3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_3, { return RMASK6( 3) && CHECK6("1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_4, { return RMASK6( 4) && CHECK6("fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_5, { return RMASK6( 5) && CHECK6("7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_6, { return RMASK6( 6) && CHECK6("3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_7, { return RMASK6( 7) && CHECK6("1ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_8, { return RMASK6( 8) && CHECK6("ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_9, { return RMASK6( 9) && CHECK6("7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_10, { return RMASK6( 10) && CHECK6("3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_11, { return RMASK6( 11) && CHECK6("1f:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_12, { return RMASK6( 12) && CHECK6("f:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_13, { return RMASK6( 13) && CHECK6("7:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_14, { return RMASK6( 14) && CHECK6("3:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_15, { return RMASK6( 15) && CHECK6("1:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); });
|
||||
EXO_TEST(ip6_rmask_create_16, { return RMASK6( 16) && (CHECK6("0:ffff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::ffff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_17, { return RMASK6( 17) && (CHECK6("0:7fff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::7fff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_18, { return RMASK6( 18) && (CHECK6("0:3fff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::3fff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_19, { return RMASK6( 19) && (CHECK6("0:1fff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::1fff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_20, { return RMASK6( 20) && (CHECK6("0:fff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::fff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_21, { return RMASK6( 21) && (CHECK6("0:7ff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::7ff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_22, { return RMASK6( 22) && (CHECK6("0:3ff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::3ff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_23, { return RMASK6( 23) && (CHECK6("0:1ff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::1ff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_24, { return RMASK6( 24) && (CHECK6("0:ff:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::ff:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_25, { return RMASK6( 25) && (CHECK6("0:7f:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::7f:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_26, { return RMASK6( 26) && (CHECK6("0:3f:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::3f:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_27, { return RMASK6( 27) && (CHECK6("0:1f:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::1f:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_28, { return RMASK6( 28) && (CHECK6("0:f:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::f:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_29, { return RMASK6( 29) && (CHECK6("0:7:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::7:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_30, { return RMASK6( 30) && (CHECK6("0:3:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::3:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
EXO_TEST(ip6_rmask_create_31, { return RMASK6( 31) && (CHECK6("0:1:ffff:ffff:ffff:ffff:ffff:ffff") || CHECK6("::1:ffff:ffff:ffff:ffff:ffff:ffff")); });
|
||||
|
||||
EXO_TEST(check_ban_setup_1, {
|
||||
return ip_convert_to_binary("2001::201:2ff:fefa:0", &ban6.lo) &&
|
||||
ip_convert_to_binary("2001::201:2ff:fefa:ffff", &ban6.hi) &&
|
||||
ip_convert_to_binary("192.168.0.0", &ban4.lo) &&
|
||||
ip_convert_to_binary("192.168.0.255", &ban4.hi);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_1, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.0", &addr);
|
||||
return acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_2, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.1", &addr);
|
||||
return acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_3, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.255", &addr);
|
||||
return acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_4, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.1.0", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_5, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.167.255.255", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_1, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:0", &addr);
|
||||
return acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_2, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:1", &addr);
|
||||
return acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_3, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:fffe", &addr);
|
||||
return acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_4, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:ffff", &addr);
|
||||
return acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_5, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefb:0", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv6_6, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_afmix_1, {
|
||||
if (!ipv6) return 1;
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_afmix_2, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("10.20.30.40", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_1, {
|
||||
ip_convert_to_binary("255.255.255.255", &ip4_a);
|
||||
ip_convert_to_binary("255.255.255.0", &ip4_b);
|
||||
ip_mask_apply_AND(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "255.255.255.0");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_2, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.255.255.0", &ip4_b);
|
||||
ip_mask_apply_AND(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "192.168.217.0");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_3, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.255.0.0", &ip4_b);
|
||||
ip_mask_apply_AND(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "192.168.0.0");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_4, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.0.0.0", &ip4_b);
|
||||
ip_mask_apply_AND(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "192.0.0.0");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_5, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("0.0.0.0", &ip4_b);
|
||||
ip_mask_apply_AND(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "0.0.0.0");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_OR_1, {
|
||||
ip_convert_to_binary("255.255.255.255", &ip4_a);
|
||||
ip_convert_to_binary("255.255.255.0", &ip4_b);
|
||||
ip_mask_apply_OR(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "255.255.255.255");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_OR_2, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.255.255.0", &ip4_b);
|
||||
ip_mask_apply_OR(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "255.255.255.113");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_OR_3, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.255.0.0", &ip4_b);
|
||||
ip_mask_apply_OR(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "255.255.217.113");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_OR_4, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("255.0.0.0", &ip4_b);
|
||||
ip_mask_apply_OR(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "255.168.217.113");
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_OR_5, {
|
||||
ip_convert_to_binary("192.168.217.113", &ip4_a);
|
||||
ip_convert_to_binary("0.0.0.0", &ip4_b);
|
||||
ip_mask_apply_OR(&ip4_a, &ip4_b, &ip4_c);
|
||||
return !strcmp(ip_convert_to_string(&ip4_c), "192.168.217.113");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_AND_1, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7f7f:ffff:ffff:3f3f:ffff:ffff:ffff:ffff", &ip6_a);
|
||||
ip_convert_to_binary("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0", &ip6_b);
|
||||
ip_mask_apply_AND(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "7f7f:ffff:ffff:3f3f:ffff:ffff:ffff:0") ||
|
||||
!strcmp(ip_convert_to_string(&ip6_c), "7f7f:ffff:ffff:3f3f:ffff:ffff:ffff::");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_AND_2, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7777:cccc:3333:1111:ffff:ffff:ffff:ffff", &ip6_a);
|
||||
ip_convert_to_binary("ffff:ffff:ffff:ffff::", &ip6_b);
|
||||
ip_mask_apply_AND(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "7777:cccc:3333:1111::");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_AND_3, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7777:cccc:3333:1111:ffff:ffff:ffff:ffff", &ip6_a);
|
||||
ip_convert_to_binary("::", &ip6_b);
|
||||
ip_mask_apply_AND(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "::");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_OR_1, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7f7f:ffff:ffff:3f3f:ffff:ffff:ffff:ffff", &ip6_a);
|
||||
ip_convert_to_binary("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0", &ip6_b);
|
||||
ip_mask_apply_OR(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_OR_2, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7777:cccc:3333:1111:ffff:ffff:ffff:ffff", &ip6_a);
|
||||
ip_convert_to_binary("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0", &ip6_b);
|
||||
ip_mask_apply_OR(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
||||
});
|
||||
|
||||
EXO_TEST(ip6_bitwise_OR_3, {
|
||||
if (!ipv6) return 1;
|
||||
ip_convert_to_binary("7777:cccc:3333:1111:ffff:ffff:ffff:1c1c", &ip6_a);
|
||||
ip_convert_to_binary("::", &ip6_b);
|
||||
ip_mask_apply_OR(&ip6_a, &ip6_b, &ip6_c);
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "7777:cccc:3333:1111:ffff:ffff:ffff:1c1c");
|
||||
});
|
||||
|
||||
EXO_TEST(shutdown_network, {
|
||||
return net_shutdown() == 0;
|
||||
});
|
137
autotest/test_list.tcc
Normal file
137
autotest/test_list.tcc
Normal file
@ -0,0 +1,137 @@
|
||||
#include <uhub.h>
|
||||
|
||||
static struct linked_list* list = NULL;
|
||||
|
||||
static char A[2] = { 'A', 0 };
|
||||
static char B[2] = { 'B', 0 };
|
||||
static char C[2] = { 'C', 0 };
|
||||
|
||||
static void null_free(void* ptr)
|
||||
{
|
||||
(void) ptr;
|
||||
}
|
||||
|
||||
|
||||
EXO_TEST(list_create_destroy, {
|
||||
int ok = 0;
|
||||
struct linked_list* alist;
|
||||
alist = list_create();
|
||||
if (alist) ok = 1;
|
||||
list_destroy(alist);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(list_create, {
|
||||
list = list_create();
|
||||
return list->size == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(list_append_1, {
|
||||
list_append(list, (char*) A);
|
||||
return list->size == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(list_remove_1, {
|
||||
list_remove(list, (char*) A);
|
||||
return list->size == 0;
|
||||
});
|
||||
|
||||
|
||||
EXO_TEST(list_append_2, {
|
||||
list_append(list, A);
|
||||
list_append(list, B);
|
||||
return list->size == 2;
|
||||
});
|
||||
|
||||
EXO_TEST(list_remove_2, {
|
||||
list_remove(list, (char*) A);
|
||||
return list->size == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(list_remove_3, {
|
||||
list_remove(list, (char*) A); /* already removed, so should have no effect */
|
||||
return list->size == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(list_remove_4, {
|
||||
list_remove(list, (char*) B); /* already removed, so should have no effect */
|
||||
return list->size == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(list_append_3, {
|
||||
list_append(list, A);
|
||||
list_append(list, B);
|
||||
list_append(list, C);
|
||||
return list->size == 3;
|
||||
});
|
||||
|
||||
EXO_TEST(list_append_4, {
|
||||
list_append(list, A); /* OK. adding the same one *AGAIN* */
|
||||
return list->size == 4;
|
||||
});
|
||||
|
||||
EXO_TEST(list_remove_5, {
|
||||
list_remove(list, A); /* removing the first one. */
|
||||
return list->size == 3;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_index_1, {
|
||||
return list_get_index(list, 0) == B;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_index_2, {
|
||||
return list_get_index(list, 1) == C;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_index_3, {
|
||||
return list_get_index(list, 2) == A;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_index_4, {
|
||||
return list_get_index(list, 3) == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_first_1, {
|
||||
return list_get_first(list) == B;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_first_next_1, {
|
||||
return list_get_next(list) == C;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_first_next_2, {
|
||||
return list_get_next(list) == A;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_last_1, {
|
||||
return list_get_last(list) == A;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_last_prev_1, {
|
||||
return list_get_prev(list) == C;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_last_prev_2, {
|
||||
return list_get_prev(list) == B;
|
||||
});
|
||||
|
||||
EXO_TEST(list_get_last_prev_next_1, {
|
||||
return list_get_next(list) == C;
|
||||
});
|
||||
|
||||
EXO_TEST(list_clear, {
|
||||
list_clear(list, &null_free);
|
||||
return list->size == 0 && list->first == 0 && list->last == 0 && list->iterator == 0;
|
||||
});
|
||||
|
||||
|
||||
EXO_TEST(list_destroy_1, {
|
||||
list_destroy(list);
|
||||
return 1;
|
||||
});
|
||||
|
||||
EXO_TEST(list_destroy_2, {
|
||||
list_destroy(0);
|
||||
return 1;
|
||||
});
|
||||
|
37
autotest/test_memory.tcc
Normal file
37
autotest/test_memory.tcc
Normal file
@ -0,0 +1,37 @@
|
||||
#include <uhub.h>
|
||||
|
||||
struct adc_message* g_msg;
|
||||
|
||||
EXO_TEST(test_message_refc_1, {
|
||||
g_msg = adc_msg_create("IMSG Hello\\sWorld!");
|
||||
return g_msg != NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_2, {
|
||||
return g_msg->references == 0; // 0
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_3, {
|
||||
adc_msg_incref(g_msg);
|
||||
return g_msg->references == 1; // 1
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_4, {
|
||||
adc_msg_incref(g_msg);
|
||||
return g_msg->references == 2; // 2
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_5, {
|
||||
adc_msg_free(g_msg);
|
||||
return g_msg->references == 1; // 1
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_6, {
|
||||
adc_msg_free(g_msg);
|
||||
return g_msg->references == 0; // 0
|
||||
});
|
||||
|
||||
EXO_TEST(test_message_refc_7, {
|
||||
adc_msg_free(g_msg);
|
||||
return 1;
|
||||
});
|
521
autotest/test_message.tcc
Normal file
521
autotest/test_message.tcc
Normal file
@ -0,0 +1,521 @@
|
||||
#include <uhub.h>
|
||||
static struct user* g_user = 0;
|
||||
static const char* test_string1 = "IINF AAfoo BBbar CCwhat\n";
|
||||
static const char* test_string2 = "BMSG AAAB Hello\\sWorld!\n";
|
||||
static const char* test_string3 = "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1 AW\n";
|
||||
static const char* test_string4 = "BMSG AAAB\n";
|
||||
static const char* test_string5 = "BMSG AAAB \n";
|
||||
|
||||
static void create_test_user()
|
||||
{
|
||||
if (g_user)
|
||||
return;
|
||||
|
||||
g_user = (struct user*) malloc(sizeof(struct user));
|
||||
memset(g_user, 0, sizeof(struct user));
|
||||
memcpy(g_user->id.nick, "exotic-tester", 13);
|
||||
g_user->id.sid = 1;
|
||||
}
|
||||
|
||||
EXO_TEST(adc_message_parse_1, {
|
||||
struct adc_message* msg = adc_msg_create("IMSG Hello\\sWorld!");
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string2);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_3, {
|
||||
create_test_user();
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAB Hello\\sWorld!", 23);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_4, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAC Hello\\sWorld!", 23);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_5, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAB Hello\\sWorld!\n", 24);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_6, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +TCP4 Hello\\sWorld!\n", 30);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_7, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB -TCP4 Hello\\sWorld!\n", 30);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_8, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +TCP4+UDP4 Hello\\sWorld!\n", 35);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_9, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +TCP4-UDP4 Hello\\sWorld!\n", 35);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_10, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB -TCP4-UDP4 Hello\\sWorld!\n", 35);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_11, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB Hello\\sWorld!\n", 24);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_12, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB Hello\\sWorld!\n", 25);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_13, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +jalla Hello\\sWorld!\n", 31);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_14, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +jall Hello\\sWorld!\n", 30);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_15, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "FMSG AAAB +TCP4 Hello\\sWorld!\n", 30);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_16, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAB Hello\\sWorld!\n", 24);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_17, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG aaab Hello\\sWorld!\n", 24);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_18, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "DMSG AAAB AAAC Hello\\sthere!\n", 29);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_19, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "DMSG AAAC AAAB Hello\\sthere!\n", 29);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_20, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "EMSG AAAB AAAC Hello\\sthere!\n", 29);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
|
||||
EXO_TEST(adc_message_parse_21, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "EMSG AAAC AAAB Hello\\sthere!\n", 29);
|
||||
return msg == NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_add_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_add_argument(msg, "XXwtf?");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_add_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_add_named_argument(msg, "XX", "wtf?");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_remove_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "AA");
|
||||
int ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_remove_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "BB");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_remove_arg_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "CC");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_remove_arg_4, {
|
||||
/* this ensures we can remove the last element also */
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string3, strlen(test_string3));
|
||||
adc_msg_remove_named_argument(msg, "AW");
|
||||
int ok = strcmp(msg->cache, "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_replace_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "AA");
|
||||
int ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_replace_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "BB");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_replace_arg_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_remove_named_argument(msg, "CC");
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_argument(msg, 0);
|
||||
int ok = strcmp(c, "AAfoo") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_argument(msg, 1);
|
||||
int ok = strcmp(c, "BBbar") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_arg_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_argument(msg, 2);
|
||||
int ok = strcmp(c, "CCwhat") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_arg_4, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_argument(msg, 3);
|
||||
int ok = c == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_named_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_named_argument(msg, "AA");
|
||||
int ok = strcmp(c, "foo") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_named_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_named_argument(msg, "BB");
|
||||
int ok = strcmp(c, "bar") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_named_arg_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_named_argument(msg, "CC");
|
||||
int ok = strcmp(c, "what") == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_get_named_arg_4, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
char* c = adc_msg_get_named_argument(msg, "XX");
|
||||
int ok = c == 0;
|
||||
adc_msg_free(msg);
|
||||
hub_free(c);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_1, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
int n = adc_msg_has_named_argument(msg, "XX");
|
||||
adc_msg_free(msg);
|
||||
return n == 0;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
int n = adc_msg_has_named_argument(msg, "BB");
|
||||
adc_msg_free(msg);
|
||||
return n == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
int n = adc_msg_has_named_argument(msg, "CC");
|
||||
adc_msg_free(msg);
|
||||
return n == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_4, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_add_argument(msg, "XXwtf?");
|
||||
int n = adc_msg_has_named_argument(msg, "XX");
|
||||
adc_msg_free(msg);
|
||||
return n == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_5, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_add_argument(msg, "XXone");
|
||||
adc_msg_add_argument(msg, "XXtwo");
|
||||
int n = adc_msg_has_named_argument(msg, "XX");
|
||||
adc_msg_free(msg);
|
||||
return n == 2;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_6, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_add_argument(msg, "XXone");
|
||||
adc_msg_add_argument(msg, "XXtwo");
|
||||
adc_msg_add_argument(msg, "XXthree");
|
||||
int n = adc_msg_has_named_argument(msg, "XX");
|
||||
adc_msg_free(msg);
|
||||
return n == 3;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_has_named_arg_7, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
int n = adc_msg_has_named_argument(msg, "AA");
|
||||
adc_msg_free(msg);
|
||||
return n == 1;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_1, {
|
||||
struct adc_message* msg = adc_msg_create("IINF AAfoo BBbar CCwhat");
|
||||
adc_msg_unterminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_2, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_unterminate(msg);
|
||||
adc_msg_terminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_3, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_unterminate(msg);
|
||||
adc_msg_terminate(msg);
|
||||
adc_msg_unterminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_4, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_unterminate(msg);
|
||||
adc_msg_terminate(msg);
|
||||
adc_msg_terminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_5, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_terminate(msg);
|
||||
adc_msg_terminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_terminate_6, {
|
||||
struct adc_message* msg = adc_msg_create(test_string1);
|
||||
adc_msg_unterminate(msg);
|
||||
adc_msg_unterminate(msg);
|
||||
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_escape_1, {
|
||||
char* s = adc_msg_escape(test_string1);
|
||||
int ok = strcmp(s, "IINF\\sAAfoo\\sBBbar\\sCCwhat\\n") == 0;
|
||||
hub_free(s);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_escape_2, {
|
||||
char* s = adc_msg_escape(test_string1);
|
||||
char* s2 = adc_msg_unescape(s);
|
||||
int ok = strcmp(s2, test_string1) == 0;
|
||||
hub_free(s);
|
||||
hub_free(s2);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_escape_3, {
|
||||
char* s = adc_msg_unescape(test_string1);
|
||||
int ok = strcmp(s, test_string1) == 0;
|
||||
hub_free(s);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_copy_1, {
|
||||
struct adc_message* msg1 = adc_msg_create(test_string1);
|
||||
struct adc_message* msg2 = adc_msg_copy(msg1);
|
||||
int ok = strncmp(msg1->cache, msg2->cache, msg1->length) == 0;
|
||||
adc_msg_free(msg1);
|
||||
adc_msg_free(msg2);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_copy_2, {
|
||||
struct adc_message* msg1 = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
|
||||
struct adc_message* msg2 = adc_msg_copy(msg1);
|
||||
int ok = msg1->source == msg2->source;
|
||||
adc_msg_free(msg1);
|
||||
adc_msg_free(msg2);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_copy_3, {
|
||||
struct adc_message* msg1 = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
|
||||
struct adc_message* msg2 = adc_msg_copy(msg1);
|
||||
int ok = ( msg1->cmd == msg2->cmd &&
|
||||
msg1->source == msg2->source &&
|
||||
msg1->target == msg2->target &&
|
||||
msg1->length == msg2->length &&
|
||||
msg1->priority == msg2->priority &&
|
||||
msg1->capacity == msg2->capacity && /* might not be true! */
|
||||
strcmp(msg1->cache, msg2->cache) == 0);
|
||||
adc_msg_free(msg1);
|
||||
adc_msg_free(msg2);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_copy_4, {
|
||||
struct adc_message* msg1 = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
|
||||
struct adc_message* msg2 = adc_msg_copy(msg1);
|
||||
int ok = msg2->target == 0;
|
||||
adc_msg_free(msg1);
|
||||
adc_msg_free(msg2);
|
||||
return ok;
|
||||
});
|
||||
|
||||
|
||||
static struct adc_message* updater1 = NULL;
|
||||
static struct adc_message* updater2 = NULL;
|
||||
static const char* update_info1 = "BINF AAAB IDABCDEFGHIJKLMNOPQRSTUVWXYZ1234567ABCDEF NItester SL10 SS12817126127 SF4125 HN3 HR0 HO0 VE++\\s0.698 US104857600 DS81911808 SUTCP4,UDP4 I4127.0.0.1\n";
|
||||
static const char* update_info2 = "BINF AAAB HN34 SF4126 SS12817526127\n";
|
||||
|
||||
EXO_TEST(adc_message_update_1, {
|
||||
updater1 = adc_msg_parse_verify(g_user, update_info1, strlen(update_info1));
|
||||
return updater1 != NULL;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_update_2, {
|
||||
user_set_info(g_user, updater1);
|
||||
return strcmp(g_user->info->cache, updater1->cache) == 0 && g_user->info == updater1;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_update_3, {
|
||||
updater2 = adc_msg_parse_verify(g_user, update_info2, strlen(update_info2));
|
||||
return updater2 != NULL;
|
||||
});
|
||||
|
||||
extern void update_user_info(struct user* u, struct adc_message* cmd);
|
||||
|
||||
EXO_TEST(adc_message_update_4, {
|
||||
update_user_info(g_user, updater2);
|
||||
return strlen(g_user->info->cache) == 159;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_empty_1, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
|
||||
int ok = adc_msg_is_empty(msg) == 0;
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_empty_2, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string4, strlen(test_string4));
|
||||
int ok = adc_msg_is_empty(msg);
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_empty_3, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string5, strlen(test_string5));
|
||||
int ok = adc_msg_is_empty(msg) == 0; /* arguably not empty, contains a space */
|
||||
adc_msg_free(msg);
|
||||
return ok;
|
||||
});
|
||||
|
103
autotest/test_misc.tcc
Normal file
103
autotest/test_misc.tcc
Normal file
@ -0,0 +1,103 @@
|
||||
#include <uhub.h>
|
||||
|
||||
EXO_TEST(is_num_0, { return is_num('0'); });
|
||||
EXO_TEST(is_num_1, { return is_num('1'); });
|
||||
EXO_TEST(is_num_2, { return is_num('2'); });
|
||||
EXO_TEST(is_num_3, { return is_num('3'); });
|
||||
EXO_TEST(is_num_4, { return is_num('4'); });
|
||||
EXO_TEST(is_num_5, { return is_num('5'); });
|
||||
EXO_TEST(is_num_6, { return is_num('6'); });
|
||||
EXO_TEST(is_num_7, { return is_num('7'); });
|
||||
EXO_TEST(is_num_8, { return is_num('8'); });
|
||||
EXO_TEST(is_num_9, { return is_num('9'); });
|
||||
EXO_TEST(is_num_10, { return !is_num('/'); });
|
||||
EXO_TEST(is_num_11, { return !is_num(':'); });
|
||||
|
||||
EXO_TEST(is_space_1, { return is_space(' '); });
|
||||
EXO_TEST(is_space_2, { return !is_space('\t'); });
|
||||
EXO_TEST(is_white_space_1, { return is_white_space(' '); });
|
||||
EXO_TEST(is_white_space_2, { return is_white_space('\t'); });
|
||||
EXO_TEST(is_white_space_3, { return !is_white_space('A'); });
|
||||
EXO_TEST(is_white_space_4, { return !is_white_space('!'); });
|
||||
|
||||
EXO_TEST(itoa_1, { return strcmp(uhub_itoa(0), "0") == 0; });
|
||||
EXO_TEST(itoa_2, { return strcmp(uhub_itoa(1), "1") == 0; });
|
||||
EXO_TEST(itoa_3, { return strcmp(uhub_itoa(-1), "-1") == 0; });
|
||||
EXO_TEST(itoa_4, { return strcmp(uhub_itoa(255), "255") == 0; });
|
||||
EXO_TEST(itoa_5, { return strcmp(uhub_itoa(-3), "-3") == 0; });
|
||||
EXO_TEST(itoa_6, { return strcmp(uhub_itoa(-2147483647), "-2147483647") == 0; });
|
||||
EXO_TEST(itoa_7, { return strcmp(uhub_itoa(2147483647), "2147483647") == 0; });
|
||||
EXO_TEST(itoa_8, { return strcmp(uhub_itoa(-65536), "-65536") == 0; });
|
||||
|
||||
EXO_TEST(base32_valid_1, { return is_valid_base32_char('A'); });
|
||||
EXO_TEST(base32_valid_2, { return is_valid_base32_char('B'); });
|
||||
EXO_TEST(base32_valid_3, { return is_valid_base32_char('C'); });
|
||||
EXO_TEST(base32_valid_4, { return is_valid_base32_char('D'); });
|
||||
EXO_TEST(base32_valid_5, { return is_valid_base32_char('E'); });
|
||||
EXO_TEST(base32_valid_6, { return is_valid_base32_char('F'); });
|
||||
EXO_TEST(base32_valid_7, { return is_valid_base32_char('G'); });
|
||||
EXO_TEST(base32_valid_8, { return is_valid_base32_char('H'); });
|
||||
EXO_TEST(base32_valid_9, { return is_valid_base32_char('I'); });
|
||||
EXO_TEST(base32_valid_10, { return is_valid_base32_char('J'); });
|
||||
EXO_TEST(base32_valid_11, { return is_valid_base32_char('K'); });
|
||||
EXO_TEST(base32_valid_12, { return is_valid_base32_char('L'); });
|
||||
EXO_TEST(base32_valid_13, { return is_valid_base32_char('M'); });
|
||||
EXO_TEST(base32_valid_14, { return is_valid_base32_char('N'); });
|
||||
EXO_TEST(base32_valid_15, { return is_valid_base32_char('O'); });
|
||||
EXO_TEST(base32_valid_16, { return is_valid_base32_char('P'); });
|
||||
EXO_TEST(base32_valid_17, { return is_valid_base32_char('Q'); });
|
||||
EXO_TEST(base32_valid_18, { return is_valid_base32_char('R'); });
|
||||
EXO_TEST(base32_valid_19, { return is_valid_base32_char('S'); });
|
||||
EXO_TEST(base32_valid_20, { return is_valid_base32_char('T'); });
|
||||
EXO_TEST(base32_valid_21, { return is_valid_base32_char('U'); });
|
||||
EXO_TEST(base32_valid_22, { return is_valid_base32_char('V'); });
|
||||
EXO_TEST(base32_valid_23, { return is_valid_base32_char('W'); });
|
||||
EXO_TEST(base32_valid_24, { return is_valid_base32_char('X'); });
|
||||
EXO_TEST(base32_valid_25, { return is_valid_base32_char('Y'); });
|
||||
EXO_TEST(base32_valid_26, { return is_valid_base32_char('Z'); });
|
||||
EXO_TEST(base32_valid_27, { return is_valid_base32_char('2'); });
|
||||
EXO_TEST(base32_valid_28, { return is_valid_base32_char('3'); });
|
||||
EXO_TEST(base32_valid_29, { return is_valid_base32_char('4'); });
|
||||
EXO_TEST(base32_valid_30, { return is_valid_base32_char('5'); });
|
||||
EXO_TEST(base32_valid_31, { return is_valid_base32_char('6'); });
|
||||
EXO_TEST(base32_valid_32, { return is_valid_base32_char('7'); });
|
||||
|
||||
EXO_TEST(base32_invalid_1, { return !is_valid_base32_char('a'); });
|
||||
EXO_TEST(base32_invalid_2, { return !is_valid_base32_char('b'); });
|
||||
EXO_TEST(base32_invalid_3, { return !is_valid_base32_char('c'); });
|
||||
EXO_TEST(base32_invalid_4, { return !is_valid_base32_char('d'); });
|
||||
EXO_TEST(base32_invalid_5, { return !is_valid_base32_char('e'); });
|
||||
EXO_TEST(base32_invalid_6, { return !is_valid_base32_char('f'); });
|
||||
EXO_TEST(base32_invalid_7, { return !is_valid_base32_char('g'); });
|
||||
EXO_TEST(base32_invalid_8, { return !is_valid_base32_char('h'); });
|
||||
EXO_TEST(base32_invalid_9, { return !is_valid_base32_char('i'); });
|
||||
EXO_TEST(base32_invalid_10, { return !is_valid_base32_char('j'); });
|
||||
EXO_TEST(base32_invalid_11, { return !is_valid_base32_char('k'); });
|
||||
EXO_TEST(base32_invalid_12, { return !is_valid_base32_char('l'); });
|
||||
EXO_TEST(base32_invalid_13, { return !is_valid_base32_char('m'); });
|
||||
EXO_TEST(base32_invalid_14, { return !is_valid_base32_char('n'); });
|
||||
EXO_TEST(base32_invalid_15, { return !is_valid_base32_char('o'); });
|
||||
EXO_TEST(base32_invalid_16, { return !is_valid_base32_char('p'); });
|
||||
EXO_TEST(base32_invalid_17, { return !is_valid_base32_char('q'); });
|
||||
EXO_TEST(base32_invalid_18, { return !is_valid_base32_char('r'); });
|
||||
EXO_TEST(base32_invalid_19, { return !is_valid_base32_char('s'); });
|
||||
EXO_TEST(base32_invalid_20, { return !is_valid_base32_char('t'); });
|
||||
EXO_TEST(base32_invalid_21, { return !is_valid_base32_char('u'); });
|
||||
EXO_TEST(base32_invalid_22, { return !is_valid_base32_char('v'); });
|
||||
EXO_TEST(base32_invalid_23, { return !is_valid_base32_char('w'); });
|
||||
EXO_TEST(base32_invalid_24, { return !is_valid_base32_char('x'); });
|
||||
EXO_TEST(base32_invalid_25, { return !is_valid_base32_char('y'); });
|
||||
EXO_TEST(base32_invalid_26, { return !is_valid_base32_char('z'); });
|
||||
EXO_TEST(base32_invalid_27, { return !is_valid_base32_char('0'); });
|
||||
EXO_TEST(base32_invalid_28, { return !is_valid_base32_char('1'); });
|
||||
EXO_TEST(base32_invalid_29, { return !is_valid_base32_char('8'); });
|
||||
EXO_TEST(base32_invalid_30, { return !is_valid_base32_char('9'); });
|
||||
EXO_TEST(base32_invalid_31, { return !is_valid_base32_char('@'); });
|
||||
|
||||
EXO_TEST(utf8_valid_1, { return is_valid_utf8("abcdefghijklmnopqrstuvwxyz"); });
|
||||
EXO_TEST(utf8_valid_2, { return is_valid_utf8("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); });
|
||||
EXO_TEST(utf8_valid_3, { return is_valid_utf8("0123456789"); });
|
||||
EXO_TEST(utf8_valid_4, { return is_valid_utf8( (char[]) { 0x65, 0x00} ); });
|
||||
EXO_TEST(utf8_valid_5, { return !is_valid_utf8( (char[]) { 0xD8, 0x00} ); });
|
||||
|
||||
|
69
autotest/test_tiger.tcc
Normal file
69
autotest/test_tiger.tcc
Normal file
@ -0,0 +1,69 @@
|
||||
#include <uhub.h>
|
||||
|
||||
#define DEBUG_HASH
|
||||
|
||||
static char* byte_to_hex(char* dest, uint8_t c)
|
||||
{
|
||||
static const char* hexchars = "0123456789abcdef";
|
||||
*dest = hexchars[c / 16]; dest++;
|
||||
*dest = hexchars[c % 16]; dest++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
static int test_tiger_hex(char* input, char* expected) {
|
||||
char buf[TIGERSIZE*2+1];
|
||||
uint64_t tiger_res[3];
|
||||
int i = 0;
|
||||
#ifdef DEBUG_HASH
|
||||
int res = 0;
|
||||
#endif
|
||||
char* ptr = buf;
|
||||
buf[TIGERSIZE*2] = 0;
|
||||
|
||||
tiger((uint64_t*) input, strlen(input), (uint64_t*) tiger_res);
|
||||
for (i = 0; i < TIGERSIZE; i++)
|
||||
ptr = byte_to_hex(ptr, (char) (((uint8_t*) tiger_res)[i]) );
|
||||
|
||||
#ifdef DEBUG_HASH
|
||||
res = strcasecmp(buf, expected) == 0 ? 1 : 0;
|
||||
|
||||
if (!res)
|
||||
{
|
||||
printf("Expected: '%s', Got: '%s'\n", expected, buf);
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
return strcasecmp(buf, expected) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
EXO_TEST(hash_tiger_1, {
|
||||
return test_tiger_hex("", "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_2, {
|
||||
return test_tiger_hex("a", "77BEFBEF2E7EF8AB2EC8F93BF587A7FC613E247F5F247809");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_3, {
|
||||
return test_tiger_hex("abc", "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_4, {
|
||||
return test_tiger_hex("message digest", "D981F8CB78201A950DCF3048751E441C517FCA1AA55A29F6");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_5, {
|
||||
return test_tiger_hex("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "0F7BF9A19B9C58F2B7610DF7E84F0AC3A71C631E7B53F78E");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_6, {
|
||||
return test_tiger_hex("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "8DCEA680A17583EE502BA38A3C368651890FFBCCDC49A8CC");
|
||||
});
|
||||
|
||||
EXO_TEST(hash_tiger_7, {
|
||||
return test_tiger_hex("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "1C14795529FD9F207A958F84C52F11E887FA0CABDFD91BFD");
|
||||
});
|
||||
|
256
doc/Doxyfile
Normal file
256
doc/Doxyfile
Normal file
@ -0,0 +1,256 @@
|
||||
# Doxyfile 1.5.5-KDevelop
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = uHub
|
||||
PROJECT_NUMBER = 0.2.0-alpha
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
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 = YES
|
||||
INLINE_INHERITED_MEMB = YES
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = YES
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = 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_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = YES
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = autotest/*
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = YES
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
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 = YES
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = YES
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NONE
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
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 = NO
|
||||
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 = uhub.tag
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = NO
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = YES
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
91
doc/architecture.txt
Normal file
91
doc/architecture.txt
Normal file
@ -0,0 +1,91 @@
|
||||
= Architecture of uHub =
|
||||
|
||||
uHub is single threaded and handles network and timer events using the
|
||||
libevent library.
|
||||
For each state there is a read event (and sometimes a write event) and timeout
|
||||
event in case an expected read (or write) event does not occur.
|
||||
|
||||
|
||||
== Protocol overview ==
|
||||
uHub use "speak" the ADC protocol, which works in short as follows:
|
||||
(C = client, S = server aka uHub).
|
||||
|
||||
C: HSUP ADBASE
|
||||
Client connects to hub and supplies a list of supported features to the hub.
|
||||
|
||||
S: ISUP ADBASE { }
|
||||
Server responds with a list of supported features.
|
||||
|
||||
S: ISID xxxx
|
||||
Server assigns a session-ID to the client (4 bytes, BASE32 encoded).
|
||||
|
||||
C: BINF xxxx (...)
|
||||
Client sends information about itself, such as nick name, etc.
|
||||
The hub will relay this information to all users, including the client.
|
||||
|
||||
S: BINF xxx1 NInick1 (...)
|
||||
S: BINF xxx2 NInick2
|
||||
S: (...)
|
||||
S: BINF xxxx (client's own nick)
|
||||
Client gets list of other clients, which ends with the client's own user info.
|
||||
At this point the client is successfully logged into the hub.
|
||||
|
||||
|
||||
== The hub architecture ==
|
||||
|
||||
Accepting new users
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------- -----------------
|
||||
| Accept connection | <---------- | libevent loop |
|
||||
--------------------- -----------------
|
||||
|
|
||||
V
|
||||
--------------------- ------------
|
||||
| Setup login timer | --+----> | Timeout? | <----+
|
||||
--------------------- | ------------ |
|
||||
| | | |
|
||||
V | V |
|
||||
--------------------- | --------------- |
|
||||
| Receive 'HSUP' | --+----> | DISCONNECT! | |
|
||||
--------------------- --------------- |
|
||||
| ^ |
|
||||
V | |
|
||||
--------------------- | |
|
||||
| Send 'ISUP', and | | |
|
||||
| assign Session ID | | |
|
||||
--------------------- | |
|
||||
| | |
|
||||
V | |
|
||||
--------------------- | |
|
||||
| Receive 'BINF' |-----------------+------------
|
||||
+--| Validate message | ^
|
||||
| --------------------- |
|
||||
| | |
|
||||
| V |
|
||||
| --------------------- ---------------------
|
||||
| | Send password | ------> | Reveive and check |
|
||||
| | request, if needed| | password. |
|
||||
| --------------------- ---------------------
|
||||
| |
|
||||
| |
|
||||
| ------------------------ |
|
||||
+->| Send welcome message |<--------------+
|
||||
------------------------
|
||||
|
|
||||
V
|
||||
------------------------
|
||||
| Send user list to |
|
||||
| newly accepted user. |
|
||||
------------------------
|
||||
|
|
||||
V
|
||||
------------------------
|
||||
| User is logged in. |
|
||||
| Announce to all. |
|
||||
------------------------
|
||||
|
||||
|
76
doc/extensions.txt
Normal file
76
doc/extensions.txt
Normal file
@ -0,0 +1,76 @@
|
||||
ADC protocol extensions supported:
|
||||
|
||||
STATUS: **** Not yet implemented.
|
||||
|
||||
the 'AUT0' extension (network connection auto detection extension).
|
||||
Rationale: Detect if client is capable of initiating active connections.
|
||||
|
||||
After logging in:
|
||||
|
||||
Client -> 'HCHK 12345 ABCD'.
|
||||
|
||||
Server sends a UDP packet containing token to the client's IP address at the given port as shown in the INF message.
|
||||
|
||||
Server -> 'ICHK ABCD'
|
||||
|
||||
The server should send it from a UDP socket bound to the same port as the TCP server, which means the server will
|
||||
have to listen to both TCP and UDP.
|
||||
|
||||
If client receives the packet, it knows it can receive UDP connections, and will advertise it in the INF message as
|
||||
a supported feature.
|
||||
|
||||
If the client does not receive any UDP packets within a few seconds, it MAY try to reconfigure the router using
|
||||
UPnP/ZeroConf, and issue a HCHK command to the server again.
|
||||
|
||||
If the client still doesn't receive any UDP packets, hole punching can be tried.
|
||||
The server will send a UDP packet to the hub (using the port of the TCP server), and reissue the HCHK command.
|
||||
The UDP packet SHOULD be echoed by the hub.
|
||||
This UDP packet should contain simply 'HECH {cid} {token}' (Hub echo).
|
||||
|
||||
The hub should send a packet containing the token back:
|
||||
'IECH {token} {host:port}', aswell as the same message via TCP.
|
||||
|
||||
If the client receives the message via UDP, it should now be able to determine the type of NAT.
|
||||
If the client receives the message via TCP only it knows it has a firewall blocking icomming communication.
|
||||
If the client does not receive the message, it should assume a firewall is blocking all UDP communication,
|
||||
and resume in passive mode.
|
||||
|
||||
Requirements:
|
||||
'AUT0' in the extensions message (SUP) for client and hub.
|
||||
Server will also listen to UDP messages on the same port as the TCP port.
|
||||
|
||||
The server MUST now respond to the 'HCHK' command via TCP
|
||||
The server MUST now respond to the 'HECH' command via UDP.
|
||||
|
||||
The client will always initiate communication.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Syntax: HCHK {port} {token}
|
||||
- port is a 16-bit port number where the client is listening for packets.
|
||||
- token is 4 bytes base32 encoded data specified by the client.
|
||||
|
||||
Example:
|
||||
Client: 'HCHK 1511 BACD' (tcp)
|
||||
Server: 'ICHK BACD' (udp)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Syntax: HECH {cid} {token}
|
||||
- cid is the client ID.
|
||||
- token is 4 bytes base32 encoded data specified by the client.
|
||||
|
||||
Example:
|
||||
Client: 'HECH 3NGFVJUDBRHX2CYRJGQ5HACRDM5CTNLGZ36M64I BACD' (udp)
|
||||
Server: 'IECH BACD 192.168.0.1:1512' (udp)
|
||||
Server: 'IECH BACD 192.168.0.1:1512' (tcp)
|
||||
|
||||
Security considerations:
|
||||
The hub must verify that IP address where the HECH command originated from
|
||||
matches the IP address where the user with the given CID is connected from.
|
||||
If the CID and IP does not match, or the CID is not used the hub MUST ignore
|
||||
the request.
|
||||
|
||||
|
||||
|
||||
|
66
doc/uhub.conf
Normal file
66
doc/uhub.conf
Normal file
@ -0,0 +1,66 @@
|
||||
# uhub.conf - A example configuration file.
|
||||
# You should normally place this file in /etc/uhub/uhub.conf
|
||||
# And change the file_acl and file_motd below.
|
||||
#
|
||||
# This file is read only to the uhub deamon, and if you
|
||||
# make changes to it while uhub is running you can send a
|
||||
# HUP signal to it, to reparse configuration (only on UNIX).
|
||||
|
||||
# Bind to this port and address
|
||||
# server_bind_addr=any means listen to "::" if IPv6 is supported
|
||||
# by the host OS, otherwise 0.0.0.0.
|
||||
server_port=1511
|
||||
server_bind_addr=any
|
||||
|
||||
# The maximum amount of users allowed on the hub.
|
||||
max_users=500
|
||||
|
||||
# If 1, will show a "This hub is running uhub/version".
|
||||
show_banner=1
|
||||
|
||||
# Allow only registered users on the hub if set to 1.
|
||||
registered_users_only=0
|
||||
|
||||
# A server name and description.
|
||||
hub_name=my hub
|
||||
hub_description=Powered by uHub
|
||||
|
||||
# Set this to 0, and the hub will disconnect everyone
|
||||
hub_enabled=1
|
||||
|
||||
# Access control list (user database)
|
||||
file_acl=/etc/uhub/users.conf
|
||||
|
||||
# This file can contain a message of the day. A welcome
|
||||
# message send to any client when connecting.
|
||||
# If the file does not exist, is empty, or cannot be opened
|
||||
# the motd will not be sent to the clients.
|
||||
# Normally this message is sent to clients when connecting.
|
||||
file_motd=/etc/uhub/motd.txt
|
||||
|
||||
# Configure status message as sent to clients in different circumstances.
|
||||
msg_hub_full = Hub is full
|
||||
msg_hub_disabled = Hub is disabled
|
||||
msg_hub_registered_users_only = Hub is for registered users only
|
||||
msg_inf_error_nick_missing = No nickname given
|
||||
msg_inf_error_nick_multiple = Multiple nicknames given
|
||||
msg_inf_error_nick_invalid = Nickname is invalid
|
||||
msg_inf_error_nick_long = Nickname too long
|
||||
msg_inf_error_nick_short = Nickname too short
|
||||
msg_inf_error_nick_spaces = Nickname cannot start with spaces
|
||||
msg_inf_error_nick_bad_chars = Nickname contains invalid characters
|
||||
msg_inf_error_nick_not_utf8 = Nickname is not valid utf8
|
||||
msg_inf_error_nick_taken = Nickname is already in use
|
||||
msg_inf_error_nick_restricted = Nickname cannot be used on this hub
|
||||
msg_inf_error_cid_invalid = CID is not valid
|
||||
msg_inf_error_cid_missing = CID is not specified
|
||||
msg_inf_error_cid_taken = CID is taken
|
||||
msg_inf_error_pid_missing = PID is not specified
|
||||
msg_inf_error_pid_invalid = PID is invalid
|
||||
msg_ban_permanently = Banned permanently
|
||||
msg_ban_temporarily = Banned temporarily
|
||||
msg_auth_invalid_password = Password is wrong
|
||||
msg_auth_user_not_found = User not found in password database
|
||||
msg_error_no_memory = No memory
|
||||
|
||||
|
59
doc/uhub.dot
Normal file
59
doc/uhub.dot
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Overview of uHub
|
||||
*/
|
||||
digraph G
|
||||
{
|
||||
|
||||
"main()" -> "event_dispatch()"
|
||||
|
||||
"event_dispatch()" -> "net_on_accept()"
|
||||
"event_dispatch()" -> "net_on_read()"
|
||||
"event_dispatch()" -> "net_on_write()"
|
||||
"event_dispatch()" -> "event_queue_process()"
|
||||
|
||||
/* net events */
|
||||
"net_on_write()" -> "net_send()"
|
||||
"net_on_write()" -> "user_disconnect()"
|
||||
"net_on_accept()" -> "user_create()"
|
||||
"net_on_read()" -> "net_recv()"
|
||||
"net_on_read()" -> "user_disconnect()"
|
||||
|
||||
"net_recv()" -> "hub_handle_message()"
|
||||
|
||||
/* adc message handling */
|
||||
"hub_handle_message()" -> "hub_handle_password()"
|
||||
"hub_handle_message()" -> "hub_handle_support()"
|
||||
|
||||
"hub_handle_password()" -> "user_disconnect()"
|
||||
"hub_handle_support()" -> "user_disconnect()"
|
||||
"hub_handle_password()" -> "route_to_user()"
|
||||
"hub_handle_support()" -> "route_to_user()"
|
||||
|
||||
"hub_handle_message()" -> "hub_handle_info()"
|
||||
"hub_handle_message()" -> "route_message()"
|
||||
"hub_handle_info()" -> "route_to_user()"
|
||||
"hub_handle_info()" -> "route_to_all()"
|
||||
|
||||
/* message routing, depending on message type */
|
||||
"route_message()" -> "route_to_user()"
|
||||
"route_message()" -> "route_to_all()" -> "route_to_user()"
|
||||
"route_message()" -> "route_to_subscribers()" -> "route_to_user()"
|
||||
|
||||
"route_to_user()" -> "net_send()"
|
||||
"route_to_user()" -> "queue_command()"
|
||||
"route_to_user()" -> "user_disconnect()"
|
||||
|
||||
|
||||
/* Message dispatcher */
|
||||
"event_queue_process()" -> "hub_event_dispatcher()"
|
||||
"hub_event_dispatcher()" -> "EVENT_USER_JOIN"
|
||||
"hub_event_dispatcher()" -> "EVENT_USER_QUIT"
|
||||
"EVENT_USER_QUIT" -> "route_to_all()"
|
||||
"EVENT_USER_QUIT" -> "user_destroy()"
|
||||
"EVENT_USER_JOIN" -> "route_to_all()"
|
||||
|
||||
/* user_disconnect() -- critical part */
|
||||
"user_disconnect()" -> "user_set_state(state_cleanup)" -> "post: EVENT_USER_QUIT"
|
||||
"user_disconnect()" -> "user_destroy()"
|
||||
|
||||
}
|
51
doc/users.conf
Normal file
51
doc/users.conf
Normal file
@ -0,0 +1,51 @@
|
||||
# uHub access control lists.
|
||||
#
|
||||
# Syntax: <command> [data]
|
||||
#
|
||||
# commands:
|
||||
# 'user_reg' - registered user with no particular privileges (data=nick:password)
|
||||
# 'user_op' - operator, can kick or ban people (data=nick:password)
|
||||
# 'user_admin' - administrator, can do everything operators can, and reconfigure the hub (data=nick:password)
|
||||
# 'deny_nick' - nick name that is not accepted (example; Administrator)
|
||||
# 'deny_ip' - Unacceptable IP (masks can be specified as CIDR: 0.0.0.0/32 will block all IPv4)
|
||||
# 'ban_nick' - banned user by nick
|
||||
# 'ban_cid' - banned user by cid
|
||||
|
||||
# Administrator
|
||||
user_admin Dj_Offset:uhub
|
||||
user_op janvidar:password
|
||||
|
||||
# We don't want users with these names
|
||||
deny_nick Hub-Security
|
||||
deny_nick Administrator
|
||||
deny_nick root
|
||||
deny_nick admin
|
||||
deny_nick username
|
||||
deny_nick user
|
||||
deny_nick guest
|
||||
deny_nick operator
|
||||
|
||||
# Banned users
|
||||
# ban_nick H4X0R
|
||||
# ban_cid FOIL5EK2UDZYAXT7UIUFEKL4SEBEAJE3INJDKAY
|
||||
|
||||
# ban by ip
|
||||
#
|
||||
# to ban by CIDR
|
||||
# deny_ip 10.21.44.0/24
|
||||
#
|
||||
# to ban by IP-range.
|
||||
# deny_ip 10.21.44.7-10.21.44.9
|
||||
#
|
||||
# to ban a single IP address
|
||||
# deny_ip 10.21.44.7
|
||||
# (which is equivalent to using):
|
||||
# deny_ip 10.21.44.7/32
|
||||
|
||||
# Will not work, yet
|
||||
# nat_ip 10.0.0.0/8
|
||||
# nat_ip 127.0.0.0/8
|
||||
|
||||
# If you have made changes to this file, you must send a HANGUP signal
|
||||
# to uHub so that it will re-read the configuration files.
|
||||
# For example by invoking: 'killall -HUP uhub'
|
29
release_setup.mk
Normal file
29
release_setup.mk
Normal file
@ -0,0 +1,29 @@
|
||||
ifeq ($(RELEASE),YES)
|
||||
HOST_SYSTEM ?= $(shell uname -s | tr [:upper:] [:lower:] | sed s/darwin/macosx/ )
|
||||
|
||||
ifeq ($(HOST_SYSTEM), macosx)
|
||||
HOST_MACHINE ?= $(shell uname -p | tr [:upper:] [:lower:] )
|
||||
else
|
||||
HOST_MACHINE ?= $(shell uname -m | tr [:upper:] [:lower:] | sed s/i686/i386/ | sed s/x86_64/amd64/ | sed s/ppc64/powerpc/ )
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_SYSTEM), mingw32_nt-5.1)
|
||||
HOST_SYSTEM = win32
|
||||
endif
|
||||
|
||||
VERSION ?= $(shell grep define\ VERSION version.h | cut -f 3 -d " " | tr -d [=\"=] )
|
||||
SNAPSHOT ?= $(shell date '+%Y%m%d' )
|
||||
|
||||
REVISION ?= $(shell svn info | grep Revision | tr -d [:alpha:][:punct:][:space:] )
|
||||
PACKAGE ?= uhub-$(VERSION)-$(REVISION)
|
||||
PACKAGE_SRC ?= $(PACKAGE)-src
|
||||
PACKAGE_BIN ?= $(PACKAGE)-$(HOST_SYSTEM)-$(HOST_MACHINE)
|
||||
|
||||
URL_ARCHIVE='build-archive:~/uhub/'
|
||||
URL_PUBLISH='domeneshop:~/www/downloads/uhub/'
|
||||
URL_SNAPSHOT='domeneshop:~/www/downloads/uhub/snapshots/'
|
||||
|
||||
else
|
||||
autotest_TMP = autotest.c
|
||||
endif
|
||||
|
80
release_targets.mk
Normal file
80
release_targets.mk
Normal file
@ -0,0 +1,80 @@
|
||||
autotest.c: $(autotest_SOURCES)
|
||||
$(shell exotic --standalone $(autotest_SOURCES) > $@)
|
||||
|
||||
ifeq ($(RELEASE),YES)
|
||||
|
||||
%.tar.bz2: %.tar
|
||||
@bzip2 -c -9 $^ > $@
|
||||
|
||||
%.tar.gz: %.tar
|
||||
@gzip -c -9 $^ > $@
|
||||
|
||||
ChangeLog-$(VERSION)-$(REVISION): ChangeLog
|
||||
@cp $^ $@
|
||||
|
||||
changelog: ChangeLog-$(VERSION)-$(REVISION)
|
||||
|
||||
$(PACKAGE_SRC).tar $(PACKAGE_SRC).zip: autotest.c
|
||||
@if [ -d $(PACKAGE) ]; then rm -Rf $(PACKAGE); fi
|
||||
@svn export . $(PACKAGE) > /dev/null
|
||||
@rm -f $(PACKAGE)/release_*.mk
|
||||
@grep -v \\-include $(PACKAGE)/GNUmakefile > $(PACKAGE)/GNUmakefile2
|
||||
@mv $(PACKAGE)/GNUmakefile2 $(PACKAGE)/GNUmakefile
|
||||
@mv $< $(PACKAGE)
|
||||
@tar cf $(PACKAGE_SRC).tar $(PACKAGE)
|
||||
@zip -r $(PACKAGE_SRC).zip $(PACKAGE)
|
||||
@rm -Rf $(PACKAGE)
|
||||
|
||||
$(PACKAGE_BIN).tar: clean $(uhub_BINARY)
|
||||
@if [ -d $(PACKAGE) ]; then rm -Rf $(PACKAGE); fi
|
||||
@svn export . $(PACKAGE) > /dev/null
|
||||
@rm -Rf $(PACKAGE)/src $(PACKAGE)/autotest $(PACKAGE)/*akefile $(PACKAGE)/$(LIBUHUB) $(PACKAGE)/release_*.mk $(PACKAGE)/version.h
|
||||
@cp $(uhub_BINARY) $(PACKAGE)
|
||||
@tar cf $@ $(PACKAGE)
|
||||
@rm -Rf $(PACKAGE)
|
||||
|
||||
$(PACKAGE_BIN).zip: clean $(uhub_BINARY)
|
||||
@if [ -d $(PACKAGE) ]; then rm -Rf $(PACKAGE); fi
|
||||
@svn export . $(PACKAGE) > /dev/null
|
||||
@rm -Rf $(PACKAGE)/src $(PACKAGE)/autotest $(PACKAGE)/*akefile $(PACKAGE)/$(LIBUHUB) $(PACKAGE)/release_*.mk $(PACKAGE)/version.h
|
||||
@cp $(uhub_BINARY) $(PACKAGE)
|
||||
@zip -r $@ $(PACKAGE)
|
||||
@rm -Rf $(PACKAGE)
|
||||
|
||||
$(PACKAGE_SRC).tar.gz: $(PACKAGE_SRC).tar
|
||||
|
||||
$(PACKAGE_SRC).tar.bz2: $(PACKAGE_SRC).tar
|
||||
|
||||
$(PACKAGE_BIN).tar.gz: $(PACKAGE_BIN).tar
|
||||
|
||||
$(PACKAGE_BIN).tar.bz2: $(PACKAGE_BIN).tar
|
||||
|
||||
snapshot: tarballs
|
||||
@mv $(PACKAGE_SRC).tar.gz uhub-snapshot-$(SNAPSHOT).tar.gz
|
||||
@rm $(PACKAGE_SRC).tar.bz2
|
||||
|
||||
publish-snapshot: snapshot
|
||||
@scp -q uhub-snapshot-$(SNAPSHOT).tar.gz $(URL_SNAPSHOT)
|
||||
|
||||
publish: release
|
||||
@scp -q $(PACKAGE_SRC).tar.gz $(PACKAGE_SRC).tar.bz2 $(PACKAGE_BIN).tar.gz $(PACKAGE_BIN).tar.bz2 ChangeLog-$(VERSION)-$(REVISION) $(URL_PUBLISH)
|
||||
|
||||
tarballs: $(PACKAGE_SRC).tar.gz $(PACKAGE_SRC).tar.bz2 $(PACKAGE_SRC).zip
|
||||
@rm $(PACKAGE_SRC).tar
|
||||
|
||||
ifeq ($(WINDOWS), YES)
|
||||
binaries: $(PACKAGE_BIN).tar.gz $(PACKAGE_BIN).tar.bz2 $(PACKAGE_BIN).zip
|
||||
@rm $(PACKAGE_BIN).tar
|
||||
|
||||
else
|
||||
binaries: $(PACKAGE_BIN).tar.gz $(PACKAGE_BIN).tar.bz2
|
||||
@rm $(PACKAGE_BIN).tar
|
||||
endif
|
||||
|
||||
release: binaries tarballs changelog
|
||||
|
||||
else
|
||||
|
||||
|
||||
endif
|
||||
|
142
src/adcconst.h
Normal file
142
src/adcconst.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_ADC_CONSTANTS_H
|
||||
#define HAVE_UHUB_ADC_CONSTANTS_H
|
||||
|
||||
typedef uint32_t sid_t;
|
||||
typedef uint32_t fourcc_t;
|
||||
|
||||
/* Internal uhub limit */
|
||||
#define MAX_ADC_CMD_LEN 4096
|
||||
|
||||
#define FOURCC(a,b,c,d) (fourcc_t) ((a << 24) | (b << 16) | (c << 8) | d)
|
||||
|
||||
/* default welcome protocol support message, as sent by this server */
|
||||
#define ADC_PROTO_SUPPORT "ADBASE ADTIGR ADPING"
|
||||
|
||||
/* Server sent commands */
|
||||
#define ADC_CMD_ISID FOURCC('I','S','I','D')
|
||||
#define ADC_CMD_ISUP FOURCC('I','S','U','P')
|
||||
#define ADC_CMD_IGPA FOURCC('I','G','P','A')
|
||||
#define ADC_CMD_ISTA FOURCC('I','S','T','A')
|
||||
#define ADC_CMD_IINF FOURCC('I','I','N','F')
|
||||
#define ADC_CMD_IMSG FOURCC('I','M','S','G')
|
||||
#define ADC_CMD_IQUI FOURCC('I','Q','U','I')
|
||||
|
||||
/* Handshake and login/passwordstuff */
|
||||
#define ADC_CMD_HSUP FOURCC('H','S','U','P')
|
||||
#define ADC_CMD_HPAS FOURCC('H','P','A','S')
|
||||
#define ADC_CMD_HINF FOURCC('H','I','N','F')
|
||||
#define ADC_CMD_BINF FOURCC('B','I','N','F')
|
||||
|
||||
/* This is a Admin extension */
|
||||
#define ADC_CMD_HDSC FOURCC('H','D','S','C')
|
||||
|
||||
/* Status/error messages */
|
||||
#define ADC_CMD_HSTA FOURCC('H','S','T','A')
|
||||
#define ADC_CMD_DSTA FOURCC('D','S','T','A')
|
||||
|
||||
/* searches */
|
||||
#define ADC_CMD_BSCH FOURCC('B','S','C','H')
|
||||
#define ADC_CMD_DSCH FOURCC('D','S','C','H')
|
||||
#define ADC_CMD_ESCH FOURCC('E','S','C','H')
|
||||
#define ADC_CMD_FSCH FOURCC('F','S','C','H')
|
||||
#define ADC_CMD_DRES FOURCC('D','R','E','S')
|
||||
|
||||
/* connection setup */
|
||||
#define ADC_CMD_DCTM FOURCC('D','C','T','M')
|
||||
#define ADC_CMD_DRCM FOURCC('D','R','C','M')
|
||||
#define ADC_CMD_ECTM FOURCC('E','C','T','M')
|
||||
#define ADC_CMD_ERCM FOURCC('E','R','C','M')
|
||||
|
||||
/* chat messages */
|
||||
#define ADC_CMD_BMSG FOURCC('B','M','S','G')
|
||||
#define ADC_CMD_DMSG FOURCC('D','M','S','G')
|
||||
#define ADC_CMD_EMSG FOURCC('E','M','S','G')
|
||||
#define ADC_CMD_FMSG FOURCC('F','M','S','G')
|
||||
|
||||
/* disallowed messages */
|
||||
#define ADC_CMD_DINF FOURCC('D','I','N','F')
|
||||
#define ADC_CMD_EINF FOURCC('E','I','N','F')
|
||||
#define ADC_CMD_FINF FOURCC('F','I','N','F')
|
||||
|
||||
/* Extension messages */
|
||||
#define ADC_CMD_HCHK FOURCC('H','C','H','K')
|
||||
|
||||
#define ADC_INF_FLAG_IPV4_ADDR "I4" /* ipv4 address */
|
||||
#define ADC_INF_FLAG_IPV6_ADDR "I6" /* ipv6 address */
|
||||
#define ADC_INF_FLAG_IPV4_UDP_PORT "U4" /* port number */
|
||||
#define ADC_INF_FLAG_IPV6_UDP_PORT "U6" /* port number */
|
||||
#define ADC_INF_FLAG_CLIENT_TYPE "CT" /* client type */
|
||||
#define ADC_INF_FLAG_PRIVATE_ID "PD" /* private id, aka PID */
|
||||
#define ADC_INF_FLAG_CLIENT_ID "ID" /* client id, aka CID */
|
||||
#define ADC_INF_FLAG_NICK "NI" /* nick name */
|
||||
#define ADC_INF_FLAG_DESCRIPTION "DE" /* user description */
|
||||
#define ADC_INF_FLAG_USER_AGENT "VE" /* software version */
|
||||
#define ADC_INF_FLAG_SUPPORT "SU" /* support (extensions, feature cast) */
|
||||
#define ADC_INF_FLAG_SHARED_SIZE "SS" /* size of total files shared in bytes */
|
||||
#define ADC_INF_FLAG_SHARED_FILES "SF" /* number of files shared */
|
||||
#define ADC_INF_FLAG_UPLOAD_SPEED "US" /* maximum upload speed acheived in bytes/sec */
|
||||
#define ADC_INF_FLAG_DOWNLOAD_SPEED "DS" /* maximum download speed acheived in bytes/sec */
|
||||
#define ADC_INF_FLAG_UPLOAD_SLOTS "SL" /* maximum upload slots (concurrent uploads) */
|
||||
#define ADC_INF_FLAG_AUTO_SLOTS "AS" /* automatic slot if upload speed is less than this in bytes/sec */
|
||||
#define ADC_INF_FLAG_AUTO_SLOTS_MAX "AM" /* maximum number of automatic slots */
|
||||
#define ADC_INF_FLAG_COUNT_HUB_NORMAL "HN" /* user is logged into this amount of hubs as a normal user (guest) */
|
||||
#define ADC_INF_FLAG_COUNT_HUB_REGISTER "HR" /* user is logged into this amount of hubs as a registered user (password) */
|
||||
#define ADC_INF_FLAG_COUNT_HUB_OPERATOR "HO" /* user is logged into this amount of hubs as an operator */
|
||||
#define ADC_INF_FLAG_AWAY "AW" /* away flag, 1=away, 2=extended away */
|
||||
#define ADC_INF_FLAG_REFERER "RF" /* URL to referer in case of hub redirect */
|
||||
#define ADC_INF_FLAG_EMAIL "EM" /* E-mail address */
|
||||
|
||||
#define ADC_MSG_FLAG_ACTION "ME" /* message is an *action* message */
|
||||
#define ADC_MSG_FLAG_PRIVATE "PM" /* message is a private message */
|
||||
|
||||
#define ADC_SCH_FLAG_INCLUDE "AN" /* include given search term */
|
||||
#define ADC_SCH_FLAG_EXCLUDE "NO" /* exclude given serach term */
|
||||
#define ADC_SCH_FLAG_FILE_EXTENSION "EX" /* search only for files with the given file extension */
|
||||
#define ADC_SCH_FLAG_FILE_TYPE "TY" /* search only for files with this file type (separate type) */
|
||||
#define ADC_SCH_FLAG_LESS_THAN "LE" /* search for files with this size or less */
|
||||
#define ADC_SCH_FLAG_GREATER_THAN "GE" /* search for files with this size or greater */
|
||||
#define ADC_SCH_FLAG_EQUAL "EQ" /* search only for files with this exact size */
|
||||
#define ADC_SCH_FLAG_TOKEN "TO" /* use this token for search replies */
|
||||
|
||||
#define ADC_RES_FLAG_FILE_NAME "FN" /* file name */
|
||||
#define ADC_RES_FLAG_FILE_SIZE "SI" /* file size */
|
||||
#define ADC_RES_FLAG_UPLOAD_SLOTS "SL" /* number of upload slots available (if > 0, download is possible) */
|
||||
#define ADC_RES_FLAG_TOKEN "TO" /* token, same as the token in the search request */
|
||||
|
||||
#define ADC_QUI_FLAG_TIME_LEFT "TL" /* time in seconds before reconnect is allowed, or -1 forever */
|
||||
#define ADC_QUI_FLAG_MESSAGE "MS" /* kick/leave message */
|
||||
#define ADC_QUI_FLAG_DISCONNECT "DI" /* all further transfers with this user should be disconnected */
|
||||
#define ADC_QUI_FLAG_REDIRECT "RD" /* redirect to URL */
|
||||
#define ADC_QUI_FLAG_KICK_OPERATOR "ID" /* SID of operator who disconnected the user */
|
||||
|
||||
#define ADC_SUP_FLAG_ADD "AD"
|
||||
#define ADC_SUP_FLAG_REMOVE "RM"
|
||||
|
||||
#define ADC_CLIENT_TYPE_BOT "1"
|
||||
#define ADC_CLIENT_TYPE_REGISTERED_USER "2"
|
||||
#define ADC_CLIENT_TYPE_OPERATOR "4"
|
||||
#define ADC_CLIENT_TYPE_SUPER_USER "8"
|
||||
#define ADC_CLIENT_TYPE_ADMIN "16" /* hub owner */
|
||||
#define ADC_CLIENT_TYPE_HUB "32" /* the hub itself */
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_ADC_CONSTANTS_H */
|
950
src/adcrush.c
Normal file
950
src/adcrush.c
Normal file
@ -0,0 +1,950 @@
|
||||
/**
|
||||
* An ADC client emulator.
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#define ADC_CLIENTS_DEFAULT 100
|
||||
#define ADC_MAX_CLIENTS 25000
|
||||
|
||||
#define ADC_BUFSIZE 16384
|
||||
#define ADC_SIDSIZE 4
|
||||
#define ADC_CID_SIZE 39
|
||||
|
||||
#define BIG_BUFSIZE 131072
|
||||
#define TIGERSIZE 24
|
||||
|
||||
#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR\n"
|
||||
#define ADCRUSH "adcrush/0.2"
|
||||
#define ADC_NICK "[BOT]adcrush"
|
||||
#define ADC_DESC "crash\\stest\\sdummy"
|
||||
|
||||
struct ADC_client;
|
||||
|
||||
static void ADC_client_on_disconnected(struct ADC_client*);
|
||||
static void ADC_client_on_connected(struct ADC_client*);
|
||||
static void ADC_client_on_login(struct ADC_client*);
|
||||
static void ADC_client_connect(struct ADC_client*);
|
||||
static void ADC_client_disconnect(struct ADC_client*);
|
||||
static int ADC_client_create(struct ADC_client* client, int num);
|
||||
static void ADC_client_destroy(struct ADC_client* client);
|
||||
|
||||
static int cfg_mode = 0; // See enum operationMode
|
||||
static char* cfg_host = 0;
|
||||
static int cfg_port = 0;
|
||||
static int cfg_debug = 0; /* debug level */
|
||||
static int cfg_level = 1; /* activity level (0..3) */
|
||||
static int cfg_chat = 0; /* chat mode, allow sending chat messages */
|
||||
static int cfg_quiet = 0; /* quiet mode (no output) */
|
||||
static int cfg_clients = ADC_CLIENTS_DEFAULT; /* number of clients */
|
||||
|
||||
static int running = 1;
|
||||
|
||||
static struct sockaddr_in saddr;
|
||||
|
||||
enum commandMode
|
||||
{
|
||||
cm_bcast = 0x01, /* B - broadcast */
|
||||
cm_dir = 0x02, /* D - direct message */
|
||||
cm_echo = 0x04, /* E - echo message */
|
||||
cm_fcast = 0x08, /* F - feature cast message */
|
||||
cm_c2h = 0x10, /* H - client to hub message */
|
||||
cm_h2c = 0x20, /* I - hub to client message */
|
||||
cm_c2c = 0x40, /* C - client to client message */
|
||||
cm_udp = 0x80, /* U - udp message (client to client) */
|
||||
};
|
||||
|
||||
enum commandValidity
|
||||
{
|
||||
cv_protocol = 0x01,
|
||||
cv_identify = 0x02,
|
||||
cv_verify = 0x04,
|
||||
cv_normal = 0x08,
|
||||
};
|
||||
|
||||
enum protocolState
|
||||
{
|
||||
ps_none = 0x00, /* none or disconnected */
|
||||
ps_conn = 0x01, /* connecting... */
|
||||
ps_protocol = 0x02,
|
||||
ps_identify = 0x04,
|
||||
ps_verify = 0x08,
|
||||
ps_normal = 0x10,
|
||||
};
|
||||
|
||||
enum operationMode
|
||||
{
|
||||
mode_performance = 0x01,
|
||||
mode_bugs = 0x02,
|
||||
mode_security = 0x04,
|
||||
mode_log = 0x08,
|
||||
};
|
||||
|
||||
struct commandPattern
|
||||
{
|
||||
unsigned char mode; /* see enum commandMode */
|
||||
char cmd[3];
|
||||
unsigned char validity; /* see enum commandValidity */
|
||||
};
|
||||
|
||||
const struct commandPattern patterns[] =
|
||||
{
|
||||
{ cm_c2h | cm_c2c | cm_h2c, "SUP", cv_protocol | cv_normal }, /* protocol support */
|
||||
{ cm_bcast | cm_h2c | cm_c2c, "INF", cv_identify | cv_verify | cv_normal }, /* info message */
|
||||
{ cm_bcast | cm_h2c | cm_c2c | cm_c2h | cm_udp, "STA", cv_protocol | cv_identify | cv_verify | cv_normal }, /* status message */
|
||||
{ cm_bcast | cm_dir | cm_echo | cm_h2c, "MSG", cv_normal }, /* chat message */
|
||||
{ cm_bcast | cm_dir | cm_echo | cm_fcast, "SCH", cv_normal }, /* search */
|
||||
{ cm_dir | cm_udp, "RES", cv_normal }, /* search result */
|
||||
{ cm_dir | cm_echo, "CTM", cv_normal }, /* connect to me */
|
||||
{ cm_dir | cm_echo, "RCM", cv_normal }, /* reversed, connect to me */
|
||||
{ cm_h2c, "QUI", cv_normal }, /* quit message */
|
||||
{ cm_h2c, "GPA", cv_identify }, /* password request */
|
||||
{ cm_c2h, "PAS", cv_verify } /* password response */
|
||||
};
|
||||
|
||||
#define MAX_CHAT_MSGS 35
|
||||
const char* chat_messages[MAX_CHAT_MSGS] = {
|
||||
"hello",
|
||||
"I'm an annoying robot, configured to chat in order to measure performance of the hub.",
|
||||
"I apologize for the inconvenience.",
|
||||
".",
|
||||
":)",
|
||||
"can anyone help me, pls?",
|
||||
"wtf?",
|
||||
"bullshit",
|
||||
"resistance is futile.",
|
||||
"You crossed the line first, sir. You squeezed them, you hammered them to the point of desperation. And in their desperation they turned to a man they didn't fully understand.",
|
||||
"beam me up, scotty",
|
||||
"morning",
|
||||
"You know where Harvey is? You know who he is?",
|
||||
"gtg",
|
||||
"thanks",
|
||||
"*punt*",
|
||||
"*nudge*",
|
||||
"that's ok",
|
||||
"...anyway",
|
||||
"hola",
|
||||
"hey",
|
||||
"hi",
|
||||
"nevermind",
|
||||
"i think so",
|
||||
"dunno",
|
||||
"debian ftw",
|
||||
"oops",
|
||||
"how do I search?",
|
||||
"how do I enable active mode?",
|
||||
"home, sweet home...",
|
||||
"later",
|
||||
"Good evening, ladies and gentlemen. We are tonight's entertainment! I only have one question. Where is Harvey Dent?",
|
||||
"You know where I can find Harvey? I need to talk to him about something. Just something, a little.",
|
||||
"We really should stop fighting, we'll miss the fireworks!",
|
||||
"Wanna know how I got these scars?",
|
||||
};
|
||||
|
||||
#define MAX_SEARCH_MSGS 10
|
||||
const char* search_messages[MAX_SEARCH_MSGS] = {
|
||||
"ANmp3 TOauto",
|
||||
"ANxxx TOauto",
|
||||
"ANdivx TOauto",
|
||||
"ANtest ANfoo TOauto",
|
||||
"ANwmv TO1289718",
|
||||
"ANbabe TO8981884",
|
||||
"ANpr0n TOauto",
|
||||
"ANmusic TOauto",
|
||||
"ANvideo TOauto",
|
||||
"ANburnout ANps3 TOauto",
|
||||
};
|
||||
|
||||
struct ADC_client
|
||||
{
|
||||
int sd;
|
||||
int num;
|
||||
sid_t sid;
|
||||
enum protocolState state;
|
||||
char info[ADC_BUFSIZE];
|
||||
char recvbuf[BIG_BUFSIZE];
|
||||
char sendbuf[BIG_BUFSIZE];
|
||||
size_t s_offset;
|
||||
size_t r_offset;
|
||||
struct event ev_read;
|
||||
struct event ev_write;
|
||||
struct event ev_timer;
|
||||
size_t timeout;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void bot_output(struct ADC_client* client, const char* format, ...)
|
||||
{
|
||||
char logmsg[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(logmsg, 1024, format, args);
|
||||
va_end(args);
|
||||
if (cfg_mode == mode_log)
|
||||
{
|
||||
fprintf(stdout, "%s\n", logmsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cfg_debug)
|
||||
fprintf(stdout, "* [%4d] %s\n", client->num, logmsg);
|
||||
}
|
||||
}
|
||||
|
||||
static void adc_cid_pid(struct ADC_client* client)
|
||||
{
|
||||
char seed[64];
|
||||
char pid[64];
|
||||
char cid[64];
|
||||
uint64_t tiger_res1[3];
|
||||
uint64_t tiger_res2[3];
|
||||
|
||||
/* create cid+pid pair */
|
||||
memset(seed, 0, 64);
|
||||
snprintf(seed, 64, ADCRUSH "%p/%d", client, (int) client->num);
|
||||
|
||||
tiger((uint64_t*) seed, strlen(seed), tiger_res1);
|
||||
base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
|
||||
tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
|
||||
base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
|
||||
|
||||
cid[ADC_CID_SIZE] = 0;
|
||||
pid[ADC_CID_SIZE] = 0;
|
||||
|
||||
strcat(client->info, " PD");
|
||||
strcat(client->info, pid);
|
||||
strcat(client->info, " ID");
|
||||
strcat(client->info, cid);
|
||||
}
|
||||
|
||||
static size_t get_wait_rand(size_t max)
|
||||
{
|
||||
static size_t next = 0;
|
||||
if (next == 0) next = (size_t) time(0);
|
||||
next = (next * 1103515245) + 12345;
|
||||
return ((size_t )(next / 65536) % max);
|
||||
}
|
||||
|
||||
static void client_reschedule_timeout(struct ADC_client* client)
|
||||
{
|
||||
size_t next_timeout = 0;
|
||||
struct timeval timeout = { 0, 0 };
|
||||
|
||||
switch (client->state)
|
||||
{
|
||||
case ps_conn: next_timeout = 30; break;
|
||||
case ps_protocol: next_timeout = 30; break;
|
||||
case ps_identify: next_timeout = 30; break;
|
||||
case ps_verify: next_timeout = 30; break;
|
||||
case ps_normal: next_timeout = 120; break;
|
||||
case ps_none: next_timeout = 120; break;
|
||||
}
|
||||
|
||||
if (client->state == ps_normal || client->state == ps_none)
|
||||
{
|
||||
switch (cfg_level)
|
||||
{
|
||||
case 0: /* polite */
|
||||
next_timeout *= 4;
|
||||
break;
|
||||
|
||||
case 1: /* normal */
|
||||
break;
|
||||
|
||||
case 2: /* aggressive */
|
||||
next_timeout /= 8;
|
||||
break;
|
||||
|
||||
case 3: /* excessive */
|
||||
next_timeout /= 16;
|
||||
|
||||
case 4: /* excessive */
|
||||
next_timeout /= 32;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (client->state == ps_conn)
|
||||
client->timeout = MAX(next_timeout, 1);
|
||||
else
|
||||
client->timeout = get_wait_rand(MAX(next_timeout, 1));
|
||||
|
||||
if (!client->timeout) client->timeout++;
|
||||
|
||||
timeout.tv_sec = (time_t) client->timeout;
|
||||
evtimer_add(&client->ev_timer, &timeout);
|
||||
}
|
||||
|
||||
static void set_state_timeout(struct ADC_client* client, enum protocolState state)
|
||||
{
|
||||
client->state = state;
|
||||
client_reschedule_timeout(client);
|
||||
}
|
||||
|
||||
static void send_client(struct ADC_client* client, char* msg)
|
||||
{
|
||||
int ret = net_send(client->sd, msg, strlen(msg), UHUB_SEND_SIGNAL);
|
||||
|
||||
if (cfg_debug > 1)
|
||||
{
|
||||
char* dump = strdup(msg);
|
||||
dump[strlen(msg) - 1] = 0;
|
||||
bot_output(client, "- SEND: '%s'", dump);
|
||||
free(dump);
|
||||
}
|
||||
|
||||
if (ret != strlen(msg))
|
||||
{
|
||||
if (ret == -1)
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
ADC_client_on_disconnected(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Not all data sent! */
|
||||
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ADC_client_on_connected(struct ADC_client* client)
|
||||
{
|
||||
send_client(client, ADC_HANDSHAKE);
|
||||
set_state_timeout(client, ps_protocol);
|
||||
bot_output(client, "connected.");
|
||||
}
|
||||
|
||||
static void ADC_client_on_disconnected(struct ADC_client* client)
|
||||
{
|
||||
event_del(&client->ev_read);
|
||||
event_del(&client->ev_write);
|
||||
|
||||
net_close(client->sd);
|
||||
client->sd = -1;
|
||||
|
||||
bot_output(client, "disconnected.");
|
||||
set_state_timeout(client, ps_none);
|
||||
}
|
||||
|
||||
static void ADC_client_on_login(struct ADC_client* client)
|
||||
{
|
||||
bot_output(client, "logged in.");
|
||||
set_state_timeout(client, ps_normal);
|
||||
}
|
||||
|
||||
|
||||
static void send_client_info(struct ADC_client* client)
|
||||
{
|
||||
client->info[0] = 0;
|
||||
strcat(client->info, "BINF ");
|
||||
strcat(client->info, sid_to_string(client->sid));
|
||||
strcat(client->info, " NI" ADC_NICK);
|
||||
if (cfg_clients > 1)
|
||||
{
|
||||
strcat(client->info, "_");
|
||||
strcat(client->info, uhub_itoa(client->num));
|
||||
}
|
||||
strcat(client->info, " VE" ADCRUSH);
|
||||
strcat(client->info, " DE" ADC_DESC);
|
||||
strcat(client->info, " I40.0.0.0");
|
||||
strcat(client->info, " EMuhub@extatic.org");
|
||||
strcat(client->info, " SL3");
|
||||
strcat(client->info, " HN1");
|
||||
strcat(client->info, " HR1");
|
||||
strcat(client->info, " HO1");
|
||||
|
||||
adc_cid_pid(client);
|
||||
|
||||
strcat(client->info, "\n");
|
||||
|
||||
send_client(client, client->info);
|
||||
}
|
||||
|
||||
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token);
|
||||
|
||||
static int recv_client(struct ADC_client* client)
|
||||
{
|
||||
ssize_t size = 0;
|
||||
if (cfg_mode != mode_performance || (cfg_mode == mode_performance && (get_wait_rand(100) < (90 - (15 * cfg_level)))))
|
||||
{
|
||||
size = net_recv(client->sd, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (get_wait_rand(1000) == 99)
|
||||
return -1; /* Can break tings badly! :-) */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (size == 0 || ((size == -1 && net_error() != EWOULDBLOCK)))
|
||||
return -1;
|
||||
client->recvbuf[client->r_offset + size] = 0;
|
||||
|
||||
char* start = client->recvbuf;
|
||||
char* pos;
|
||||
char* lastPos;
|
||||
while ((pos = strchr(start, '\n')))
|
||||
{
|
||||
lastPos = pos;
|
||||
pos[0] = 0;
|
||||
|
||||
if (cfg_debug > 1)
|
||||
{
|
||||
bot_output(client, "- RECV: '%s'", start);
|
||||
}
|
||||
|
||||
fourcc_t cmd = 0;
|
||||
if (strlen(start) < 4)
|
||||
{
|
||||
bot_output(client, "Unexpected response from hub: '%s'", start);
|
||||
start = &pos[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd = FOURCC(start[0], start[1], start[2], start[3]);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case ADC_CMD_ISUP:
|
||||
break;
|
||||
|
||||
case ADC_CMD_ISID:
|
||||
if (client->state == ps_protocol)
|
||||
{
|
||||
client->sid = string_to_sid(&start[5]);
|
||||
client->state = ps_identify;
|
||||
send_client_info(client);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ADC_CMD_IINF:
|
||||
break;
|
||||
|
||||
case ADC_CMD_BSCH:
|
||||
case ADC_CMD_FSCH:
|
||||
{
|
||||
if (get_wait_rand(100) > (90 - (10 * cfg_level)) && cfg_mode == mode_performance)
|
||||
{
|
||||
sid_t target = string_to_sid(&start[5]);
|
||||
const char* what = strstr(&start[5], " AN");
|
||||
const char* token = strstr(&start[5], " TO");
|
||||
char* split = 0;
|
||||
if (!token || !what) break;
|
||||
|
||||
token += 3;
|
||||
what += 3;
|
||||
|
||||
split = strchr(what, ' ');
|
||||
if (!split) break;
|
||||
else split[0] = '0';
|
||||
|
||||
split = strchr(token, ' ');
|
||||
if (split) split[0] = '0';
|
||||
|
||||
perf_result(client, target, what, token);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADC_CMD_BINF:
|
||||
{
|
||||
if (strlen(start) > 9)
|
||||
{
|
||||
char t = start[9]; start[9] = 0; sid_t sid = string_to_sid(&start[5]); start[9] = t;
|
||||
|
||||
if (sid == client->sid)
|
||||
{
|
||||
if (client->state == ps_verify || client->state == ps_identify)
|
||||
{
|
||||
ADC_client_on_login(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ADC_CMD_ISTA:
|
||||
if (strncmp(start, "ISTA 000", 8))
|
||||
{
|
||||
bot_output(client, "status: '%s'\n", (start + 9));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
start = &pos[1];
|
||||
}
|
||||
|
||||
client->r_offset = strlen(lastPos);
|
||||
memmove(client->recvbuf, lastPos, strlen(lastPos));
|
||||
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ADC_client_connect(struct ADC_client* client)
|
||||
{
|
||||
struct timeval timeout = { TIMEOUT_IDLE, 0 };
|
||||
net_connect(client->sd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in));
|
||||
set_state_timeout(client, ps_conn);
|
||||
event_add(&client->ev_read, &timeout);
|
||||
event_add(&client->ev_write, &timeout);
|
||||
bot_output(client, "connecting...");
|
||||
}
|
||||
|
||||
void ADC_client_wait_connect(struct ADC_client* client)
|
||||
{
|
||||
set_state_timeout(client, ps_none);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ADC_client_disconnect(struct ADC_client* client)
|
||||
{
|
||||
if (client->sd != -1)
|
||||
{
|
||||
net_close(client->sd);
|
||||
client->sd = -1;
|
||||
event_del(&client->ev_read);
|
||||
event_del(&client->ev_write);
|
||||
bot_output(client, "disconnected.");
|
||||
|
||||
if (running)
|
||||
{
|
||||
ADC_client_destroy(client);
|
||||
ADC_client_create(client, client->num);
|
||||
ADC_client_connect(client);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void perf_chat(struct ADC_client* client, int priv)
|
||||
{
|
||||
char buf[1024] = { 0, };
|
||||
size_t r = get_wait_rand(MAX_CHAT_MSGS-1);
|
||||
char* msg = adc_msg_escape(chat_messages[r]);
|
||||
|
||||
if (priv)
|
||||
{
|
||||
strcat(buf, "EMSG ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(buf, "BMSG ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
}
|
||||
strcat(buf, " ");
|
||||
|
||||
strcat(buf, msg);
|
||||
hub_free(msg);
|
||||
|
||||
strcat(buf, "\n");
|
||||
send_client(client, buf);
|
||||
}
|
||||
|
||||
static void perf_search(struct ADC_client* client)
|
||||
{
|
||||
char buf[1024] = { 0, };
|
||||
size_t r = get_wait_rand(MAX_SEARCH_MSGS-1);
|
||||
size_t pst = get_wait_rand(100);
|
||||
|
||||
if (pst > 80)
|
||||
{
|
||||
strcat(buf, "FSCH ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " +TCP4 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(buf, "BSCH ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " ");
|
||||
}
|
||||
strcat(buf, search_messages[r]);
|
||||
strcat(buf, "\n");
|
||||
send_client(client, buf);
|
||||
}
|
||||
|
||||
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token)
|
||||
{
|
||||
char buf[1024] = { 0, };
|
||||
strcat(buf, "DRES ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, sid_to_string(target));
|
||||
strcat(buf, " FN" "test/");
|
||||
strcat(buf, what);
|
||||
strcat(buf, ".dat");
|
||||
strcat(buf, " SL" "0");
|
||||
strcat(buf, " SI" "908987128912");
|
||||
strcat(buf, " TR" "5T6YJYKO3WECS52BKWVSOP5VUG4IKNSZBZ5YHBA");
|
||||
strcat(buf, " TO");
|
||||
strcat(buf, token);
|
||||
strcat(buf, "\n");
|
||||
send_client(client, buf);
|
||||
}
|
||||
|
||||
static void perf_ctm(struct ADC_client* client)
|
||||
{
|
||||
char buf[1024] = { 0, };
|
||||
strcat(buf, "DCTM ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, "ADC/1.0");
|
||||
strcat(buf, " TOKEN111");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, "\n");
|
||||
send_client(client, buf);
|
||||
}
|
||||
|
||||
|
||||
static void perf_update(struct ADC_client* client)
|
||||
{
|
||||
char buf[1024] = { 0, };
|
||||
int n = (int) get_wait_rand(10)+1;
|
||||
|
||||
strcat(buf, "BINF ");
|
||||
strcat(buf, sid_to_string(client->sid));
|
||||
strcat(buf, " HN");
|
||||
strcat(buf, uhub_itoa(n));
|
||||
|
||||
strcat(buf, "\n");
|
||||
send_client(client, buf);
|
||||
}
|
||||
|
||||
|
||||
static void perf_normal_action(struct ADC_client* client)
|
||||
{
|
||||
size_t r = get_wait_rand(5);
|
||||
size_t p = get_wait_rand(100);
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case 0:
|
||||
if (p > (90 - (10 * cfg_level)))
|
||||
{
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> disconnect");
|
||||
ADC_client_disconnect(client);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (cfg_chat)
|
||||
{
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> chat");
|
||||
perf_chat(client, 0);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> search");
|
||||
perf_search(client);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> update");
|
||||
perf_update(client);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> privmsg");
|
||||
perf_chat(client, 1);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (cfg_debug > 1) bot_output(client, "timeout -> ctm/rcm");
|
||||
perf_ctm(client);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
client_reschedule_timeout(client);
|
||||
}
|
||||
|
||||
void event_callback(int fd, short ev, void *arg)
|
||||
{
|
||||
struct ADC_client* client = (struct ADC_client*) arg;
|
||||
|
||||
if (ev & EV_READ)
|
||||
{
|
||||
if (recv_client(client) == -1)
|
||||
{
|
||||
ADC_client_on_disconnected(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & EV_TIMEOUT)
|
||||
{
|
||||
if (client->state == ps_none)
|
||||
{
|
||||
if (client->sd == -1)
|
||||
{
|
||||
ADC_client_create(client, client->num);
|
||||
}
|
||||
|
||||
ADC_client_connect(client);
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
if (client->state == ps_normal && cfg_mode == mode_performance)
|
||||
{
|
||||
perf_normal_action(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev & EV_WRITE)
|
||||
{
|
||||
if (client->state == ps_conn)
|
||||
{
|
||||
ADC_client_on_connected(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Call send again */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int ADC_client_create(struct ADC_client* client, int num)
|
||||
{
|
||||
struct timeval timeout = { 0, 0 };
|
||||
|
||||
memset(client, 0, sizeof(struct ADC_client));
|
||||
client->num = num;
|
||||
|
||||
client->sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (client->sd == -1) return -1;
|
||||
|
||||
event_set(&client->ev_write, client->sd, EV_WRITE, event_callback, client);
|
||||
event_set(&client->ev_read, client->sd, EV_READ | EV_PERSIST, event_callback, client);
|
||||
|
||||
net_set_nonblocking(client->sd, 1);
|
||||
|
||||
timeout.tv_sec = client->timeout;
|
||||
evtimer_set(&client->ev_timer, event_callback, client);
|
||||
|
||||
set_state_timeout(client, ps_none);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ADC_client_destroy(struct ADC_client* client)
|
||||
{
|
||||
ADC_client_disconnect(client);
|
||||
evtimer_del(&client->ev_timer);
|
||||
}
|
||||
|
||||
|
||||
void runloop(size_t clients)
|
||||
{
|
||||
size_t n = 0;
|
||||
struct ADC_client* client[ADC_MAX_CLIENTS];
|
||||
|
||||
for (n = 0; n < clients; n++)
|
||||
{
|
||||
struct ADC_client* c = malloc(sizeof(struct ADC_client));
|
||||
client[n] = c;
|
||||
|
||||
ADC_client_create(c, n);
|
||||
if (n == 0)
|
||||
{
|
||||
ADC_client_connect(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
ADC_client_wait_connect(c);
|
||||
}
|
||||
}
|
||||
|
||||
event_dispatch();
|
||||
|
||||
for (n = 0; n < clients; n++)
|
||||
{
|
||||
ADC_client_destroy(client[n]);
|
||||
free(client[n]);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_version()
|
||||
{
|
||||
printf(ADCRUSH "\n");
|
||||
printf("Copyright (C) 2008-2009, Jan Vidar Krey\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_usage(const char* program)
|
||||
{
|
||||
print_version();
|
||||
|
||||
printf("Usage: %s <mode> (adc://<host>:<port>) [options]\n", program);
|
||||
|
||||
printf("\n");
|
||||
printf(" Modes\n");
|
||||
printf(" perf Do performance testing using multiple clients\n");
|
||||
printf(" bugs Bugs mode, use fuzzer to construct pseudo-random commands.\n");
|
||||
printf(" security Perform security tests for the hub.\n");
|
||||
printf(" log Connect one client to the hub and log the output hub.\n");
|
||||
|
||||
printf("\n");
|
||||
printf(" General options\n");
|
||||
printf(" -c Allow broadcasting chat messages.\n");
|
||||
printf(" -d Enable debug output.\n");
|
||||
printf(" -q Quiet mode (no output).\n");
|
||||
|
||||
printf("\n");
|
||||
printf(" Performance options:\n");
|
||||
printf(" -l <0-3> Level: 0=polite, 1=normal (default), 2=aggressive, 3=excessive.\n");
|
||||
printf(" -n <num> Number of concurrent connections\n");
|
||||
|
||||
printf("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
int set_defaults()
|
||||
{
|
||||
switch (cfg_mode)
|
||||
{
|
||||
case mode_performance:
|
||||
break;
|
||||
case mode_bugs:
|
||||
break;
|
||||
case mode_security:
|
||||
break;
|
||||
case mode_log:
|
||||
cfg_quiet = 0;
|
||||
cfg_debug = 2;
|
||||
cfg_clients = 1;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_mode(const char* arg)
|
||||
{
|
||||
cfg_mode = 0;
|
||||
|
||||
if (!strcmp(arg, "perf"))
|
||||
cfg_mode = mode_performance;
|
||||
else if (!strcmp(arg, "bugs"))
|
||||
cfg_mode = mode_bugs;
|
||||
else if (!strcmp(arg, "security"))
|
||||
cfg_mode = mode_security;
|
||||
else if (!strcmp(arg, "log"))
|
||||
cfg_mode = mode_log;
|
||||
|
||||
return cfg_mode;
|
||||
}
|
||||
|
||||
int parse_address(const char* arg)
|
||||
{
|
||||
char* split;
|
||||
struct hostent* dns;
|
||||
struct in_addr* addr;
|
||||
|
||||
if (!arg)
|
||||
return 0;
|
||||
|
||||
if (strlen(arg) < 9)
|
||||
return 0;
|
||||
|
||||
if (strncmp(arg, "adc://", 6))
|
||||
return 0;
|
||||
|
||||
split = strrchr(arg+6, ':');
|
||||
if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
|
||||
return 0;
|
||||
|
||||
cfg_port = strtol(split+1, NULL, 10);
|
||||
if (cfg_port <= 0 || cfg_port > 65535)
|
||||
return 0;
|
||||
|
||||
split[0] = 0;
|
||||
|
||||
dns = gethostbyname(arg+6);
|
||||
if (dns)
|
||||
{
|
||||
addr = (struct in_addr*) dns->h_addr_list[0];
|
||||
cfg_host = strdup(inet_ntoa(*addr));
|
||||
}
|
||||
|
||||
if (!cfg_host)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_arguments(int argc, char** argv)
|
||||
{
|
||||
int ok = 1;
|
||||
int opt;
|
||||
for (opt = 3; opt < argc; opt++)
|
||||
{
|
||||
if (!strcmp(argv[opt], "-c"))
|
||||
cfg_chat = 1;
|
||||
else if (!strncmp(argv[opt], "-d", 2))
|
||||
cfg_debug += strlen(argv[opt]) - 1;
|
||||
else if (!strcmp(argv[opt], "-q"))
|
||||
cfg_quiet = 1;
|
||||
else if (!strcmp(argv[opt], "-l") && (++opt) < argc)
|
||||
{
|
||||
cfg_level = MIN(MAX(uhub_atoi(argv[opt]), 0), 3);
|
||||
}
|
||||
else if (!strcmp(argv[opt], "-n") && (++opt) < argc)
|
||||
{
|
||||
cfg_clients = MIN(MAX(uhub_atoi(argv[opt]), 1), ADC_MAX_CLIENTS);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void parse_command_line(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2 ||
|
||||
!parse_mode(argv[1]) ||
|
||||
!set_defaults() ||
|
||||
!parse_address(argv[2]) ||
|
||||
!parse_arguments(argc, argv))
|
||||
{
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
net_initialize();
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(cfg_port);
|
||||
net_string_to_address(AF_INET, cfg_host, &saddr.sin_addr);
|
||||
|
||||
runloop(cfg_clients);
|
||||
net_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
555
src/auth.c
Normal file
555
src/auth.c
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#define ACL_ADD_USER(S, L, V) do { ret = check_cmd_user(S, V, L, line, line_count); if (ret != 0) return ret; } while(0)
|
||||
#define ACL_ADD_BOOL(S, L) do { ret = check_cmd_bool(S, L, line, line_count); if (ret != 0) return ret; } while(0)
|
||||
#define ACL_ADD_ADDR(S, L) do { ret = check_cmd_addr(S, L, line, line_count); if (ret != 0) return ret; } while(0)
|
||||
|
||||
static const char* get_user_credential_string(enum user_credentials cred)
|
||||
{
|
||||
switch (cred)
|
||||
{
|
||||
case cred_none: return "none";
|
||||
case cred_bot: return "bot";
|
||||
case cred_guest: return "guest";
|
||||
case cred_user: return "user";
|
||||
case cred_operator: return "operator";
|
||||
case cred_super: return "super";
|
||||
case cred_admin: return "admin";
|
||||
case cred_link: return "link";
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
static int check_cmd_bool(const char* cmd, struct linked_list* list, char* line, int line_count)
|
||||
{
|
||||
char* data;
|
||||
char* data_extra;
|
||||
|
||||
if (!strncmp(line, cmd, strlen(cmd)))
|
||||
{
|
||||
data = &line[strlen(cmd)];
|
||||
data_extra = 0;
|
||||
data[0] = '\0';
|
||||
data++;
|
||||
|
||||
data = strip_white_space(data);
|
||||
if (!strlen(data))
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_append(list, hub_strdup(data));
|
||||
hub_log(log_debug, "ACL: Deny access for: '%s' (%s)", data, cmd);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_cmd_user(const char* cmd, int status, struct linked_list* list, char* line, int line_count)
|
||||
{
|
||||
char* data;
|
||||
char* data_extra;
|
||||
struct user_access_info* info = 0;
|
||||
|
||||
if (!strncmp(line, cmd, strlen(cmd)))
|
||||
{
|
||||
data = &line[strlen(cmd)];
|
||||
data_extra = 0;
|
||||
data[0] = '\0';
|
||||
data++;
|
||||
|
||||
data = strip_white_space(data);
|
||||
if (!strlen(data))
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = hub_malloc_zero(sizeof(struct user_access_info));
|
||||
|
||||
if (!info)
|
||||
{
|
||||
hub_log(log_error, "ACL parse error. Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(cmd, "user_", 5) == 0)
|
||||
{
|
||||
data_extra = strrchr(data, ':');
|
||||
if (data_extra)
|
||||
{
|
||||
data_extra[0] = 0;
|
||||
data_extra++;
|
||||
}
|
||||
}
|
||||
|
||||
info->username = hub_strdup(data);
|
||||
info->password = data_extra ? hub_strdup(data_extra) : 0;
|
||||
info->status = status;
|
||||
list_append(list, info);
|
||||
hub_log(log_debug, "ACL: Added user '%s' (%s)", info->username, get_user_credential_string(info->status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void add_ip_range(struct linked_list* list, struct ip_ban_record* info)
|
||||
{
|
||||
char buf1[INET6_ADDRSTRLEN+1];
|
||||
char buf2[INET6_ADDRSTRLEN+1];
|
||||
|
||||
if (info->lo.af == AF_INET)
|
||||
{
|
||||
net_address_to_string(AF_INET, &info->lo.internal_ip_data.in.s_addr, buf1, INET6_ADDRSTRLEN);
|
||||
net_address_to_string(AF_INET, &info->hi.internal_ip_data.in.s_addr, buf2, INET6_ADDRSTRLEN);
|
||||
}
|
||||
else if (info->lo.af == AF_INET6)
|
||||
{
|
||||
net_address_to_string(AF_INET6, &info->lo.internal_ip_data.in6, buf1, INET6_ADDRSTRLEN);
|
||||
net_address_to_string(AF_INET6, &info->hi.internal_ip_data.in6, buf2, INET6_ADDRSTRLEN);
|
||||
}
|
||||
hub_log(log_debug, "ACL: Deny access for: %s-%s", buf1, buf2);
|
||||
|
||||
list_append(list, info);
|
||||
}
|
||||
|
||||
|
||||
static int check_ip_range(const char* lo, const char* hi, struct ip_ban_record* info)
|
||||
{
|
||||
int ret1, ret2;
|
||||
|
||||
if ((ip_is_valid_ipv4(lo) && ip_is_valid_ipv4(hi)) ||
|
||||
(ip_is_valid_ipv6(lo) && ip_is_valid_ipv6(hi)))
|
||||
{
|
||||
ret1 = ip_convert_to_binary(lo, &info->lo);
|
||||
ret2 = ip_convert_to_binary(hi, &info->hi);
|
||||
if (ret1 == -1 || ret2 == -1 || ret1 != ret2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int check_ip_mask(const char* text_addr, int bits, struct ip_ban_record* info)
|
||||
{
|
||||
hub_log(log_debug, "ACL: Deny access for: %s/%d", text_addr, bits);
|
||||
|
||||
if (ip_is_valid_ipv4(text_addr) ||
|
||||
ip_is_valid_ipv6(text_addr))
|
||||
{
|
||||
struct ip_addr_encap addr;
|
||||
struct ip_addr_encap mask1;
|
||||
struct ip_addr_encap mask2;
|
||||
int af = ip_convert_to_binary(text_addr, &addr); /* 192.168.1.2 */
|
||||
int maxbits = af == AF_INET6 ? 128 : 32;
|
||||
ip_mask_create_left(af, bits, &mask1); /* 255.255.255.0 */
|
||||
ip_mask_create_right(af, maxbits - bits, &mask2); /* 0.0.0.255 */
|
||||
ip_mask_apply_AND(&addr, &mask1, &info->lo); /* 192.168.1.0 */
|
||||
ip_mask_apply_OR(&info->lo, &mask2, &info->hi); /* 192.168.1.255 */
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int check_cmd_addr(const char* cmd, struct linked_list* list, char* line, int line_count)
|
||||
{
|
||||
char* data1;
|
||||
char* data2;
|
||||
struct ip_ban_record* info = 0;
|
||||
int cidr_bits = 0;
|
||||
|
||||
if (!strncmp(line, cmd, strlen(cmd)))
|
||||
{
|
||||
data1 = &line[strlen(cmd)];
|
||||
data2 = 0;
|
||||
data1[0] = '\0';
|
||||
data1++;
|
||||
|
||||
data1 = strip_white_space(data1);
|
||||
if (!strlen(data1))
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = hub_malloc_zero(sizeof(struct ip_ban_record));
|
||||
|
||||
if (!info)
|
||||
{
|
||||
hub_log(log_error, "ACL parse error. Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract IP-range */
|
||||
data2 = strrchr(data1, '-');
|
||||
if (data2)
|
||||
{
|
||||
cidr_bits = -1;
|
||||
data2[0] = 0;
|
||||
data2++;
|
||||
|
||||
if (check_ip_range(data1, data2, info) == -1)
|
||||
{
|
||||
hub_free(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_ip_range(list, info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extract IP-bitmask */
|
||||
data2 = strrchr(data1, '/');
|
||||
if (data2)
|
||||
{
|
||||
data2[0] = 0;
|
||||
data2++;
|
||||
cidr_bits = uhub_atoi(data2);
|
||||
}
|
||||
else
|
||||
{
|
||||
cidr_bits = 128;
|
||||
}
|
||||
|
||||
if (check_ip_mask(data1, cidr_bits, info) == -1)
|
||||
{
|
||||
hub_free(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_ip_range(list, info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int acl_parse_line(char* line, int line_count, void* ptr_data)
|
||||
{
|
||||
char* pos;
|
||||
struct acl_handle* handle = (struct acl_handle*) ptr_data;
|
||||
int ret;
|
||||
|
||||
if ((pos = strchr(line, '#')) != NULL)
|
||||
{
|
||||
pos[0] = 0;
|
||||
}
|
||||
|
||||
if (strlen(line) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "acl_parse_line(): '%s'", line);
|
||||
#endif
|
||||
line = strip_white_space(line);
|
||||
|
||||
if (!strlen(line))
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "acl_parse_line: '%s'", line);
|
||||
#endif
|
||||
|
||||
ACL_ADD_USER("bot", handle->users, cred_bot);
|
||||
ACL_ADD_USER("user_admin", handle->users, cred_admin);
|
||||
ACL_ADD_USER("user_super", handle->users, cred_super);
|
||||
ACL_ADD_USER("user_op", handle->users, cred_operator);
|
||||
ACL_ADD_USER("user_reg", handle->users, cred_user);
|
||||
ACL_ADD_USER("link", handle->users, cred_link);
|
||||
ACL_ADD_BOOL("deny_nick", handle->users_denied);
|
||||
ACL_ADD_BOOL("ban_nick", handle->users_banned);
|
||||
ACL_ADD_BOOL("ban_cid", handle->cids);
|
||||
ACL_ADD_ADDR("deny_ip", handle->networks);
|
||||
ACL_ADD_ADDR("nat_ip", handle->nat_override);
|
||||
|
||||
hub_log(log_error, "Unknown ACL command on line %d: '%s'", line_count, line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int acl_initialize(struct hub_config* config, struct acl_handle* handle)
|
||||
{
|
||||
int ret;
|
||||
memset(handle, 0, sizeof(struct acl_handle));
|
||||
|
||||
handle->users = list_create();
|
||||
handle->users_denied = list_create();
|
||||
handle->users_banned = list_create();
|
||||
handle->cids = list_create();
|
||||
handle->networks = list_create();
|
||||
handle->nat_override = list_create();
|
||||
|
||||
if (!handle->users || !handle->cids || !handle->networks || !handle->users_denied || !handle->users_banned || !handle->nat_override)
|
||||
{
|
||||
hub_log(log_fatal, "acl_initialize: Out of memory");
|
||||
|
||||
list_destroy(handle->users);
|
||||
list_destroy(handle->users_denied);
|
||||
list_destroy(handle->users_banned);
|
||||
list_destroy(handle->cids);
|
||||
list_destroy(handle->networks);
|
||||
list_destroy(handle->nat_override);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config)
|
||||
{
|
||||
if (strlen(config->file_acl) == 0) return 0;
|
||||
|
||||
ret = file_read_lines(config->file_acl, handle, &acl_parse_line);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void acl_free_access_info(void* ptr)
|
||||
{
|
||||
struct user_access_info* info = (struct user_access_info*) ptr;
|
||||
if (info)
|
||||
{
|
||||
hub_free(info->username);
|
||||
hub_free(info->password);
|
||||
hub_free(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void acl_free_ip_info(void* ptr)
|
||||
{
|
||||
struct access_info* info = (struct access_info*) ptr;
|
||||
if (info)
|
||||
{
|
||||
hub_free(info);
|
||||
}
|
||||
}
|
||||
|
||||
int acl_shutdown(struct acl_handle* handle)
|
||||
{
|
||||
if (handle->users)
|
||||
{
|
||||
list_clear(handle->users, &acl_free_access_info);
|
||||
list_destroy(handle->users);
|
||||
}
|
||||
|
||||
if (handle->users_denied)
|
||||
{
|
||||
list_clear(handle->users_denied, &hub_free);
|
||||
list_destroy(handle->users_denied);
|
||||
}
|
||||
|
||||
if (handle->users_banned)
|
||||
{
|
||||
list_clear(handle->users_banned, &hub_free);
|
||||
list_destroy(handle->users_banned);
|
||||
}
|
||||
|
||||
|
||||
if (handle->cids)
|
||||
{
|
||||
list_clear(handle->cids, &hub_free);
|
||||
list_destroy(handle->cids);
|
||||
}
|
||||
|
||||
if (handle->networks)
|
||||
{
|
||||
list_clear(handle->networks, &acl_free_ip_info);
|
||||
list_destroy(handle->networks);
|
||||
}
|
||||
|
||||
if (handle->nat_override)
|
||||
{
|
||||
list_clear(handle->nat_override, &acl_free_ip_info);
|
||||
list_destroy(handle->nat_override);
|
||||
}
|
||||
|
||||
|
||||
memset(handle, 0, sizeof(struct acl_handle));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name)
|
||||
{
|
||||
struct user_access_info* info = (struct user_access_info*) list_get_first(handle->users);
|
||||
while (info)
|
||||
{
|
||||
if (strcasecmp(info->username, name) == 0)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
info = (struct user_access_info*) list_get_next(handle->users);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STR_LIST_CONTAINS(LIST, STR) \
|
||||
char* str = (char*) list_get_first(LIST); \
|
||||
while (str) \
|
||||
{ \
|
||||
if (strcasecmp(str, STR) == 0) \
|
||||
return 1; \
|
||||
str = (char*) list_get_next(LIST); \
|
||||
} \
|
||||
return 0
|
||||
|
||||
int acl_is_cid_banned(struct acl_handle* handle, const char* data)
|
||||
{
|
||||
if (!handle) return 0;
|
||||
STR_LIST_CONTAINS(handle->cids, data);
|
||||
}
|
||||
|
||||
int acl_is_user_banned(struct acl_handle* handle, const char* data)
|
||||
{
|
||||
if (!handle) return 0;
|
||||
STR_LIST_CONTAINS(handle->users_banned, data);
|
||||
}
|
||||
|
||||
int acl_is_user_denied(struct acl_handle* handle, const char* data)
|
||||
{
|
||||
if (!handle) return 0;
|
||||
STR_LIST_CONTAINS(handle->users_denied, data);
|
||||
}
|
||||
|
||||
int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address)
|
||||
{
|
||||
struct ip_addr_encap raw;
|
||||
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->networks);
|
||||
ip_convert_to_binary(ip_address, &raw);
|
||||
|
||||
while (info)
|
||||
{
|
||||
if (acl_check_ip_range(&raw, info))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
info = (struct ip_ban_record*) list_get_next(handle->networks);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address)
|
||||
{
|
||||
struct ip_addr_encap raw;
|
||||
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->nat_override);
|
||||
ip_convert_to_binary(ip_address, &raw);
|
||||
|
||||
while (info)
|
||||
{
|
||||
if (acl_check_ip_range(&raw, info))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
info = (struct ip_ban_record*) list_get_next(handle->nat_override);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info)
|
||||
{
|
||||
return (addr->af == info->lo.af && ip_compare(&info->lo, addr) <= 0 && ip_compare(addr, &info->hi) <= 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will generate the same challenge to the same user, always.
|
||||
* The challenge is made up of the time of the user connected
|
||||
* seconds since the unix epoch (modulus 1 million)
|
||||
* and the SID of the user (0-1 million).
|
||||
*/
|
||||
const char* password_generate_challenge(struct user* user)
|
||||
{
|
||||
char buf[32];
|
||||
uint64_t tiger_res[3];
|
||||
static char tiger_buf[MAX_CID_LEN+1];
|
||||
|
||||
snprintf(buf, 32, "%d%d%d", (int) user->tm_connected, (int) user->id.sid, (int) user->sd);
|
||||
|
||||
tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res);
|
||||
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
|
||||
tiger_buf[MAX_CID_LEN] = 0;
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "Generating challenge for user %s: '%s'", user->id.nick, tiger_buf);
|
||||
#endif
|
||||
return (const char*) tiger_buf;
|
||||
}
|
||||
|
||||
|
||||
int password_verify(struct user* user, const char* password)
|
||||
{
|
||||
char buf[1024];
|
||||
struct user_access_info* access;
|
||||
const char* challenge;
|
||||
char raw_challenge[64];
|
||||
char password_calc[64];
|
||||
uint64_t tiger_res[3];
|
||||
|
||||
if (!password || !user || strlen(password) != MAX_CID_LEN)
|
||||
return password_invalid;
|
||||
|
||||
access = acl_get_access_info(user->hub->acl, user->id.nick);
|
||||
if (!access || !access->password)
|
||||
return password_invalid;
|
||||
|
||||
if (TIGERSIZE+strlen(access->password) >= 1024)
|
||||
return password_invalid;
|
||||
|
||||
challenge = password_generate_challenge(user);
|
||||
|
||||
base32_decode(challenge, (unsigned char*) raw_challenge, MAX_CID_LEN);
|
||||
|
||||
memcpy(&buf[0], (char*) access->password, strlen(access->password));
|
||||
memcpy(&buf[strlen(access->password)], raw_challenge, TIGERSIZE);
|
||||
|
||||
tiger((uint64_t*) buf, TIGERSIZE+strlen(access->password), (uint64_t*) tiger_res);
|
||||
base32_encode((unsigned char*) tiger_res, TIGERSIZE, password_calc);
|
||||
password_calc[MAX_CID_LEN] = 0;
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "Checking password %s against %s", password, password_calc);
|
||||
#endif
|
||||
if (strcasecmp(password, password_calc) == 0)
|
||||
{
|
||||
return password_ok;
|
||||
}
|
||||
return password_invalid;
|
||||
}
|
||||
|
||||
|
||||
|
91
src/auth.h
Normal file
91
src/auth.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_ACL_H
|
||||
#define HAVE_UHUB_ACL_H
|
||||
|
||||
struct hub_config;
|
||||
struct user;
|
||||
struct ip_addr_encap;
|
||||
|
||||
enum password_status
|
||||
{
|
||||
password_invalid = 0,
|
||||
password_ok = 1,
|
||||
};
|
||||
|
||||
enum acl_status
|
||||
{
|
||||
acl_not_found = 0,
|
||||
acl_found = 1,
|
||||
};
|
||||
|
||||
enum user_credentials
|
||||
{
|
||||
cred_none, /**<<< "User has no credentials (not yet logged in)" */
|
||||
cred_bot, /**<<< "User is a robot" */
|
||||
cred_guest, /**<<< "User is a guest (unregistered user)" */
|
||||
cred_user, /**<<< "User is identified as a registered user" */
|
||||
cred_operator, /**<<< "User is identified as a hub operator" */
|
||||
cred_super, /**<<< "User is a super user" (not used) */
|
||||
cred_admin, /**<<< "User is identified as a hub administrator/owner" */
|
||||
cred_link, /**<<< "User is a link (not used currently)" */
|
||||
};
|
||||
|
||||
struct user_access_info
|
||||
{
|
||||
char* username; /* name of user, cid or IP range */
|
||||
char* password; /* password */
|
||||
enum user_credentials status;
|
||||
};
|
||||
|
||||
struct ip_ban_record
|
||||
{
|
||||
struct ip_addr_encap lo;
|
||||
struct ip_addr_encap hi;
|
||||
};
|
||||
|
||||
struct acl_handle
|
||||
{
|
||||
struct linked_list* users; /* Known users. See enum user_status */
|
||||
struct linked_list* cids; /* Known CIDs */
|
||||
struct linked_list* networks; /* IP ranges, used for banning */
|
||||
struct linked_list* nat_override; /* IPs inside these ranges can provide their false IP. Use with care! */
|
||||
struct linked_list* users_banned; /* Users permanently banned */
|
||||
struct linked_list* users_denied; /* bad nickname */
|
||||
};
|
||||
|
||||
|
||||
extern int acl_initialize(struct hub_config* config, struct acl_handle* handle);
|
||||
extern int acl_shutdown(struct acl_handle* handle);
|
||||
|
||||
extern struct user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name);
|
||||
extern int acl_is_cid_banned(struct acl_handle* handle, const char* cid);
|
||||
extern int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address);
|
||||
extern int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address);
|
||||
|
||||
extern int acl_is_user_banned(struct acl_handle* handle, const char* name);
|
||||
extern int acl_is_user_denied(struct acl_handle* handle, const char* name);
|
||||
|
||||
extern int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info);
|
||||
|
||||
extern const char* password_generate_challenge(struct user* user);
|
||||
extern int password_verify(struct user* user, const char* password);
|
||||
|
||||
#endif /* HAVE_UHUB_ACL_H */
|
127
src/commands.c
Normal file
127
src/commands.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
static int command_access_denied(struct user* user)
|
||||
{
|
||||
struct adc_message* command;
|
||||
char* buffer = adc_msg_escape("Access denied.");
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int command_stats(struct user* user, const char* message)
|
||||
{
|
||||
struct adc_message* command;
|
||||
|
||||
if (user->credentials < cred_super)
|
||||
return command_access_denied(user);
|
||||
|
||||
char temp[64];
|
||||
snprintf(temp, 64, "*** Stats: %u users, peak %u", (unsigned int) user->hub->users->count, (unsigned int) user->hub->users->count_peak);
|
||||
char* buffer = adc_msg_escape(temp);
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int command_help(struct user* user, const char* message)
|
||||
{
|
||||
struct adc_message* command;
|
||||
char* buffer = adc_msg_escape(
|
||||
"*** Available commands:\n"
|
||||
"!help - Show this help message\n"
|
||||
"!stats - Show hub stats (super)\n"
|
||||
"!version - Show this help message\n"
|
||||
"!uptime - Display hub uptime\n"
|
||||
"!kick <user> - Kick user (operator)\n"
|
||||
);
|
||||
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_uptime(struct user* user, const char* message)
|
||||
{
|
||||
struct adc_message* command;
|
||||
char temp[64];
|
||||
snprintf(temp, 64, "*** Uptime: %s seconds", uhub_itoa((int) difftime(time(0), user->hub->tm_started)));
|
||||
char* buffer = adc_msg_escape(temp);
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_kick(struct user* user, const char* message)
|
||||
{
|
||||
struct adc_message* command;
|
||||
|
||||
if (user->credentials < cred_operator)
|
||||
return command_access_denied(user);
|
||||
|
||||
char* buffer = adc_msg_escape("*** Kick not implemented!");
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_version(struct user* user, const char* message)
|
||||
{
|
||||
struct adc_message* command;
|
||||
char* buffer = adc_msg_escape("*** Powered by " PRODUCT "/" VERSION);
|
||||
command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
|
||||
adc_msg_add_argument(command, buffer);
|
||||
route_to_user(user, command);
|
||||
adc_msg_free(command);
|
||||
hub_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int command_dipatcher(struct user* user, const char* message)
|
||||
{
|
||||
if (!strncmp(message, "!stats", 6)) command_stats(user, message);
|
||||
else if (!strncmp(message, "!help", 5)) command_help(user, message);
|
||||
else if (!strncmp(message, "!kick", 5)) command_kick(user, message);
|
||||
else if (!strncmp(message, "!version", 8)) command_version(user, message);
|
||||
else if (!strncmp(message, "!uptime", 7)) command_uptime(user, message);
|
||||
else
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
35
src/commands.h
Normal file
35
src/commands.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#define CHAT_MSG_HANDLED 1
|
||||
#define CHAT_MSG_IGNORED 0
|
||||
#define CHAT_MSG_INVALID -1
|
||||
|
||||
typedef int (*plugin_event_chat_message)(struct hub_info*, struct user*, struct adc_message*);
|
||||
|
||||
struct command_info
|
||||
{
|
||||
const char* prefix;
|
||||
enum user_credentials cred;
|
||||
plugin_event_chat_message function;
|
||||
};
|
||||
|
||||
int command_dipatcher(struct user* user, const char* message);
|
519
src/config.c
Normal file
519
src/config.c
Normal file
@ -0,0 +1,519 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 0x7fffffff
|
||||
#endif
|
||||
|
||||
#ifndef INT_MIN
|
||||
#define INT_MIN (-0x7fffffff - 1)
|
||||
#endif
|
||||
|
||||
#define CFG_APPLY_BOOLEAN(KEY, TARGET) \
|
||||
if (strcmp(KEY, key) == 0) \
|
||||
{ \
|
||||
if (strlen(data) == 1 && (data[0] == '1')) TARGET = 1; \
|
||||
else if (strlen(data) == 1 && (data[0] == '0')) TARGET = 0; \
|
||||
else if (strncasecmp(data, "true", 4) == 0) TARGET = 1; \
|
||||
else if (strncasecmp(data, "false", 5) == 0) TARGET = 0; \
|
||||
else if (strncasecmp(data, "yes", 3) == 0) TARGET = 1; \
|
||||
else if (strncasecmp(data, "no", 2) == 0) TARGET = 0; \
|
||||
else if (strncasecmp(data, "on", 2) == 0) TARGET = 1; \
|
||||
else if (strncasecmp(data, "off", 3) == 0) TARGET = 0; \
|
||||
else\
|
||||
{ \
|
||||
hub_log(log_fatal, "Configuration error on line %d: '%s' must be either '1' or '0'", line_count, key); \
|
||||
return -1; \
|
||||
} \
|
||||
TARGET |= 0x80000000; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define CFG_APPLY_STRING(KEY, TARGET) \
|
||||
if (strcmp(KEY, key) == 0) \
|
||||
{ \
|
||||
TARGET = hub_strdup(data); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#define CFG_APPLY_INTEGER(KEY, TARGET) \
|
||||
if (strcmp(KEY, key) == 0) \
|
||||
{ \
|
||||
char* endptr; \
|
||||
int val; \
|
||||
errno = 0; \
|
||||
val = strtol(data, &endptr, 10); \
|
||||
if (((errno == ERANGE && (val == INT_MAX || val == INT_MIN)) || (errno != 0 && val == 0)) || endptr == data /*|| endptr != &data[strlen(data)-1]*/) { \
|
||||
hub_log(log_fatal, "Configuration error on line %d: '%s' must be a number", line_count, key); \
|
||||
return -1; \
|
||||
} \
|
||||
TARGET = val; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#define DEFAULT_STRING(KEY, VALUE) \
|
||||
{ \
|
||||
if (config->KEY == 0) \
|
||||
config->KEY = hub_strdup(VALUE); \
|
||||
}
|
||||
|
||||
#define DEFAULT_INTEGER(KEY, VALUE) \
|
||||
{ \
|
||||
if (config->KEY == 0) \
|
||||
config->KEY = VALUE; \
|
||||
}
|
||||
|
||||
#define DEFAULT_BOOLEAN(KEY, VALUE) \
|
||||
{ \
|
||||
if (config->KEY & 0x80000000) \
|
||||
{ \
|
||||
config->KEY = config->KEY & 0x000000ff; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
config->KEY = VALUE; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GET_STR(NAME) CFG_APPLY_STRING ( #NAME , config->NAME )
|
||||
#define GET_INT(NAME) CFG_APPLY_INTEGER( #NAME , config->NAME )
|
||||
#define GET_BOOL(NAME) CFG_APPLY_BOOLEAN( #NAME , config->NAME )
|
||||
#define IGNORED(NAME) \
|
||||
if (strcmp(#NAME, key) == 0) \
|
||||
{ \
|
||||
hub_log(log_warning, "Configuration option %s deprecated and ingnored.", key); \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
/* default configuration values */
|
||||
#define DEF_SERVER_BIND_ADDR "any"
|
||||
#define DEF_SERVER_PORT 1511
|
||||
#define DEF_HUB_NAME "uhub"
|
||||
#define DEF_HUB_DESCRIPTION ""
|
||||
#define DEF_HUB_ENABLED 1
|
||||
#define DEF_FILE_ACL ""
|
||||
#define DEF_FILE_MOTD ""
|
||||
#define DEF_MAX_USERS 500
|
||||
#define DEF_MAX_RECV_BUFFER 4096
|
||||
#define DEF_MAX_SEND_BUFFER 131072
|
||||
#define DEF_MAX_SEND_BUFFER_SOFT 98304
|
||||
#define DEF_SHOW_BANNER 1
|
||||
#define DEF_REGISTERED_USERS_ONLY 0
|
||||
#define DEF_CHAT_ONLY 0
|
||||
#define DEF_CHAT_IS_PRIVILEGED 0
|
||||
#define DEF_LOW_BANDWIDTH_MODE 0
|
||||
#define DEF_LIMIT_MAX_HUBS_USER 0
|
||||
#define DEF_LIMIT_MAX_HUBS_REG 0
|
||||
#define DEF_LIMIT_MAX_HUBS_OP 0
|
||||
#define DEF_LIMIT_MAX_HUBS 0
|
||||
#define DEF_LIMIT_MIN_HUBS_USER 0
|
||||
#define DEF_LIMIT_MIN_HUBS_REG 0
|
||||
#define DEF_LIMIT_MIN_HUBS_OP 0
|
||||
#define DEF_LIMIT_MIN_SHARE 0
|
||||
#define DEF_LIMIT_MAX_SHARE 0
|
||||
#define DEF_LIMIT_MIN_SLOTS 0
|
||||
#define DEF_LIMIT_MAX_SLOTS 0
|
||||
#define DEF_MSG_HUB_FULL "Hub is full"
|
||||
#define DEF_MSG_HUB_DISABLED "Hub is disabled"
|
||||
#define DEF_MSG_HUB_REGISTERED_USERS_ONLY "Hub is for registered users only"
|
||||
#define DEF_MSG_INF_ERROR_NICK_MISSING "No nickname given"
|
||||
#define DEF_MSG_INF_ERROR_NICK_MULTIPLE "Multiple nicknames given"
|
||||
#define DEF_MSG_INF_ERROR_NICK_INVALID "Nickname is invalid"
|
||||
#define DEF_MSG_INF_ERROR_NICK_LONG "Nickname too long"
|
||||
#define DEF_MSG_INF_ERROR_NICK_SHORT "Nickname too short"
|
||||
#define DEF_MSG_INF_ERROR_NICK_SPACES "Nickname cannot start with spaces"
|
||||
#define DEF_MSG_INF_ERROR_NICK_BAD_CHARS "Nickname contains invalid characters"
|
||||
#define DEF_MSG_INF_ERROR_NICK_NOT_UTF8 "Nickname is not valid utf8"
|
||||
#define DEF_MSG_INF_ERROR_NICK_TAKEN "Nickname is already in use"
|
||||
#define DEF_MSG_INF_ERROR_NICK_RESTRICTED "Nickname cannot be used on this hub"
|
||||
#define DEF_MSG_INF_ERROR_CID_INVALID "CID is not valid"
|
||||
#define DEF_MSG_INF_ERROR_CID_MISSING "CID is not specified"
|
||||
#define DEF_MSG_INF_ERROR_CID_TAKEN "CID is taken"
|
||||
#define DEF_MSG_INF_ERROR_PID_MISSING "PID is not specified"
|
||||
#define DEF_MSG_INF_ERROR_PID_INVALID "PID is invalid"
|
||||
#define DEF_MSG_BAN_PERMANENTLY "Banned permanently"
|
||||
#define DEF_MSG_BAN_TEMPORARILY "Banned temporarily"
|
||||
#define DEF_MSG_AUTH_INVALID_PASSWORD "Password is wrong"
|
||||
#define DEF_MSG_AUTH_USER_NOT_FOUND "User not found in password database"
|
||||
#define DEF_MSG_ERROR_NO_MEMORY "No memory"
|
||||
#define DEF_MSG_USER_SHARE_SIZE_LOW "User is not sharing enough"
|
||||
#define DEF_MSG_USER_SHARE_SIZE_HIGH "User is sharing too much"
|
||||
#define DEF_MSG_USER_SLOTS_LOW "User have too few upload slots."
|
||||
#define DEF_MSG_USER_SLOTS_HIGH "User have too many upload slots."
|
||||
#define DEF_MSG_USER_HUB_LIMIT_LOW "User is on too few hubs."
|
||||
#define DEF_MSG_USER_HUB_LIMIT_HIGH "User is on too many hubs."
|
||||
|
||||
void config_defaults(struct hub_config* config)
|
||||
{
|
||||
DEFAULT_STRING (server_bind_addr, DEF_SERVER_BIND_ADDR);
|
||||
DEFAULT_STRING (hub_name, DEF_HUB_NAME);
|
||||
DEFAULT_STRING (hub_description, DEF_HUB_DESCRIPTION);
|
||||
DEFAULT_BOOLEAN(hub_enabled, DEF_HUB_ENABLED);
|
||||
DEFAULT_STRING (file_acl, DEF_FILE_ACL);
|
||||
DEFAULT_STRING (file_motd, DEF_FILE_MOTD);
|
||||
DEFAULT_INTEGER(server_port, DEF_SERVER_PORT);
|
||||
DEFAULT_INTEGER(max_users, DEF_MAX_USERS);
|
||||
DEFAULT_INTEGER(max_recv_buffer, DEF_MAX_RECV_BUFFER);
|
||||
DEFAULT_INTEGER(max_send_buffer, DEF_MAX_SEND_BUFFER);
|
||||
DEFAULT_INTEGER(max_send_buffer_soft, DEF_MAX_SEND_BUFFER_SOFT);
|
||||
DEFAULT_BOOLEAN(show_banner, DEF_SHOW_BANNER);
|
||||
DEFAULT_BOOLEAN(chat_only, DEF_CHAT_ONLY);
|
||||
DEFAULT_BOOLEAN(chat_is_privileged, DEF_CHAT_IS_PRIVILEGED);
|
||||
DEFAULT_BOOLEAN(low_bandwidth_mode, DEF_LOW_BANDWIDTH_MODE);
|
||||
DEFAULT_BOOLEAN(registered_users_only, DEF_REGISTERED_USERS_ONLY);
|
||||
|
||||
/* Limits enforced on users */
|
||||
DEFAULT_INTEGER(limit_max_hubs_user, DEF_LIMIT_MAX_HUBS_USER);
|
||||
DEFAULT_INTEGER(limit_max_hubs_reg, DEF_LIMIT_MAX_HUBS_REG);
|
||||
DEFAULT_INTEGER(limit_max_hubs_op, DEF_LIMIT_MAX_HUBS_OP);
|
||||
DEFAULT_INTEGER(limit_min_hubs_user, DEF_LIMIT_MIN_HUBS_USER);
|
||||
DEFAULT_INTEGER(limit_min_hubs_reg, DEF_LIMIT_MIN_HUBS_REG);
|
||||
DEFAULT_INTEGER(limit_min_hubs_op, DEF_LIMIT_MIN_HUBS_OP);
|
||||
DEFAULT_INTEGER(limit_max_hubs, DEF_LIMIT_MAX_HUBS);
|
||||
DEFAULT_INTEGER(limit_min_share, DEF_LIMIT_MIN_SHARE);
|
||||
DEFAULT_INTEGER(limit_max_share, DEF_LIMIT_MAX_SHARE);
|
||||
DEFAULT_INTEGER(limit_min_slots, DEF_LIMIT_MIN_SLOTS);
|
||||
DEFAULT_INTEGER(limit_max_slots, DEF_LIMIT_MAX_SLOTS);
|
||||
|
||||
/* Status/error strings */
|
||||
DEFAULT_STRING (msg_hub_full, DEF_MSG_HUB_FULL);
|
||||
DEFAULT_STRING (msg_hub_disabled, DEF_MSG_HUB_DISABLED)
|
||||
DEFAULT_STRING (msg_hub_registered_users_only, DEF_MSG_HUB_REGISTERED_USERS_ONLY);
|
||||
DEFAULT_STRING (msg_inf_error_nick_missing, DEF_MSG_INF_ERROR_NICK_MISSING);
|
||||
DEFAULT_STRING (msg_inf_error_nick_multiple, DEF_MSG_INF_ERROR_NICK_MULTIPLE);
|
||||
DEFAULT_STRING (msg_inf_error_nick_invalid, DEF_MSG_INF_ERROR_NICK_INVALID);
|
||||
DEFAULT_STRING (msg_inf_error_nick_long, DEF_MSG_INF_ERROR_NICK_LONG);
|
||||
DEFAULT_STRING (msg_inf_error_nick_short, DEF_MSG_INF_ERROR_NICK_SHORT);
|
||||
DEFAULT_STRING (msg_inf_error_nick_spaces, DEF_MSG_INF_ERROR_NICK_SPACES);
|
||||
DEFAULT_STRING (msg_inf_error_nick_bad_chars, DEF_MSG_INF_ERROR_NICK_BAD_CHARS);
|
||||
DEFAULT_STRING (msg_inf_error_nick_not_utf8, DEF_MSG_INF_ERROR_NICK_NOT_UTF8);
|
||||
DEFAULT_STRING (msg_inf_error_nick_taken, DEF_MSG_INF_ERROR_NICK_TAKEN);
|
||||
DEFAULT_STRING (msg_inf_error_nick_restricted, DEF_MSG_INF_ERROR_NICK_RESTRICTED);
|
||||
DEFAULT_STRING (msg_inf_error_cid_invalid, DEF_MSG_INF_ERROR_CID_INVALID);
|
||||
DEFAULT_STRING (msg_inf_error_cid_missing, DEF_MSG_INF_ERROR_CID_MISSING);
|
||||
DEFAULT_STRING (msg_inf_error_cid_taken, DEF_MSG_INF_ERROR_CID_TAKEN);
|
||||
DEFAULT_STRING (msg_inf_error_pid_missing, DEF_MSG_INF_ERROR_PID_MISSING);
|
||||
DEFAULT_STRING (msg_inf_error_pid_invalid, DEF_MSG_INF_ERROR_PID_INVALID);
|
||||
DEFAULT_STRING (msg_ban_permanently, DEF_MSG_BAN_PERMANENTLY);
|
||||
DEFAULT_STRING (msg_ban_temporarily, DEF_MSG_BAN_TEMPORARILY);
|
||||
DEFAULT_STRING (msg_auth_invalid_password, DEF_MSG_AUTH_INVALID_PASSWORD);
|
||||
DEFAULT_STRING (msg_auth_user_not_found, DEF_MSG_AUTH_USER_NOT_FOUND);
|
||||
DEFAULT_STRING (msg_error_no_memory, DEF_MSG_ERROR_NO_MEMORY);
|
||||
DEFAULT_STRING (msg_user_share_size_low, DEF_MSG_USER_SHARE_SIZE_LOW);
|
||||
DEFAULT_STRING (msg_user_share_size_high, DEF_MSG_USER_SHARE_SIZE_HIGH);
|
||||
DEFAULT_STRING (msg_user_slots_low, DEF_MSG_USER_SLOTS_LOW);
|
||||
DEFAULT_STRING (msg_user_slots_high, DEF_MSG_USER_SLOTS_HIGH);
|
||||
DEFAULT_STRING (msg_user_hub_limit_low, DEF_MSG_USER_HUB_LIMIT_LOW);
|
||||
DEFAULT_STRING (msg_user_hub_limit_high, DEF_MSG_USER_HUB_LIMIT_HIGH);
|
||||
|
||||
DEFAULT_INTEGER(tls_enable, 0);
|
||||
DEFAULT_INTEGER(tls_require, 0);
|
||||
DEFAULT_STRING (tls_certificate, "");
|
||||
DEFAULT_STRING (tls_private_key, "");
|
||||
}
|
||||
|
||||
|
||||
static int apply_config(struct hub_config* config, char* key, char* data, int line_count)
|
||||
{
|
||||
GET_STR (file_acl);
|
||||
GET_STR (file_motd);
|
||||
GET_STR (server_bind_addr);
|
||||
GET_INT (server_port);
|
||||
GET_STR (hub_name);
|
||||
GET_STR (hub_description);
|
||||
GET_BOOL(hub_enabled);
|
||||
GET_INT (max_users);
|
||||
GET_INT (max_recv_buffer);
|
||||
GET_INT (max_send_buffer);
|
||||
GET_INT (max_send_buffer_soft);
|
||||
GET_BOOL(show_banner);
|
||||
GET_BOOL(chat_only);
|
||||
GET_BOOL(chat_is_privileged);
|
||||
GET_BOOL(low_bandwidth_mode);
|
||||
GET_BOOL(registered_users_only);
|
||||
|
||||
/* Limits enforced on users */
|
||||
GET_INT(limit_max_hubs_user);
|
||||
GET_INT(limit_max_hubs_reg);
|
||||
GET_INT(limit_max_hubs_op);
|
||||
GET_INT(limit_min_hubs_user);
|
||||
GET_INT(limit_min_hubs_reg);
|
||||
GET_INT(limit_min_hubs_op);
|
||||
GET_INT(limit_max_hubs);
|
||||
GET_INT(limit_min_share);
|
||||
GET_INT(limit_max_share);
|
||||
GET_INT(limit_min_slots);
|
||||
GET_INT(limit_max_slots);
|
||||
|
||||
/* Status/error strings */
|
||||
GET_STR (msg_hub_full);
|
||||
GET_STR (msg_hub_disabled);
|
||||
GET_STR (msg_hub_registered_users_only);
|
||||
GET_STR (msg_inf_error_nick_missing);
|
||||
GET_STR (msg_inf_error_nick_multiple);
|
||||
GET_STR (msg_inf_error_nick_invalid);
|
||||
GET_STR (msg_inf_error_nick_long);
|
||||
GET_STR (msg_inf_error_nick_short);
|
||||
GET_STR (msg_inf_error_nick_spaces);
|
||||
GET_STR (msg_inf_error_nick_bad_chars);
|
||||
GET_STR (msg_inf_error_nick_not_utf8);
|
||||
GET_STR (msg_inf_error_nick_taken);
|
||||
GET_STR (msg_inf_error_nick_restricted);
|
||||
GET_STR (msg_inf_error_cid_invalid);
|
||||
GET_STR (msg_inf_error_cid_missing);
|
||||
GET_STR (msg_inf_error_cid_taken);
|
||||
GET_STR (msg_inf_error_pid_missing);
|
||||
GET_STR (msg_inf_error_pid_invalid);
|
||||
GET_STR (msg_ban_permanently);
|
||||
GET_STR (msg_ban_temporarily);
|
||||
GET_STR (msg_auth_invalid_password);
|
||||
GET_STR (msg_auth_user_not_found);
|
||||
GET_STR (msg_error_no_memory);
|
||||
GET_STR (msg_user_share_size_low);
|
||||
GET_STR (msg_user_share_size_high);
|
||||
GET_STR (msg_user_slots_low);
|
||||
GET_STR (msg_user_slots_high);
|
||||
GET_STR (msg_user_hub_limit_low);
|
||||
GET_STR (msg_user_hub_limit_high);
|
||||
|
||||
GET_BOOL(tls_enable);
|
||||
GET_BOOL(tls_require);
|
||||
GET_STR (tls_certificate);
|
||||
GET_STR (tls_private_key);
|
||||
|
||||
/* Still here -- unknown directive */
|
||||
hub_log(log_fatal, "Unknown configuration directive: '%s'", key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void free_config(struct hub_config* config)
|
||||
{
|
||||
hub_free(config->server_bind_addr);
|
||||
hub_free(config->file_motd);
|
||||
hub_free(config->file_acl);
|
||||
hub_free(config->hub_name);
|
||||
hub_free(config->hub_description);
|
||||
|
||||
hub_free(config->msg_hub_full);
|
||||
hub_free(config->msg_hub_disabled);
|
||||
hub_free(config->msg_hub_registered_users_only);
|
||||
hub_free(config->msg_inf_error_nick_missing);
|
||||
hub_free(config->msg_inf_error_nick_multiple);
|
||||
hub_free(config->msg_inf_error_nick_invalid);
|
||||
hub_free(config->msg_inf_error_nick_long);
|
||||
hub_free(config->msg_inf_error_nick_short);
|
||||
hub_free(config->msg_inf_error_nick_spaces);
|
||||
hub_free(config->msg_inf_error_nick_bad_chars);
|
||||
hub_free(config->msg_inf_error_nick_not_utf8);
|
||||
hub_free(config->msg_inf_error_nick_taken);
|
||||
hub_free(config->msg_inf_error_nick_restricted);
|
||||
hub_free(config->msg_inf_error_cid_invalid);
|
||||
hub_free(config->msg_inf_error_cid_missing);
|
||||
hub_free(config->msg_inf_error_cid_taken);
|
||||
hub_free(config->msg_inf_error_pid_missing);
|
||||
hub_free(config->msg_inf_error_pid_invalid);
|
||||
hub_free(config->msg_ban_permanently);
|
||||
hub_free(config->msg_ban_temporarily);
|
||||
hub_free(config->msg_auth_invalid_password);
|
||||
hub_free(config->msg_auth_user_not_found);
|
||||
hub_free(config->msg_error_no_memory);
|
||||
hub_free(config->msg_user_share_size_low);
|
||||
hub_free(config->msg_user_share_size_high);
|
||||
hub_free(config->msg_user_slots_low);
|
||||
hub_free(config->msg_user_slots_high);
|
||||
hub_free(config->msg_user_hub_limit_low);
|
||||
hub_free(config->msg_user_hub_limit_high);
|
||||
|
||||
hub_free(config->tls_certificate);
|
||||
hub_free(config->tls_private_key);
|
||||
|
||||
memset(config, 0, sizeof(struct hub_config));
|
||||
}
|
||||
|
||||
#define DUMP_STR(NAME, DEFAULT) \
|
||||
if (ignore_defaults) \
|
||||
{ \
|
||||
if (strcmp(config->NAME, DEFAULT) != 0) \
|
||||
fprintf(stdout, "%s = \"%s\"\n", #NAME , config->NAME); \
|
||||
} \
|
||||
else \
|
||||
fprintf(stdout, "%s = \"%s\"\n", #NAME , config->NAME); \
|
||||
|
||||
#define DUMP_INT(NAME, DEFAULT) \
|
||||
if (ignore_defaults) \
|
||||
{ \
|
||||
if (config->NAME != DEFAULT) \
|
||||
fprintf(stdout, "%s = \"%d\"\n", #NAME , config->NAME); \
|
||||
} \
|
||||
else \
|
||||
fprintf(stdout, "%s = \"%d\"\n", #NAME , config->NAME); \
|
||||
|
||||
|
||||
#define DUMP_BOOL(NAME, DEFAULT) \
|
||||
if (ignore_defaults) \
|
||||
{ \
|
||||
if (config->NAME != DEFAULT) \
|
||||
fprintf(stdout, "%s = \"%s\"\n", #NAME , (config->NAME ? "yes" : "no")); \
|
||||
} \
|
||||
else \
|
||||
fprintf(stdout, "%s = \"%s\"\n", #NAME , (config->NAME ? "yes" : "no"));
|
||||
|
||||
void dump_config(struct hub_config* config, int ignore_defaults)
|
||||
{
|
||||
DUMP_STR (file_acl, DEF_FILE_ACL);
|
||||
DUMP_STR (file_motd, DEF_FILE_MOTD);
|
||||
DUMP_STR (server_bind_addr, DEF_SERVER_BIND_ADDR);
|
||||
DUMP_INT (server_port, DEF_SERVER_PORT);
|
||||
DUMP_STR (hub_name, DEF_HUB_NAME);
|
||||
DUMP_STR (hub_description, DEF_HUB_DESCRIPTION);
|
||||
DUMP_BOOL(hub_enabled, DEF_HUB_ENABLED);
|
||||
DUMP_INT (max_users, DEF_MAX_USERS);
|
||||
DUMP_INT (max_recv_buffer, DEF_MAX_RECV_BUFFER);
|
||||
DUMP_INT (max_send_buffer, DEF_MAX_SEND_BUFFER);
|
||||
DUMP_INT (max_send_buffer_soft, DEF_MAX_SEND_BUFFER_SOFT);
|
||||
DUMP_BOOL(show_banner, DEF_SHOW_BANNER);
|
||||
DUMP_BOOL(chat_only, DEF_CHAT_ONLY);
|
||||
DUMP_BOOL(chat_is_privileged, DEF_CHAT_IS_PRIVILEGED);
|
||||
DUMP_BOOL(low_bandwidth_mode, DEF_LOW_BANDWIDTH_MODE);
|
||||
DUMP_BOOL(registered_users_only, DEF_REGISTERED_USERS_ONLY);
|
||||
|
||||
/* Limits enforced on users */
|
||||
DUMP_INT(limit_max_hubs_user, DEF_LIMIT_MAX_HUBS_USER);
|
||||
DUMP_INT(limit_max_hubs_reg, DEF_LIMIT_MAX_HUBS_REG);
|
||||
DUMP_INT(limit_max_hubs_op, DEF_LIMIT_MAX_HUBS_OP);
|
||||
DUMP_INT(limit_min_hubs_user, DEF_LIMIT_MIN_HUBS_USER);
|
||||
DUMP_INT(limit_min_hubs_reg, DEF_LIMIT_MIN_HUBS_REG);
|
||||
DUMP_INT(limit_min_hubs_op, DEF_LIMIT_MIN_HUBS_OP);
|
||||
DUMP_INT(limit_max_hubs, DEF_LIMIT_MAX_HUBS);
|
||||
DUMP_INT(limit_min_share, DEF_LIMIT_MIN_SHARE);
|
||||
DUMP_INT(limit_max_share, DEF_LIMIT_MAX_SHARE);
|
||||
DUMP_INT(limit_min_slots, DEF_LIMIT_MIN_SLOTS);
|
||||
DUMP_INT(limit_max_slots, DEF_LIMIT_MAX_SLOTS);
|
||||
|
||||
/* Status/error strings */
|
||||
DUMP_STR (msg_hub_full, DEF_MSG_HUB_FULL);
|
||||
DUMP_STR (msg_hub_disabled, DEF_MSG_HUB_DISABLED);
|
||||
DUMP_STR (msg_hub_registered_users_only, DEF_MSG_HUB_REGISTERED_USERS_ONLY);
|
||||
DUMP_STR (msg_inf_error_nick_missing, DEF_MSG_INF_ERROR_NICK_MISSING);
|
||||
DUMP_STR (msg_inf_error_nick_multiple, DEF_MSG_INF_ERROR_NICK_MULTIPLE);
|
||||
DUMP_STR (msg_inf_error_nick_invalid, DEF_MSG_INF_ERROR_NICK_INVALID);
|
||||
DUMP_STR (msg_inf_error_nick_long, DEF_MSG_INF_ERROR_NICK_LONG);
|
||||
DUMP_STR (msg_inf_error_nick_short, DEF_MSG_INF_ERROR_NICK_SHORT);
|
||||
DUMP_STR (msg_inf_error_nick_spaces, DEF_MSG_INF_ERROR_NICK_SPACES);
|
||||
DUMP_STR (msg_inf_error_nick_bad_chars, DEF_MSG_INF_ERROR_NICK_BAD_CHARS);
|
||||
DUMP_STR (msg_inf_error_nick_not_utf8, DEF_MSG_INF_ERROR_NICK_NOT_UTF8);
|
||||
DUMP_STR (msg_inf_error_nick_taken, DEF_MSG_INF_ERROR_NICK_TAKEN);
|
||||
DUMP_STR (msg_inf_error_nick_restricted, DEF_MSG_INF_ERROR_NICK_RESTRICTED);
|
||||
DUMP_STR (msg_inf_error_cid_invalid, DEF_MSG_INF_ERROR_CID_INVALID);
|
||||
DUMP_STR (msg_inf_error_cid_missing, DEF_MSG_INF_ERROR_CID_MISSING);
|
||||
DUMP_STR (msg_inf_error_cid_taken, DEF_MSG_INF_ERROR_CID_TAKEN);
|
||||
DUMP_STR (msg_inf_error_pid_missing, DEF_MSG_INF_ERROR_PID_MISSING);
|
||||
DUMP_STR (msg_inf_error_pid_invalid, DEF_MSG_INF_ERROR_PID_INVALID);
|
||||
DUMP_STR (msg_ban_permanently, DEF_MSG_BAN_PERMANENTLY);
|
||||
DUMP_STR (msg_ban_temporarily, DEF_MSG_BAN_TEMPORARILY);
|
||||
DUMP_STR (msg_auth_invalid_password, DEF_MSG_AUTH_INVALID_PASSWORD);
|
||||
DUMP_STR (msg_auth_user_not_found, DEF_MSG_AUTH_USER_NOT_FOUND);
|
||||
DUMP_STR (msg_error_no_memory, DEF_MSG_ERROR_NO_MEMORY);
|
||||
DUMP_STR (msg_user_share_size_low, DEF_MSG_USER_SHARE_SIZE_LOW);
|
||||
DUMP_STR (msg_user_share_size_high, DEF_MSG_USER_SHARE_SIZE_HIGH);
|
||||
DUMP_STR (msg_user_slots_low, DEF_MSG_USER_SLOTS_LOW);
|
||||
DUMP_STR (msg_user_slots_high, DEF_MSG_USER_SLOTS_HIGH);
|
||||
DUMP_STR (msg_user_hub_limit_low, DEF_MSG_USER_HUB_LIMIT_LOW);
|
||||
DUMP_STR (msg_user_hub_limit_high, DEF_MSG_USER_HUB_LIMIT_HIGH);
|
||||
}
|
||||
|
||||
|
||||
static int config_parse_line(char* line, int line_count, void* ptr_data)
|
||||
{
|
||||
char* pos;
|
||||
char* key;
|
||||
char* data;
|
||||
struct hub_config* config = (struct hub_config*) ptr_data;
|
||||
|
||||
if ((pos = strchr(line, '#')) != NULL)
|
||||
{
|
||||
pos[0] = 0;
|
||||
}
|
||||
|
||||
if (strlen(line) == 0) return 0;
|
||||
|
||||
#ifdef CONFIG_DUMP
|
||||
hub_log(log_trace, "config_parse_line(): '%s'", line);
|
||||
#endif
|
||||
|
||||
if ((pos = strchr(line, '=')) != NULL)
|
||||
{
|
||||
pos[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
key = line;
|
||||
data = &pos[1];
|
||||
|
||||
key = strip_white_space(key);
|
||||
data = strip_white_space(data);
|
||||
|
||||
if (!strlen(key) || !strlen(data))
|
||||
{
|
||||
hub_log(log_fatal, "Configuration parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DUMP
|
||||
hub_log(log_trace, "config_parse_line: '%s' => '%s'", key, data);
|
||||
#endif
|
||||
|
||||
return apply_config(config, key, data, line_count);
|
||||
}
|
||||
|
||||
|
||||
int read_config(const char* file, struct hub_config* config, int allow_missing)
|
||||
{
|
||||
int ret;
|
||||
|
||||
memset(config, 0, sizeof(struct hub_config));
|
||||
|
||||
ret = file_read_lines(file, config, &config_parse_line);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (allow_missing && ret == -2)
|
||||
{
|
||||
hub_log(log_debug, "Using default configuration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
config_defaults(config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
122
src/config.h
Normal file
122
src/config.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_CONFIG_H
|
||||
#define HAVE_UHUB_CONFIG_H
|
||||
|
||||
struct hub_config
|
||||
{
|
||||
int server_port; /**<<< "Server port to bind to (default: 1511)" */
|
||||
char* server_bind_addr; /**<<< "Server bind address (default: '0.0.0.0' or '::')" */
|
||||
int hub_enabled; /**<<< "Is server enabled (default: 1)" */
|
||||
int show_banner; /**<<< "Show banner on connect (default: 1)" */
|
||||
int max_users; /**<<< "Maximum number of users allowed on the hub (default: 500)" */
|
||||
int registered_users_only; /**<<< "Allow registered users only (default: 0)" */
|
||||
int chat_only; /**<<< "Allow chat only operation on hub (default: 0)" */
|
||||
int chat_is_privileged; /**<<< "Allow chat for operators and above only (default: 0) */
|
||||
char* file_motd; /**<<< "File containing the 'message of the day' (default: '' - no motd)" */
|
||||
char* file_acl; /**<<< "File containing user database (default: '' - no known users)" */
|
||||
char* hub_name; /**<<< "Name of hub (default: 'My uhub hub')" */
|
||||
char* hub_description; /**<<< "Name of hub (default: 'no description')" */
|
||||
int max_recv_buffer; /**<<< "Max read buffer before parse, per user (default: 4096)" */
|
||||
int max_send_buffer; /**<<< "Max send buffer before disconnect, per user (default: 16384)" */
|
||||
int max_send_buffer_soft; /**<<< "Max send buffer before message drops, per user (default: 8192)" */
|
||||
int low_bandwidth_mode; /**<<< "If this is enabled, the hub will strip off elements from each user's info message to reduce bandwidth usage" */
|
||||
|
||||
/* Limits enforced on users */
|
||||
int limit_max_hubs_user; /**<<< "Max concurrent hubs as a user. (0=off, default: 10)" */
|
||||
int limit_max_hubs_reg; /**<<< "Max concurrent hubs as registered user. (0=off, default: 10)" */
|
||||
int limit_max_hubs_op; /**<<< "Max concurrent hubs as operator. (0=off, default: 10)" */
|
||||
int limit_min_hubs_user; /**<<< "Min concurrent hubs as a user. (0=off, default: 0)" */
|
||||
int limit_min_hubs_reg; /**<<< "Min concurrent hubs as registered user. (0=off, default: 0)" */
|
||||
int limit_min_hubs_op; /**<<< "Min concurrent hubs as operator. (0=off, default: 0)" */
|
||||
int limit_max_hubs; /**<<< "Max total hub connections allowed, user/reg/op combined. (0=off, default: 25)" */
|
||||
int limit_min_share; /**<<< "Limit minimum share size in megabytes (MiB) (0=off, default: 0)" */
|
||||
int limit_max_share; /**<<< "Limit maximum share size in megabytes (MiB) (0=off, default: 0)" */
|
||||
int limit_min_slots; /**<<< "Limit minimum number of slots open per user (0=off, default: 0)" */
|
||||
int limit_max_slots; /**<<< "Limit maximum number of slots open per user (0=off, default: 0)" */
|
||||
|
||||
/* Messages that can be sent to a user */
|
||||
char* msg_hub_full; /**<<< "hub is full" */
|
||||
char* msg_hub_disabled; /**<<< "hub is disabled" */
|
||||
char* msg_hub_registered_users_only; /**<<< "hub is for registered users only" */
|
||||
char* msg_inf_error_nick_missing; /**<<< "no nickname given" */
|
||||
char* msg_inf_error_nick_multiple; /**<<< "multiple nicknames given" */
|
||||
char* msg_inf_error_nick_invalid; /**<<< "generic/unkown" */
|
||||
char* msg_inf_error_nick_long; /**<<< "nickname too long" */
|
||||
char* msg_inf_error_nick_short; /**<<< "nickname too short" */
|
||||
char* msg_inf_error_nick_spaces; /**<<< "nickname cannot start with spaces" */
|
||||
char* msg_inf_error_nick_bad_chars; /**<<< "nickname contains chars below ascii 32" */
|
||||
char* msg_inf_error_nick_not_utf8; /**<<< "nickname is not valid utf8" */
|
||||
char* msg_inf_error_nick_taken; /**<<< "nickname is in use" */
|
||||
char* msg_inf_error_nick_restricted; /**<<< "nickname cannot be used on this hub" */
|
||||
char* msg_inf_error_cid_invalid; /**<<< "CID is not valid" */
|
||||
char* msg_inf_error_cid_missing; /**<<< "CID is not specified" */
|
||||
char* msg_inf_error_cid_taken; /**<<< "CID is taken" */
|
||||
char* msg_inf_error_pid_missing; /**<<< "PID is not specified" */
|
||||
char* msg_inf_error_pid_invalid; /**<<< "PID is invalid" */
|
||||
char* msg_ban_permanently; /**<<< "Banned permanently" */
|
||||
char* msg_ban_temporarily; /**<<< "Banned temporarily" */
|
||||
char* msg_auth_invalid_password; /**<<< "Password is wrong" */
|
||||
char* msg_auth_user_not_found; /**<<< "User not found in password database" */
|
||||
char* msg_error_no_memory; /**<<< "No memory" */
|
||||
char* msg_user_share_size_low; /**<<< "User is not sharing enough" */
|
||||
char* msg_user_share_size_high; /**<<< "User is sharing too much" */
|
||||
char* msg_user_slots_low; /**<<< "User have too few upload slots." */
|
||||
char* msg_user_slots_high; /**<<< "User have too many upload slots." */
|
||||
char* msg_user_hub_limit_low; /**<<< "User is on too few hubs." */
|
||||
char* msg_user_hub_limit_high; /**<<< "User is on too many hubs." */
|
||||
|
||||
int tls_enable; /**<<< "Enable SSL/TLS support (default: 0)" */
|
||||
int tls_require; /**<<< "If SSL/TLS enabled, should it be required (default: 0) */
|
||||
char* tls_certificate; /**<<< "Certificate file (PEM)" */
|
||||
char* tls_private_key; /**<<< "Private key" */
|
||||
};
|
||||
|
||||
/**
|
||||
* This initializes the configuration variables, and sets the default
|
||||
* variables.
|
||||
*
|
||||
* NOTE: Any variable is set to it's default variable if zero.
|
||||
* This function is automatically called in read_config to set any
|
||||
* configuration that was missing there.
|
||||
*/
|
||||
extern void config_defaults(struct hub_config* config);
|
||||
|
||||
/**
|
||||
* Read configuration from file, and use the default variables for
|
||||
* the missing variables.
|
||||
*
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int read_config(const char* file, struct hub_config* config, int allow_missing);
|
||||
|
||||
/**
|
||||
* Free the configuration data (allocated by read_config, or config_defaults).
|
||||
*/
|
||||
extern void free_config(struct hub_config* config);
|
||||
|
||||
/**
|
||||
* Print all configuration data to standard out.
|
||||
*/
|
||||
extern void dump_config(struct hub_config* config, int ignore_defaults);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_CONFIG_H */
|
||||
|
37
src/eventid.h
Normal file
37
src/eventid.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_EVENT_ID_H
|
||||
#define HAVE_UHUB_EVENT_ID_H
|
||||
|
||||
/* User join or quit messages */
|
||||
#define UHUB_EVENT_USER_JOIN 0x1001
|
||||
#define UHUB_EVENT_USER_QUIT 0x1002
|
||||
#define UHUB_EVENT_USER_DESTROY 0x1003
|
||||
|
||||
/* Send a broadcast message */
|
||||
#define UHUB_EVENT_BROADCAST 0x2000
|
||||
|
||||
/* Statistics, OOM, reconfigure */
|
||||
#define UHUB_EVENT_STATISTICS 0x4000
|
||||
#define UHUB_EVENT_OUT_OF_MEMORY 0x4001
|
||||
#define UHUB_EVENT_RECONFIGURE 0x4002
|
||||
|
||||
#endif /* HAVE_UHUB_EVENT_ID_H */
|
||||
|
172
src/eventqueue.c
Normal file
172
src/eventqueue.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#ifdef EQ_DEBUG
|
||||
static void eq_debug(const char* prefix, struct event_data* data)
|
||||
{
|
||||
printf(">>> %s: %p, id: %x, flags=%d\n", prefix, data, data->id, data->flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int event_queue_initialize(struct event_queue** queue, event_queue_callback callback, void* ptr)
|
||||
{
|
||||
*queue = (struct event_queue*) hub_malloc_zero(sizeof(struct event_queue));
|
||||
if (!(*queue))
|
||||
return -1;
|
||||
|
||||
(*queue)->q1 = list_create();
|
||||
(*queue)->q2 = list_create();
|
||||
(*queue)->event = (struct event*) hub_malloc_zero(sizeof(struct event));
|
||||
|
||||
if (!(*queue)->q1 || !(*queue)->q2 || !(*queue)->event)
|
||||
{
|
||||
list_destroy((*queue)->q1);
|
||||
list_destroy((*queue)->q2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*queue)->callback = callback;
|
||||
(*queue)->callback_data = ptr;
|
||||
|
||||
evtimer_set((*queue)->event, libevent_queue_process, *queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void event_queue_shutdown(struct event_queue* queue)
|
||||
{
|
||||
/* Should be empty at this point! */
|
||||
list_destroy(queue->q1);
|
||||
list_destroy(queue->q2);
|
||||
|
||||
if (queue->event)
|
||||
{
|
||||
evtimer_del(queue->event);
|
||||
hub_free(queue->event);
|
||||
}
|
||||
hub_free(queue);
|
||||
}
|
||||
|
||||
static void event_queue_cleanup_callback(void* ptr)
|
||||
{
|
||||
#ifdef EQ_DEBUG
|
||||
struct event_data* data = (struct event_data*) ptr;
|
||||
eq_debug("NUKE", data);
|
||||
#endif
|
||||
|
||||
hub_free((struct event_data*) ptr);
|
||||
}
|
||||
|
||||
int event_queue_process(struct event_queue* queue)
|
||||
{
|
||||
struct event_data* data;
|
||||
if (queue->locked)
|
||||
return 0;
|
||||
|
||||
/* lock primary queue, and handle the primary queue messages. */
|
||||
queue->locked = 1;
|
||||
|
||||
data = (struct event_data*) list_get_first(queue->q1);
|
||||
while (data)
|
||||
{
|
||||
#ifdef EQ_DEBUG
|
||||
eq_debug("EXEC", data);
|
||||
#endif
|
||||
queue->callback(queue->callback_data, data);
|
||||
data = (struct event_data*) list_get_next(queue->q1);
|
||||
}
|
||||
|
||||
list_clear(queue->q1, event_queue_cleanup_callback);
|
||||
assert(list_size(queue->q1) == 0);
|
||||
|
||||
/* unlock queue */
|
||||
queue->locked = 0;
|
||||
|
||||
/* transfer from secondary queue to the primary queue. */
|
||||
data = (struct event_data*) list_get_first(queue->q2);
|
||||
while (data)
|
||||
{
|
||||
list_remove(queue->q2, data);
|
||||
list_append(queue->q1, data);
|
||||
data = (struct event_data*) list_get_first(queue->q2);
|
||||
}
|
||||
|
||||
/* if more events exist, schedule it */
|
||||
if (list_size(queue->q1))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void event_queue_post(struct event_queue* queue, struct event_data* message)
|
||||
{
|
||||
struct linked_list* q = (!queue->locked) ? queue->q1 : queue->q2;
|
||||
struct event_data* data;
|
||||
|
||||
data = (struct event_data*) hub_malloc(sizeof(struct event_data));
|
||||
if (data)
|
||||
{
|
||||
data->id = message->id;
|
||||
data->ptr = message->ptr;
|
||||
data->flags = message->flags;
|
||||
|
||||
#ifdef EQ_DEBUG
|
||||
eq_debug("POST", data);
|
||||
#endif
|
||||
|
||||
list_append(q, data);
|
||||
|
||||
|
||||
if (!queue->locked && queue->event)
|
||||
{
|
||||
libevent_queue_schedule(queue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_error, "event_queue_post: OUT OF MEMORY");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t event_queue_size(struct event_queue* queue)
|
||||
{
|
||||
return list_size(queue->q1) + list_size(queue->q2);
|
||||
}
|
||||
|
||||
void libevent_queue_schedule(struct event_queue* queue)
|
||||
{
|
||||
struct timeval zero = { 0, };
|
||||
evtimer_add(queue->event, &zero);
|
||||
}
|
||||
|
||||
void libevent_queue_process(int fd, short events, void* arg)
|
||||
{
|
||||
struct event_queue* queue = (struct event_queue*) arg;
|
||||
if (event_queue_process(queue))
|
||||
{
|
||||
libevent_queue_schedule(queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
55
src/eventqueue.h
Normal file
55
src/eventqueue.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_EVENT_QUEUE_H
|
||||
#define HAVE_UHUB_EVENT_QUEUE_H
|
||||
|
||||
struct event_data
|
||||
{
|
||||
int id;
|
||||
void* ptr;
|
||||
int flags;
|
||||
};
|
||||
|
||||
typedef void (*event_queue_callback)(void* callback_data, struct event_data* event_data);
|
||||
|
||||
struct event_queue
|
||||
{
|
||||
int locked;
|
||||
struct linked_list* q1; /* primary */
|
||||
struct linked_list* q2; /* secondary, when primary is locked */
|
||||
event_queue_callback callback;
|
||||
void* callback_data;
|
||||
struct event* event; /* libevent handle */
|
||||
};
|
||||
|
||||
extern int event_queue_initialize(struct event_queue** queue, event_queue_callback callback, void* ptr);
|
||||
extern int event_queue_process(struct event_queue* queue);
|
||||
extern void event_queue_shutdown(struct event_queue* queue);
|
||||
extern void event_queue_post(struct event_queue* queue, struct event_data* message);
|
||||
extern size_t event_queue_size(struct event_queue* queue);
|
||||
|
||||
/**
|
||||
* Only used internally with libevent.
|
||||
*/
|
||||
extern void libevent_queue_process(int fd, short events, void* arg);
|
||||
extern void libevent_queue_schedule(struct event_queue* queue);
|
||||
|
||||
#endif /* HAVE_UHUB_EVENT_QUEUE_H */
|
||||
|
950
src/hub.c
Normal file
950
src/hub.c
Normal file
@ -0,0 +1,950 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
{
|
||||
int ret = 0;
|
||||
struct adc_message* cmd = 0;
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
hub_log(log_protocol, "recv %s: %s", sid_to_string(u->id.sid), line);
|
||||
#endif
|
||||
|
||||
if (user_is_disconnecting(u))
|
||||
return -1;
|
||||
|
||||
cmd = adc_msg_parse_verify(u, line, length);
|
||||
if (cmd)
|
||||
{
|
||||
switch (cmd->cmd)
|
||||
{
|
||||
case ADC_CMD_HSUP: ret = hub_handle_support(u, cmd); break;
|
||||
case ADC_CMD_HPAS: ret = hub_handle_password(u, cmd); break;
|
||||
case ADC_CMD_BINF: ret = hub_handle_info(u, cmd); break;
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
case ADC_CMD_HCHK: ret = hub_handle_autocheck(u, cmd); break;
|
||||
#endif
|
||||
case ADC_CMD_DINF:
|
||||
case ADC_CMD_EINF:
|
||||
case ADC_CMD_FINF:
|
||||
/* these must never be allowed for security reasons,
|
||||
so we ignore them. */
|
||||
break;
|
||||
|
||||
case ADC_CMD_BSCH:
|
||||
case ADC_CMD_DSCH:
|
||||
case ADC_CMD_ESCH:
|
||||
case ADC_CMD_FSCH:
|
||||
case ADC_CMD_DRES:
|
||||
case ADC_CMD_DRCM:
|
||||
case ADC_CMD_DCTM:
|
||||
if (u->hub->config->chat_only && u->credentials < cred_operator)
|
||||
{
|
||||
/* These below aren't allowed in chat only hubs */
|
||||
break;
|
||||
}
|
||||
|
||||
case ADC_CMD_EMSG:
|
||||
case ADC_CMD_DMSG:
|
||||
case ADC_CMD_BMSG:
|
||||
case ADC_CMD_FMSG:
|
||||
ret = hub_handle_chat_message(u, cmd); break;
|
||||
|
||||
default:
|
||||
if (user_is_logged_in(u))
|
||||
{
|
||||
ret = route_message(u, cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
adc_msg_free(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!user_is_logged_in(u))
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_support(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
int index = 0;
|
||||
int ok = 1;
|
||||
char* arg = adc_msg_get_argument(cmd, index);
|
||||
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
|
||||
|
||||
if (u->hub->status == hub_status_disabled && u->state == state_protocol)
|
||||
{
|
||||
on_login_failure(u, status_msg_hub_disabled);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (arg)
|
||||
{
|
||||
|
||||
if (strlen(arg) == 6)
|
||||
{
|
||||
fourcc_t fourcc = FOURCC(arg[2], arg[3], arg[4], arg[5]);
|
||||
if (strncmp(arg, ADC_SUP_FLAG_ADD, 2) == 0)
|
||||
{
|
||||
user_support_add(u, fourcc);
|
||||
}
|
||||
else if (strncmp(arg, ADC_SUP_FLAG_REMOVE, 2) == 0)
|
||||
{
|
||||
user_support_remove(u, fourcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
index++;
|
||||
hub_free(arg);
|
||||
arg = adc_msg_get_argument(cmd, index);
|
||||
}
|
||||
|
||||
if (u->state == state_protocol)
|
||||
{
|
||||
if (index == 0) ok = 0; /* Need to support *SOMETHING*, at least BASE */
|
||||
|
||||
if (ok)
|
||||
{
|
||||
hub_send_handshake(u);
|
||||
if (u->ev_read)
|
||||
event_add(u->ev_read, &timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disconnect user. Do not send crap during initial handshake! */
|
||||
user_disconnect(u, quit_logon_error);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_password(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char* password = adc_msg_get_argument(cmd, 0);
|
||||
int ret = 0;
|
||||
|
||||
if (u->state == state_verify)
|
||||
{
|
||||
if (password_verify(u, password))
|
||||
{
|
||||
on_login_success(u);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_login_failure(u, status_msg_auth_invalid_password);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
hub_free(password);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_chat_message(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char* message = adc_msg_get_argument(cmd, 0);
|
||||
int ret = 0;
|
||||
int relay = 1;
|
||||
|
||||
/* TODO: Check for hub-commands here. Set relay to 0 and the message will not be sent to other users. */
|
||||
if (message[0] == '!')
|
||||
{
|
||||
relay = command_dipatcher(u, message);
|
||||
}
|
||||
|
||||
if (relay && user_is_logged_in(u))
|
||||
{
|
||||
/* adc_msg_remove_named_argument(cmd, "PM"); */
|
||||
ret = route_message(u, cmd);
|
||||
}
|
||||
|
||||
free(message);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int on_kick(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
hub_log(log_error, "on_kick() not implemented");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int hub_handle_autocheck(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char* port_str = adc_msg_get_argument(cmd, 0);
|
||||
char* token = adc_msg_get_argument(cmd, 1);
|
||||
int port = 0;
|
||||
|
||||
if (!port_str || !token || strlen(token) != 4)
|
||||
{
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = uhub_atoi(port_str);
|
||||
|
||||
if (port == 0 || port > 65535)
|
||||
{
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub_send_autocheck(u, port, token);
|
||||
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void hub_send_autocheck(struct user* u, uint16_t port, const char* token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hub_send_support(struct user* u)
|
||||
{
|
||||
if (user_is_connecting(u) || user_is_logged_in(u))
|
||||
{
|
||||
route_to_user(u, u->hub->command_support);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_sid(struct user* u)
|
||||
{
|
||||
struct adc_message* command;
|
||||
if (user_is_connecting(u))
|
||||
{
|
||||
command = adc_msg_construct(ADC_CMD_ISID, 10);
|
||||
u->id.sid = user_manager_get_free_sid(u->hub);
|
||||
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
|
||||
route_to_user(u, command);
|
||||
adc_msg_free(command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_ping(struct user* user)
|
||||
{
|
||||
/* This will just send a newline, despite appearing to do more below. */
|
||||
struct adc_message* ping = adc_msg_construct(0, 0);
|
||||
ping->cache[0] = '\n';
|
||||
ping->cache[1] = 0;
|
||||
ping->length = 1;
|
||||
ping->priority = 1;
|
||||
route_to_user(user, ping);
|
||||
adc_msg_free(ping);
|
||||
}
|
||||
|
||||
|
||||
void hub_send_hubinfo(struct user* u)
|
||||
{
|
||||
struct adc_message* info = adc_msg_copy(u->hub->command_info);
|
||||
int value = 0;
|
||||
|
||||
if (user_flag_get(u, feature_ping))
|
||||
{
|
||||
/*
|
||||
FIXME: These are missing:
|
||||
HH - Hub Host address ( DNS or IP )
|
||||
WS - Hub Website
|
||||
NE - Hub Network
|
||||
OW - Hub Owner name
|
||||
*/
|
||||
adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(u->hub)));
|
||||
adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(u->hub)));
|
||||
adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(u->hub)));
|
||||
adc_msg_add_named_argument(info, "SF", uhub_itoa(hub_get_shared_files(u->hub)));
|
||||
|
||||
/* Maximum/minimum share size */
|
||||
value = hub_get_max_share(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XS", uhub_itoa(value));
|
||||
value = hub_get_min_share(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MS", uhub_itoa(value));
|
||||
|
||||
/* Maximum/minimum upload slots allowed per user */
|
||||
value = hub_get_max_slots(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XL", uhub_itoa(value));
|
||||
value = hub_get_min_slots(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "ML", uhub_itoa(value));
|
||||
|
||||
/* guest users must be on min/max hubs */
|
||||
value = hub_get_max_hubs_user(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XU", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_user(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MU", uhub_itoa(value));
|
||||
|
||||
/* registered users must be on min/max hubs */
|
||||
value = hub_get_max_hubs_reg(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XR", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_reg(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MR", uhub_itoa(value));
|
||||
|
||||
/* operators must be on min/max hubs */
|
||||
value = hub_get_max_hubs_op(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XO", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_op(u->hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MO", uhub_itoa(value));
|
||||
|
||||
/* uptime in seconds */
|
||||
adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), u->hub->tm_started)));
|
||||
}
|
||||
|
||||
if (user_is_connecting(u) || user_is_logged_in(u))
|
||||
{
|
||||
route_to_user(u, info);
|
||||
}
|
||||
adc_msg_free(info);
|
||||
|
||||
/* Only send banner when connecting */
|
||||
if (u->hub->config->show_banner && user_is_connecting(u))
|
||||
{
|
||||
route_to_user(u, u->hub->command_banner);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hub_send_handshake(struct user* u)
|
||||
{
|
||||
hub_send_support(u);
|
||||
hub_send_sid(u);
|
||||
hub_send_hubinfo(u);
|
||||
|
||||
if (!user_is_disconnecting(u))
|
||||
{
|
||||
user_set_state(u, state_identify);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_motd(struct user* u)
|
||||
{
|
||||
if (u->hub->command_motd)
|
||||
{
|
||||
route_to_user(u, u->hub->command_motd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_password_challenge(struct user* u)
|
||||
{
|
||||
struct adc_message* igpa;
|
||||
igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
|
||||
adc_msg_add_argument(igpa, password_generate_challenge(u));
|
||||
user_set_state(u, state_verify);
|
||||
route_to_user(u, igpa);
|
||||
adc_msg_free(igpa);
|
||||
}
|
||||
|
||||
static void hub_event_dispatcher(void* callback_data, struct event_data* message)
|
||||
{
|
||||
/*
|
||||
struct hub_info* hub = (struct hub_info*) callback_data;
|
||||
hub_log(log_trace, "hub_event_dispatcher: %x (ptr=%p)", message->id, message->ptr);
|
||||
*/
|
||||
|
||||
switch (message->id)
|
||||
{
|
||||
case UHUB_EVENT_USER_JOIN:
|
||||
{
|
||||
if (user_is_disconnecting((struct user*) message->ptr))
|
||||
break;
|
||||
|
||||
if (message->flags)
|
||||
{
|
||||
hub_send_password_challenge((struct user*) message->ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_login_success((struct user*) message->ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UHUB_EVENT_USER_QUIT:
|
||||
{
|
||||
user_manager_remove((struct user*) message->ptr);
|
||||
send_quit_message((struct user*) message->ptr);
|
||||
on_logout_user((struct user*) message->ptr);
|
||||
user_schedule_destroy((struct user*) message->ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case UHUB_EVENT_USER_DESTROY:
|
||||
{
|
||||
hub_log(log_trace, "hub_event_dispatcher: UHUB_EVENT_USER_DESTROY (ptr=%p)", message->ptr);
|
||||
user_destroy((struct user*) message->ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* FIXME: ignored */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct hub_info* hub_start_service(struct hub_config* config)
|
||||
{
|
||||
struct hub_info* hub = 0;
|
||||
int server_tcp, ret, ipv6_supported, af;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int server_udp;
|
||||
#endif
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t sockaddr_size;
|
||||
char address_buf[INET6_ADDRSTRLEN+1];
|
||||
|
||||
hub = hub_malloc_zero(sizeof(struct hub_info));
|
||||
if (!hub)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to allocate memory for hub");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub->tm_started = time(0);
|
||||
|
||||
ipv6_supported = net_is_ipv6_supported();
|
||||
|
||||
if (ipv6_supported)
|
||||
hub_log(log_debug, "IPv6 supported.");
|
||||
else
|
||||
hub_log(log_debug, "IPv6 not supported.");
|
||||
|
||||
if (ip_convert_address(config->server_bind_addr, config->server_port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
af = addr.ss_family;
|
||||
if (af == AF_INET)
|
||||
{
|
||||
net_address_to_string(AF_INET, &((struct sockaddr_in*) &addr)->sin_addr, address_buf, INET6_ADDRSTRLEN);
|
||||
}
|
||||
else if (af == AF_INET6)
|
||||
{
|
||||
net_address_to_string(AF_INET6, &((struct sockaddr_in6*) &addr)->sin6_addr, address_buf, INET6_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
hub_log(log_info, "Starting server, listening on %s:%d...", address_buf, config->server_port);
|
||||
|
||||
server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_tcp == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
server_udp = net_socket_create(af, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (server_udp == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = net_set_reuseaddress(server_tcp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_set_reuseaddress(server_udp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret = net_set_nonblocking(server_tcp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_set_nonblocking(server_udp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret = net_bind(server_tcp, (struct sockaddr*) &addr, sockaddr_size);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_bind(server_udp, (struct sockaddr*) &addr, sockaddr_size);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "hub_start_service(): Unable to bind to UDP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = net_listen(server_tcp, SERVER_BACKLOG);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "hub_start_service(): Unable to listen to socket");
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub->fd_tcp = server_tcp;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
hub->fd_udp = server_udp;
|
||||
#endif
|
||||
hub->config = config;
|
||||
hub->users = NULL;
|
||||
|
||||
if (user_manager_init(hub) == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
event_set(&hub->ev_accept, hub->fd_tcp, EV_READ | EV_PERSIST, net_on_accept, hub);
|
||||
if (event_add(&hub->ev_accept, NULL) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
event_set(&hub->ev_datagram, hub->fd_udp, EV_READ | EV_PERSIST, net_on_packet, hub);
|
||||
if (event_add(&hub->ev_datagram, NULL) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub->status = hub_status_running;
|
||||
|
||||
return hub;
|
||||
}
|
||||
|
||||
|
||||
void hub_shutdown_service(struct hub_info* hub)
|
||||
{
|
||||
hub_log(log_trace, "hub_shutdown_service()");
|
||||
|
||||
event_queue_shutdown(hub->queue);
|
||||
event_del(&hub->ev_accept);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
event_del(&hub->ev_datagram);
|
||||
net_close(hub->fd_udp);
|
||||
#endif
|
||||
net_close(hub->fd_tcp);
|
||||
user_manager_shutdown(hub);
|
||||
hub->status = hub_status_stopped;
|
||||
hub_free(hub);
|
||||
hub = 0;
|
||||
}
|
||||
|
||||
#define SERVER "" PRODUCT "/" VERSION ""
|
||||
|
||||
void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
|
||||
{
|
||||
int fd, ret;
|
||||
char buf[MAX_RECV_BUF];
|
||||
char* tmp;
|
||||
|
||||
|
||||
hub->acl = acl;
|
||||
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15 + strlen(SERVER));
|
||||
if (hub->command_info)
|
||||
{
|
||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
|
||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, SERVER);
|
||||
|
||||
tmp = adc_msg_escape(hub->config->hub_name);
|
||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_NICK, tmp);
|
||||
hub_free(tmp);
|
||||
|
||||
tmp = adc_msg_escape(hub->config->hub_description);
|
||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp);
|
||||
hub_free(tmp);
|
||||
}
|
||||
|
||||
/* (Re-)read the message of the day */
|
||||
hub->command_motd = 0;
|
||||
fd = open(hub->config->file_motd, 0);
|
||||
if (fd != -1)
|
||||
{
|
||||
ret = read(fd, buf, MAX_RECV_BUF);
|
||||
if (ret > 0)
|
||||
{
|
||||
buf[ret] = 0;
|
||||
tmp = adc_msg_escape(buf);
|
||||
hub->command_motd = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp));
|
||||
adc_msg_add_argument(hub->command_motd, tmp);
|
||||
hub_free(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT));
|
||||
if (hub->command_support)
|
||||
{
|
||||
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
|
||||
}
|
||||
|
||||
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(SERVER));
|
||||
if (hub->command_banner)
|
||||
{
|
||||
adc_msg_add_argument(hub->command_banner, "000 Powered\\sby\\s" SERVER);
|
||||
}
|
||||
|
||||
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
|
||||
}
|
||||
|
||||
|
||||
void hub_free_variables(struct hub_info* hub)
|
||||
{
|
||||
adc_msg_free(hub->command_info);
|
||||
adc_msg_free(hub->command_banner);
|
||||
|
||||
if (hub->command_motd)
|
||||
adc_msg_free(hub->command_motd);
|
||||
|
||||
adc_msg_free(hub->command_support);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 1 if nickname is in use, or 0 if not used.
|
||||
*/
|
||||
static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
|
||||
{
|
||||
struct user* lookup = get_user_by_nick(hub, nick);
|
||||
if (lookup)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 1 if CID is in use, or 0 if not used.
|
||||
*/
|
||||
static inline int is_cid_in_use(struct hub_info* hub, const char* cid)
|
||||
{
|
||||
struct user* lookup = get_user_by_cid(hub, cid);
|
||||
if (lookup)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void set_status_code(enum msg_status_level level, int code, char buffer[4])
|
||||
{
|
||||
buffer[0] = ('0' + (int) level);
|
||||
buffer[1] = ('0' + (code / 10));
|
||||
buffer[2] = ('0' + (code % 10));
|
||||
buffer[3] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hub The hub instance this message is sent from.
|
||||
* @param user The user this message is sent to.
|
||||
* @param msg See enum status_message
|
||||
* @param level See enum status_level
|
||||
*/
|
||||
void hub_send_status(struct user* user, enum status_message msg, enum msg_status_level level)
|
||||
{
|
||||
struct hub_config* cfg = user->hub->config;
|
||||
struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
|
||||
if (!cmd) return;
|
||||
char code[4];
|
||||
const char* text = 0;
|
||||
const char* flag = 0;
|
||||
char* escaped_text = 0;
|
||||
|
||||
#define STATUS(CODE, MSG, FLAG) case status_ ## MSG : set_status_code(level, CODE, code); text = cfg->MSG; flag = FLAG; break
|
||||
switch (msg)
|
||||
{
|
||||
STATUS(11, msg_hub_full, 0);
|
||||
STATUS(12, msg_hub_disabled, 0);
|
||||
STATUS(26, msg_hub_registered_users_only, 0);
|
||||
STATUS(43, msg_inf_error_nick_missing, 0);
|
||||
STATUS(43, msg_inf_error_nick_multiple, 0);
|
||||
STATUS(21, msg_inf_error_nick_invalid, 0);
|
||||
STATUS(21, msg_inf_error_nick_long, 0);
|
||||
STATUS(21, msg_inf_error_nick_short, 0);
|
||||
STATUS(21, msg_inf_error_nick_spaces, 0);
|
||||
STATUS(21, msg_inf_error_nick_bad_chars, 0);
|
||||
STATUS(21, msg_inf_error_nick_not_utf8, 0);
|
||||
STATUS(22, msg_inf_error_nick_taken, 0);
|
||||
STATUS(21, msg_inf_error_nick_restricted, 0);
|
||||
STATUS(43, msg_inf_error_cid_invalid, "FBID");
|
||||
STATUS(43, msg_inf_error_cid_missing, "FMID");
|
||||
STATUS(24, msg_inf_error_cid_taken, 0);
|
||||
STATUS(43, msg_inf_error_pid_missing, "FMPD");
|
||||
STATUS(27, msg_inf_error_pid_invalid, "FBPD");
|
||||
STATUS(31, msg_ban_permanently, 0);
|
||||
STATUS(32, msg_ban_temporarily, "TL600"); /* FIXME: Use a proper timeout */
|
||||
STATUS(23, msg_auth_invalid_password, 0);
|
||||
STATUS(20, msg_auth_user_not_found, 0);
|
||||
STATUS(30, msg_error_no_memory, 0);
|
||||
STATUS(43, msg_user_share_size_low, "FB" ADC_INF_FLAG_SHARED_SIZE);
|
||||
STATUS(43, msg_user_share_size_high, "FB" ADC_INF_FLAG_SHARED_SIZE);
|
||||
STATUS(43, msg_user_slots_low, "FB" ADC_INF_FLAG_UPLOAD_SLOTS);
|
||||
STATUS(43, msg_user_slots_high, "FB" ADC_INF_FLAG_UPLOAD_SLOTS);
|
||||
STATUS(43, msg_user_hub_limit_low, 0);
|
||||
STATUS(43, msg_user_hub_limit_high, 0);
|
||||
}
|
||||
#undef STATUS
|
||||
|
||||
escaped_text = adc_msg_escape(text);
|
||||
|
||||
adc_msg_add_argument(cmd, code);
|
||||
adc_msg_add_argument(cmd, escaped_text);
|
||||
|
||||
hub_free(escaped_text);
|
||||
|
||||
if (flag)
|
||||
{
|
||||
adc_msg_add_argument(cmd, flag);
|
||||
}
|
||||
|
||||
route_to_user(user, cmd);
|
||||
adc_msg_free(cmd);
|
||||
|
||||
}
|
||||
|
||||
const char* hub_get_status_message(struct hub_info* hub, enum status_message msg)
|
||||
{
|
||||
#define STATUS(MSG) case status_ ## MSG : return cfg->MSG; break
|
||||
struct hub_config* cfg = hub->config;
|
||||
switch (msg)
|
||||
{
|
||||
STATUS(msg_hub_full);
|
||||
STATUS(msg_hub_disabled);
|
||||
STATUS(msg_hub_registered_users_only);
|
||||
STATUS(msg_inf_error_nick_missing);
|
||||
STATUS(msg_inf_error_nick_multiple);
|
||||
STATUS(msg_inf_error_nick_invalid);
|
||||
STATUS(msg_inf_error_nick_long);
|
||||
STATUS(msg_inf_error_nick_short);
|
||||
STATUS(msg_inf_error_nick_spaces);
|
||||
STATUS(msg_inf_error_nick_bad_chars);
|
||||
STATUS(msg_inf_error_nick_not_utf8);
|
||||
STATUS(msg_inf_error_nick_taken);
|
||||
STATUS(msg_inf_error_nick_restricted);
|
||||
STATUS(msg_inf_error_cid_invalid);
|
||||
STATUS(msg_inf_error_cid_missing);
|
||||
STATUS(msg_inf_error_cid_taken);
|
||||
STATUS(msg_inf_error_pid_missing);
|
||||
STATUS(msg_inf_error_pid_invalid);
|
||||
STATUS(msg_ban_permanently);
|
||||
STATUS(msg_ban_temporarily);
|
||||
STATUS(msg_auth_invalid_password);
|
||||
STATUS(msg_auth_user_not_found);
|
||||
STATUS(msg_error_no_memory);
|
||||
STATUS(msg_user_share_size_low);
|
||||
STATUS(msg_user_share_size_high);
|
||||
STATUS(msg_user_slots_low);
|
||||
STATUS(msg_user_slots_high);
|
||||
STATUS(msg_user_hub_limit_low);
|
||||
STATUS(msg_user_hub_limit_high);
|
||||
}
|
||||
#undef STATUS
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
size_t hub_get_user_count(struct hub_info* hub)
|
||||
{
|
||||
return hub->users->count;
|
||||
}
|
||||
|
||||
size_t hub_get_max_user_count(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->max_users;
|
||||
}
|
||||
|
||||
uint64_t hub_get_shared_size(struct hub_info* hub)
|
||||
{
|
||||
return hub->users->shared_size;
|
||||
}
|
||||
|
||||
uint64_t hub_get_shared_files(struct hub_info* hub)
|
||||
{
|
||||
return hub->users->shared_files;
|
||||
}
|
||||
|
||||
uint64_t hub_get_min_share(struct hub_info* hub)
|
||||
{
|
||||
return 1024 * 1024 * hub->config->limit_min_share;
|
||||
}
|
||||
|
||||
uint64_t hub_get_max_share(struct hub_info* hub)
|
||||
{
|
||||
return 1024 * 1024 * hub->config->limit_max_share;
|
||||
}
|
||||
|
||||
size_t hub_get_min_slots(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_min_slots;
|
||||
}
|
||||
|
||||
size_t hub_get_max_slots(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_max_slots;
|
||||
}
|
||||
|
||||
size_t hub_get_max_hubs_total(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_max_hubs;
|
||||
}
|
||||
|
||||
size_t hub_get_max_hubs_user(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_max_hubs_user;
|
||||
}
|
||||
|
||||
size_t hub_get_min_hubs_user(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_min_hubs_user;
|
||||
}
|
||||
|
||||
size_t hub_get_max_hubs_reg(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_max_hubs_reg;
|
||||
}
|
||||
|
||||
size_t hub_get_min_hubs_reg(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_min_hubs_reg;
|
||||
}
|
||||
|
||||
size_t hub_get_max_hubs_op(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_max_hubs_op;
|
||||
}
|
||||
|
||||
size_t hub_get_min_hubs_op(struct hub_info* hub)
|
||||
{
|
||||
return hub->config->limit_min_hubs_op;
|
||||
}
|
||||
|
||||
|
326
src/hub.h
Normal file
326
src/hub.h
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_HUB_H
|
||||
#define HAVE_UHUB_HUB_H
|
||||
|
||||
enum status_message
|
||||
{
|
||||
status_msg_hub_full = -1, /* hub is full */
|
||||
status_msg_hub_disabled = -2, /* hub is disabled */
|
||||
status_msg_hub_registered_users_only = -3, /* hub is for registered users only */
|
||||
status_msg_inf_error_nick_missing = -4, /* no nickname given */
|
||||
status_msg_inf_error_nick_multiple = -5, /* multiple nicknames given */
|
||||
status_msg_inf_error_nick_invalid = -6, /* generic/unkown */
|
||||
status_msg_inf_error_nick_long = -7, /* nickname too long */
|
||||
status_msg_inf_error_nick_short = -8, /* nickname too short */
|
||||
status_msg_inf_error_nick_spaces = -9, /* nickname cannot start with spaces */
|
||||
status_msg_inf_error_nick_bad_chars = -10, /* nickname contains chars below ascii 32 */
|
||||
status_msg_inf_error_nick_not_utf8 = -11, /* nickname is not valid utf8 */
|
||||
status_msg_inf_error_nick_taken = -12, /* nickname is in use */
|
||||
status_msg_inf_error_nick_restricted = -13, /* nickname cannot be used on this hub */
|
||||
status_msg_inf_error_cid_invalid = -14, /* CID is not valid (generic error) */
|
||||
status_msg_inf_error_cid_missing = -15, /* CID is not specified */
|
||||
status_msg_inf_error_cid_taken = -16, /* CID is taken (already logged in?). */
|
||||
status_msg_inf_error_pid_missing = -17, /* PID is not specified */
|
||||
status_msg_inf_error_pid_invalid = -18, /* PID is invalid */
|
||||
status_msg_ban_permanently = -19, /* Banned permanently */
|
||||
status_msg_ban_temporarily = -20, /* Banned temporarily */
|
||||
status_msg_auth_invalid_password = -21, /* Password is wrong */
|
||||
status_msg_auth_user_not_found = -22, /* User not found in password database */
|
||||
status_msg_error_no_memory = -23, /* Hub is out of memory */
|
||||
|
||||
status_msg_user_share_size_low = -40, /* User is not sharing enough. */
|
||||
status_msg_user_share_size_high = -41, /* User is sharing too much. */
|
||||
status_msg_user_slots_low = -42, /* User has too few slots open. */
|
||||
status_msg_user_slots_high = -43, /* User has too many slots open. */
|
||||
status_msg_user_hub_limit_low = -44, /* Use is on too few hubs. */
|
||||
status_msg_user_hub_limit_high = -45, /* Use is on too many hubs. */
|
||||
|
||||
};
|
||||
|
||||
|
||||
enum hub_state
|
||||
{
|
||||
hub_status_uninitialized = 0, /**<<<"Hub is uninitialized" */
|
||||
hub_status_running = 1, /**<<<"Hub is running (normal operation)" */
|
||||
hub_status_restart = 2, /**<<<"Hub is restarting (re-reading configuration, etc)" */
|
||||
hub_status_shutdown = 3, /**<<<"Hub is shutting down, but not yet stopped. */
|
||||
hub_status_stopped = 4, /**<<<"Hub is stopped (Pretty much the same as initialized) */
|
||||
hub_status_disabled = 5, /**<<<"Hub is disabled (Running, but not accepting users) */
|
||||
};
|
||||
|
||||
struct hub_info
|
||||
{
|
||||
int fd_tcp;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int fd_udp;
|
||||
#endif
|
||||
struct event ev_accept;
|
||||
struct event ev_timer;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
struct event ev_datagram;
|
||||
#endif
|
||||
struct event_queue* queue;
|
||||
struct hub_config* config;
|
||||
struct user_manager* users;
|
||||
struct acl_handle* acl;
|
||||
struct adc_message* command_info; /* The hub's INF command */
|
||||
struct adc_message* command_support; /* The hub's SUP command */
|
||||
struct adc_message* command_motd; /* The message of the day */
|
||||
struct adc_message* command_banner; /* The default welcome message */
|
||||
time_t tm_started;
|
||||
int status;
|
||||
#ifdef SSL_SUPPORT
|
||||
SSL_METHOD* ssl_method;
|
||||
SSL_CTX* ssl_ctx;
|
||||
#endif /* SSL_SUPPORT */
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the message pre-routing centre.
|
||||
*
|
||||
* Any message coming in to the hub comes through here first,
|
||||
* and will be routed further if valid.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_message(struct user* u, const char* message, size_t length);
|
||||
|
||||
/**
|
||||
* Handle protocol support/subscription messages received clients.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_support(struct user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Handle password messages received from clients.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_password(struct user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Handle chat messages received from clients.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
extern int hub_handle_chat_message(struct user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Used internally by hub_handle_info
|
||||
* @return 1 if nickname is OK, or 0 if nickname is not accepted.
|
||||
*/
|
||||
extern int hub_handle_info_check_nick(struct user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Used internally by hub_handle_info
|
||||
* @return 1 if CID/PID is OK, or 0 if not valid.
|
||||
*/
|
||||
extern int hub_handle_info_check_cid(struct user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Can only be used by administrators or operators.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_kick(struct user* u, struct adc_message* cmd);
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
/**
|
||||
* Handle incoming autocheck message.
|
||||
*/
|
||||
extern int hub_handle_autocheck(struct user* u, struct adc_message* cmd);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Send the support line for the hub to a particular user.
|
||||
* Only used during the initial handshake.
|
||||
*/
|
||||
extern void hub_send_support(struct user* u);
|
||||
|
||||
/**
|
||||
* Send a message assigning a SID for a user.
|
||||
* This is only sent after hub_send_support() during initial handshake.
|
||||
*/
|
||||
extern void hub_send_sid(struct user* u);
|
||||
|
||||
/**
|
||||
* Send a 'ping' message to user.
|
||||
*/
|
||||
extern void hub_send_ping(struct user* user);
|
||||
|
||||
/**
|
||||
* Send a message containing hub information to a particular user.
|
||||
* This is sent during user connection, but can safely be sent at any
|
||||
* point later.
|
||||
*/
|
||||
extern void hub_send_hubinfo(struct user* u);
|
||||
|
||||
/**
|
||||
* Send handshake. This basically calls
|
||||
* hub_send_support() and hub_send_sid()
|
||||
*/
|
||||
extern void hub_send_handshake(struct user* u);
|
||||
|
||||
/**
|
||||
* Send a welcome message containing the message of the day to
|
||||
* one particular user. This can be sent in any point in time.
|
||||
*/
|
||||
extern void hub_send_motd(struct user* u);
|
||||
|
||||
/**
|
||||
* Send a password challenge to a user.
|
||||
* This is only used if the user tries to access the hub using a
|
||||
* password protected nick name.
|
||||
*/
|
||||
extern void hub_send_password_challenge(struct user* u);
|
||||
|
||||
/**
|
||||
* Send an autocheck message to a user.
|
||||
* This is basically a UDP message. The user's client can then determine
|
||||
* if UDP communication works by either hole punching or configuring UPnP.
|
||||
*/
|
||||
extern void hub_send_autocheck(struct user* u, uint16_t port, const char* token);
|
||||
|
||||
/**
|
||||
* This starts the hub.
|
||||
*/
|
||||
extern struct hub_info* hub_start_service(struct hub_config* config);
|
||||
|
||||
/**
|
||||
* This shuts down the hub.
|
||||
*/
|
||||
extern void hub_shutdown_service(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* This configures the hub.
|
||||
*/
|
||||
extern void hub_set_variables(struct hub_info* hub, struct acl_handle* acl);
|
||||
|
||||
/**
|
||||
* This frees the configuration of the hub.
|
||||
*/
|
||||
extern void hub_free_variables(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns a string for the given status_message (See enum status_message).
|
||||
*/
|
||||
extern const char* hub_get_status_message(struct hub_info* hub, enum status_message msg);
|
||||
|
||||
/**
|
||||
* Sends a status_message to a user.
|
||||
*/
|
||||
extern void hub_send_status(struct user* user, enum status_message msg, enum msg_status_level level);
|
||||
|
||||
/**
|
||||
* Returns the number of logged in users on the hub.
|
||||
*/
|
||||
extern size_t hub_get_user_count(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of allowed users on the hub.
|
||||
*/
|
||||
extern size_t hub_get_max_user_count(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the accumulated shared size for all logged in
|
||||
* users on the hub.
|
||||
*/
|
||||
extern uint64_t hub_get_shared_size(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the accumulated number of files for all logged
|
||||
* in users on the hub.
|
||||
*/
|
||||
extern uint64_t hub_get_shared_files(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the minimal share size limit as enforced by
|
||||
* this hub's configuration.
|
||||
*/
|
||||
extern uint64_t hub_get_min_share(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the minimal share size limit as enforced by
|
||||
* this hub's configuration.
|
||||
*/
|
||||
extern uint64_t hub_get_max_share(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the minimum upload slot limit as enforced by
|
||||
* this hub's configuration.
|
||||
* Users with fewer slots in total will not be allowed
|
||||
* to enter the hub.
|
||||
* @return limit or 0 if no limit.
|
||||
*/
|
||||
extern size_t hub_get_min_slots(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum upload slot limit as enforced by
|
||||
* this hub's configuration.
|
||||
* Users with more allowed upload slots will not be
|
||||
* allowed to enter the hub.
|
||||
* @return limit or 0 if no limit.
|
||||
*/
|
||||
extern size_t hub_get_max_slots(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of hubs a user can
|
||||
* be logged in to simultaneously as a regular user (guest).
|
||||
* Users on more hubs will not be allowed to stay on this hub.
|
||||
* @return limit or 0 if no limit.
|
||||
*/
|
||||
extern size_t hub_get_max_hubs_user(struct hub_info* hub);
|
||||
extern size_t hub_get_min_hubs_user(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of hubs a user can
|
||||
* be logged in to simultaneously as a registered user (password required).
|
||||
* Users on more hubs will not be allowed to stay on this hub.
|
||||
* @return limit or 0 if no limit.
|
||||
*/
|
||||
extern size_t hub_get_max_hubs_reg(struct hub_info* hub);
|
||||
extern size_t hub_get_min_hubs_reg(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of hubs a user can
|
||||
* be logged in to simultaneously as an operator.
|
||||
* Users who are operator on more than this amount of hubs
|
||||
* will not be allowed to stay on this hub.
|
||||
* @return limit or 0 if no limit.
|
||||
*/
|
||||
extern size_t hub_get_max_hubs_op(struct hub_info* hub);
|
||||
extern size_t hub_get_min_hubs_op(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of hubs a user can
|
||||
* be logged in to simultaneously regardless of the type of user.
|
||||
*/
|
||||
extern size_t hub_get_max_hubs_total(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Schedule runslice.
|
||||
*/
|
||||
extern void hub_schedule_runslice(struct hub_info* hub);
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_HUB_H */
|
||||
|
107
src/hubevent.c
Normal file
107
src/hubevent.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
/* Send MOTD, do logging etc */
|
||||
void on_login_success(struct user* u)
|
||||
{
|
||||
/* Logging - FIXME: Move this to a plugin */
|
||||
const char* addr = net_get_peer_address(u->sd);
|
||||
const char* credentials_string[] = { "!none!", "link", "guest", "user", "operator", "super", "admin" };
|
||||
struct timeval timeout = { TIMEOUT_IDLE, 0 };
|
||||
|
||||
/* Send user list of all existing users */
|
||||
if (!send_user_list(u))
|
||||
return;
|
||||
|
||||
/* Mark as being in the normal state, and add user to the user list */
|
||||
user_set_state(u, state_normal);
|
||||
user_manager_add(u);
|
||||
|
||||
/* Print log message */
|
||||
hub_log(log_user, "Login OK %s/%s \"%s\" [%s] (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, u->id.nick, addr, credentials_string[u->credentials], u->user_agent);
|
||||
|
||||
/* Announce new user to all connected users */
|
||||
if (user_is_logged_in(u))
|
||||
route_info_message(u);
|
||||
|
||||
/* Send message of the day (if any) */
|
||||
if (user_is_logged_in(u)) /* Previous send() can fail! */
|
||||
hub_send_motd(u);
|
||||
|
||||
/* reset to idle timeout */
|
||||
if (u->ev_read)
|
||||
event_add(u->ev_read, &timeout);
|
||||
}
|
||||
|
||||
|
||||
void on_login_failure(struct user* u, enum status_message msg)
|
||||
{
|
||||
const char* addr = net_get_peer_address(u->sd);
|
||||
const char* message = hub_get_status_message(u->hub, msg);
|
||||
hub_log(log_user, "Login FAIL %s/%s \"%s\" [%s] (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, u->id.nick, addr, message, u->user_agent);
|
||||
|
||||
hub_send_status(u, msg, status_level_fatal);
|
||||
user_disconnect(u, quit_logon_error);
|
||||
}
|
||||
|
||||
|
||||
void on_nick_change(struct user* u, const char* nick)
|
||||
{
|
||||
if (user_is_logged_in(u))
|
||||
{
|
||||
hub_log(log_user, "Nick change %s/%s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, u->id.nick, nick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void on_logout_user(struct user* user)
|
||||
{
|
||||
const char* reason = "";
|
||||
const char* addr;
|
||||
|
||||
/* These are used for logging purposes */
|
||||
switch (user->quit_reason)
|
||||
{
|
||||
case quit_disconnected: reason = "disconnected"; break;
|
||||
case quit_kicked: reason = "kicked"; break;
|
||||
case quit_banned: reason = "banned"; break;
|
||||
case quit_timeout: reason = "timeout"; break;
|
||||
case quit_send_queue: reason = "send queue"; break;
|
||||
case quit_memory_error: reason = "out of memory"; break;
|
||||
case quit_socket_error: reason = "socket error"; break;
|
||||
case quit_protocol_error: reason = "protocol error"; break;
|
||||
case quit_logon_error: reason = "login error"; break;
|
||||
case quit_hub_disabled: reason = "hub disabled"; break;
|
||||
default:
|
||||
if (user->hub->status == hub_status_shutdown)
|
||||
reason = "hub shutdown";
|
||||
else
|
||||
reason = "unknown error";
|
||||
break;
|
||||
}
|
||||
|
||||
addr = ip_convert_to_string(&user->ipaddr);
|
||||
hub_log(log_user, "Logout %s/%s \"%s\" [%s] (%s)", sid_to_string(user->id.sid), user->id.cid, user->id.nick, addr, reason);
|
||||
|
||||
|
||||
user->quit_reason = 0;
|
||||
}
|
||||
|
45
src/hubevent.h
Normal file
45
src/hubevent.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_HUB_EVENT_H
|
||||
#define HAVE_UHUB_HUB_EVENT_H
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a user successfully logs in to the hub.
|
||||
*/
|
||||
extern void on_login_success(struct user* u);
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a user failed to log in to the hub.
|
||||
*/
|
||||
extern void on_login_failure(struct user* u, enum status_message msg);
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a previously logged in user leaves the hub.
|
||||
*/
|
||||
extern void on_logout_user(struct user* u);
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a user changes his/her nickname.
|
||||
*/
|
||||
extern void on_nick_change(struct user* u, const char* nick);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_HUB_EVENT_H */
|
||||
|
859
src/inf.c
Normal file
859
src/inf.c
Normal file
@ -0,0 +1,859 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
/*
|
||||
* These flags can only be set by the hub.
|
||||
* Make sure we don't allow clients to specify these themselves.
|
||||
*
|
||||
* NOTE: Some of them are legacy ADC flags and no longer used, these
|
||||
* should be removed at some point in the future when functionality no
|
||||
* longer depend on them.
|
||||
*/
|
||||
static void remove_server_restricted_flags(struct adc_message* cmd)
|
||||
{
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE); /* Client type flag (CT, obsoletes BO, RG, OP, HU) */
|
||||
adc_msg_remove_named_argument(cmd, "BO"); /* Obsolete: bot flag (CT) */
|
||||
adc_msg_remove_named_argument(cmd, "RG"); /* Obsolete: registered user flag (CT) */
|
||||
adc_msg_remove_named_argument(cmd, "OP"); /* Obsolete: operator flag (CT) */
|
||||
adc_msg_remove_named_argument(cmd, "HU"); /* Obsolete: hub flag (CT) */
|
||||
adc_msg_remove_named_argument(cmd, "HI"); /* Obsolete: hidden user flag */
|
||||
adc_msg_remove_named_argument(cmd, "TO"); /* Client to client token - should not be seen here */
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_REFERER);
|
||||
}
|
||||
|
||||
static int user_is_protected(struct user* user);
|
||||
|
||||
static int set_feature_cast_supports(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char *it, *tmp;
|
||||
|
||||
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_SUPPORT))
|
||||
{
|
||||
tmp = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SUPPORT);
|
||||
user_clear_feature_cast_support(u);
|
||||
|
||||
it = tmp;
|
||||
while (strlen(it) > 4)
|
||||
{
|
||||
it[4] = 0; /* FIXME: Not really needed */
|
||||
user_set_feature_cast_support(u, it);
|
||||
it = &it[5];
|
||||
}
|
||||
|
||||
if (strlen(it) > 0)
|
||||
{
|
||||
user_set_feature_cast_support(u, it);
|
||||
}
|
||||
hub_free(tmp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_hash_tiger(const char* cid, const char* pid)
|
||||
{
|
||||
char x_pid[64];
|
||||
char raw_pid[64];
|
||||
uint64_t tiger_res[3];
|
||||
|
||||
memset(x_pid, 0, MAX_CID_LEN+1);
|
||||
|
||||
base32_decode(pid, (unsigned char*) raw_pid, MAX_CID_LEN);
|
||||
tiger((uint64_t*) raw_pid, TIGERSIZE, (uint64_t*) tiger_res);
|
||||
base32_encode((unsigned char*) tiger_res, TIGERSIZE, x_pid);
|
||||
x_pid[MAX_CID_LEN] = 0;
|
||||
if (strncasecmp(x_pid, cid, MAX_CID_LEN) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FIXME: Only works for tiger hash. If a client doesnt support tiger we cannot let it in!
|
||||
*/
|
||||
static int check_cid(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
size_t pos;
|
||||
char* cid = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
|
||||
char* pid = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
|
||||
|
||||
if (!cid || !pid)
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_error_no_memory;
|
||||
}
|
||||
|
||||
if (strlen(cid) != MAX_CID_LEN)
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_inf_error_cid_invalid;
|
||||
}
|
||||
|
||||
if (strlen(pid) != MAX_CID_LEN)
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_inf_error_pid_invalid;
|
||||
}
|
||||
|
||||
for (pos = 0; pos < MAX_CID_LEN; pos++)
|
||||
{
|
||||
if (!is_valid_base32_char(cid[pos]))
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_inf_error_cid_invalid;
|
||||
}
|
||||
|
||||
if (!is_valid_base32_char(pid[pos]))
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_inf_error_pid_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_hash_tiger(cid, pid))
|
||||
{
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return status_msg_inf_error_cid_invalid;
|
||||
}
|
||||
|
||||
/* Set the cid in the user object */
|
||||
memcpy(user->id.cid, cid, MAX_CID_LEN);
|
||||
user->id.cid[MAX_CID_LEN] = 0;
|
||||
|
||||
hub_free(cid);
|
||||
hub_free(pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_required_login_flags(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
num = adc_msg_has_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
|
||||
if (num != 1)
|
||||
{
|
||||
if (!num)
|
||||
return status_msg_inf_error_cid_missing;
|
||||
return status_msg_inf_error_cid_invalid;
|
||||
}
|
||||
|
||||
num = adc_msg_has_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
|
||||
if (num != 1)
|
||||
{
|
||||
if (!num)
|
||||
return status_msg_inf_error_pid_missing;
|
||||
return status_msg_inf_error_pid_invalid;
|
||||
}
|
||||
|
||||
num = adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK);
|
||||
if (num != 1)
|
||||
{
|
||||
if (!num)
|
||||
return status_msg_inf_error_nick_missing;
|
||||
return status_msg_inf_error_nick_multiple;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This will check the ip address of the user, and
|
||||
* remove any wrong address, and replace it with the correct one
|
||||
* as seen by the hub.
|
||||
*/
|
||||
int check_network(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
int want_ipv4 = 0;
|
||||
int want_ipv6 = 0;
|
||||
int nat_override = 0;
|
||||
const char* address = 0;
|
||||
|
||||
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR))
|
||||
{
|
||||
want_ipv6 = 1;
|
||||
}
|
||||
|
||||
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR))
|
||||
{
|
||||
want_ipv4 = 1;
|
||||
}
|
||||
|
||||
if (!want_ipv4 && !want_ipv6)
|
||||
return 0;
|
||||
|
||||
/* Add correct/verified IP addresses instead (if requested/stripped) */
|
||||
address = (char*) net_get_peer_address(user->sd);
|
||||
if (address)
|
||||
{
|
||||
if (want_ipv4 && strchr(address, '.'))
|
||||
{
|
||||
want_ipv6 = 0;
|
||||
}
|
||||
else if (want_ipv6)
|
||||
{
|
||||
want_ipv4 = 0;
|
||||
}
|
||||
|
||||
/* check if user can do nat override */
|
||||
if (want_ipv4 && acl_is_ip_nat_override(user->hub->acl, address))
|
||||
{
|
||||
char* client_given_ip = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
|
||||
if (strcmp(client_given_ip, "0.0.0.0") != 0)
|
||||
{
|
||||
user_set_nat_override(user);
|
||||
nat_override = 1;
|
||||
}
|
||||
hub_free(client_given_ip);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nat_override)
|
||||
{
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
|
||||
if (!want_ipv4)
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_UDP_PORT);
|
||||
else
|
||||
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
|
||||
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR);
|
||||
if (!want_ipv6)
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_UDP_PORT);
|
||||
else
|
||||
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR, address);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int nick_length_ok(const char* nick)
|
||||
{
|
||||
size_t length = strlen(nick);
|
||||
if (length <= 1)
|
||||
{
|
||||
return nick_invalid_short;
|
||||
}
|
||||
|
||||
if (length > MAX_NICK_LEN)
|
||||
{
|
||||
return nick_invalid_long;
|
||||
}
|
||||
|
||||
return nick_ok;
|
||||
}
|
||||
|
||||
|
||||
static int nick_bad_characters(const char* nick)
|
||||
{
|
||||
const char* tmp;
|
||||
|
||||
/* Nick must not start with a space */
|
||||
if (nick[0] == ' ')
|
||||
return nick_invalid_spaces;
|
||||
|
||||
/* Check for ASCII values below 32 */
|
||||
for (tmp = nick; *tmp; tmp++)
|
||||
if ((*tmp < 32) && (*tmp > 0))
|
||||
return nick_invalid_bad_ascii;
|
||||
|
||||
return nick_ok;
|
||||
}
|
||||
|
||||
|
||||
static int nick_is_utf8(const char* nick)
|
||||
{
|
||||
/*
|
||||
* Nick should be valid utf-8, but
|
||||
* perhaps we should check if the nick is unicode normalized?
|
||||
*/
|
||||
if (!is_valid_utf8(nick))
|
||||
return nick_invalid_bad_utf8;
|
||||
return nick_ok;
|
||||
}
|
||||
|
||||
|
||||
static int check_nick(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* nick;
|
||||
char* tmp;
|
||||
enum nick_status status;
|
||||
|
||||
tmp = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_NICK);
|
||||
if (!tmp) return 0;
|
||||
nick = adc_msg_unescape(tmp);
|
||||
free(tmp); tmp = 0;
|
||||
if (!nick) return 0;
|
||||
|
||||
status = nick_length_ok(nick);
|
||||
if (status != nick_ok)
|
||||
{
|
||||
hub_free(nick);
|
||||
if (status == nick_invalid_short)
|
||||
return status_msg_inf_error_nick_short;
|
||||
return status_msg_inf_error_nick_long;
|
||||
}
|
||||
|
||||
status = nick_bad_characters(nick);
|
||||
if (status != nick_ok)
|
||||
{
|
||||
hub_free(nick);
|
||||
if (status == nick_invalid_spaces)
|
||||
return status_msg_inf_error_nick_spaces;
|
||||
return status_msg_inf_error_nick_bad_chars;
|
||||
}
|
||||
|
||||
status = nick_is_utf8(nick);
|
||||
if (status != nick_ok)
|
||||
{
|
||||
hub_free(nick);
|
||||
return status_msg_inf_error_nick_not_utf8;
|
||||
}
|
||||
|
||||
if (user_is_connecting(user))
|
||||
{
|
||||
memcpy(user->id.nick, nick, strlen(nick));
|
||||
user->id.nick[strlen(nick)] = 0;
|
||||
}
|
||||
|
||||
hub_free(nick);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_logged_in(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
struct user* lookup1 = get_user_by_nick(user->hub, user->id.nick);
|
||||
struct user* lookup2 = get_user_by_cid(user->hub, user->id.cid);
|
||||
|
||||
if (lookup1 == user)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lookup1 || lookup2)
|
||||
{
|
||||
if (lookup1 == lookup2)
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: exact same user is logged in: %s", user->id.nick);
|
||||
user_disconnect(lookup1, quit_timeout);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lookup1)
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: nickname is in use: %s", user->id.nick);
|
||||
return status_msg_inf_error_nick_taken;
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: CID is in use: %s", user->id.cid);
|
||||
return status_msg_inf_error_cid_taken;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* It is possible to do user-agent checking here.
|
||||
* But this is not something we want to do, and is deprecated in the ADC specification.
|
||||
* One should rather look at capabilities/features.
|
||||
*/
|
||||
static int check_user_agent(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* ua_encoded = 0;
|
||||
char* ua = 0;
|
||||
|
||||
/* Get client user agent version */
|
||||
ua_encoded = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_USER_AGENT);
|
||||
if (ua_encoded)
|
||||
{
|
||||
ua = adc_msg_unescape(ua_encoded);
|
||||
if (ua)
|
||||
{
|
||||
memcpy(user->user_agent, ua, MIN(strlen(ua), MAX_UA_LEN));
|
||||
hub_free(ua);
|
||||
}
|
||||
}
|
||||
hub_free(ua_encoded);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_acl(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
if (acl_is_cid_banned(user->hub->acl, user->id.cid))
|
||||
{
|
||||
return status_msg_ban_permanently;
|
||||
}
|
||||
|
||||
if (acl_is_user_banned(user->hub->acl, user->id.nick))
|
||||
{
|
||||
return status_msg_ban_permanently;
|
||||
}
|
||||
|
||||
if (acl_is_user_denied(user->hub->acl, user->id.nick))
|
||||
{
|
||||
return status_msg_inf_error_nick_restricted;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SHARED_SIZE);
|
||||
if (arg)
|
||||
{
|
||||
int64_t shared_size = atoll(arg);
|
||||
if (shared_size < 0)
|
||||
shared_size = 0;
|
||||
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
user->hub->users->shared_size -= user->limits.shared_size;
|
||||
user->hub->users->shared_size += shared_size;
|
||||
}
|
||||
user->limits.shared_size = shared_size;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SHARED_FILES);
|
||||
if (arg)
|
||||
{
|
||||
ssize_t shared_files = atoll(arg);
|
||||
if (shared_files < 0)
|
||||
shared_files = 0;
|
||||
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
user->hub->users->shared_files -= user->limits.shared_files;
|
||||
user->hub->users->shared_files += shared_files;
|
||||
}
|
||||
user->limits.shared_files = shared_files;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_NORMAL);
|
||||
if (arg)
|
||||
{
|
||||
ssize_t num = atoll(arg);
|
||||
if (num < 0) num = 0;
|
||||
user->limits.hub_count_user = num;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_REGISTER);
|
||||
if (arg)
|
||||
{
|
||||
ssize_t num = atoll(arg);
|
||||
if (num < 0) num = 0;
|
||||
user->limits.hub_count_registered = num;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_OPERATOR);
|
||||
if (arg)
|
||||
{
|
||||
ssize_t num = atoll(arg);
|
||||
if (num < 0) num = 0;
|
||||
user->limits.hub_count_operator = num;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_UPLOAD_SLOTS);
|
||||
if (arg)
|
||||
{
|
||||
ssize_t num = atoll(arg);
|
||||
if (num < 0) num = 0;
|
||||
user->limits.upload_slots = num;
|
||||
hub_free(arg);
|
||||
arg = 0;
|
||||
}
|
||||
|
||||
/* summarize total slots */
|
||||
user->limits.hub_count_total = user->limits.hub_count_user + user->limits.hub_count_registered + user->limits.hub_count_operator;
|
||||
|
||||
if (!user_is_protected(user))
|
||||
{
|
||||
if (user->limits.shared_size < hub_get_min_share(user->hub) && hub_get_min_share(user->hub))
|
||||
{
|
||||
return status_msg_user_share_size_low;
|
||||
}
|
||||
|
||||
if (user->limits.shared_size > hub_get_max_share(user->hub) && hub_get_max_share(user->hub))
|
||||
{
|
||||
return status_msg_user_share_size_high;
|
||||
}
|
||||
|
||||
if ((user->limits.hub_count_user > hub_get_max_hubs_user(user->hub) && hub_get_max_hubs_user(user->hub)) ||
|
||||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(user->hub) && hub_get_max_hubs_reg(user->hub)) ||
|
||||
(user->limits.hub_count_operator > hub_get_max_hubs_op(user->hub) && hub_get_max_hubs_op(user->hub)) ||
|
||||
(user->limits.hub_count_total > hub_get_max_hubs_total(user->hub) && hub_get_max_hubs_total(user->hub)))
|
||||
{
|
||||
return status_msg_user_hub_limit_high;
|
||||
}
|
||||
|
||||
if ((user->limits.hub_count_user < hub_get_min_hubs_user(user->hub) && hub_get_min_hubs_user(user->hub)) ||
|
||||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(user->hub) && hub_get_min_hubs_reg(user->hub)) ||
|
||||
(user->limits.hub_count_operator < hub_get_min_hubs_op(user->hub) && hub_get_min_hubs_op(user->hub)))
|
||||
{
|
||||
return status_msg_user_hub_limit_low;
|
||||
}
|
||||
|
||||
if (user->limits.upload_slots < hub_get_min_slots(user->hub) && hub_get_min_slots(user->hub))
|
||||
{
|
||||
return status_msg_user_slots_low;
|
||||
}
|
||||
|
||||
if (user->limits.upload_slots > hub_get_max_slots(user->hub) && hub_get_max_slots(user->hub))
|
||||
{
|
||||
return status_msg_user_slots_high;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the expected credentials, and returns 1 if authentication is needed,
|
||||
* or 0 if not.
|
||||
* If the hub is configured to allow only registered users and the user
|
||||
* is not recognized this will return 1.
|
||||
*/
|
||||
static int set_credentials(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct user_access_info* info = acl_get_access_info(user->hub->acl, user->id.nick);
|
||||
|
||||
if (info)
|
||||
{
|
||||
user->credentials = info->status;
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
user->credentials = cred_guest;
|
||||
}
|
||||
|
||||
switch (user->credentials)
|
||||
{
|
||||
case cred_none:
|
||||
break;
|
||||
|
||||
case cred_bot:
|
||||
adc_msg_add_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE ADC_CLIENT_TYPE_BOT);
|
||||
break;
|
||||
|
||||
case cred_guest:
|
||||
/* Nothing to be added to the info message */
|
||||
break;
|
||||
|
||||
case cred_user:
|
||||
adc_msg_add_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE ADC_CLIENT_TYPE_REGISTERED_USER);
|
||||
break;
|
||||
|
||||
case cred_operator:
|
||||
adc_msg_add_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE ADC_CLIENT_TYPE_OPERATOR);
|
||||
break;
|
||||
|
||||
case cred_super:
|
||||
adc_msg_add_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE ADC_CLIENT_TYPE_SUPER_USER);
|
||||
break;
|
||||
|
||||
case cred_admin:
|
||||
adc_msg_add_argument(cmd, ADC_INF_FLAG_CLIENT_TYPE ADC_CLIENT_TYPE_ADMIN);
|
||||
break;
|
||||
|
||||
case cred_link:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a user is to be let into the hub even if the hub is "full".
|
||||
*/
|
||||
static int user_is_protected(struct user* user)
|
||||
{
|
||||
switch (user->credentials)
|
||||
{
|
||||
case cred_bot:
|
||||
case cred_operator:
|
||||
case cred_super:
|
||||
case cred_admin:
|
||||
case cred_link:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if a user is registered.
|
||||
* Only registered users will be let in if the hub is configured for registered
|
||||
* users only.
|
||||
*/
|
||||
static int user_is_registered(struct user* user)
|
||||
{
|
||||
switch (user->credentials)
|
||||
{
|
||||
case cred_bot:
|
||||
case cred_user:
|
||||
case cred_operator:
|
||||
case cred_super:
|
||||
case cred_admin:
|
||||
case cred_link:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void update_user_info(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char prefix[2];
|
||||
char* argument;
|
||||
size_t n = 0;
|
||||
struct adc_message* cmd_new = adc_msg_copy(u->info);
|
||||
if (!cmd_new)
|
||||
{
|
||||
/* FIXME: OOM! */
|
||||
return;
|
||||
}
|
||||
|
||||
argument = adc_msg_get_argument(cmd, n++);
|
||||
while (argument)
|
||||
{
|
||||
if (strlen(argument) >= 2)
|
||||
{
|
||||
prefix[0] = argument[0];
|
||||
prefix[1] = argument[1];
|
||||
adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
|
||||
}
|
||||
|
||||
hub_free(argument);
|
||||
argument = adc_msg_get_argument(cmd, n++);
|
||||
}
|
||||
user_set_info(u, cmd_new);
|
||||
}
|
||||
|
||||
|
||||
static int check_is_hub_full(struct user* user)
|
||||
{
|
||||
/*
|
||||
* If hub is full, don't let users in, but we still want to allow
|
||||
* operators and admins to enter the hub.
|
||||
*/
|
||||
if (user->hub->config->max_users && user->hub->users->count >= user->hub->config->max_users && !user_is_protected(user))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_registered_users_only(struct user* user)
|
||||
{
|
||||
if (user->hub->config->registered_users_only && !user_is_registered(user))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INF_CHECK(FUNC, USER, CMD) \
|
||||
do { \
|
||||
int ret = FUNC(USER, CMD); \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
} while(0)
|
||||
|
||||
static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
/* Remove server restricted flags */
|
||||
remove_server_restricted_flags(cmd);
|
||||
|
||||
/* Update/set the feature cast flags. */
|
||||
set_feature_cast_supports(user, cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hub_handle_info_low_bandwidth(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
if (user->hub->config->low_bandwidth_mode)
|
||||
{
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_USER_AGENT);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_SHARED_FILES);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_NORMAL);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_REGISTER);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_COUNT_HUB_OPERATOR);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_UPLOAD_SPEED);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_DOWNLOAD_SPEED);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_AUTO_SLOTS);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_AUTO_SLOTS_MAX);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_AWAY);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_DESCRIPTION);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_EMAIL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hub_handle_info_login(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
int need_auth = 0;
|
||||
|
||||
/* Make syntax checks. */
|
||||
INF_CHECK(check_required_login_flags, user, cmd);
|
||||
INF_CHECK(check_cid, user, cmd);
|
||||
INF_CHECK(check_nick, user, cmd);
|
||||
INF_CHECK(check_network, user, cmd);
|
||||
INF_CHECK(check_user_agent, user, cmd);
|
||||
INF_CHECK(check_acl, user, cmd);
|
||||
INF_CHECK(check_logged_in, user, cmd);
|
||||
|
||||
/* Private ID must never be broadcasted - drop it! */
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
|
||||
|
||||
/* FIXME: This needs some cleaning up */
|
||||
need_auth = set_credentials(user, cmd);
|
||||
|
||||
/* Note: this must be done *after* set_credentials. */
|
||||
if (check_is_hub_full(user))
|
||||
{
|
||||
return status_msg_hub_full;
|
||||
}
|
||||
|
||||
if (check_registered_users_only(user))
|
||||
{
|
||||
return status_msg_hub_registered_users_only;
|
||||
}
|
||||
|
||||
INF_CHECK(check_limits, user, cmd);
|
||||
|
||||
/* strip off stuff if low_bandwidth_mode is enabled */
|
||||
hub_handle_info_low_bandwidth(user, cmd);
|
||||
|
||||
/* Set initial user info */
|
||||
user_set_info(user, cmd);
|
||||
|
||||
return need_auth;
|
||||
}
|
||||
|
||||
/*
|
||||
* If user is in the connecting state, we need to do fairly
|
||||
* strict checking of all arguments.
|
||||
* This means we disconnect users when they provide invalid data
|
||||
* during the login sequence.
|
||||
* When users are merely updating their data after successful login
|
||||
* we can just ignore any invalid data and not broadcast it.
|
||||
*
|
||||
* The data we need to check is:
|
||||
* - nick name (valid, not taken, etc)
|
||||
* - CID/PID (valid, not taken, etc).
|
||||
* - IP addresses (IPv4 and IPv6)
|
||||
*/
|
||||
int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
|
||||
{
|
||||
struct adc_message* cmd = adc_msg_copy(cmd_unmodified); /* FIXME: Have a small memory leak here! */
|
||||
if (!cmd) return -1; /* OOM */
|
||||
|
||||
hub_handle_info_common(user, cmd);
|
||||
|
||||
/* If user is logging in, perform more checks,
|
||||
otherwise only a few things need to be checked.
|
||||
*/
|
||||
if (user_is_connecting(user))
|
||||
{
|
||||
int ret = hub_handle_info_login(user, cmd);
|
||||
if (ret < 0)
|
||||
{
|
||||
on_login_failure(user, ret);
|
||||
adc_msg_free(cmd);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Post a message, the user has joined */
|
||||
struct event_data post;
|
||||
memset(&post, 0, sizeof(post));
|
||||
post.id = UHUB_EVENT_USER_JOIN;
|
||||
post.ptr = user;
|
||||
post.flags = ret; /* 0 - all OK, 1 - need authentication */
|
||||
event_queue_post(user->hub->queue, &post);
|
||||
adc_msg_free(cmd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* These must not be allowed updated, let's remove them! */
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
|
||||
|
||||
/*
|
||||
* If the nick is not accepted, do not relay it.
|
||||
* Otherwise, the nickname will be updated.
|
||||
*/
|
||||
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK))
|
||||
{
|
||||
#if ALLOW_CHANGE_NICK
|
||||
if (!check_nick(user, cmd))
|
||||
#endif
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK);
|
||||
}
|
||||
|
||||
/* FIXME - What if limits are not met ? */
|
||||
check_limits(user, cmd);
|
||||
hub_handle_info_low_bandwidth(user, cmd);
|
||||
update_user_info(user, cmd);
|
||||
|
||||
if (!adc_msg_is_empty(cmd))
|
||||
{
|
||||
route_message(user, cmd);
|
||||
}
|
||||
|
||||
adc_msg_free(cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
54
src/inf.h
Normal file
54
src/inf.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_INF_PARSER_H
|
||||
#define HAVE_UHUB_INF_PARSER_H
|
||||
|
||||
enum nick_status
|
||||
{
|
||||
nick_ok = 0,
|
||||
nick_invalid_short = -1,
|
||||
nick_invalid_long = -2,
|
||||
nick_invalid_spaces = -3,
|
||||
nick_invalid_bad_ascii = -4,
|
||||
nick_invalid_bad_utf8 = -5,
|
||||
nick_invalid = -6, /* some unknown reason */
|
||||
nick_not_allowed = -7, /* Not allowed according to configuration */
|
||||
nick_banned = -8, /* Nickname is banned */
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle info messages as received from clients.
|
||||
* This can be an initial info message, which might end up requiring password
|
||||
* authentication, etc.
|
||||
* All sorts of validation is performed here.
|
||||
* - Nickname valid?
|
||||
* - CID/PID valid?
|
||||
* - Network IP address valid?
|
||||
*
|
||||
* This can be triggered multiple times, as users can update their information,
|
||||
* in such case nickname and CID/PID changes are not allowed.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_info(struct user* u, const struct adc_message* cmd);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_INF_PARSER_H */
|
||||
|
425
src/ipcalc.c
Normal file
425
src/ipcalc.c
Normal file
@ -0,0 +1,425 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
int ip_is_valid_ipv4(const char* address)
|
||||
{
|
||||
int i = 0; /* address index */
|
||||
int o = 0; /* octet number */
|
||||
int n = 0; /* numbers after each dot */
|
||||
int d = 0; /* dots */
|
||||
|
||||
if (!address || strlen(address) > 15 || strlen(address) < 7)
|
||||
return 0;
|
||||
|
||||
for (; i < strlen(address); i++)
|
||||
{
|
||||
if (is_num(address[i]))
|
||||
{
|
||||
n++;
|
||||
o *= 10;
|
||||
o += (address[i] - '0');
|
||||
}
|
||||
else if (address[i] == '.')
|
||||
{
|
||||
if (n == 0 || n > 3 || o > 255) return 0;
|
||||
n = 0;
|
||||
o = 0;
|
||||
d++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0 || n > 3 || o > 255 || d != 3) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ip_is_valid_ipv6(const char* address)
|
||||
{
|
||||
unsigned char buf[16];
|
||||
int ret = net_string_to_address(AF_INET6, address, buf);
|
||||
if (ret <= 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ip_convert_to_binary(const char* taddr, struct ip_addr_encap* raw)
|
||||
{
|
||||
if (ip_is_valid_ipv6(taddr))
|
||||
{
|
||||
if (net_string_to_address(AF_INET6, taddr, &raw->internal_ip_data.in6) <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
raw->af = AF_INET6;
|
||||
return AF_INET6;
|
||||
}
|
||||
else if (ip_is_valid_ipv4(taddr))
|
||||
{
|
||||
if (net_string_to_address(AF_INET, taddr, &raw->internal_ip_data.in) <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
raw->af = AF_INET;
|
||||
return AF_INET;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
char* ip_convert_to_string(struct ip_addr_encap* raw)
|
||||
{
|
||||
static char address[INET6_ADDRSTRLEN+1];
|
||||
memset(address, 0, INET6_ADDRSTRLEN);
|
||||
net_address_to_string(raw->af, (void*) &raw->internal_ip_data, address, INET6_ADDRSTRLEN+1);
|
||||
if (strncmp(address, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
|
||||
{
|
||||
return &address[7];
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
int ip_convert_address(const char* text_address, int port, struct sockaddr* addr, socklen_t* addr_len)
|
||||
{
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr_in addr4;
|
||||
size_t sockaddr_size;
|
||||
const char* taddr = 0;
|
||||
|
||||
int ipv6sup = net_is_ipv6_supported();
|
||||
|
||||
if (strcmp(text_address, "any") == 0)
|
||||
{
|
||||
if (ipv6sup)
|
||||
{
|
||||
taddr = "::";
|
||||
}
|
||||
else
|
||||
{
|
||||
taddr = "0.0.0.0";
|
||||
}
|
||||
}
|
||||
else if (strcmp(text_address, "loopback") == 0)
|
||||
{
|
||||
if (ipv6sup)
|
||||
{
|
||||
taddr = "::1";
|
||||
}
|
||||
else
|
||||
{
|
||||
taddr = "127.0.0.1";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
taddr = text_address;
|
||||
}
|
||||
|
||||
|
||||
if (ip_is_valid_ipv6(taddr) && ipv6sup)
|
||||
{
|
||||
sockaddr_size = sizeof(struct sockaddr_in6);
|
||||
memset(&addr6, 0, sockaddr_size);
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(port);
|
||||
if (net_string_to_address(AF_INET6, taddr, &addr6.sin6_addr) <= 0)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to convert socket address (ipv6)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(addr, &addr6, sockaddr_size);
|
||||
*addr_len = sockaddr_size;
|
||||
|
||||
}
|
||||
else if (ip_is_valid_ipv4(taddr))
|
||||
{
|
||||
sockaddr_size = sizeof(struct sockaddr_in);
|
||||
memset(&addr4, 0, sockaddr_size);
|
||||
addr4.sin_family = AF_INET;
|
||||
addr4.sin_port = htons(port);
|
||||
if (net_string_to_address(AF_INET, taddr, &addr4.sin_addr) <= 0)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to convert socket address (ipv4)");
|
||||
return 0;
|
||||
}
|
||||
memcpy(addr, &addr4, sockaddr_size);
|
||||
*addr_len = sockaddr_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = 0;
|
||||
*addr_len = 0;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result)
|
||||
{
|
||||
uint32_t mask;
|
||||
int fill, remain_bits, n;
|
||||
|
||||
memset(result, 0, sizeof(struct ip_addr_encap));
|
||||
result->af = af;
|
||||
|
||||
if (bits < 0) bits = 0;
|
||||
|
||||
if (af == AF_INET)
|
||||
{
|
||||
if (bits > 32) bits = 32;
|
||||
mask = (0xffffffff << (32 - bits));
|
||||
if (bits == 0) mask = 0;
|
||||
|
||||
result->internal_ip_data.in.s_addr = (((uint8_t*) &mask)[0] << 24) | (((uint8_t*) &mask)[1] << 16) | (((uint8_t*) &mask)[2] << 8) | (((uint8_t*) &mask)[3] << 0);
|
||||
}
|
||||
else if (af == AF_INET6)
|
||||
{
|
||||
if (bits > 128) bits = 128;
|
||||
|
||||
fill = (128-bits) / 8;
|
||||
remain_bits = (128-bits) % 8;
|
||||
mask = (0xff << (8 - remain_bits));
|
||||
n = 0;
|
||||
|
||||
for (n = 0; n < fill; n++)
|
||||
((uint8_t*) &result->internal_ip_data.in6)[n] = (uint8_t) 0xff;
|
||||
|
||||
if (fill < 16)
|
||||
((uint8_t*) &result->internal_ip_data.in6)[fill] = (uint8_t) mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef IP_CALC_DEBUG
|
||||
char* r_str = hub_strdup(ip_convert_to_string(result));
|
||||
hub_log(log_debug, "Created left mask: %s", r_str);
|
||||
hub_free(r_str);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result)
|
||||
{
|
||||
uint32_t mask;
|
||||
int fill, remain_bits, n, start;
|
||||
uint8_t mask8;
|
||||
|
||||
memset(result, 0, sizeof(struct ip_addr_encap));
|
||||
result->af = af;
|
||||
|
||||
if (bits < 0) bits = 0;
|
||||
|
||||
if (af == AF_INET)
|
||||
{
|
||||
if (bits > 32) bits = 32;
|
||||
mask = (0xffffffff >> (32-bits));
|
||||
if (bits == 0) mask = 0;
|
||||
result->internal_ip_data.in.s_addr = (((uint8_t*) &mask)[0] << 24) | (((uint8_t*) &mask)[1] << 16) | (((uint8_t*) &mask)[2] << 8) | (((uint8_t*) &mask)[3] << 0);
|
||||
|
||||
}
|
||||
else if (af == AF_INET6)
|
||||
{
|
||||
if (bits > 128) bits = 128;
|
||||
|
||||
fill = (128-bits) / 8;
|
||||
remain_bits = (128-bits) % 8;
|
||||
mask8 = (0xff >> (8 - remain_bits));
|
||||
n = 0;
|
||||
start = 16-fill;
|
||||
|
||||
for (n = 0; n < start; n++)
|
||||
((uint8_t*) &result->internal_ip_data.in6)[n] = (uint8_t) 0x00;
|
||||
|
||||
for (n = start; n < 16; n++)
|
||||
((uint8_t*) &result->internal_ip_data.in6)[n] = (uint8_t) 0xff;
|
||||
|
||||
if (start > 0)
|
||||
((uint8_t*) &result->internal_ip_data.in6)[start-1] = (uint8_t) mask8;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef IP_CALC_DEBUG
|
||||
char* r_str = hub_strdup(ip_convert_to_string(result));
|
||||
hub_log(log_debug, "Created right mask: %s", r_str);
|
||||
hub_free(r_str);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ip_mask_apply_AND(struct ip_addr_encap* addr, struct ip_addr_encap* mask, struct ip_addr_encap* result)
|
||||
{
|
||||
memset(result, 0, sizeof(struct ip_addr_encap));
|
||||
result->af = addr->af;
|
||||
|
||||
if (addr->af == AF_INET)
|
||||
{
|
||||
result->internal_ip_data.in.s_addr = addr->internal_ip_data.in.s_addr & mask->internal_ip_data.in.s_addr;
|
||||
}
|
||||
else if (addr->af == AF_INET6)
|
||||
{
|
||||
uint32_t A, B, C, D;
|
||||
int n = 0;
|
||||
int offset = 0;
|
||||
for (n = 0; n < 4; n++)
|
||||
{
|
||||
offset = n * 4;
|
||||
|
||||
A = (((uint8_t*) &addr->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
B = (((uint8_t*) &mask->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
C = A & B;
|
||||
|
||||
D = (((uint8_t*) &C)[0] << 24) |
|
||||
(((uint8_t*) &C)[1] << 16) |
|
||||
(((uint8_t*) &C)[2] << 8) |
|
||||
(((uint8_t*) &C)[3] << 0);
|
||||
((uint32_t*) &result->internal_ip_data.in6)[n] = D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ip_mask_apply_OR(struct ip_addr_encap* addr, struct ip_addr_encap* mask, struct ip_addr_encap* result)
|
||||
{
|
||||
memset(result, 0, sizeof(struct ip_addr_encap));
|
||||
result->af = addr->af;
|
||||
|
||||
if (addr->af == AF_INET)
|
||||
{
|
||||
result->internal_ip_data.in.s_addr = addr->internal_ip_data.in.s_addr | mask->internal_ip_data.in.s_addr;
|
||||
}
|
||||
else if (addr->af == AF_INET6)
|
||||
{
|
||||
uint32_t A, B, C, D;
|
||||
int n = 0;
|
||||
int offset = 0;
|
||||
for (n = 0; n < 4; n++)
|
||||
{
|
||||
offset = n * 4;
|
||||
|
||||
A = (((uint8_t*) &addr->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &addr->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
B = (((uint8_t*) &mask->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &mask->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
C = A | B;
|
||||
|
||||
D = (((uint8_t*) &C)[0] << 24) |
|
||||
(((uint8_t*) &C)[1] << 16) |
|
||||
(((uint8_t*) &C)[2] << 8) |
|
||||
(((uint8_t*) &C)[3] << 0);
|
||||
((uint32_t*) &result->internal_ip_data.in6)[n] = D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t A, B;
|
||||
|
||||
if (a->af == AF_INET)
|
||||
{
|
||||
A = (((uint8_t*) &a->internal_ip_data.in.s_addr)[0] << 24) |
|
||||
(((uint8_t*) &a->internal_ip_data.in.s_addr)[1] << 16) |
|
||||
(((uint8_t*) &a->internal_ip_data.in.s_addr)[2] << 8) |
|
||||
(((uint8_t*) &a->internal_ip_data.in.s_addr)[3] << 0);
|
||||
|
||||
B = (((uint8_t*) &b->internal_ip_data.in.s_addr)[0] << 24) |
|
||||
(((uint8_t*) &b->internal_ip_data.in.s_addr)[1] << 16) |
|
||||
(((uint8_t*) &b->internal_ip_data.in.s_addr)[2] << 8) |
|
||||
(((uint8_t*) &b->internal_ip_data.in.s_addr)[3] << 0);
|
||||
ret = A - B;
|
||||
}
|
||||
else if (a->af == AF_INET6)
|
||||
{
|
||||
int n = 0;
|
||||
int offset = 0;
|
||||
for (n = 0; n < 4; n++)
|
||||
{
|
||||
offset = n * 4;
|
||||
A = (((uint8_t*) &a->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &a->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &a->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &a->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
B = (((uint8_t*) &b->internal_ip_data.in6)[offset+0] << 24) |
|
||||
(((uint8_t*) &b->internal_ip_data.in6)[offset+1] << 16) |
|
||||
(((uint8_t*) &b->internal_ip_data.in6)[offset+2] << 8) |
|
||||
(((uint8_t*) &b->internal_ip_data.in6)[offset+3] << 0);
|
||||
|
||||
if (A == B) continue;
|
||||
|
||||
return A - B;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IP_CALC_DEBUG
|
||||
char* a_str = hub_strdup(ip_convert_to_string(a));
|
||||
char* b_str = hub_strdup(ip_convert_to_string(b));
|
||||
hub_log(log_debug, "Comparing IPs '%s' AND '%s' => %d", a_str, b_str, ret);
|
||||
hub_free(a_str);
|
||||
hub_free(b_str);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
84
src/ipcalc.h
Normal file
84
src/ipcalc.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is used for fiddling with IP-addresses,
|
||||
* primarily used for IP-banning in uhub.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_IPCALC_H
|
||||
#define HAVE_UHUB_IPCALC_H
|
||||
|
||||
struct ip_addr_encap {
|
||||
int af;
|
||||
union {
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
} internal_ip_data;
|
||||
};
|
||||
|
||||
|
||||
extern int ip_convert_to_binary(const char* text_addr, struct ip_addr_encap* raw);
|
||||
|
||||
extern char* ip_convert_to_string(struct ip_addr_encap* raw);
|
||||
|
||||
|
||||
/*
|
||||
* @return 1 if address is a valid IPv4 address in text notation
|
||||
* 0 if invalid
|
||||
*/
|
||||
extern int ip_is_valid_ipv4(const char* address);
|
||||
|
||||
/*
|
||||
* @return 1 if address is a valid IPv6 address in text notation
|
||||
* 0 if invalid
|
||||
*/
|
||||
extern int ip_is_valid_ipv6(const char* address);
|
||||
|
||||
|
||||
/*
|
||||
* This function converts an IP address in text_address to a binary
|
||||
* struct sockaddr.
|
||||
* This will auto-detect if the IP-address is IPv6 (and that is supported),
|
||||
* or if IPv4 should be used.
|
||||
* NOTE: Use sockaddr_storage to allocate enough memory for IPv6.
|
||||
*
|
||||
* @param text_addr is an ipaddress either ipv6 or ipv4.
|
||||
* Special magic addresses called "any" and "loopback" exist,
|
||||
* and will work accross IPv6/IPv4.
|
||||
* @param port Fill the struct sockaddr* with the given port, can safely be ignored.
|
||||
*/
|
||||
extern int ip_convert_address(const char* text_address, int port, struct sockaddr* addr, socklen_t* addr_len);
|
||||
|
||||
|
||||
extern int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result);
|
||||
extern int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result);
|
||||
|
||||
extern void ip_mask_apply_AND(struct ip_addr_encap* address, struct ip_addr_encap* mask, struct ip_addr_encap* result);
|
||||
extern void ip_mask_apply_OR(struct ip_addr_encap* address, struct ip_addr_encap* mask, struct ip_addr_encap* result);
|
||||
|
||||
/**
|
||||
* @return <0 if a is less than b
|
||||
* @return >0 if a is greater than b
|
||||
* @return 0 if they are equal
|
||||
*/
|
||||
extern int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b);
|
||||
|
||||
#endif /* HAVE_UHUB_IPCALC_H */
|
||||
|
192
src/list.c
Normal file
192
src/list.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
struct linked_list* list_create()
|
||||
{
|
||||
struct linked_list* list = NULL;
|
||||
list = (struct linked_list*) hub_malloc_zero(sizeof(struct linked_list));
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void list_destroy(struct linked_list* list)
|
||||
{
|
||||
if (list)
|
||||
hub_free(list);
|
||||
}
|
||||
|
||||
|
||||
void list_clear(struct linked_list* list, void (*free_handle)(void* ptr))
|
||||
{
|
||||
struct node* node = list->first;
|
||||
struct node* tmp = NULL;
|
||||
while (node)
|
||||
{
|
||||
tmp = node->next;
|
||||
free_handle(node->ptr);
|
||||
hub_free(node);
|
||||
node = tmp;
|
||||
}
|
||||
memset(list, 0, sizeof(struct linked_list));
|
||||
}
|
||||
|
||||
|
||||
void list_append(struct linked_list* list, void* data_ptr)
|
||||
{
|
||||
struct node* new_node = (struct node*) hub_malloc_zero(sizeof(struct node));
|
||||
new_node->ptr = data_ptr;
|
||||
|
||||
if (list->last)
|
||||
{
|
||||
list->last->next = new_node;
|
||||
new_node->prev = list->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->first = new_node;
|
||||
}
|
||||
|
||||
list->last = new_node;
|
||||
list->size++;
|
||||
}
|
||||
|
||||
|
||||
void list_remove(struct linked_list* list, void* data_ptr)
|
||||
{
|
||||
struct node* node = list->first;
|
||||
assert(data_ptr);
|
||||
|
||||
list->iterator = NULL;
|
||||
|
||||
while (node)
|
||||
{
|
||||
if (node->ptr == data_ptr)
|
||||
{
|
||||
if (node->next)
|
||||
node->next->prev = node->prev;
|
||||
|
||||
if (node->prev)
|
||||
node->prev->next = node->next;
|
||||
|
||||
if (node == list->last)
|
||||
list->last = node->prev;
|
||||
|
||||
if (node == list->first)
|
||||
list->first = node->next;
|
||||
|
||||
hub_free(node);
|
||||
|
||||
list->size--;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t list_size(struct linked_list* list)
|
||||
{
|
||||
return list->size;
|
||||
}
|
||||
|
||||
|
||||
void* list_get_index(struct linked_list* list, size_t offset)
|
||||
{
|
||||
struct node* node = list->first;
|
||||
size_t n = 0;
|
||||
for (n = 0; n < list->size; n++)
|
||||
{
|
||||
if (n == offset)
|
||||
{
|
||||
return node->ptr;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void* list_get_first(struct linked_list* list)
|
||||
{
|
||||
list->iterator = list->first;
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator->ptr;
|
||||
}
|
||||
|
||||
struct node* list_get_first_node(struct linked_list* list)
|
||||
{
|
||||
list->iterator = list->first;
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator;
|
||||
}
|
||||
|
||||
void* list_get_last(struct linked_list* list)
|
||||
{
|
||||
list->iterator = list->last;
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator->ptr;
|
||||
}
|
||||
|
||||
struct node* list_get_last_node(struct linked_list* list)
|
||||
{
|
||||
list->iterator = list->last;
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator;
|
||||
|
||||
}
|
||||
|
||||
void* list_get_next(struct linked_list* list)
|
||||
{
|
||||
if (list->iterator == NULL)
|
||||
list->iterator = list->first;
|
||||
else
|
||||
list->iterator = list->iterator->next;
|
||||
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator->ptr;
|
||||
}
|
||||
|
||||
|
||||
void* list_get_prev(struct linked_list* list)
|
||||
{
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
list->iterator = list->iterator->prev;
|
||||
|
||||
if (list->iterator == NULL)
|
||||
return NULL;
|
||||
|
||||
return list->iterator->ptr;
|
||||
}
|
||||
|
61
src/list.h
Normal file
61
src/list.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_LINKED_LIST_H
|
||||
#define HAVE_UHUB_LINKED_LIST_H
|
||||
|
||||
struct linked_list
|
||||
{
|
||||
size_t size;
|
||||
struct node* first;
|
||||
struct node* last;
|
||||
struct node* iterator;
|
||||
};
|
||||
|
||||
struct node
|
||||
{
|
||||
void* ptr;
|
||||
struct node* next;
|
||||
struct node* prev;
|
||||
};
|
||||
|
||||
extern struct linked_list* list_create();
|
||||
extern void list_destroy(struct linked_list*);
|
||||
extern void list_clear(struct linked_list*, void (*free_handle)(void* ptr) );
|
||||
|
||||
|
||||
extern void list_append(struct linked_list* list, void* data_ptr);
|
||||
|
||||
/**
|
||||
* Remove data_ptr from the list. If multiple versions occur, only the first one is removed.
|
||||
*/
|
||||
extern void list_remove(struct linked_list* list, void* data_ptr);
|
||||
extern size_t list_size(struct linked_list* list);
|
||||
|
||||
extern void* list_get_index(struct linked_list*, size_t offset);
|
||||
extern void* list_get_first(struct linked_list*);
|
||||
extern void* list_get_last(struct linked_list*);
|
||||
extern void* list_get_next(struct linked_list*);
|
||||
extern void* list_get_prev(struct linked_list*);
|
||||
|
||||
extern struct node* list_get_first_node(struct linked_list*);
|
||||
extern struct node* list_get_last_node(struct linked_list*);
|
||||
|
||||
#endif /* HAVE_UHUB_LINKED_LIST_H */
|
||||
|
231
src/log.c
Normal file
231
src/log.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
#include <locale.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <syslog.h>
|
||||
static int use_syslog = 0;
|
||||
#endif
|
||||
|
||||
static int verbosity = 4;
|
||||
static FILE* logfile = NULL;
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
static FILE* memfile = NULL;
|
||||
#define MEMORY_DEBUG_FILE "memlog.txt"
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
#define NETWORK_DUMP_FILE "netdump.log"
|
||||
static FILE* netdump = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
static const char* prefixes[] =
|
||||
{
|
||||
"FATAL",
|
||||
"ERROR",
|
||||
"WARN",
|
||||
"USER",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
"TRACE",
|
||||
"DUMP",
|
||||
"MEM",
|
||||
"PROTO",
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
void hub_log_initialize(const char* file, int syslog)
|
||||
{
|
||||
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
memfile = fopen(MEMORY_DEBUG_FILE, "w");
|
||||
if (!memfile)
|
||||
{
|
||||
fprintf(stderr, "Unable to create " MEMORY_DEBUG_FILE " for logging memory allocations\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
netdump = fopen(NETWORK_DUMP_FILE, "w");
|
||||
if (!netdump)
|
||||
{
|
||||
fprintf(stderr, "Unable to create " NETWORK_DUMP_FILE " for logging network traffic\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
if (syslog)
|
||||
{
|
||||
use_syslog = 1;
|
||||
openlog("uhub", LOG_PID, LOG_USER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!file)
|
||||
{
|
||||
logfile = stderr;
|
||||
return;
|
||||
}
|
||||
|
||||
logfile = fopen(file, "a");
|
||||
if (!logfile)
|
||||
{
|
||||
logfile = stderr;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hub_log_shutdown()
|
||||
{
|
||||
if (logfile && logfile != stderr)
|
||||
{
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
if (memfile)
|
||||
{
|
||||
fclose(memfile);
|
||||
memfile = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
if (netdump)
|
||||
{
|
||||
fclose(netdump);
|
||||
netdump = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
if (use_syslog)
|
||||
{
|
||||
use_syslog = 0;
|
||||
closelog();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void hub_set_log_verbosity(int verb)
|
||||
{
|
||||
verbosity = verb;
|
||||
}
|
||||
|
||||
void hub_log(int log_verbosity, const char *format, ...)
|
||||
{
|
||||
static char logmsg[1024];
|
||||
static char timestamp[32];
|
||||
struct tm *tmp;
|
||||
time_t t;
|
||||
va_list args;
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
if (memfile && log_verbosity == log_memory)
|
||||
{
|
||||
va_start(args, format);
|
||||
vsnprintf(logmsg, 1024, format, args);
|
||||
va_end(args);
|
||||
fprintf(memfile, "%s\n", logmsg);
|
||||
fflush(memfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
if (netdump && log_verbosity == log_protocol)
|
||||
{
|
||||
va_start(args, format);
|
||||
vsnprintf(logmsg, 1024, format, args);
|
||||
va_end(args);
|
||||
fprintf(netdump, "%s\n", logmsg);
|
||||
fflush(netdump);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (log_verbosity < verbosity)
|
||||
{
|
||||
t = time(NULL);
|
||||
tmp = gmtime(&t);
|
||||
strftime(timestamp, 32, "%a, %d %b %Y %H:%M:%S +0000", tmp);
|
||||
va_start(args, format);
|
||||
vsnprintf(logmsg, 1024, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (logfile)
|
||||
{
|
||||
fprintf(logfile, "%s %5s: %s\n", timestamp, prefixes[log_verbosity], logmsg);
|
||||
fflush(logfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s %5s: %s\n", timestamp, prefixes[log_verbosity], logmsg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (use_syslog)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
if (verbosity < log_info)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(logmsg, 1024, format, args);
|
||||
va_end(args);
|
||||
|
||||
switch (log_verbosity)
|
||||
{
|
||||
case log_fatal: level = LOG_CRIT; break;
|
||||
case log_error: level = LOG_ERR; break;
|
||||
case log_warning: level = LOG_WARNING; break;
|
||||
case log_user: level = LOG_INFO | LOG_AUTH; break;
|
||||
case log_info: level = LOG_INFO; break;
|
||||
case log_debug: level = LOG_DEBUG; break;
|
||||
|
||||
default:
|
||||
level = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (level == 0)
|
||||
return;
|
||||
|
||||
level |= (LOG_USER | LOG_DAEMON);
|
||||
syslog(level, "%s", logmsg);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
59
src/log.h
Normal file
59
src/log.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_LOG_H
|
||||
#define HAVE_UHUB_LOG_H
|
||||
|
||||
enum log_verbosity {
|
||||
log_fatal = 0,
|
||||
log_error = 1,
|
||||
log_warning = 2,
|
||||
log_user = 3,
|
||||
log_info = 4,
|
||||
log_debug = 5,
|
||||
log_trace = 6,
|
||||
log_dump = 7,
|
||||
log_memory = 8,
|
||||
log_protocol = 9,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specify a minimum log verbosity for what messages should
|
||||
* be printed in the log.
|
||||
*/
|
||||
extern void hub_set_log_verbosity(int log_verbosity);
|
||||
|
||||
/**
|
||||
* Print a message in the log.
|
||||
*/
|
||||
extern void hub_log(int log_verbosity, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Initialize the log subsystem, if no output file is given (file is null)
|
||||
* stderr is assumed by default.
|
||||
* If the file cannot be opened for writing, stdout is also used.
|
||||
*/
|
||||
extern void hub_log_initialize(const char* file, int syslog);
|
||||
|
||||
/**
|
||||
* Shut down and close the logfile.
|
||||
*/
|
||||
extern void hub_log_shutdown();
|
||||
|
||||
#endif /* HAVE_UHUB_LOG_H */
|
441
src/main.c
Normal file
441
src/main.c
Normal file
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
static int arg_verbose = 5;
|
||||
static int arg_fork = 0;
|
||||
static int arg_check_config = 0;
|
||||
static int arg_dump_config = 0;
|
||||
static int arg_have_config = 0;
|
||||
static const char* arg_uid = 0;
|
||||
static const char* arg_gid = 0;
|
||||
static const char* arg_config = 0;
|
||||
static const char* arg_log = 0;
|
||||
static int arg_log_syslog = 0;
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
void hub_handle_signal(int fd, short events, void* arg)
|
||||
{
|
||||
struct hub_info* hub = (struct hub_info*) arg;
|
||||
int signal = fd;
|
||||
struct timeval now = {0, 0};
|
||||
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT:
|
||||
hub_log(log_info, "Interrupted. Shutting down...");
|
||||
hub->status = hub_status_shutdown;
|
||||
event_loopexit(&now);
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
hub_log(log_info, "Terminated. Shutting down...");
|
||||
hub->status = hub_status_shutdown;
|
||||
event_loopexit(&now);
|
||||
break;
|
||||
|
||||
case SIGPIPE:
|
||||
hub_log(log_trace, "hub_handle_signal(): caught SIGPIPE (ignoring)");
|
||||
break;
|
||||
|
||||
case SIGHUP:
|
||||
hub_log(log_info, "Caught hangup signal. Reloading configuration files...");
|
||||
hub->status = hub_status_restart;
|
||||
event_loopexit(&now);
|
||||
break;
|
||||
|
||||
case SIGUSR1:
|
||||
hub_log(log_trace, "hub_handle_signal(): caught SIGUSR1 -- FIXME");
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
hub_log(log_trace, "hub_handle_signal(): caught SIGUSR2");
|
||||
{
|
||||
user_manager_stats(hub);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
hub_log(log_trace, "hub_handle_signal(): caught unknown signal: %d", signal);
|
||||
hub->status = hub_status_shutdown;
|
||||
event_loopexit(&now);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct event signal_events[10];
|
||||
static int signals[] =
|
||||
{
|
||||
SIGINT, /* Interrupt the application */
|
||||
SIGTERM, /* Terminate the application */
|
||||
SIGPIPE, /* prevent sigpipe from kills the application */
|
||||
SIGHUP, /* reload configuration */
|
||||
SIGUSR1, /* dump statistics */
|
||||
SIGUSR2, /* (unused) */
|
||||
0
|
||||
};
|
||||
|
||||
void setup_signal_handlers(struct hub_info* hub)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; signals[i]; i++)
|
||||
{
|
||||
signal_set(&signal_events[i], signals[i], hub_handle_signal, hub);
|
||||
if (signal_add(&signal_events[i], NULL))
|
||||
{
|
||||
hub_log(log_error, "Error setting signal handler %d", signals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown_signal_handlers(struct hub_info* hub)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; signals[i]; i++)
|
||||
{
|
||||
signal_del(&signal_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
int main_loop()
|
||||
{
|
||||
struct hub_config configuration;
|
||||
struct acl_handle acl;
|
||||
struct hub_info* hub = 0;
|
||||
|
||||
if (net_initialize() == -1)
|
||||
return -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (read_config(arg_config, &configuration, !arg_have_config) == -1)
|
||||
return -1;
|
||||
|
||||
if (acl_initialize(&configuration, &acl) == -1)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Don't restart networking when re-reading configuration.
|
||||
* This might not be possible either, since we might have
|
||||
* dropped our privileges to do so.
|
||||
*/
|
||||
if (!hub)
|
||||
{
|
||||
hub = hub_start_service(&configuration);
|
||||
if (!hub)
|
||||
return -1;
|
||||
#ifndef WIN32
|
||||
setup_signal_handlers(hub);
|
||||
#endif
|
||||
}
|
||||
|
||||
hub_set_variables(hub, &acl);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
hub_free_variables(hub);
|
||||
acl_shutdown(&acl);
|
||||
free_config(&configuration);
|
||||
|
||||
} while(hub->status != hub_status_shutdown);
|
||||
|
||||
#ifndef WIN32
|
||||
shutdown_signal_handlers(hub);
|
||||
#endif
|
||||
|
||||
if (hub)
|
||||
{
|
||||
hub_shutdown_service(hub);
|
||||
}
|
||||
|
||||
net_shutdown();
|
||||
hub_log_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int check_configuration(int dump)
|
||||
{
|
||||
struct hub_config configuration;
|
||||
int ret = read_config(arg_config, &configuration, 0);
|
||||
|
||||
if (dump)
|
||||
{
|
||||
dump_config(&configuration, dump > 1);
|
||||
puts("");
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
fprintf(stderr, "ERROR\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(stdout, "OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void print_version()
|
||||
{
|
||||
fprintf(stdout, "" PRODUCT " " VERSION " " PRODUCT_TITLE "\n");
|
||||
fprintf(stdout, "Copyright (C) 2007-2009, Jan Vidar Krey <janvidar@extatic.org>\n"
|
||||
"This is free software with ABSOLUTELY NO WARRANTY.\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void print_usage(char* program)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options]\n\n", program);
|
||||
fprintf(stderr,
|
||||
"Options:\n"
|
||||
" -v Verbose mode. Add more -v's for higher verbosity.\n"
|
||||
" -q Quiet mode - no output\n"
|
||||
" -f Fork to background\n"
|
||||
" -l <file> Log messages to given file (default: stderr)\n"
|
||||
" -L Log messages to syslog\n"
|
||||
" -c <file> Specify configuration file (default: " SERVER_CONFIG ")\n"
|
||||
" -C Check configuration and return\n"
|
||||
" -s Show configuration parameters\n"
|
||||
" -S Show configuration parameters, but ignore defaults\n"
|
||||
" -h This message\n"
|
||||
#ifndef WIN32
|
||||
" -u <user> Run as given user\n"
|
||||
" -g <group> Run with given group permissions\n"
|
||||
#endif
|
||||
" -V Show version number.\n"
|
||||
);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void parse_command_line(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "vqfc:l:hu:g:VCsSL")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'V':
|
||||
print_version();
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
arg_verbose++;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
arg_verbose -= 99;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
arg_fork = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
arg_config = optarg;
|
||||
arg_have_config = 1;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
arg_check_config = 1;
|
||||
arg_have_config = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
arg_dump_config = 1;
|
||||
arg_check_config = 1;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
arg_dump_config = 2;
|
||||
arg_check_config = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
arg_log = optarg;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
arg_log_syslog = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
arg_uid = optarg;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
arg_gid = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_config == NULL)
|
||||
{
|
||||
arg_config = SERVER_CONFIG;
|
||||
}
|
||||
|
||||
hub_log_initialize(arg_log, arg_log_syslog);
|
||||
hub_set_log_verbosity(arg_verbose);
|
||||
}
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
int drop_privileges()
|
||||
{
|
||||
struct group* perm_group = 0;
|
||||
struct passwd* perm_user = 0;
|
||||
gid_t perm_gid = 0;
|
||||
uid_t perm_uid = 0;
|
||||
int gid_ok = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (arg_gid)
|
||||
{
|
||||
ret = 0;
|
||||
while ((perm_group = getgrent()) != NULL)
|
||||
{
|
||||
if (strcmp(perm_group->gr_name, arg_gid) == 0)
|
||||
{
|
||||
perm_gid = perm_group->gr_gid;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endgrent();
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to determine group id, check group name.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
ret = setgid(perm_gid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change group id, permission denied.");
|
||||
return -1;
|
||||
}
|
||||
gid_ok = 1;
|
||||
}
|
||||
|
||||
if (arg_uid)
|
||||
{
|
||||
ret = 0;
|
||||
while ((perm_user = getpwent()) != NULL)
|
||||
{
|
||||
if (strcmp(perm_user->pw_name, arg_uid) == 0)
|
||||
{
|
||||
perm_uid = perm_user->pw_uid;
|
||||
if (!gid_ok)
|
||||
perm_gid = perm_user->pw_gid;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endpwent();
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to determine user id, check user name.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!gid_ok) {
|
||||
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
ret = setgid(perm_gid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change group id, permission denied.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
hub_log(log_trace, "Setting user id %d (%s)", (int) perm_uid, arg_uid);
|
||||
ret = setuid(perm_uid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change user id, permission denied.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
if (arg_check_config)
|
||||
{
|
||||
return check_configuration(arg_dump_config);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (arg_fork)
|
||||
{
|
||||
ret = fork();
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to fork to background!");
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* child process */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* parent process */
|
||||
hub_log(log_debug, "Forked to background\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_privileges() == -1)
|
||||
return -1;
|
||||
#endif /* WIN32 */
|
||||
|
||||
ret = main_loop();
|
||||
return ret;
|
||||
}
|
||||
|
248
src/memory.c
Normal file
248
src/memory.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
|
||||
#define REALTIME_MALLOC_TRACKING
|
||||
|
||||
#ifdef REALTIME_MALLOC_TRACKING
|
||||
#define UHUB_MAX_ALLOCS 50000
|
||||
struct malloc_info
|
||||
{
|
||||
void* ptr;
|
||||
size_t size;
|
||||
void* stack1;
|
||||
void* stack2;
|
||||
};
|
||||
|
||||
static int hub_alloc_count = 0;
|
||||
static size_t hub_alloc_size = 0;
|
||||
static int hub_alloc_peak_count = 0;
|
||||
static size_t hub_alloc_peak_size = 0;
|
||||
static size_t hub_alloc_oom = 0;
|
||||
|
||||
static struct malloc_info hub_allocs[UHUB_MAX_ALLOCS] = { { 0, }, };
|
||||
static int malloc_slot = -1; /* free slot (-1, no slot) */
|
||||
|
||||
void internal_debug_print_leaks()
|
||||
{
|
||||
size_t n = 0;
|
||||
size_t leak = 0;
|
||||
size_t count = 0;
|
||||
hub_log(log_memory, "--- exit (allocs: %d, size: %zu) ---", hub_alloc_count, hub_alloc_size);
|
||||
|
||||
for (; n < UHUB_MAX_ALLOCS; n++)
|
||||
{
|
||||
if (hub_allocs[n].ptr)
|
||||
{
|
||||
leak += hub_allocs[n].size;
|
||||
count++;
|
||||
hub_log(log_memory, "leak %p size: %zu (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2);
|
||||
}
|
||||
}
|
||||
|
||||
hub_log(log_memory, "--- done (allocs: %d, size: %zu, peak: %d/%zu, oom: %zu) ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom);
|
||||
}
|
||||
#endif /* REALTIME_MALLOC_TRACKING */
|
||||
|
||||
void* internal_debug_mem_malloc(size_t size, const char* where)
|
||||
{
|
||||
size_t n = 0;
|
||||
char* ptr = malloc(size);
|
||||
|
||||
#ifdef REALTIME_MALLOC_TRACKING
|
||||
|
||||
/* Make sure the malloc info struct is initialized */
|
||||
if (!hub_alloc_count)
|
||||
{
|
||||
hub_log(log_memory, "--- start ---");
|
||||
for (n = 0; n < UHUB_MAX_ALLOCS; n++)
|
||||
{
|
||||
hub_allocs[n].ptr = 0;
|
||||
hub_allocs[n].size = 0;
|
||||
hub_allocs[n].stack1 = 0;
|
||||
hub_allocs[n].stack2 = 0;
|
||||
}
|
||||
|
||||
atexit(&internal_debug_print_leaks);
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
if (malloc_slot != -1)
|
||||
n = (size_t) malloc_slot;
|
||||
else
|
||||
n = 0;
|
||||
|
||||
for (; n < UHUB_MAX_ALLOCS; n++)
|
||||
{
|
||||
if (!hub_allocs[n].ptr)
|
||||
{
|
||||
hub_allocs[n].ptr = ptr;
|
||||
hub_allocs[n].size = size;
|
||||
hub_allocs[n].stack1 = __builtin_return_address(1);
|
||||
hub_allocs[n].stack2 = __builtin_return_address(2);
|
||||
|
||||
hub_alloc_size += size;
|
||||
hub_alloc_count++;
|
||||
|
||||
hub_alloc_peak_count = MAX(hub_alloc_count, hub_alloc_peak_count);
|
||||
hub_alloc_peak_size = MAX(hub_alloc_size, hub_alloc_peak_size);
|
||||
|
||||
hub_log(log_memory, "%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: %zu}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_memory, "%s *** OOM for %d bytes", where, size);
|
||||
hub_alloc_oom++;
|
||||
return 0;
|
||||
}
|
||||
#endif /* REALTIME_MALLOC_TRACKING */
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void internal_debug_mem_free(void* ptr)
|
||||
{
|
||||
#ifdef REALTIME_MALLOC_TRACKING
|
||||
size_t n = 0;
|
||||
void* stack1 = __builtin_return_address(1);
|
||||
void* stack2 = __builtin_return_address(2);
|
||||
|
||||
if (!ptr) return;
|
||||
|
||||
for (; n < UHUB_MAX_ALLOCS; n++)
|
||||
{
|
||||
if (hub_allocs[n].ptr == ptr)
|
||||
{
|
||||
hub_alloc_size -= hub_allocs[n].size;
|
||||
hub_alloc_count--;
|
||||
hub_allocs[n].ptr = 0;
|
||||
hub_allocs[n].size = 0;
|
||||
hub_allocs[n].stack1 = 0;
|
||||
hub_allocs[n].stack2 = 0;
|
||||
hub_log(log_memory, "free %p (bt: %p %p) {allocs: %d, size: %zu}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
|
||||
malloc_slot = n;
|
||||
free(ptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
malloc_slot = -1;
|
||||
abort();
|
||||
hub_log(log_memory, "free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif /* REALTIME_MALLOC_TRACKING */
|
||||
}
|
||||
|
||||
char* debug_mem_strdup(const char* s)
|
||||
{
|
||||
size_t size = strlen(s);
|
||||
char* ptr = internal_debug_mem_malloc(size+1, "strdup");
|
||||
if (ptr)
|
||||
{
|
||||
memcpy(ptr, s, size);
|
||||
ptr[size] = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char* debug_mem_strndup(const char* s, size_t n)
|
||||
{
|
||||
size_t size = MIN(strlen(s), n);
|
||||
char* ptr = internal_debug_mem_malloc(size+1, "strndup");
|
||||
if (ptr)
|
||||
{
|
||||
memcpy(ptr, s, size);
|
||||
ptr[size] = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* debug_mem_malloc(size_t size)
|
||||
{
|
||||
void* ptr = internal_debug_mem_malloc(size, "malloc");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void debug_mem_free(void *ptr)
|
||||
{
|
||||
internal_debug_mem_free(ptr);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void* hub_malloc_zero(size_t size)
|
||||
{
|
||||
void* data = hub_malloc(size);
|
||||
if (data)
|
||||
{
|
||||
memset(data, 0, size);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FUNCTION_TRACE
|
||||
#define FTRACE_LOG "ftrace.log"
|
||||
static FILE* functrace = 0;
|
||||
|
||||
void main_constructor() __attribute__ ((no_instrument_function, constructor));
|
||||
void main_deconstructor() __attribute__ ((no_instrument_function, destructor));
|
||||
void __cyg_profile_func_enter(void* frame, void* callsite) __attribute__ ((no_instrument_function));
|
||||
void __cyg_profile_func_exit(void* frame, void* callsite) __attribute__ ((no_instrument_function));
|
||||
|
||||
|
||||
void main_constructor()
|
||||
{
|
||||
functrace = fopen(FTRACE_LOG, "w");
|
||||
if (functrace == NULL)
|
||||
{
|
||||
fprintf(stderr, "Cannot create function trace file: " FTRACE_LOG "\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main_deconstructor()
|
||||
{
|
||||
fclose(functrace);
|
||||
}
|
||||
|
||||
|
||||
void __cyg_profile_func_enter(void* frame, void* callsite)
|
||||
{
|
||||
if (functrace)
|
||||
fprintf(functrace, "E%p\n", frame);
|
||||
}
|
||||
|
||||
void __cyg_profile_func_exit(void* frame, void* callsite)
|
||||
{
|
||||
if (functrace)
|
||||
fprintf(functrace, "X%p\n", frame);
|
||||
}
|
||||
|
||||
#endif /* DEBUG_FUNCTION_TRACE */
|
||||
|
||||
|
45
src/memory.h
Normal file
45
src/memory.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_MEMORY_HANDLER_H
|
||||
#define HAVE_UHUB_MEMORY_HANDLER_H
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
|
||||
#define hub_malloc debug_mem_malloc
|
||||
#define hub_free debug_mem_free
|
||||
#define hub_strdup debug_mem_strdup
|
||||
#define hub_strndup debug_mem_strndup
|
||||
extern void* debug_mem_malloc(size_t size);
|
||||
extern void debug_mem_free(void* ptr);
|
||||
extern char* debug_mem_strdup(const char* s);
|
||||
extern char* debug_mem_strndup(const char* s, size_t n);
|
||||
|
||||
#else
|
||||
|
||||
#define hub_malloc malloc
|
||||
#define hub_free free
|
||||
#define hub_strdup strdup
|
||||
#define hub_strndup strndup
|
||||
|
||||
#endif
|
||||
|
||||
extern void* hub_malloc_zero(size_t size);
|
||||
|
||||
#endif /* HAVE_UHUB_MEMORY_HANDLER_H */
|
836
src/message.c
Normal file
836
src/message.c
Normal file
@ -0,0 +1,836 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ADC_MSG_ASSERT(X) \
|
||||
uhub_assert(X); \
|
||||
uhub_assert(X->cache); \
|
||||
uhub_assert(X->capacity); \
|
||||
uhub_assert(X->length); \
|
||||
uhub_assert(X->length <= X->capacity); \
|
||||
uhub_assert(X->length == strlen(X->cache)); \
|
||||
uhub_assert(X->references >= 0);
|
||||
#else
|
||||
#define ADC_MSG_ASSERT(X) do { } while(0)
|
||||
#endif
|
||||
|
||||
struct adc_message* adc_msg_incref(struct adc_message* msg)
|
||||
{
|
||||
#ifndef ADC_MESSAGE_INCREF
|
||||
msg->references++;
|
||||
return msg;
|
||||
#else
|
||||
struct adc_message* copy = adc_msg_copy(msg);
|
||||
return copy;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void adc_msg_set_length(struct adc_message* msg, size_t len)
|
||||
{
|
||||
msg->length = len;
|
||||
}
|
||||
|
||||
static int adc_msg_grow(struct adc_message* msg, size_t size)
|
||||
{
|
||||
char* buf;
|
||||
size_t newsize = 0;
|
||||
|
||||
if (msg->capacity > size)
|
||||
return 1;
|
||||
|
||||
/* Make sure we align our data */
|
||||
newsize = size;
|
||||
newsize += 2; /* termination */
|
||||
newsize += (newsize % sizeof(size_t)); /* alignment padding */
|
||||
|
||||
buf = hub_malloc_zero(newsize);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
if (msg->cache)
|
||||
{
|
||||
memcpy(buf, msg->cache, msg->length);
|
||||
hub_free(msg->cache);
|
||||
}
|
||||
|
||||
msg->cache = buf;
|
||||
msg->capacity = newsize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* NOTE: msg must be unterminated here */
|
||||
static int adc_msg_cache_append(struct adc_message* msg, const char* string, size_t len)
|
||||
{
|
||||
if (!adc_msg_grow(msg, msg->length + len))
|
||||
{
|
||||
/* FIXME: OOM! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&msg->cache[msg->length], string, len);
|
||||
adc_msg_set_length(msg, msg->length + len);
|
||||
|
||||
assert(msg->capacity > msg->length);
|
||||
msg->cache[msg->length] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns position of the first argument of the message.
|
||||
* Excludes mandatory arguments for the given type of message
|
||||
* like source and target.
|
||||
*/
|
||||
int adc_msg_get_arg_offset(struct adc_message* msg)
|
||||
{
|
||||
if (!msg || !msg->cache)
|
||||
return -1;
|
||||
|
||||
switch (msg->cache[0])
|
||||
{
|
||||
/* These *SHOULD* never be seen on a hub */
|
||||
case 'U':
|
||||
case 'C':
|
||||
return 4; /* Actually: 4 + strlen(cid). */
|
||||
|
||||
case 'I':
|
||||
case 'H':
|
||||
return 4;
|
||||
|
||||
case 'B':
|
||||
return 9;
|
||||
|
||||
case 'F':
|
||||
return (10 + (list_size(msg->feature_cast_include)*5) + (list_size(msg->feature_cast_exclude)*5));
|
||||
|
||||
case 'D':
|
||||
case 'E':
|
||||
return 14;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_is_empty(struct adc_message* msg)
|
||||
{
|
||||
int offset = adc_msg_get_arg_offset(msg);
|
||||
|
||||
if (offset == -1)
|
||||
return -1;
|
||||
|
||||
if ((msg->length - 1) == (size_t) offset)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void adc_msg_free(struct adc_message* msg)
|
||||
{
|
||||
if (!msg) return;
|
||||
|
||||
ADC_MSG_ASSERT(msg);
|
||||
|
||||
if (msg->references > 0)
|
||||
{
|
||||
msg->references--;
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_free(msg->cache);
|
||||
|
||||
if (msg->feature_cast_include)
|
||||
{
|
||||
list_clear(msg->feature_cast_include, &hub_free);
|
||||
list_destroy(msg->feature_cast_include);
|
||||
msg->feature_cast_include = 0;
|
||||
}
|
||||
|
||||
if (msg->feature_cast_exclude)
|
||||
{
|
||||
list_clear(msg->feature_cast_exclude, &hub_free);
|
||||
list_destroy(msg->feature_cast_exclude);
|
||||
msg->feature_cast_exclude = 0;
|
||||
}
|
||||
|
||||
hub_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_copy(const struct adc_message* cmd)
|
||||
{
|
||||
char* tmp = 0;
|
||||
struct adc_message* copy = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message));
|
||||
if (!copy) return NULL; /* OOM */
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
/* deep copy */
|
||||
copy->cmd = cmd->cmd;
|
||||
copy->source = cmd->source;
|
||||
copy->target = cmd->target;
|
||||
copy->cache = 0;
|
||||
copy->length = cmd->length;
|
||||
copy->capacity = 0;
|
||||
copy->priority = cmd->priority;
|
||||
copy->references = 0;
|
||||
copy->feature_cast_include = 0;
|
||||
copy->feature_cast_exclude = 0;
|
||||
|
||||
if (cmd->cache)
|
||||
{
|
||||
if (!adc_msg_grow(copy, copy->length))
|
||||
{
|
||||
adc_msg_free(copy);
|
||||
return NULL; /* OOM */
|
||||
}
|
||||
memcpy(copy->cache, cmd->cache, cmd->length);
|
||||
copy->cache[copy->length] = 0;
|
||||
}
|
||||
|
||||
if (cmd->feature_cast_include)
|
||||
{
|
||||
copy->feature_cast_include = list_create();
|
||||
tmp = list_get_first(cmd->feature_cast_include);
|
||||
while (tmp)
|
||||
{
|
||||
list_append(copy->feature_cast_include, hub_strdup(tmp));
|
||||
tmp = list_get_next(cmd->feature_cast_include);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->feature_cast_exclude)
|
||||
{
|
||||
copy->feature_cast_exclude = list_create();
|
||||
tmp = list_get_first(cmd->feature_cast_exclude);
|
||||
while (tmp)
|
||||
{
|
||||
list_append(copy->feature_cast_exclude, hub_strdup(tmp));
|
||||
tmp = list_get_next(cmd->feature_cast_exclude);
|
||||
}
|
||||
}
|
||||
|
||||
ADC_MSG_ASSERT(copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_t length)
|
||||
{
|
||||
struct adc_message* command = adc_msg_parse(line, length);
|
||||
|
||||
if (!command)
|
||||
return 0;
|
||||
|
||||
if (command->source && (!u || command->source != u->id.sid))
|
||||
{
|
||||
adc_msg_free(command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_parse(const char* line, size_t length)
|
||||
{
|
||||
struct adc_message* command = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message));
|
||||
char prefix = line[0];
|
||||
size_t n = 0;
|
||||
char temp_sid[5];
|
||||
int ok = 1;
|
||||
int need_terminate = 0;
|
||||
struct linked_list* feature_cast_list;
|
||||
|
||||
if (command == NULL)
|
||||
return NULL; /* OOM */
|
||||
|
||||
if (line[length-1] != '\n')
|
||||
{
|
||||
need_terminate = 1;
|
||||
}
|
||||
|
||||
if (!adc_msg_grow(command, length + need_terminate))
|
||||
{
|
||||
hub_free(command);
|
||||
return NULL; /* OOM */
|
||||
}
|
||||
|
||||
adc_msg_set_length(command, length + need_terminate);
|
||||
memcpy(command->cache, line, length);
|
||||
|
||||
/* Ensure we are zero terminated */
|
||||
command->cache[length] = 0;
|
||||
command->cache[length+need_terminate] = 0;
|
||||
|
||||
command->cmd = FOURCC(line[0], line[1], line[2], line[3]);
|
||||
command->priority = 0;
|
||||
|
||||
switch (prefix)
|
||||
{
|
||||
case 'U':
|
||||
case 'C':
|
||||
/* these should never be seen on a hub */
|
||||
ok = 0;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
case 'H':
|
||||
ok = (length > 3);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
ok = (length > 8 &&
|
||||
is_space(line[4]) &&
|
||||
is_valid_base32_char(line[5]) &&
|
||||
is_valid_base32_char(line[6]) &&
|
||||
is_valid_base32_char(line[7]) &&
|
||||
is_valid_base32_char(line[8]));
|
||||
|
||||
if (!ok) break;
|
||||
|
||||
temp_sid[0] = line[5];
|
||||
temp_sid[1] = line[6];
|
||||
temp_sid[2] = line[7];
|
||||
temp_sid[3] = line[8];
|
||||
temp_sid[4] = '\0';
|
||||
|
||||
command->source = string_to_sid(temp_sid);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
ok = (length > 8 &&
|
||||
is_space(line[4]) &&
|
||||
is_valid_base32_char(line[5]) &&
|
||||
is_valid_base32_char(line[6]) &&
|
||||
is_valid_base32_char(line[7]) &&
|
||||
is_valid_base32_char(line[8]));
|
||||
|
||||
if (!ok) break;
|
||||
|
||||
temp_sid[0] = line[5];
|
||||
temp_sid[1] = line[6];
|
||||
temp_sid[2] = line[7];
|
||||
temp_sid[3] = line[8];
|
||||
temp_sid[4] = '\0';
|
||||
|
||||
command->source = string_to_sid(temp_sid);
|
||||
|
||||
/* Create feature cast lists */
|
||||
command->feature_cast_include = list_create();
|
||||
command->feature_cast_exclude = list_create();
|
||||
|
||||
if (!command->feature_cast_include || !command->feature_cast_exclude)
|
||||
{
|
||||
list_destroy(command->feature_cast_include);
|
||||
list_destroy(command->feature_cast_exclude);
|
||||
hub_free(command->cache);
|
||||
hub_free(command);
|
||||
return NULL; /* OOM */
|
||||
}
|
||||
|
||||
n = 10;
|
||||
while (line[n] == '+' || line[n] == '-')
|
||||
{
|
||||
if (line[n++] == '+')
|
||||
feature_cast_list = command->feature_cast_include;
|
||||
else
|
||||
feature_cast_list = command->feature_cast_exclude;
|
||||
|
||||
temp_sid[0] = line[n++];
|
||||
temp_sid[1] = line[n++];
|
||||
temp_sid[2] = line[n++];
|
||||
temp_sid[3] = line[n++];
|
||||
temp_sid[4] = '\0';
|
||||
|
||||
list_append(feature_cast_list, hub_strdup(temp_sid));
|
||||
}
|
||||
|
||||
if (n == 10)
|
||||
ok = 0;
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
case 'E':
|
||||
ok = (length > 13 &&
|
||||
is_space(line[4]) &&
|
||||
is_valid_base32_char(line[5]) &&
|
||||
is_valid_base32_char(line[6]) &&
|
||||
is_valid_base32_char(line[7]) &&
|
||||
is_valid_base32_char(line[8]) &&
|
||||
is_space(line[9]) &&
|
||||
is_valid_base32_char(line[10]) &&
|
||||
is_valid_base32_char(line[11]) &&
|
||||
is_valid_base32_char(line[12]) &&
|
||||
is_valid_base32_char(line[13]));
|
||||
|
||||
if (!ok) break;
|
||||
|
||||
temp_sid[0] = line[5];
|
||||
temp_sid[1] = line[6];
|
||||
temp_sid[2] = line[7];
|
||||
temp_sid[3] = line[8];
|
||||
temp_sid[4] = '\0';
|
||||
|
||||
command->source = string_to_sid(temp_sid);
|
||||
|
||||
temp_sid[0] = line[10];
|
||||
temp_sid[1] = line[11];
|
||||
temp_sid[2] = line[12];
|
||||
temp_sid[3] = line[13];
|
||||
temp_sid[4] = '\0';
|
||||
|
||||
command->target = string_to_sid(temp_sid);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
if (need_terminate)
|
||||
{
|
||||
command->cache[length] = '\n';
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
adc_msg_free(command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* At this point the arg_offset should point to a space, or the end of message */
|
||||
n = adc_msg_get_arg_offset(command);
|
||||
if (command->cache[n] == ' ')
|
||||
{
|
||||
if (command->cache[n+1] == ' ') ok = 0;
|
||||
}
|
||||
else if (command->cache[n] == '\n') ok = 1;
|
||||
else ok = 0;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
adc_msg_free(command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADC_MSG_ASSERT(command);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_create(const char* line)
|
||||
{
|
||||
return adc_msg_parse_verify(NULL, line, strlen(line));
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size)
|
||||
{
|
||||
struct adc_message* msg = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message));
|
||||
|
||||
if (!msg)
|
||||
return NULL; /* OOM */
|
||||
|
||||
if (size < sizeof(fourcc)) size = sizeof(fourcc);
|
||||
|
||||
if (!adc_msg_grow(msg, size+1))
|
||||
{
|
||||
hub_free(msg);
|
||||
return NULL; /* OOM */
|
||||
}
|
||||
|
||||
if (fourcc)
|
||||
{
|
||||
msg->cache[0] = (char) ((fourcc >> 24) & 0xff);
|
||||
msg->cache[1] = (char) ((fourcc >> 16) & 0xff);
|
||||
msg->cache[2] = (char) ((fourcc >> 8) & 0xff);
|
||||
msg->cache[3] = (char) ((fourcc ) & 0xff);
|
||||
msg->cache[4] = '\n';
|
||||
|
||||
/* Ensure we are zero terminated */
|
||||
adc_msg_set_length(msg, 5);
|
||||
msg->cache[msg->length] = 0;
|
||||
}
|
||||
|
||||
msg->cmd = fourcc;
|
||||
msg->priority = 0;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_remove_named_argument(struct adc_message* cmd, const char prefix_[2])
|
||||
{
|
||||
char* start;
|
||||
char* end;
|
||||
char* endInfo;
|
||||
size_t endlen;
|
||||
char prefix[4] = { ' ', prefix_[0], prefix_[1], '\0' };
|
||||
int found = 0;
|
||||
int arg_offset = adc_msg_get_arg_offset(cmd);
|
||||
size_t temp_len = 0;
|
||||
|
||||
adc_msg_unterminate(cmd);
|
||||
|
||||
start = memmem(&cmd->cache[arg_offset], (cmd->length - arg_offset), prefix, 3);
|
||||
while (start)
|
||||
{
|
||||
endInfo = &cmd->cache[cmd->length];
|
||||
|
||||
if (&start[0] < &endInfo[0])
|
||||
{
|
||||
end = memchr(&start[1], ' ', &endInfo[0]-&start[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
end = NULL;
|
||||
}
|
||||
|
||||
if (end)
|
||||
{
|
||||
|
||||
temp_len = &end[0] - &start[0]; // strlen(start);
|
||||
/* hub_log(log_trace, " length=%d", (int) (temp_len)); */
|
||||
endlen = strlen(end);
|
||||
|
||||
memmove(start, end, endlen);
|
||||
start[endlen] = '\0';
|
||||
found++;
|
||||
adc_msg_set_length(cmd, cmd->length - temp_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
found++;
|
||||
adc_msg_set_length(cmd, cmd->length - strlen(start));
|
||||
start[0] = '\0';
|
||||
break;
|
||||
}
|
||||
start = memmem(&cmd->cache[arg_offset], (cmd->length - arg_offset), prefix, 3);
|
||||
}
|
||||
|
||||
adc_msg_terminate(cmd);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_has_named_argument(struct adc_message* cmd, const char prefix_[2])
|
||||
{
|
||||
int count = 0;
|
||||
char* start;
|
||||
char prefix[4] = { ' ', prefix_[0], prefix_[1], '\0' };
|
||||
int arg_offset = adc_msg_get_arg_offset(cmd);
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
start = memmem(&cmd->cache[arg_offset], (cmd->length - arg_offset), prefix, 3);
|
||||
while (start)
|
||||
{
|
||||
count++;
|
||||
if ((&start[0] - &cmd->cache[0]) < 1+cmd->length)
|
||||
start = memmem(&start[1], (&cmd->cache[cmd->length] - &start[0]), prefix, 3);
|
||||
else
|
||||
start = NULL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
char* adc_msg_get_named_argument(struct adc_message* cmd, const char prefix_[2])
|
||||
{
|
||||
char* start;
|
||||
char* end;
|
||||
char* argument;
|
||||
size_t length;
|
||||
char prefix[4] = { ' ', prefix_[0], prefix_[1], '\0' };
|
||||
int arg_offset = adc_msg_get_arg_offset(cmd);
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
start = memmem(&cmd->cache[arg_offset], cmd->length - arg_offset, prefix, 3);
|
||||
if (!start)
|
||||
return NULL;
|
||||
|
||||
start = &start[3];
|
||||
end = strchr(start, ' ');
|
||||
if (!end) end = &cmd->cache[cmd->length];
|
||||
length = &end[0] - &start[0];
|
||||
|
||||
argument = hub_strndup(start, length);
|
||||
|
||||
if (length > 0 && argument[length-1] == '\n')
|
||||
{
|
||||
argument[length-1] = 0;
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_replace_named_argument(struct adc_message* cmd, const char prefix[2], const char* string)
|
||||
{
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
while (adc_msg_has_named_argument(cmd, prefix))
|
||||
{
|
||||
adc_msg_remove_named_argument(cmd, prefix);
|
||||
}
|
||||
|
||||
if (adc_msg_add_named_argument(cmd, prefix, string) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void adc_msg_terminate(struct adc_message* cmd)
|
||||
{
|
||||
if (cmd->cache[cmd->length - 1] != '\n')
|
||||
{
|
||||
adc_msg_cache_append(cmd, "\n", 1);
|
||||
}
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
}
|
||||
|
||||
/* FIXME: this looks bogus */
|
||||
void adc_msg_unterminate(struct adc_message* cmd)
|
||||
{
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
if (cmd->length > 0 && cmd->cache[cmd->length-1] == '\n')
|
||||
{
|
||||
cmd->length--;
|
||||
cmd->cache[cmd->length] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int adc_msg_add_named_argument(struct adc_message* cmd, const char prefix[2], const char* string)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!string)
|
||||
return -1;
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
adc_msg_unterminate(cmd);
|
||||
adc_msg_cache_append(cmd, " ", 1);
|
||||
adc_msg_cache_append(cmd, prefix, 2);
|
||||
adc_msg_cache_append(cmd, string, strlen(string));
|
||||
adc_msg_terminate(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_add_argument(struct adc_message* cmd, const char* string)
|
||||
{
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
adc_msg_unterminate(cmd);
|
||||
adc_msg_cache_append(cmd, " ", 1);
|
||||
adc_msg_cache_append(cmd, string, strlen(string));
|
||||
adc_msg_terminate(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char* adc_msg_get_argument(struct adc_message* cmd, int offset)
|
||||
{
|
||||
char* start;
|
||||
char* end;
|
||||
char* argument;
|
||||
int count = 0;
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
adc_msg_unterminate(cmd);
|
||||
|
||||
start = strchr(&cmd->cache[adc_msg_get_arg_offset(cmd)-1], ' ');
|
||||
while (start)
|
||||
{
|
||||
end = strchr(&start[1], ' ');
|
||||
|
||||
if (count == offset)
|
||||
{
|
||||
if (end)
|
||||
{
|
||||
argument = hub_strndup(&start[1], (&end[0] - &start[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
argument = hub_strdup(&start[1]);
|
||||
if (argument[strlen(argument)-1] == '\n')
|
||||
argument[strlen(argument)-1] = 0;
|
||||
}
|
||||
|
||||
if (strlen(argument))
|
||||
{
|
||||
adc_msg_terminate(cmd);
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
start = end;
|
||||
}
|
||||
|
||||
adc_msg_terminate(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Untested code.
|
||||
*/
|
||||
int adc_msg_get_argument_index(struct adc_message* cmd, const char prefix[2])
|
||||
{
|
||||
char* start;
|
||||
char* end;
|
||||
int count = 0;
|
||||
|
||||
ADC_MSG_ASSERT(cmd);
|
||||
|
||||
adc_msg_unterminate(cmd);
|
||||
|
||||
start = strchr(&cmd->cache[adc_msg_get_arg_offset(cmd)-1], ' ');
|
||||
while (start)
|
||||
{
|
||||
end = strchr(&start[1], ' ');
|
||||
if (((&end[0] - &start[1]) > 2) && ((start[1] == prefix[0]) && (start[2] == prefix[1])))
|
||||
{
|
||||
adc_msg_terminate(cmd);
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
start = end;
|
||||
}
|
||||
adc_msg_terminate(cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int adc_msg_escape_length(const char* str)
|
||||
{
|
||||
int add = 0;
|
||||
int n = 0;
|
||||
for (; str[n]; n++)
|
||||
if (str[n] == ' ' || str[n] == '\n' || str[n] == '\\') add++;
|
||||
return n + add;
|
||||
}
|
||||
|
||||
|
||||
int adc_msg_unescape_length(const char* str)
|
||||
{
|
||||
int add = 0;
|
||||
int n = 0;
|
||||
int escape = 0;
|
||||
for (; str[n]; n++)
|
||||
{
|
||||
if (escape)
|
||||
{
|
||||
escape = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str[n] == '\\')
|
||||
{
|
||||
escape = 1;
|
||||
add++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n - add;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char* adc_msg_unescape(const char* string)
|
||||
{
|
||||
char* new_string = hub_malloc(adc_msg_unescape_length(string)+1);
|
||||
char* ptr = (char*) new_string;
|
||||
char* str = (char*) string;
|
||||
int escaped = 0;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
if (escaped) {
|
||||
if (*str == 's')
|
||||
*ptr++ = ' ';
|
||||
else if (*str == '\\')
|
||||
*ptr++ = '\\';
|
||||
else if (*str == 'n')
|
||||
*ptr++ = '\n';
|
||||
else
|
||||
*ptr++ = *str;
|
||||
|
||||
escaped = 0;
|
||||
} else {
|
||||
if (*str == '\\')
|
||||
escaped = 1;
|
||||
else
|
||||
*ptr++ = *str;
|
||||
|
||||
}
|
||||
str++;
|
||||
}
|
||||
*ptr = 0;
|
||||
return new_string;
|
||||
}
|
||||
|
||||
|
||||
char* adc_msg_escape(const char* string)
|
||||
{
|
||||
char* str = hub_malloc(adc_msg_escape_length(string)+1);
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
for (i = 0; i < strlen(string); i++)
|
||||
{
|
||||
switch (string[i]) {
|
||||
case '\\': /* fall through */
|
||||
str[n++] = '\\';
|
||||
str[n++] = '\\';
|
||||
break;
|
||||
case '\n':
|
||||
str[n++] = '\\';
|
||||
str[n++] = 'n';
|
||||
break;
|
||||
case ' ':
|
||||
str[n++] = '\\';
|
||||
str[n++] = 's';
|
||||
break;
|
||||
default:
|
||||
str[n++] = string[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
str[n] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
206
src/message.h
Normal file
206
src/message.h
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_COMMAND_H
|
||||
#define HAVE_UHUB_COMMAND_H
|
||||
|
||||
struct user;
|
||||
|
||||
struct adc_message
|
||||
{
|
||||
fourcc_t cmd;
|
||||
sid_t source;
|
||||
sid_t target;
|
||||
char* cache;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
size_t priority;
|
||||
size_t references;
|
||||
struct linked_list* feature_cast_include;
|
||||
struct linked_list* feature_cast_exclude;
|
||||
};
|
||||
|
||||
enum msg_status_level
|
||||
{
|
||||
status_level_info = 0, /* Success/informative status message */
|
||||
status_level_error = 1, /* Recoverable error */
|
||||
status_level_fatal = 2, /* Fatal error (disconnect) */
|
||||
};
|
||||
|
||||
/**
|
||||
* Increase the reference counter for an ADC message struct.
|
||||
* NOTE: Always use the returned value, and not the passed value, as
|
||||
* it ensures we can actually copy the value if needed.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_incref(struct adc_message* msg);
|
||||
|
||||
/**
|
||||
* Decrease the reference counter, and free the memory when apropriate.
|
||||
*/
|
||||
extern void adc_msg_free(struct adc_message* msg);
|
||||
|
||||
/**
|
||||
* Perform deep copy a command.
|
||||
* NOTE: 'references' will be zero for the copied command.
|
||||
* @return a copy of cmd or NULL if not able to allocate memory.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_copy(const struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* This will parse 'string' and return it as a adc_message struct, or
|
||||
* NULL if not able to allocate memory or 'string' does not contain
|
||||
* a valid ADC command.
|
||||
*
|
||||
* The message is only considered valid if the user who sent it
|
||||
* is the rightful origin of the message.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_parse_verify(struct user* u, const char* string, size_t length);
|
||||
|
||||
/**
|
||||
* This will parse 'string' and return it as a adc_message struct, or
|
||||
* NULL if not able to allocate memory or 'string' does not contain
|
||||
* a valid ADC command.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_parse(const char* string, size_t length);
|
||||
|
||||
/**
|
||||
* This will construct a adc_message based on 'string'.
|
||||
* Only to be used for server generated commands.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_create(const char* string);
|
||||
|
||||
/**
|
||||
* Construct a message with the given 'fourcc' and allocate
|
||||
* 'size' bytes for later use.
|
||||
*/
|
||||
extern struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size);
|
||||
|
||||
/**
|
||||
* Remove a named argument from the command.
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @return the number of named arguments removed.
|
||||
*/
|
||||
extern int adc_msg_remove_named_argument(struct adc_message* cmd, const char prefix[2]);
|
||||
|
||||
/**
|
||||
* Count the number of arguments matching the given 2 character prefix.
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @return the number of matching arguments
|
||||
*/
|
||||
extern int adc_msg_has_named_argument(struct adc_message* cmd, const char prefix[2]);
|
||||
|
||||
/**
|
||||
* Returns a named arguments based on the 2 character prefix.
|
||||
* If multiple matching arguments exists, only the first one will be returned
|
||||
* by this function.
|
||||
*
|
||||
* NOTE: Returned memory must be free'd with hub_free().
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @return the argument or NULL if OOM/not found.
|
||||
*/
|
||||
extern char* adc_msg_get_named_argument(struct adc_message* cmd, const char prefix[2]);
|
||||
|
||||
/**
|
||||
* Returns a offset of an argument based on the 2 character prefix.
|
||||
* If multiple matching arguments exists, only the first one will be returned
|
||||
* by this function.
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @return the offset or -1 if the argument is not found.
|
||||
*/
|
||||
extern int adc_msg_get_named_argument_index(struct adc_message* cmd, const char prefix[2]);
|
||||
|
||||
/**
|
||||
* @param cmd command to be checked
|
||||
* @return 1 if the command does not have any arguments (parameters), 0 otherwise, -1 if cmd is invalid.
|
||||
*/
|
||||
extern int adc_msg_is_empty(struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Returns the argument on the offset position in the command.
|
||||
* If offset is invalid NULL is returned.
|
||||
*
|
||||
* NOTE: Returned memory must be free'd with hub_free().
|
||||
*
|
||||
* @return the argument or NULL if OOM/not found.
|
||||
*/
|
||||
extern char* adc_msg_get_argument(struct adc_message* cmd, int offset);
|
||||
|
||||
/**
|
||||
* Replace a named argument in the command.
|
||||
* This will remove any matching arguments (multiple, or none),
|
||||
* then add 'string' as an argument using the given prefix.
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @arg string must be escaped (see adc_msg_escape).
|
||||
* @return 0 if successful, or -1 if an error occured.
|
||||
*/
|
||||
extern int adc_msg_replace_named_argument(struct adc_message* cmd, const char prefix[2], const char* string);
|
||||
|
||||
/**
|
||||
* Append an argument
|
||||
*
|
||||
* @arg string must be escaped (see adc_msg_escape).
|
||||
* @return 0 if successful, or -1 if an error occured (out of memory).
|
||||
*/
|
||||
extern int adc_msg_add_argument(struct adc_message* cmd, const char* string);
|
||||
|
||||
/**
|
||||
* Append a named argument
|
||||
*
|
||||
* @arg prefix a 2 character argument prefix
|
||||
* @arg string must be escaped (see adc_msg_escape).
|
||||
* @return 0 if successful, or -1 if an error occured (out of memory).
|
||||
*/
|
||||
extern int adc_msg_add_named_argument(struct adc_message* cmd, const char prefix[2], const char* string);
|
||||
|
||||
/**
|
||||
* Convert a ADC command escaped string to a regular string.
|
||||
* @return string or NULL if out of memory
|
||||
*/
|
||||
extern char* adc_msg_unescape(const char* string);
|
||||
|
||||
/**
|
||||
* Convert a string to a ADC command escaped string.
|
||||
* @return adc command escaped string or NULL if out of memory.
|
||||
*/
|
||||
extern char* adc_msg_escape(const char* string);
|
||||
|
||||
/**
|
||||
* This will ensure a newline is at the end of the command.
|
||||
*/
|
||||
void adc_msg_terminate(struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* This will remove any newline from the end of the command
|
||||
*/
|
||||
void adc_msg_unterminate(struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* @return the offset for the first command argument in msg->cache.
|
||||
* or -1 if the command is not understood.
|
||||
* NOTE: for 'U' and 'C' commands (normally not seen by hubs),
|
||||
* this returns 4. Should be 4 + lengthOf(cid).
|
||||
*/
|
||||
int adc_msg_get_arg_offset(struct adc_message* msg);
|
||||
|
||||
#endif /* HAVE_UHUB_COMMAND_H */
|
299
src/misc.c
Normal file
299
src/misc.c
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
int is_space(char c)
|
||||
{
|
||||
if (c == ' ') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_white_space(char c)
|
||||
{
|
||||
if (c == ' ' || c == '\t' || c == '\r') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char* strip_white_space(char* string)
|
||||
{
|
||||
char* pos;
|
||||
|
||||
while (string[0] && is_white_space(string[0])) string++;
|
||||
|
||||
if (!strlen(string))
|
||||
return string;
|
||||
|
||||
/* Strip appending whitespace */
|
||||
pos = &string[strlen(string)-1];
|
||||
while (&string[0] < &pos[0] && is_white_space(pos[0])) { pos[0] = 0; pos--; }
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
int is_valid_utf8(const char* string)
|
||||
{
|
||||
int expect = 0;
|
||||
char div = 0;
|
||||
int pos = 0;
|
||||
int length = strlen(string);
|
||||
|
||||
if (length == 0) return 1;
|
||||
|
||||
for (pos = 0; pos < strlen(string); pos++)
|
||||
{
|
||||
if (expect)
|
||||
{
|
||||
if ((string[pos] & 0xC0) == 0x80) expect--;
|
||||
else return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string[pos] & 0x80)
|
||||
{
|
||||
for (div = 0x40; div > 0x10; div /= 2)
|
||||
{
|
||||
if (string[pos] & div) expect++;
|
||||
else break;
|
||||
}
|
||||
if ((string[pos] & div) || (pos+expect >= strlen(string))) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int is_valid_base32_char(char c)
|
||||
{
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void base32_encode(const unsigned char* buffer, size_t len, char* result) {
|
||||
unsigned char word = 0;
|
||||
size_t n = 0;
|
||||
size_t i = 0;
|
||||
size_t index = 0;
|
||||
for (; i < len;) {
|
||||
if (index > 3) {
|
||||
word = (buffer[i] & (0xFF >> index));
|
||||
index = (index + 5) % 8;
|
||||
word <<= index;
|
||||
if (i < len - 1)
|
||||
word |= buffer[i + 1] >> (8 - index);
|
||||
i++;
|
||||
} else {
|
||||
word = (buffer[i] >> (8 - (index + 5))) & 0x1F;
|
||||
index = (index + 5) % 8;
|
||||
if (index == 0) i++;
|
||||
}
|
||||
result[n++] = BASE32_ALPHABET[word];
|
||||
}
|
||||
result[n] = '\0';
|
||||
}
|
||||
|
||||
void base32_decode(const char* src, unsigned char* dst, size_t len) {
|
||||
size_t index = 0;
|
||||
size_t offset = 0;
|
||||
size_t i = 0;
|
||||
memset(dst, 0, len);
|
||||
for (i = 0; src[i]; i++) {
|
||||
unsigned char n = 0;
|
||||
for (; n < 32; n++) if (src[i] == BASE32_ALPHABET[n]) break;
|
||||
if (n == 32) continue;
|
||||
if (index <= 3) {
|
||||
index = (index + 5) % 8;
|
||||
if (index == 0) {
|
||||
dst[offset++] |= n;
|
||||
if (offset == len) break;
|
||||
} else {
|
||||
dst[offset] |= n << (8 - index);
|
||||
}
|
||||
} else {
|
||||
index = (index + 5) % 8;
|
||||
dst[offset++] |= (n >> index);
|
||||
if (offset == len) break;
|
||||
dst[offset] |= n << (8 - index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int file_read_lines(const char* file, void* data, file_line_handler_t handler)
|
||||
{
|
||||
int fd;
|
||||
ssize_t ret;
|
||||
char buf[MAX_RECV_BUF];
|
||||
char *pos, *start;
|
||||
size_t line_count = 0;
|
||||
|
||||
memset(buf, 0, MAX_RECV_BUF);
|
||||
|
||||
hub_log(log_trace, "Opening file %s for line reading.", file);
|
||||
|
||||
fd = open(file, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
hub_log(log_error, "Unable to open file %s: %s", file, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = read(fd, buf, MAX_RECV_BUF);
|
||||
if (ret < 0)
|
||||
{
|
||||
hub_log(log_error, "Unable to read from file %s: %s", file, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
close(fd);
|
||||
hub_log(log_warning, "File is empty.");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
close(fd);
|
||||
|
||||
/* Parse configuaration */
|
||||
start = buf;
|
||||
while ((pos = strchr(start, '\n')))
|
||||
{
|
||||
pos[0] = '\0';
|
||||
if (strlen(start) > 0)
|
||||
{
|
||||
hub_log(log_dump, "Line: %s", start);
|
||||
if (handler(start, line_count+1, data) < 0)
|
||||
return -1;
|
||||
}
|
||||
start = &pos[1];
|
||||
line_count++;
|
||||
}
|
||||
|
||||
if (strlen(start) > 0)
|
||||
{
|
||||
buf[strlen(start)] = 0;
|
||||
hub_log(log_dump, "Line: %s", start);
|
||||
if (handler(start, line_count+1, data) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return line_count+1;
|
||||
}
|
||||
|
||||
|
||||
int uhub_atoi(const char* value) {
|
||||
int len = strlen(value);
|
||||
int offset = 0;
|
||||
int val = 0;
|
||||
int i = 0;
|
||||
for (; i < len; i++)
|
||||
if (value[i] > '9' || value[i] < '0')
|
||||
offset++;
|
||||
|
||||
for (i = offset; i< len; i++)
|
||||
val = val*10 + (value[i] - '0');
|
||||
|
||||
return value[0] == '-' ? -val : val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FIXME: -INTMIN is wrong!
|
||||
*/
|
||||
const char* uhub_itoa(int val)
|
||||
{
|
||||
size_t i;
|
||||
int value;
|
||||
static char buf[22];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (!val)
|
||||
{
|
||||
strcat(buf, "0");
|
||||
return buf;
|
||||
}
|
||||
i = sizeof(buf) - 1;
|
||||
for (value = abs(val); value && i > 0; value /= 10)
|
||||
buf[--i] = "0123456789"[value % 10];
|
||||
|
||||
if (val < 0 && i > 0)
|
||||
buf[--i] = '-';
|
||||
return buf+i;
|
||||
}
|
||||
|
||||
|
||||
const char* uhub_ulltoa(uint64_t val)
|
||||
{
|
||||
size_t i;
|
||||
static char buf[22] = { 0, };
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!val)
|
||||
{
|
||||
strcat(buf, "0");
|
||||
return buf;
|
||||
}
|
||||
i = sizeof(buf) - 1;
|
||||
for (; val && i > 0; val /= 10)
|
||||
buf[--i] = "0123456789"[val % 10];
|
||||
return buf+i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char* strndup(const char* string, size_t n)
|
||||
{
|
||||
size_t max = MIN(strlen(string), n);
|
||||
char* tmp = hub_malloc(max+1);
|
||||
memcpy(tmp, string, max);
|
||||
tmp[max] = 0;
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MEMMEM
|
||||
void* memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
|
||||
{
|
||||
char* c_buf = (char*) haystack;
|
||||
char* c_pat = (char*) needle;
|
||||
char* ptr = memchr(c_buf, c_pat[0], haystacklen);
|
||||
|
||||
while (ptr && (&ptr[0] - &c_buf[0] < haystacklen))
|
||||
{
|
||||
if (!memcmp(ptr, c_pat, needlelen))
|
||||
return ptr;
|
||||
ptr = memchr(&ptr[1], c_pat[0], &c_buf[haystacklen] - &ptr[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
58
src/misc.h
Normal file
58
src/misc.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_MISC_H
|
||||
#define HAVE_UHUB_MISC_H
|
||||
|
||||
typedef int (*file_line_handler_t)(char* line, int line_number, void* data);
|
||||
|
||||
extern int is_num(char c);
|
||||
extern int is_space(char c);
|
||||
extern int is_white_space(char c);
|
||||
extern int is_valid_utf8(const char* string);
|
||||
extern int is_valid_base32_char(char c);
|
||||
extern void base32_encode(const unsigned char* buffer, size_t len, char* result);
|
||||
extern void base32_decode(const char* src, unsigned char* dst, size_t len);
|
||||
extern char* strip_white_space(char* string);
|
||||
|
||||
extern int file_read_lines(const char* file, void* data, file_line_handler_t handler);
|
||||
|
||||
|
||||
extern const char* uhub_itoa(int val);
|
||||
extern const char* uhub_ulltoa(uint64_t val);
|
||||
|
||||
extern int uhub_atoi(const char* value);
|
||||
|
||||
#ifdef NEED_ATOLL
|
||||
extern int atoll(const char* value);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
extern char* strndup(const char* string, size_t n);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MEMMEM
|
||||
void* memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_MISC_H */
|
||||
|
||||
|
292
src/netevent.c
Normal file
292
src/netevent.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
void net_on_read(int fd, short ev, void *arg)
|
||||
{
|
||||
static char buf[MAX_RECV_BUF];
|
||||
struct user* user = (struct user*) arg;
|
||||
char* pos;
|
||||
char* start;
|
||||
ssize_t offset;
|
||||
ssize_t size;
|
||||
ssize_t buflen;
|
||||
int more = 1;
|
||||
int flag_close = 0;
|
||||
|
||||
hub_log(log_trace, "net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg);
|
||||
|
||||
if (ev == EV_TIMEOUT)
|
||||
{
|
||||
more = 0;
|
||||
if (user_is_connecting(user))
|
||||
{
|
||||
flag_close = quit_timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_send_ping(user);
|
||||
}
|
||||
}
|
||||
|
||||
while (more)
|
||||
{
|
||||
offset = 0;
|
||||
if (user->recv_buf)
|
||||
{
|
||||
memcpy(buf, user->recv_buf, user->recv_buf_offset);
|
||||
offset = user->recv_buf_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
size = net_recv(fd, &buf[offset], MAX_RECV_BUF - offset, 0);
|
||||
if (size == -1)
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
flag_close = quit_socket_error;
|
||||
break;
|
||||
}
|
||||
else if (size == 0)
|
||||
{
|
||||
flag_close = quit_disconnected;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
buflen = offset + size;
|
||||
start = buf;
|
||||
while ((pos = strchr(start, '\n')))
|
||||
{
|
||||
pos[0] = '\0';
|
||||
if (strlen(start) > 0 && strlen(start) < user->hub->config->max_recv_buffer)
|
||||
{
|
||||
if (hub_handle_message(user, start, &pos[0]-&start[0]) == -1)
|
||||
{
|
||||
flag_close = quit_protocol_error;
|
||||
more = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
start = &pos[1];
|
||||
}
|
||||
|
||||
if (!more) break;
|
||||
|
||||
if (&buf[offset + size] > &start[0])
|
||||
{
|
||||
if (!user->recv_buf)
|
||||
{
|
||||
user->recv_buf = hub_malloc(user->hub->config->max_recv_buffer);
|
||||
}
|
||||
|
||||
if (!user->recv_buf)
|
||||
{
|
||||
flag_close = quit_memory_error;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(user->recv_buf, start, &buf[offset + size] - &start[0]);
|
||||
user->recv_buf_offset = &buf[offset + size] - &start[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user->recv_buf)
|
||||
{
|
||||
hub_free(user->recv_buf);
|
||||
user->recv_buf = 0;
|
||||
user->recv_buf_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag_close)
|
||||
{
|
||||
user_disconnect(user, flag_close);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
if (user->ev_read)
|
||||
{
|
||||
struct timeval timeout = { TIMEOUT_IDLE, 0 };
|
||||
event_add(user->ev_read, &timeout);
|
||||
}
|
||||
}
|
||||
else if (user_is_connecting(user))
|
||||
{
|
||||
if (user->ev_read)
|
||||
{
|
||||
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
|
||||
event_add(user->ev_read, &timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void net_on_write(int fd, short ev, void *arg)
|
||||
{
|
||||
struct user* user = (struct user*) arg;
|
||||
struct adc_message* msg;
|
||||
int ret;
|
||||
int length;
|
||||
int close_flag = 0;
|
||||
|
||||
msg = list_get_first(user->send_queue);
|
||||
while (msg)
|
||||
{
|
||||
length = msg->length - user->send_queue_offset;
|
||||
ret = net_send(user->sd, &msg->cache[user->send_queue_offset], length, UHUB_SEND_SIGNAL);
|
||||
|
||||
if (ret == 0 || (ret == -1 && net_error() == EWOULDBLOCK))
|
||||
{
|
||||
close_flag = 0;
|
||||
break;
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
|
||||
user->tm_last_write = time(NULL);
|
||||
|
||||
if (ret == length)
|
||||
{
|
||||
user->send_queue_size -= ret;
|
||||
user->send_queue_offset = 0;
|
||||
list_remove(user->send_queue, msg);
|
||||
|
||||
if (user_flag_get(user, flag_user_list) && (msg == user->info || user->send_queue_size == 0))
|
||||
{
|
||||
user_flag_unset(user, flag_user_list);
|
||||
}
|
||||
|
||||
adc_msg_free(msg);
|
||||
msg = 0;
|
||||
|
||||
if (user->send_queue_size == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
user->send_queue_size -= ret;
|
||||
user->send_queue_offset -= ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
close_flag = quit_socket_error;
|
||||
break;
|
||||
}
|
||||
msg = list_get_first(user->send_queue);
|
||||
}
|
||||
|
||||
|
||||
if (close_flag)
|
||||
{
|
||||
user_disconnect(user, close_flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user->send_queue_size > 0 && user->ev_write)
|
||||
event_add(user->ev_write, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void net_on_accept(int server_fd, short ev, void *arg)
|
||||
{
|
||||
struct hub_info* hub = (struct hub_info*) arg;
|
||||
struct user* user = 0;
|
||||
int accept_more = 1;
|
||||
const char* addr;
|
||||
struct timeval timeout = { TIMEOUT_CONNECTED, 0 };
|
||||
|
||||
while (accept_more)
|
||||
{
|
||||
int fd = net_accept(server_fd);
|
||||
if (fd == -1)
|
||||
{
|
||||
if (net_error() == EWOULDBLOCK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_error, "Accept error: %d %s", net_error(), strerror(net_error()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addr = net_get_peer_address(fd);
|
||||
|
||||
/* FIXME: Should have a plugin log this */
|
||||
hub_log(log_trace, "Got connection from %s", addr);
|
||||
|
||||
/* FIXME: A plugin should perform this check: is IP banned? */
|
||||
if (acl_is_ip_banned(hub->acl, addr))
|
||||
{
|
||||
hub_log(log_info, "Denied [%s] (IP banned)", addr);
|
||||
net_close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
user = user_create(hub, fd);
|
||||
if (!user)
|
||||
{
|
||||
hub_log(log_error, "Unable to create user after socket accepted. Out of memory?");
|
||||
net_close(fd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Store IP address in user object */
|
||||
ip_convert_to_binary(addr, &user->ipaddr);
|
||||
|
||||
net_set_nonblocking(fd, 1);
|
||||
net_set_nosigpipe(fd, 1);
|
||||
|
||||
event_set(user->ev_read, fd, EV_READ | EV_PERSIST, net_on_read, user);
|
||||
event_set(user->ev_write, fd, EV_WRITE, net_on_write, user);
|
||||
event_add(user->ev_read, &timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
extern void net_on_packet(int fd, short ev, void *arg)
|
||||
{
|
||||
static char buffer[1024] = {0,};
|
||||
// struct hub_info* hub = (struct hub_info*) arg;
|
||||
// struct user* user = 0;
|
||||
ssize_t size;
|
||||
struct sockaddr_storage from;
|
||||
socklen_t fromlen;
|
||||
|
||||
size = recvfrom(fd, buffer, 1024, 0, (struct sockaddr*) &from, &fromlen);
|
||||
|
||||
// FIXME: A plugin should handle this!
|
||||
hub_log(log_info, "Datagram [%s] (%d bytes)", buffer, (int) size);
|
||||
}
|
||||
#endif
|
53
src/netevent.h
Normal file
53
src/netevent.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_NET_EVENT_H
|
||||
#define HAVE_UHUB_NET_EVENT_H
|
||||
|
||||
/**
|
||||
* Network callback for reading data from a socket.
|
||||
*/
|
||||
extern void net_on_read(int fd, short ev, void *arg);
|
||||
|
||||
/**
|
||||
* Network callback for writing data to a socket.
|
||||
*/
|
||||
extern void net_on_write(int fd, short ev, void *arg);
|
||||
|
||||
/**
|
||||
* Network callback for timers.
|
||||
*/
|
||||
extern void net_on_read_timeout(int fd, short ev, void* arg);
|
||||
|
||||
|
||||
/**
|
||||
* Network callback to accept incoming connections.
|
||||
*/
|
||||
extern void net_on_accept(int fd, short ev, void *arg);
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
/**
|
||||
* Network callback to receive incoming UDP datagram.
|
||||
*/
|
||||
extern void net_on_packet(int fd, short ev, void *arg);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_NET_EVENT_H */
|
||||
|
326
src/network-epoll.c
Normal file
326
src/network-epoll.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
|
||||
// #define DEBUG_EPOLL
|
||||
static struct epoll_event* events = 0;
|
||||
static int epfd = -1;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
static void dump_listeners()
|
||||
{
|
||||
int i;
|
||||
struct net_event_listener* listener;
|
||||
|
||||
|
||||
hub_log(log_dump, "listeners: number=%d", num_connections);
|
||||
|
||||
for (i = 0; i < num_connections; i++)
|
||||
{
|
||||
listener = &listeners[i];
|
||||
|
||||
if (listener)
|
||||
{
|
||||
if (listener->fd != -1)
|
||||
{
|
||||
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d fd=%d, ptr=%p", i, num_connections, listeners->fd, listeners);
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d (unused)", i, num_connections);
|
||||
}
|
||||
|
||||
listener = 0;
|
||||
}
|
||||
}
|
||||
|
||||
getc(stdin);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void set_poll_events(struct epoll_event* handle, short trigger)
|
||||
{
|
||||
memset(handle, 0, sizeof(struct epoll_event));
|
||||
|
||||
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
|
||||
handle->events |= EPOLLIN;
|
||||
|
||||
if (trigger & evt_write)
|
||||
handle->events |= EPOLLOUT;
|
||||
|
||||
if (trigger & evt_urgent)
|
||||
handle->events |= EPOLLPRI;
|
||||
|
||||
#ifdef EPOLLRDHUP
|
||||
if (triggers & evt_close)
|
||||
handle->events |= EPOLLRDHUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static short get_poll_events(struct epoll_event* handle)
|
||||
{
|
||||
short trig = handle->events;
|
||||
short evt = 0;
|
||||
|
||||
if (trig & EPOLLIN)
|
||||
evt |= evt_read;
|
||||
|
||||
if (trig & EPOLLPRI)
|
||||
evt |= evt_urgent;
|
||||
|
||||
if (trig & EPOLLOUT)
|
||||
evt |= evt_write;
|
||||
|
||||
if (trig & EPOLLHUP)
|
||||
evt |= evt_close;
|
||||
|
||||
if (trig & EPOLLERR)
|
||||
evt |= evt_error;
|
||||
|
||||
#ifdef EPOLLRDHUP
|
||||
if (trig & EPOLLRDHUP)
|
||||
evt |= evt_close;
|
||||
#endif
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
|
||||
int net_initialize(int capacity)
|
||||
{
|
||||
int i;
|
||||
max_connections = capacity;
|
||||
num_connections = 0;
|
||||
epfd = epoll_create(max_connections);
|
||||
if (epfd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): epoll_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
events = hub_malloc_zero(sizeof(struct epoll_event) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
monitor_allocate((size_t) capacity);
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
net_stats_initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_shutdown()
|
||||
{
|
||||
hub_log(log_trace, "Shutting down network monitor");
|
||||
if (epfd != -1)
|
||||
{
|
||||
close(epfd);
|
||||
}
|
||||
|
||||
hub_free(events);
|
||||
hub_free(listeners);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
uint64_t get_time_difference_in_msec(struct timeval before, struct timeval after)
|
||||
{
|
||||
uint64_t seconds = (after.tv_sec - before.tv_sec);
|
||||
uint64_t out = seconds*1000;
|
||||
if (seconds > 0)
|
||||
out += ((after.tv_usec / 1000) + (1000 - (before.tv_usec / 1000)));
|
||||
else
|
||||
out += ((after.tv_usec - before.tv_usec) / 1000);
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
int net_wait(int timeout_ms)
|
||||
{
|
||||
int fired, n, max, ret;
|
||||
struct net_event_listener* listener;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
struct timeval tm_before;
|
||||
struct timeval tm_after;
|
||||
gettimeofday(&tm_before, NULL);
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
fired = epoll_wait(epfd, events, num_connections, timeout_ms);
|
||||
if (fired == -1) {
|
||||
if (errno != EINTR)
|
||||
{
|
||||
hub_log(log_error, "net_wait(): epoll_wait failed");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < fired; n++)
|
||||
{
|
||||
listener = (struct net_event_listener*) events[n].data.ptr;
|
||||
listener->revents = get_poll_events(&events[n]);
|
||||
hub_log(log_dump, "net_wait(): epoll event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
|
||||
max = num_connections;
|
||||
|
||||
for (n = 0; n < max; n++)
|
||||
{
|
||||
listener = &listeners[n];
|
||||
if (listener && listener->fd != -1 && listener->revents)
|
||||
{
|
||||
hub_log(log_dump, "net_wait(): epoll trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
ret = listener->handler(listener);
|
||||
listener->revents = 0;
|
||||
}
|
||||
#ifdef DEBUG_EPOLL
|
||||
else
|
||||
{
|
||||
if (listener)
|
||||
hub_log(log_dump, "net_wait(): epoll trigger ignore (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
gettimeofday(&tm_after, NULL);
|
||||
size_t diff = (size_t) get_time_difference_in_msec(tm_before, tm_after);
|
||||
dump_listeners();
|
||||
hub_log(log_debug, "net_wait(): time=%dms, triggered=%d", diff, fired);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_add(int fd, short events, void* data, net_event_handler_t handler)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_free_listener();
|
||||
|
||||
hub_log(log_trace, "net_add(): adding socket (fd=%d, pos=%d)", fd, pos);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_add(): unable to poll more sockets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_set(listener, fd, events, data, handler);
|
||||
|
||||
set_poll_events(&ev, events);
|
||||
ev.data.ptr = listener;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_add(): epoll_ctl error while adding socket (fd=%d)", fd);
|
||||
net_event_listener_clear(listener);
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_connections++;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_modify(int fd, short events)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
hub_log(log_trace, "net_modify(): modifying socket events (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_modify(): unable to find socket.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener->events = events;
|
||||
set_poll_events(&ev, events);
|
||||
ev.data.ptr = listener;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_add(): epoll_ctl error while modifying socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_remove(int fd)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_remove(): removing socket (fd=%d, pos=%d)", fd, pos);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_clear(listener);
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_remove(): epoll_ctl error while removing socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
num_connections--;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
|
||||
|
290
src/network-kqueue.c
Normal file
290
src/network-kqueue.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#ifdef HAVE_KQUEUE
|
||||
|
||||
static struct kevent* events = 0;
|
||||
static struct kevent* change = 0;
|
||||
static int kfd = -1;
|
||||
|
||||
|
||||
static void set_poll_events(struct kevent* handle, short trigger)
|
||||
{
|
||||
if (!handle) {
|
||||
hub_log(log_error, "OOOPS!!");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(handle, 0, sizeof(struct kevent));
|
||||
|
||||
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
|
||||
handle->filter |= EVFILT_READ;
|
||||
|
||||
if (trigger & evt_write /* || trigger & evt_accept*/)
|
||||
handle->filter |= EVFILT_WRITE;
|
||||
}
|
||||
|
||||
static short get_poll_events(struct kevent* handle)
|
||||
{
|
||||
short trig = handle->flags;
|
||||
short evt = 0;
|
||||
|
||||
if (trig & EVFILT_READ)
|
||||
evt |= evt_read;
|
||||
|
||||
if (trig & EVFILT_WRITE)
|
||||
evt |= evt_write;
|
||||
|
||||
if (trig & EV_EOF)
|
||||
{
|
||||
evt |= evt_close;
|
||||
|
||||
if (handle->fflags)
|
||||
evt |= evt_error;
|
||||
}
|
||||
|
||||
if (handle->filter == -1)
|
||||
{
|
||||
|
||||
evt |= evt_error;
|
||||
}
|
||||
|
||||
if (handle->data)
|
||||
{
|
||||
evt |= evt_accept;
|
||||
}
|
||||
|
||||
if (evt)
|
||||
{
|
||||
hub_log(log_error, "Evt: fd=%d, filter=%d, flags=%d, fflags=%d, data=%d evt=%#x", handle->ident, handle->filter, handle->flags, handle->fflags, (int) handle->data, evt);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
int net_initialize(int capacity)
|
||||
{
|
||||
int i;
|
||||
max_connections = capacity;
|
||||
num_connections = 0;
|
||||
kfd = kqueue();
|
||||
if (kfd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): kqueue failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
events = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
change = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
hub_free(events);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
listeners = (void*) hub_malloc_zero(sizeof(struct net_event_listener) * max_connections);
|
||||
if (!listeners)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
hub_free(change);
|
||||
hub_free(events);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_connections; i++)
|
||||
{
|
||||
listeners[i].fd = -1;
|
||||
}
|
||||
|
||||
net_stats_initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_shutdown()
|
||||
{
|
||||
if (kfd != -1) {
|
||||
return close(kfd);
|
||||
}
|
||||
|
||||
hub_free(events);
|
||||
hub_free(change);
|
||||
hub_free(listeners);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_wait(int timeout_ms)
|
||||
{
|
||||
int fired, n, max, ret;
|
||||
struct net_event_listener* listener;
|
||||
struct timespec timeout = { (timeout_ms / 1000), (timeout_ms % 1000) * 1000 };
|
||||
|
||||
fired = kevent(kfd, events, num_connections, change, num_connections, &timeout);
|
||||
if (fired == -1) {
|
||||
if (errno != EINTR)
|
||||
{
|
||||
hub_log(log_error, "net_wait(): kevent failed");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < fired; n++)
|
||||
{
|
||||
listener = (struct net_event_listener*) events[n].udata;
|
||||
if (listener)
|
||||
{
|
||||
listener->revents = get_poll_events(&events[n]);
|
||||
hub_log(log_dump, "net_wait(): kqueue event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
}
|
||||
|
||||
max = num_connections;
|
||||
for (n = 0; n < max; n++)
|
||||
{
|
||||
listener = &listeners[n];
|
||||
if (listener && listener->fd != -1 && listener->revents != 0)
|
||||
{
|
||||
hub_log(log_dump, "net_wait(): kqueue trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
ret = listener->handler(listener);
|
||||
listener->revents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_add(int fd, short events_, void* data, net_event_handler_t handler)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_add(): adding socket (fd=%d)", fd);
|
||||
|
||||
if (listener)
|
||||
{
|
||||
/* Already added! */
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener = monitor_get_free_listener();
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_add(): unable to poll more sockets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_set(listener, fd, events_, data, handler);
|
||||
|
||||
event = &events[pos];
|
||||
set_poll_events(event, events_);
|
||||
event->ident = fd;
|
||||
|
||||
event->flags |= EV_ADD;
|
||||
event->flags |= EV_ONESHOT;
|
||||
|
||||
#ifdef __APPLE__
|
||||
event->flags |= EV_ENABLE;
|
||||
#endif
|
||||
event->udata = listener;
|
||||
|
||||
num_connections++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_modify(int fd, short events_)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_modify(): modifying socket (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_modify(): unable to find socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event = &events[pos];
|
||||
// set_poll_events(event, events_);
|
||||
|
||||
event->ident = fd;
|
||||
event->flags |= EV_ADD;
|
||||
event->flags |= EV_ONESHOT;
|
||||
#ifdef __APPLE__
|
||||
event->flags |= EV_ENABLE;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_remove(int fd)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_remove(): removing socket (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_clear(listener);
|
||||
|
||||
event = &events[pos];
|
||||
event->ident = fd;
|
||||
event->filter = 0;
|
||||
event->flags = EV_DELETE;
|
||||
|
||||
#ifdef __APPLE__
|
||||
event->flasg |= EV_DISABLE;
|
||||
#endif
|
||||
|
||||
event->fflags = 0;
|
||||
event->data = 0;
|
||||
event->udata = 0;
|
||||
|
||||
num_connections--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_KQUEUE */
|
||||
|
||||
|
||||
|
656
src/network.c
Normal file
656
src/network.c
Normal file
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
static int is_ipv6_supported = -1; /* -1 = CHECK, 0 = NO, 1 = YES */
|
||||
static int net_initialized = 0;
|
||||
static struct net_statistics stats;
|
||||
static struct net_statistics stats_total;
|
||||
static struct event_base* evbase;
|
||||
|
||||
#if defined(IPV6_BINDV6ONLY)
|
||||
#define SOCK_DUAL_STACK_OPT IPV6_BINDV6ONLY
|
||||
#elif defined(IPV6_V6ONLY)
|
||||
#define SOCK_DUAL_STACK_OPT IPV6_V6ONLY
|
||||
#endif
|
||||
|
||||
|
||||
int net_initialize()
|
||||
{
|
||||
if (!net_initialized)
|
||||
{
|
||||
|
||||
#ifdef WINSOCK
|
||||
struct WSAData wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
|
||||
{
|
||||
hub_log(log_error, "Unable to initialize winsock.");
|
||||
return -1;
|
||||
}
|
||||
#endif /* WINSOCK */
|
||||
|
||||
hub_log(log_trace, "Initializing network monitor.");
|
||||
net_stats_initialize();
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
/* FIXME: Initialize OpenSSL here. */
|
||||
#endif /* SSL_SUPPORT */
|
||||
|
||||
#ifdef OLD_LIBEVENT
|
||||
event_init();
|
||||
#else
|
||||
evbase = event_init();
|
||||
if (!evbase)
|
||||
{
|
||||
hub_log(log_error, "Unable to initialize libevent.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
net_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int net_shutdown()
|
||||
{
|
||||
if (net_initialized)
|
||||
{
|
||||
hub_log(log_trace, "Shutting down network monitor");
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
/* FIXME: Shutdown OpenSSL here. */
|
||||
#endif
|
||||
|
||||
#ifndef OLD_LIBEVENT
|
||||
event_base_free(evbase);
|
||||
#endif
|
||||
evbase = 0;
|
||||
|
||||
#ifdef WINSOCK
|
||||
WSACleanup();
|
||||
#endif
|
||||
net_initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int net_error()
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char* net_error_string(int code)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
static char string[32];
|
||||
snprintf(string, 32, "error code: %d", code);
|
||||
return string;
|
||||
#else
|
||||
return strerror(code);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int net_setsockopt(int fd, int level, int opt, const void* optval, socklen_t optlen)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return setsockopt(fd, level, opt, (const char*) optval, optlen);
|
||||
#else
|
||||
return setsockopt(fd, level, opt, optval, optlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int net_set_nonblocking(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_nonblocking(): fd=%d", fd);
|
||||
#endif
|
||||
|
||||
#ifdef WINSOCK
|
||||
u_long on = toggle ? 1 : 0;
|
||||
ret = ioctlsocket(fd, FIONBIO, &on);
|
||||
#else
|
||||
ret = ioctl(fd, FIONBIO, &toggle);
|
||||
#endif
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_nonblocking(): ioctl failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* NOTE: Possibly only supported on BSD and OSX? */
|
||||
int net_set_nosigpipe(int fd, int toggle)
|
||||
{
|
||||
#ifdef SO_NOSIGPIPE
|
||||
int ret;
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_nosigpipe(): fd=%d", fd);
|
||||
#endif
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_set_close_on_exec(int fd, int toggle)
|
||||
{
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_close_on_exec(): fd=%d", fd);
|
||||
#endif
|
||||
#ifdef WINSOCK
|
||||
return -1; /* FIXME: How is this done on Windows? */
|
||||
#else
|
||||
return fcntl(fd, F_SETFD, toggle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int net_set_linger(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_linger(): fd=%d", fd);
|
||||
#endif
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_LINGER, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_set_keepalive(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_keepalive(): fd=%d", fd);
|
||||
#endif
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_keepalive(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_set_reuseaddress(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_reuseaddress(): fd=%d", fd);
|
||||
#endif
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_reuseaddress(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_close(int fd)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
int ret = closesocket(fd);
|
||||
#else
|
||||
int ret = close(fd);
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
net_stats_add_close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fd != -1)
|
||||
{
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_accept(int fd)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_size;
|
||||
int ret = 0;
|
||||
addr_size = sizeof(struct sockaddr_storage);
|
||||
memset(&addr, 0, addr_size);
|
||||
ret = accept(fd, (struct sockaddr*) &addr, &addr_size);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
switch (net_error())
|
||||
{
|
||||
#if defined(__linux__)
|
||||
case ENETDOWN:
|
||||
case EPROTO:
|
||||
case ENOPROTOOPT:
|
||||
case EHOSTDOWN:
|
||||
case ENONET:
|
||||
case EHOSTUNREACH:
|
||||
case EOPNOTSUPP:
|
||||
errno = EWOULDBLOCK;
|
||||
#endif
|
||||
case EWOULDBLOCK:
|
||||
break;
|
||||
default:
|
||||
hub_log(log_error, "net_accept(): accept failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
net_stats_add_accept();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
|
||||
{
|
||||
int ret = connect(fd, serv_addr, addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (net_error() != EINPROGRESS)
|
||||
{
|
||||
hub_log(log_error, "net_connect(): connect failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int net_is_ipv6_supported()
|
||||
{
|
||||
if (is_ipv6_supported == -1)
|
||||
{
|
||||
int ret = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (ret == -1)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
if (net_error() == WSAEAFNOSUPPORT)
|
||||
#else
|
||||
if (net_error() == EAFNOSUPPORT)
|
||||
#endif
|
||||
{
|
||||
hub_log(log_trace, "net_is_ipv6_supported(): IPv6 is not supported on this system.");
|
||||
is_ipv6_supported = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub_log(log_error, "net_is_ipv6_supported(): Unknown error (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SOCK_DUAL_STACK_OPT
|
||||
int off = 0;
|
||||
if (net_setsockopt(ret, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
|
||||
is_ipv6_supported = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_ipv6_supported = 1;
|
||||
}
|
||||
#else
|
||||
is_ipv6_supported = 0;
|
||||
#endif
|
||||
net_close(ret);
|
||||
}
|
||||
}
|
||||
return is_ipv6_supported;
|
||||
}
|
||||
|
||||
|
||||
int net_socket_create(int af, int type, int protocol)
|
||||
{
|
||||
int sd = socket(af, type, protocol);
|
||||
if (sd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): socket failed (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
|
||||
}
|
||||
|
||||
#ifdef SOCK_DUAL_STACK_OPT
|
||||
/* BSD style */
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
int off = 0;
|
||||
if (net_setsockopt(sd, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
const char* net_address_to_string(int af, const void* src, char* dst, socklen_t cnt)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
struct sockaddr_in sin4;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct in_addr* addr4 = (struct in_addr*) src;
|
||||
struct in6_addr* addr6 = (struct in6_addr*) src;
|
||||
size_t size;
|
||||
LPSOCKADDR addr;
|
||||
DWORD len = cnt;
|
||||
|
||||
switch (af)
|
||||
{
|
||||
case AF_INET:
|
||||
sin4.sin_family = AF_INET;
|
||||
sin4.sin_port = 0;
|
||||
sin4.sin_addr = *addr4;
|
||||
size = sizeof(sin4);
|
||||
addr = (LPSOCKADDR) &sin4;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = 0;
|
||||
sin6.sin6_addr = *addr6;
|
||||
size = sizeof(sin6);
|
||||
addr = (LPSOCKADDR) &sin6;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WSAAddressToString(addr, size, NULL, dst, &len) == 0)
|
||||
{
|
||||
return dst;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_string_to_address(int af, const char* src, void* dst)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
int ret, size;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr* addr = 0;
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
if (net_is_ipv6_supported() != 1) return -1;
|
||||
size = sizeof(struct sockaddr_in6);
|
||||
addr = (struct sockaddr*) &addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = sizeof(struct sockaddr_in);
|
||||
addr = (struct sockaddr*) &addr4;
|
||||
}
|
||||
|
||||
if (!net_initialized)
|
||||
net_initialize();
|
||||
|
||||
ret = WSAStringToAddressA((char*) src, af, NULL, addr, &size);
|
||||
if (ret == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
memcpy(dst, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, &addr4.sin_addr, sizeof(addr4.sin_addr));
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return inet_pton(af, src, dst);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const char* net_get_peer_address(int fd)
|
||||
{
|
||||
static char address[INET6_ADDRSTRLEN+1];
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr_in6* name6;
|
||||
struct sockaddr_in* name4;
|
||||
struct sockaddr* name;
|
||||
|
||||
memset(address, 0, INET6_ADDRSTRLEN);
|
||||
socklen_t namelen = sizeof(struct sockaddr_storage);
|
||||
memset(&storage, 0, namelen);
|
||||
|
||||
name6 = (struct sockaddr_in6*) &storage;
|
||||
name4 = (struct sockaddr_in*) &storage;
|
||||
name = (struct sockaddr*) &storage;
|
||||
|
||||
|
||||
int af = net_is_ipv6_supported() ? AF_INET6 : AF_INET;
|
||||
|
||||
if (getpeername(fd, (struct sockaddr*) name, &namelen) != -1)
|
||||
{
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
|
||||
if (strncmp(address, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
|
||||
{
|
||||
return &address[7];
|
||||
}
|
||||
hub_log(log_trace, "net_get_peer_address(): address=%s", address);
|
||||
return address;
|
||||
}
|
||||
else
|
||||
{
|
||||
net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
|
||||
hub_log(log_trace, "net_get_peer_address(): address=%s", address);
|
||||
return address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_error, "net_get_peer_address(): getsockname failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
}
|
||||
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
|
||||
ssize_t net_recv(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
ssize_t ret = recv(fd, buf, len, flags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
net_stats_add_rx(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
hub_log(log_debug, "net_recv(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t net_send(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
ssize_t ret = send(fd, buf, len, flags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
net_stats_add_tx(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
hub_log(log_debug, "net_send(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
|
||||
{
|
||||
int ret = bind(fd, my_addr, addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_bind(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_listen(int fd, int backlog)
|
||||
{
|
||||
int ret = listen(fd, backlog);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_listen(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_initialize()
|
||||
{
|
||||
memset(&stats_total, 0, sizeof(struct net_statistics));
|
||||
stats_total.timestamp = time(NULL);
|
||||
|
||||
memset(&stats, 0, sizeof(struct net_statistics));
|
||||
stats.timestamp = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total)
|
||||
{
|
||||
*intermediate = &stats;
|
||||
*total = &stats_total;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_report()
|
||||
{
|
||||
int factor = (time(NULL) - stats.timestamp);
|
||||
if (!factor) factor++;
|
||||
|
||||
hub_log(log_info, "Statistics NET: tx=%d KB/s, rx=%d KB/s, (acc=%d/cls=%d/err=%d)",
|
||||
(int) ((stats.tx / factor) / 1024),
|
||||
(int) ((stats.rx / factor) / 1024),
|
||||
(int) stats.accept,
|
||||
(int) stats.closed,
|
||||
(int) stats.errors);
|
||||
}
|
||||
|
||||
void net_stats_reset()
|
||||
{
|
||||
stats_total.tx += stats.tx;
|
||||
stats_total.rx += stats.rx;
|
||||
stats_total.accept += stats.accept;
|
||||
stats_total.errors += stats.errors;
|
||||
stats_total.closed += stats.closed;
|
||||
|
||||
memset(&stats, 0, sizeof(struct net_statistics));
|
||||
stats.timestamp = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
int net_stats_timeout()
|
||||
{
|
||||
/* FIXME: Configurable time for dumping network statistics */
|
||||
return (time(NULL) - stats.timestamp > 60) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_add_tx(size_t bytes)
|
||||
{
|
||||
stats.tx += bytes;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_add_rx(size_t bytes)
|
||||
{
|
||||
stats.rx += bytes;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_add_accept()
|
||||
{
|
||||
stats.accept++;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_add_error()
|
||||
{
|
||||
stats.errors++;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_add_close()
|
||||
{
|
||||
stats.closed++;
|
||||
}
|
||||
|
||||
|
256
src/network.h
Normal file
256
src/network.h
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_NETWORK_H
|
||||
#define HAVE_UHUB_NETWORK_H
|
||||
|
||||
struct net_statistics
|
||||
{
|
||||
time_t timestamp;
|
||||
size_t tx;
|
||||
size_t rx;
|
||||
size_t accept;
|
||||
size_t closed;
|
||||
size_t errors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the socket monitor subsystem.
|
||||
* On some operating systems this will also involve loading the TCP/IP stack
|
||||
* (needed on Windows at least).
|
||||
*
|
||||
* @param max_connections The maximum number of sockets the monitor can handle.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_initialize();
|
||||
|
||||
/**
|
||||
* Shutdown the socket monitor.
|
||||
* On some operating systems this will also ensure the TCP/IP stack
|
||||
* is loaded.
|
||||
*
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_shutdown();
|
||||
|
||||
/**
|
||||
* @return the number of sockets currrently being monitored.
|
||||
*/
|
||||
extern int net_monitor_count();
|
||||
|
||||
/**
|
||||
* @return the monitor's socket capacity.
|
||||
*/
|
||||
extern int net_monitor_capacity();
|
||||
|
||||
/**
|
||||
* @return the last error code occured.
|
||||
*
|
||||
* NOTE: On Windows this is the last error code from the socket library, but
|
||||
* on UNIX this is the errno variable that can be overwritten by any
|
||||
* libc function.
|
||||
* For this reason, only rely on net_error() immediately after a
|
||||
* socket function call.
|
||||
*/
|
||||
extern int net_error();
|
||||
extern const char* net_error_string(int code);
|
||||
|
||||
/**
|
||||
* A wrapper for the socket() function call.
|
||||
*/
|
||||
extern int net_socket_create(int af, int type, int protocol);
|
||||
|
||||
/**
|
||||
* A wrapper for the close() function call.
|
||||
*/
|
||||
extern int net_close(int fd);
|
||||
|
||||
/**
|
||||
* A wrapper for the accept() function call.
|
||||
*/
|
||||
extern int net_accept(int fd);
|
||||
|
||||
/**
|
||||
* A wrapper for the connect() call.
|
||||
*/
|
||||
extern int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* A wrapper for the bind() function call.
|
||||
*/
|
||||
extern int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* A wrapper for the listen() function call.
|
||||
*/
|
||||
extern int net_listen(int sockfd, int backlog);
|
||||
|
||||
/**
|
||||
* This will set the socket to blocking or nonblocking mode.
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero nonblocking mode, otherwise blocking mode is assumed
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_nonblocking(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will prevent the socket to generate a SIGPIPE in case the socket goes down.
|
||||
* NOTE: Not all operating systems support this feature. In that case this will return success value.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero ignore sigpipe, otherwise disable it.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_nosigpipe(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will set the close-on-exec flag. This means if any subprocess is
|
||||
* started any open file descriptors or sockets will not be inherited if this
|
||||
* is turned on. Otherwise, subprocesses invoked via exec() can read/write
|
||||
* to these sockets.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero close-on-exec is enabled, otherwise disabled.
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_close_on_exec(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* Enable/disable linger on close if data is present.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle enable if non-zero
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_linger(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will set or unset the SO_REUSEADDR flag.
|
||||
* @param fd socket descriptor
|
||||
* @param toggle Set SO_REUSEADDR if non-zero, otherwise unset it.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_reuseaddress(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* A wrapper for the recv() function call.
|
||||
*/
|
||||
extern ssize_t net_recv(int fd, void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* A wrapper for the send() function call.
|
||||
*/
|
||||
extern ssize_t net_send(int fd, void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* This tries to create a AF_INET6 socket.
|
||||
* If it succeeds it concludes IPv6 is supported on the host operating
|
||||
* system. If the call fails with EAFNOSUPPORT the host system
|
||||
* does not support IPv6.
|
||||
* The result is cached so further calls to this function are cheap.
|
||||
*/
|
||||
extern int net_is_ipv6_supported();
|
||||
|
||||
/**
|
||||
* This will return a string containing the peer IP-address of
|
||||
* the connected peer associated with the given socket.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @return IP address (IPv6 or IPv4), or "0.0.0.0" if unable to determine the address.
|
||||
*/
|
||||
extern const char* net_get_peer_address(int fd);
|
||||
|
||||
/**
|
||||
* See man(3) inet_ntop.
|
||||
*/
|
||||
extern const char* net_address_to_string(int af, const void *src, char *dst, socklen_t cnt);
|
||||
|
||||
/**
|
||||
* See man(3) inet_pton.
|
||||
*/
|
||||
extern int net_string_to_address(int af, const char *src, void *dst);
|
||||
|
||||
|
||||
/**
|
||||
* Network statistics monitor.
|
||||
*
|
||||
* Keeps track of bandwidth usage, sockets accepted, closed,
|
||||
* errors etc.
|
||||
*/
|
||||
extern void net_stats_initialize();
|
||||
extern void net_stats_report();
|
||||
extern void net_stats_reset();
|
||||
extern void net_stats_add_tx(size_t bytes);
|
||||
extern void net_stats_add_rx(size_t bytes);
|
||||
extern void net_stats_add_accept();
|
||||
extern void net_stats_add_error();
|
||||
extern void net_stats_add_close();
|
||||
extern int net_stats_timeout();
|
||||
extern void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total);
|
||||
|
||||
|
||||
#if defined(WINSOCK) && !defined(__CYGWIN__)
|
||||
|
||||
// #define EINTR WSAEINTR
|
||||
// #define EACCES WSAEACCES
|
||||
// #define EFAULT WSAEFAULT
|
||||
// #define EINVAL WSAEINVAL
|
||||
// #define EMFILE WSAEMFILE
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define EALREADY WSAEALREADY
|
||||
#define ENOTSOCK WSAENOTSOCK
|
||||
#define EDESTADDRREQ WSAEDESTADDRREQ
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define EPROTOTYPE WSAEPROTOTYPE
|
||||
#define ENOPROTOOPT WSAENOPROTOOPT
|
||||
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
|
||||
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
|
||||
#define EOPNOTSUPP WSAEOPNOTSUPP
|
||||
#define EPFNOSUPPORT WSAEPFNOSUPPORT
|
||||
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
||||
#define EADDRINUSE WSAEADDRINUSE
|
||||
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
||||
#define ENETDOWN WSAENETDOWN
|
||||
#define ENETUNREACH WSAENETUNREACH
|
||||
#define ENETRESET WSAENETRESET
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define ENOBUFS WSAENOBUFS
|
||||
#define EISCONN WSAEISCONN
|
||||
#define ENOTCONN WSAENOTCONN
|
||||
#define ESHUTDOWN WSAESHUTDOWN
|
||||
#define ETOOMANYREFS WSAETOOMANYREFS
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define ELOOP WSAELOOP
|
||||
// #define ENAMETOOLONG WSAENAMETOOLONG
|
||||
#define EHOSTDOWN WSAEHOSTDOWN
|
||||
#define EHOSTUNREACH WSAEHOSTUNREACH
|
||||
// #define ENOTEMPTY WSAENOTEMPTY
|
||||
#define EPROCLIM WSAEPROCLIM
|
||||
#define EUSERS WSAEUSERS
|
||||
#define EDQUOT WSAEDQUOT
|
||||
#define ESTALE WSAESTALE
|
||||
#define EREMOTE WSAEREMOTE
|
||||
|
||||
#endif /* WINSOCK && !__CYGWIN__ */
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_NETWORK_H */
|
52
src/plugin.h
Normal file
52
src/plugin.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef void (*plugin_event_startup)(struct hub*);
|
||||
typedef void (*plugin_event_shutdown)(struct hub*);
|
||||
typedef void (*plugin_event_user_login)(struct hub*, struct user*);
|
||||
typedef void (*plugin_event_user_logout)(struct hub*, struct user*);
|
||||
typedef int (*plugin_event_connect)(struct hub*, struct ip_addr_encap);
|
||||
typedef void (*plugin_event_disconnect)(struct hub*, struct user*);
|
||||
typedef int (*plugin_event_message)(struct hub*, struct user*, struct adc_message*);
|
||||
typedef void (*plugin_event_support)(struct hub*, struct user*, int);
|
||||
|
||||
struct uhub_plugin
|
||||
{
|
||||
/** Starting the hub */
|
||||
plugin_event_startup evt_startup;
|
||||
|
||||
/** Shutting down the hub */
|
||||
plugin_event_shutdown evt_shutdown;
|
||||
|
||||
/** Someone connected to the hub (we only have IP at this point). */
|
||||
plugin_event_connect evt_connect;
|
||||
|
||||
/** Someone disconnected from the hub (but was not successfully logged in). */
|
||||
plugin_event_disconnect evt_disconnect;
|
||||
|
||||
/** A client sent a message about which protocol extensions it supports */
|
||||
plugin_event_support evt_support;
|
||||
|
||||
/** A client was successfully logged in to the hub */
|
||||
plugin_event_user_login evt_login;
|
||||
|
||||
/** A client (previously logged in) has disconnected. */
|
||||
plugin_event_user_logout evt_logout;
|
||||
};
|
||||
|
237
src/route.c
Normal file
237
src/route.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
int route_message(struct user* u, struct adc_message* msg)
|
||||
{
|
||||
struct user* target = NULL;
|
||||
|
||||
switch (msg->cache[0])
|
||||
{
|
||||
case 'B': /* Broadcast to all logged in clients */
|
||||
route_to_all(u->hub, msg);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
target = get_user_by_sid(u->hub, msg->target);
|
||||
if (target)
|
||||
{
|
||||
route_to_user(target, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
target = get_user_by_sid(u->hub, msg->target);
|
||||
if (target)
|
||||
{
|
||||
route_to_user(target, msg);
|
||||
route_to_user(u, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
route_to_subscribers(u->hub, msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ignore the message */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void queue_command(struct user* user, struct adc_message* msg__, int offset)
|
||||
{
|
||||
struct adc_message* msg = adc_msg_incref(msg__);
|
||||
list_append(user->send_queue, msg);
|
||||
|
||||
hub_log(log_trace, "queue_command(), user=%p, msg=%p (%zu), offset=%d", user, msg, msg->references, offset);
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
user->send_queue_size += msg->length - offset;
|
||||
user->send_queue_offset = offset;
|
||||
user->tm_last_write = time(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
user->send_queue_size += msg->length;
|
||||
user->send_queue_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// #define ALWAYS_QUEUE_MESSAGES
|
||||
|
||||
int route_to_user(struct user* user, struct adc_message* msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if LOG_SEND_MESSAGES_WHEN_ROUTED
|
||||
char* data = strndup(msg->cache, msg->length-1);
|
||||
hub_log(log_protocol, "send %s: %s", sid_to_string(user->sid), data);
|
||||
free(data);
|
||||
#endif
|
||||
|
||||
#ifndef ALWAYS_QUEUE_MESSAGES
|
||||
if (user->send_queue_size == 0 && !user_is_disconnecting(user))
|
||||
{
|
||||
ret = net_send(user->sd, msg->cache, msg->length, UHUB_SEND_SIGNAL);
|
||||
|
||||
if (ret == msg->length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ret >= 0 || (ret == -1 && net_error() == EWOULDBLOCK))
|
||||
{
|
||||
queue_command(user, msg, ret);
|
||||
|
||||
if (user->send_queue_size && user->ev_write)
|
||||
event_add(user->ev_write, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A socket error occured */
|
||||
user_disconnect(user, quit_socket_error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!user_flag_get(user, flag_user_list) && user->send_queue_size + msg->length > user->hub->config->max_send_buffer && msg->priority >= 0)
|
||||
{
|
||||
/* User is not able to swallow the data, let's cut our losses and disconnect. */
|
||||
user_disconnect(user, quit_send_queue);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user->send_queue_size + msg->length > user->hub->config->max_send_buffer_soft && msg->priority >= 0)
|
||||
{
|
||||
/* Don't queue this message if it is low priority! */
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_command(user, msg, 0);
|
||||
if (user->ev_write)
|
||||
event_add(user->ev_write, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
|
||||
{
|
||||
struct user* user = (struct user*) list_get_first(hub->users->list);
|
||||
while (user)
|
||||
{
|
||||
route_to_user(user, command);
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
|
||||
{
|
||||
int do_send;
|
||||
char* tmp;
|
||||
|
||||
struct user* user = (struct user*) list_get_first(hub->users->list);
|
||||
while (user)
|
||||
{
|
||||
if (user->feature_cast)
|
||||
{
|
||||
do_send = 1;
|
||||
|
||||
tmp = list_get_first(command->feature_cast_include);
|
||||
while (tmp)
|
||||
{
|
||||
if (!user_have_feature_cast_support(user, tmp))
|
||||
{
|
||||
do_send = 0;
|
||||
break;
|
||||
}
|
||||
tmp = list_get_next(command->feature_cast_include);;
|
||||
}
|
||||
|
||||
if (!do_send) {
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = list_get_first(command->feature_cast_exclude);
|
||||
while (tmp)
|
||||
{
|
||||
if (user_have_feature_cast_support(user, tmp))
|
||||
{
|
||||
do_send = 0;
|
||||
break;
|
||||
}
|
||||
tmp = list_get_next(command->feature_cast_exclude);
|
||||
}
|
||||
|
||||
if (do_send)
|
||||
{
|
||||
route_to_user(user, command);
|
||||
}
|
||||
}
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_info_message(struct user* u)
|
||||
{
|
||||
if (!user_is_nat_override(u))
|
||||
{
|
||||
return route_to_all(u->hub, u->info);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct adc_message* cmd = adc_msg_copy(u->info);
|
||||
const char* address = (char*) net_get_peer_address(u->sd);
|
||||
struct user* user = 0;
|
||||
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
|
||||
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
|
||||
|
||||
user = (struct user*) list_get_first(u->hub->users->list);
|
||||
while (user)
|
||||
{
|
||||
if (user_is_nat_override(user))
|
||||
route_to_user(user, cmd);
|
||||
else
|
||||
route_to_user(user, u->info);
|
||||
|
||||
user = (struct user*) list_get_next(u->hub->users->list);
|
||||
}
|
||||
adc_msg_free(cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
51
src/route.h
Normal file
51
src/route.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_ROUTE_H
|
||||
#define HAVE_UHUB_ROUTE_H
|
||||
|
||||
/**
|
||||
* Route a message by sending it to it's final destination.
|
||||
*/
|
||||
extern int route_message(struct user* u, struct adc_message* msg);
|
||||
|
||||
/**
|
||||
* Transmit message directly to one user.
|
||||
*/
|
||||
extern int route_to_user(struct user*, struct adc_message* command);
|
||||
|
||||
/**
|
||||
* Broadcast message to all users.
|
||||
*/
|
||||
extern int route_to_all(struct hub_info* hub, struct adc_message* command);
|
||||
|
||||
/**
|
||||
* Broadcast message to all users subscribing to the type of message.
|
||||
*/
|
||||
extern int route_to_subscribers(struct hub_info* hub, struct adc_message* command);
|
||||
|
||||
/**
|
||||
* Broadcast initial info message to all users.
|
||||
* This will ensure the correct IP is seen by other users
|
||||
* in case nat override is in use.
|
||||
*/
|
||||
extern int route_info_message(struct user* user);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_ROUTE_H */
|
61
src/sid.c
Normal file
61
src/sid.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
char* sid_to_string(sid_t sid_)
|
||||
{
|
||||
static char t_sid[5];
|
||||
sid_t sid = (sid_ & 0xFFFFF); /* 20 bits only */
|
||||
sid_t A, B, C, D = 0;
|
||||
D = (sid % 32);
|
||||
sid = (sid - D) / 32;
|
||||
C = (sid % 32);
|
||||
sid = (sid - C) / 32;
|
||||
B = (sid % 32);
|
||||
sid = (sid - B) / 32;
|
||||
A = (sid % 32);
|
||||
t_sid[0] = BASE32_ALPHABET[A];
|
||||
t_sid[1] = BASE32_ALPHABET[B];
|
||||
t_sid[2] = BASE32_ALPHABET[C];
|
||||
t_sid[3] = BASE32_ALPHABET[D];
|
||||
t_sid[4] = 0;
|
||||
return t_sid;
|
||||
}
|
||||
|
||||
|
||||
sid_t string_to_sid(const char* sid)
|
||||
{
|
||||
sid_t nsid = 0;
|
||||
sid_t n, x;
|
||||
sid_t factors[] = { 32768, 1024, 32, 1};
|
||||
|
||||
if (!sid || strlen(sid) != 4) return 0;
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
for (x = 0; x < strlen(BASE32_ALPHABET); x++)
|
||||
if (sid[n] == BASE32_ALPHABET[x]) break;
|
||||
if (x == 32) return 0;
|
||||
nsid += x * factors[n];
|
||||
}
|
||||
return nsid;
|
||||
}
|
||||
|
67
src/sid.h
Normal file
67
src/sid.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_SID_H
|
||||
#define HAVE_UHUB_SID_H
|
||||
|
||||
#define SID_MAX 1048576
|
||||
|
||||
extern const char* BASE32_ALPHABET;
|
||||
extern char* sid_to_string(sid_t sid_);
|
||||
extern sid_t string_to_sid(const char* sid);
|
||||
|
||||
struct sid_map
|
||||
{
|
||||
struct user* ptr;
|
||||
struct sid_map* next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Session IDs are heavily reused, since they are a fairly scarce
|
||||
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
|
||||
* value and 'AAAA' (0) is reserved for the hub.
|
||||
*
|
||||
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
|
||||
*
|
||||
* When allocating a session ID:
|
||||
* - If 'count' is less than the pool size (max-min), then allocate within the pool
|
||||
* - Increase the pool size (see below)
|
||||
* - If unable to do that, hub is really full - don't let anyone in!
|
||||
*
|
||||
* When freeing a session ID:
|
||||
* - If the session ID being freed is 'max', then decrease the pool size by one.
|
||||
*
|
||||
*/
|
||||
struct sid_pool
|
||||
{
|
||||
sid_t min;
|
||||
sid_t max;
|
||||
sid_t count;
|
||||
struct sid_map* map;
|
||||
};
|
||||
|
||||
|
||||
extern void sid_initialize(struct sid_pool*);
|
||||
extern sid_t sid_alloc(struct sid_pool*, struct user*);
|
||||
extern void sid_free(struct sid_pool*, sid_t);
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_SID_H */
|
||||
|
1241
src/tiger.c
Normal file
1241
src/tiger.c
Normal file
File diff suppressed because it is too large
Load Diff
26
src/tiger.h
Normal file
26
src/tiger.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HAVE_UHUB_HASH_TIGER_H
|
||||
#define HAVE_UHUB_HASH_TIGER_H
|
||||
|
||||
extern void tiger(uint64_t* str, uint64_t length, uint64_t* res);
|
||||
|
||||
#endif /* HAVE_UHUB_HASH_TIGER_H */
|
168
src/uhub.h
Normal file
168
src/uhub.h
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_COMMON_H
|
||||
#define HAVE_UHUB_COMMON_H
|
||||
|
||||
/* Debugging */
|
||||
/* #define NETWORK_DUMP_DEBUG */
|
||||
/* #define MEMORY_DEBUG */
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
#ifndef WINSOCK
|
||||
#define WINSOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WINSOCK
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#define HAVE_STRNDUP
|
||||
#define HAVE_MEMMEM
|
||||
#endif
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#define uhub_assert assert
|
||||
|
||||
#include <event.h>
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#undef HAVE_STRNDUP
|
||||
#undef HAVE_MEMMEM
|
||||
#endif
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
#define UHUB_SEND_SIGNAL MSG_NOSIGNAL
|
||||
#else
|
||||
#ifdef MSG_NOPIPE
|
||||
#define UHUB_SEND_SIGNAL MSG_NOPIPE
|
||||
#else
|
||||
#define UHUB_SEND_SIGNAL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define SERVER_PORT 1511
|
||||
#define SERVER_ADDR_IPV6 "::"
|
||||
#define SERVER_ADDR_IPV4 "0.0.0.0"
|
||||
#define SERVER_BACKLOG 50
|
||||
|
||||
#ifndef WIN32
|
||||
#define SERVER_CONFIG "/etc/uhub/uhub.conf"
|
||||
#define SERVER_ACL_FILE "/etc/uhub/users.conf"
|
||||
#else
|
||||
#define SERVER_CONFIG "uhub.conf"
|
||||
#define SERVER_ACL_FILE "users.conf"
|
||||
#ifndef stderr
|
||||
#define stderr stdout
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TIMEOUT_CONNECTED 15
|
||||
#define TIMEOUT_HANDSHAKE 30
|
||||
#define TIMEOUT_SENDQ 120
|
||||
#define TIMEOUT_IDLE 7200
|
||||
#define TIMEOUT_STATS 3600
|
||||
|
||||
#define MAX_CLIENTS 512
|
||||
#define MAX_CID_LEN 39
|
||||
#define MAX_NICK_LEN 64
|
||||
#define MAX_UA_LEN 32
|
||||
#define TIGERSIZE 24
|
||||
|
||||
#define MAX_RECV_BUF 65535
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
#endif
|
||||
|
||||
#include "adcconst.h"
|
||||
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "misc.h"
|
||||
#include "eventid.h"
|
||||
#include "eventqueue.h"
|
||||
#include "ipcalc.h"
|
||||
#include "list.h"
|
||||
#include "sid.h"
|
||||
#include "network.h"
|
||||
#include "netevent.h"
|
||||
#include "auth.h"
|
||||
#include "tiger.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "user.h"
|
||||
#include "usermanager.h"
|
||||
#include "message.h"
|
||||
#include "route.h"
|
||||
#include "hub.h"
|
||||
#include "commands.h"
|
||||
#include "inf.h"
|
||||
#include "hubevent.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_UHUB_COMMON_H */
|
||||
|
||||
|
||||
|
308
src/user.c
Normal file
308
src/user.c
Normal file
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
struct user* user_create(struct hub_info* hub, int sd)
|
||||
{
|
||||
struct user* user = NULL;
|
||||
|
||||
hub_log(log_trace, "user_create(), hub=%p, sd=%d", hub, sd);
|
||||
|
||||
user = (struct user*) hub_malloc_zero(sizeof(struct user));
|
||||
|
||||
if (user == NULL)
|
||||
return NULL; /* OOM */
|
||||
|
||||
user->ev_write = hub_malloc_zero(sizeof(struct event));
|
||||
user->ev_read = hub_malloc_zero(sizeof(struct event));
|
||||
|
||||
if (!user->ev_write || !user->ev_read)
|
||||
{
|
||||
hub_free(user->ev_read);
|
||||
hub_free(user->ev_write);
|
||||
hub_free(user);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user->sd = sd;
|
||||
user->tm_connected = time(NULL);
|
||||
user->hub = hub;
|
||||
user->feature_cast = 0;
|
||||
|
||||
user->send_queue = list_create();
|
||||
user->send_queue_offset = 0;
|
||||
user->send_queue_size = 0;
|
||||
user->recv_buf_offset = 0;
|
||||
user->recv_buf = 0;
|
||||
|
||||
user_set_state(user, state_protocol);
|
||||
return user;
|
||||
}
|
||||
|
||||
static void clear_send_queue_callback(void* ptr)
|
||||
{
|
||||
adc_msg_free((struct adc_message*) ptr);
|
||||
}
|
||||
|
||||
void user_destroy(struct user* user)
|
||||
{
|
||||
hub_log(log_trace, "user_destroy(), user=%p", user);
|
||||
|
||||
if (user->ev_write)
|
||||
{
|
||||
event_del(user->ev_write);
|
||||
hub_free(user->ev_write);
|
||||
user->ev_write = 0;
|
||||
}
|
||||
|
||||
if (user->ev_read)
|
||||
{
|
||||
event_del(user->ev_read);
|
||||
hub_free(user->ev_read);
|
||||
user->ev_read = 0;
|
||||
}
|
||||
|
||||
net_close(user->sd);
|
||||
|
||||
adc_msg_free(user->info);
|
||||
user_clear_feature_cast_support(user);
|
||||
|
||||
if (user->recv_buf)
|
||||
{
|
||||
hub_free(user->recv_buf);
|
||||
}
|
||||
|
||||
if (user->send_queue)
|
||||
{
|
||||
list_clear(user->send_queue, &clear_send_queue_callback);
|
||||
list_destroy(user->send_queue);
|
||||
}
|
||||
|
||||
hub_free(user);
|
||||
}
|
||||
|
||||
void user_set_state(struct user* user, enum user_state state)
|
||||
{
|
||||
if ((user->state == state_cleanup && state != state_disconnected) || (user->state == state_disconnected))
|
||||
{
|
||||
puts("PANIC - Ignoring new state");
|
||||
return;
|
||||
}
|
||||
|
||||
user->state = state;
|
||||
}
|
||||
|
||||
void user_set_info(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
adc_msg_free(user->info);
|
||||
user->info = adc_msg_incref(cmd);
|
||||
}
|
||||
|
||||
|
||||
static int convert_support_fourcc(int fourcc)
|
||||
{
|
||||
switch (fourcc)
|
||||
{
|
||||
case FOURCC('B','A','S','0'): /* Obsolete */
|
||||
case FOURCC('B','A','S','E'):
|
||||
return feature_base;
|
||||
|
||||
case FOURCC('A','U','T','0'):
|
||||
return feature_auto;
|
||||
|
||||
case FOURCC('U','C','M','0'):
|
||||
case FOURCC('U','C','M','D'):
|
||||
return feature_ucmd;
|
||||
|
||||
case FOURCC('Z','L','I','F'):
|
||||
return feature_zlif;
|
||||
|
||||
case FOURCC('B','B','S','0'):
|
||||
return feature_bbs;
|
||||
|
||||
case FOURCC('T','I','G','R'):
|
||||
return feature_tiger;
|
||||
|
||||
case FOURCC('B','L','O','M'):
|
||||
case FOURCC('B','L','O','0'):
|
||||
return feature_bloom;
|
||||
|
||||
case FOURCC('P','I','N','G'):
|
||||
return feature_ping;
|
||||
|
||||
case FOURCC('L','I','N','K'):
|
||||
return feature_link;
|
||||
|
||||
default:
|
||||
hub_log(log_debug, "Unknown extension: %x", fourcc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void user_support_add(struct user* user, int fourcc)
|
||||
{
|
||||
int feature_mask = convert_support_fourcc(fourcc);
|
||||
user->flags |= feature_mask;
|
||||
}
|
||||
|
||||
int user_flag_get(struct user* user, enum user_flags flag)
|
||||
{
|
||||
return user->flags & flag;
|
||||
}
|
||||
|
||||
void user_flag_set(struct user* user, enum user_flags flag)
|
||||
{
|
||||
user->flags |= flag;
|
||||
}
|
||||
|
||||
void user_flag_unset(struct user* user, enum user_flags flag)
|
||||
{
|
||||
user->flags &= ~flag;
|
||||
}
|
||||
|
||||
void user_set_nat_override(struct user* user)
|
||||
{
|
||||
user_flag_set(user, flag_nat);
|
||||
}
|
||||
|
||||
int user_is_nat_override(struct user* user)
|
||||
{
|
||||
return user_flag_get(user, flag_nat);
|
||||
}
|
||||
|
||||
void user_support_remove(struct user* user, int fourcc)
|
||||
{
|
||||
int feature_mask = convert_support_fourcc(fourcc);
|
||||
user->flags &= ~feature_mask;
|
||||
}
|
||||
|
||||
void user_schedule_destroy(struct user* user)
|
||||
{
|
||||
struct event_data post;
|
||||
memset(&post, 0, sizeof(post));
|
||||
post.id = UHUB_EVENT_USER_DESTROY;
|
||||
post.ptr = user;
|
||||
event_queue_post(user->hub->queue, &post);
|
||||
}
|
||||
|
||||
void user_disconnect(struct user* user, int reason)
|
||||
{
|
||||
struct event_data post;
|
||||
int need_notify = 0;
|
||||
|
||||
if (user_is_disconnecting(user))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* dont read more data from this user */
|
||||
if (user->ev_read)
|
||||
{
|
||||
event_del(user->ev_read);
|
||||
hub_free(user->ev_read);
|
||||
user->ev_read = 0;
|
||||
}
|
||||
|
||||
hub_log(log_trace, "user_disconnect(), user=%p, reason=%d, state=%d", user, reason, user->state);
|
||||
|
||||
need_notify = user_is_logged_in(user);
|
||||
user->quit_reason = reason;
|
||||
user_set_state(user, state_cleanup);
|
||||
|
||||
if (need_notify)
|
||||
{
|
||||
memset(&post, 0, sizeof(post));
|
||||
post.id = UHUB_EVENT_USER_QUIT;
|
||||
post.ptr = user;
|
||||
event_queue_post(user->hub->queue, &post);
|
||||
}
|
||||
else
|
||||
{
|
||||
user->quit_reason = quit_unknown;
|
||||
user_schedule_destroy(user);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int user_have_feature_cast_support(struct user* user, char feature[4])
|
||||
{
|
||||
char* tmp = list_get_first(user->feature_cast);
|
||||
while (tmp)
|
||||
{
|
||||
if (strncmp(tmp, feature, 4) == 0)
|
||||
return 1;
|
||||
|
||||
tmp = list_get_next(user->feature_cast);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int user_set_feature_cast_support(struct user* u, char feature[4])
|
||||
{
|
||||
if (!u->feature_cast)
|
||||
{
|
||||
u->feature_cast = list_create();
|
||||
}
|
||||
|
||||
if (!u->feature_cast)
|
||||
{
|
||||
return 0; /* OOM! */
|
||||
}
|
||||
|
||||
list_append(u->feature_cast, hub_strndup(feature, 4));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void user_clear_feature_cast_support(struct user* u)
|
||||
{
|
||||
if (u->feature_cast)
|
||||
{
|
||||
list_clear(u->feature_cast, &hub_free);
|
||||
list_destroy(u->feature_cast);
|
||||
u->feature_cast = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int user_is_logged_in(struct user* user)
|
||||
{
|
||||
if (user->state == state_normal)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int user_is_connecting(struct user* user)
|
||||
{
|
||||
if (user->state == state_protocol || user->state == state_identify || user->state == state_verify)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int user_is_disconnecting(struct user* user)
|
||||
{
|
||||
if (user->state == state_cleanup || user->state == state_disconnected)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
261
src/user.h
Normal file
261
src/user.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_USER_H
|
||||
#define HAVE_UHUB_USER_H
|
||||
|
||||
|
||||
struct hub_info;
|
||||
|
||||
|
||||
enum user_state
|
||||
{
|
||||
state_protocol = 0, /**<< "User must send a valid protocol handshake" */
|
||||
state_identify = 1, /**<< "User must send identification message (INF) " */
|
||||
state_verify = 2, /**<< "User must send password to verify identification" */
|
||||
state_normal = 3, /**<< "User is logged in." */
|
||||
state_cleanup = 4, /**<< "User is disconnected, but other users need to be notified." */
|
||||
state_disconnected = 5, /**<< "User is disconnected" */
|
||||
};
|
||||
|
||||
|
||||
enum user_flags
|
||||
{
|
||||
feature_base = 0x00000001, /** BASE: Basic configuration (required by all clients) */
|
||||
feature_auto = 0x00000002, /** AUT0: Automatic nat detection traversal */
|
||||
feature_bbs = 0x00000004, /** BBS0: Bulletin board system (not supported) */
|
||||
feature_ucmd = 0x00000008, /** UCMD: User commands (not supported by this software) */
|
||||
feature_zlif = 0x00000010, /** ZLIF: gzip stream compression (not supported) */
|
||||
feature_tiger = 0x00000020, /** TIGR: Client supports the tiger hash algorithm */
|
||||
feature_bloom = 0x00000040, /** BLO0: Bloom filter (not supported) */
|
||||
feature_ping = 0x00000080, /** PING: Hub pinger information extension */
|
||||
feature_link = 0x00000100, /** LINK: Hub link (not supported) */
|
||||
flag_ignore = 0x01000000, /** Ignore further reads */
|
||||
flag_choke = 0x02000000, /** Choked: Cannot send, waiting for write event */
|
||||
flag_want_read = 0x04000000, /** Need to read (SSL) */
|
||||
flag_want_write = 0x08000000, /** Need to write (SSL) */
|
||||
flag_user_list = 0x10000000, /** Send queue bypass (when receiving the send queue) */
|
||||
flag_nat = 0x20000000, /** nat override enabled */
|
||||
};
|
||||
|
||||
|
||||
enum user_quit_reason
|
||||
{
|
||||
quit_unknown = 0,
|
||||
quit_disconnected = 1, /** User disconnected */
|
||||
quit_kicked = 2, /** User was kicked */
|
||||
quit_banned = 3, /** User was banned */
|
||||
quit_timeout = 4, /** User timed out (no data for a while) */
|
||||
quit_send_queue = 5, /** User's send queue was overflowed */
|
||||
quit_memory_error = 6, /** Not enough memory available */
|
||||
quit_socket_error = 7, /** A socket error occured */
|
||||
quit_protocol_error = 8, /** Fatal protocol error */
|
||||
quit_logon_error = 9, /** Unable to login (wrong password, CID/PID, etc) */
|
||||
quit_hub_disabled = 10, /** Hub is disabled. No new connections allowed */
|
||||
};
|
||||
|
||||
|
||||
struct user_info
|
||||
{
|
||||
sid_t sid; /** session ID */
|
||||
char cid[MAX_CID_LEN+1]; /** global client ID */
|
||||
char nick[MAX_NICK_LEN+1]; /** User's nick name */
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct contains additional information about the user, such
|
||||
* as the number of bytes and files shared, and the number of hubs the
|
||||
* user is connected to, etc.
|
||||
*/
|
||||
struct user_counts
|
||||
{
|
||||
uint64_t shared_size; /** Shared size in bytes */
|
||||
size_t shared_files; /** The number of shared files */
|
||||
size_t upload_slots; /** The number of upload slots */
|
||||
size_t hub_count_user; /** The number of hubs connected as user */
|
||||
size_t hub_count_registered; /** The number of hubs connected as registered user */
|
||||
size_t hub_count_operator; /** The number of hubs connected as operator */
|
||||
size_t hub_count_total; /** The number of hubs connected to in total */
|
||||
};
|
||||
|
||||
struct user
|
||||
{
|
||||
int sd; /** socket descriptor */
|
||||
struct event* ev_read; /** libevent struct for read events */
|
||||
struct event* ev_write; /** libevent struct for write events */
|
||||
enum user_state state; /** see enum user_state */
|
||||
enum user_credentials credentials; /** see enum user_credentials */
|
||||
struct user_info id; /** Contains nick name and CID */
|
||||
int flags; /** see enum user_features */
|
||||
char user_agent[MAX_UA_LEN+1];/** User agent string */
|
||||
time_t tm_connected; /** time when user connected */
|
||||
time_t tm_last_read; /** time the user last received something from the hub */
|
||||
time_t tm_last_write; /** time the user last sent something to the hub */
|
||||
struct linked_list* feature_cast; /** Features supported by feature cast */
|
||||
struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */
|
||||
size_t send_queue_offset; /** Send queue byte offset */
|
||||
struct linked_list* send_queue; /** Send queue */
|
||||
int send_queue_size; /** Size of send queue (in bytes, not messages) */
|
||||
int send_queue_esize; /** Effective send queue size */
|
||||
char* recv_buf; /** Recv buffer */
|
||||
size_t recv_buf_offset; /** Recv buffer offset */
|
||||
struct hub_info* hub; /** The hub instance this user belong to */
|
||||
int quit_reason; /** Quit reason (see user_quit_reason) */
|
||||
struct ip_addr_encap ipaddr; /** IP address of connected user */
|
||||
struct user_counts limits; /** Data used for limitation */
|
||||
#ifdef SSL_SUPPORT
|
||||
SSL* ssl; /** SSL handle */
|
||||
#endif /* SSL_SUPPORT */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a user with the given socket descriptor.
|
||||
* This basically only allocates memory and initializes all variables
|
||||
* to an initial state.
|
||||
*
|
||||
* state is set to state_protocol.
|
||||
*
|
||||
* @param sd socket descriptor associated with the user
|
||||
* @return User object or NULL if not enough memory is available.
|
||||
*/
|
||||
extern struct user* user_create(struct hub_info* hub, int sd);
|
||||
|
||||
/**
|
||||
* Delete a user.
|
||||
*
|
||||
* !WRONG! If the user is logged in a quit message is issued.
|
||||
*/
|
||||
extern void user_destroy(struct user* user);
|
||||
|
||||
/**
|
||||
* Will post a message that will delete the user later.
|
||||
*/
|
||||
extern void user_schedule_destroy(struct user* user);
|
||||
|
||||
/**
|
||||
* Disconnect a user.
|
||||
* This will mark the user connection ready for being terminated.
|
||||
* A reason can be given using the enum user_quit_reason.
|
||||
*
|
||||
* Things to be done when calling this:
|
||||
* - Mark the user with state_cleanup
|
||||
*
|
||||
* If the user is logged in to the hub:
|
||||
* - post message: UHUB_EVENT_USER_QUIT
|
||||
*
|
||||
* @param user User to disconnect
|
||||
* @param reason See enum user_quit_reason
|
||||
*/
|
||||
extern void user_disconnect(struct user* user, int reason);
|
||||
|
||||
/**
|
||||
* This associates a INF message to the user.
|
||||
* If the user already has a INF message associated, then this is
|
||||
* released before setting the new one.
|
||||
*/
|
||||
extern void user_set_info(struct user* user, struct adc_message* info);
|
||||
|
||||
/**
|
||||
* Specify a user's state.
|
||||
* NOTE: DON'T, unless you know what you are doing.
|
||||
*/
|
||||
extern void user_set_state(struct user* user, enum user_state);
|
||||
|
||||
/**
|
||||
* Returns 1 if the user is in state state_normal, or 0 otherwise.
|
||||
*/
|
||||
extern int user_is_logged_in(struct user* user);
|
||||
|
||||
/**
|
||||
* Returns 1 if the user is in state_protocol, state_identify or state_verify.
|
||||
* Returns 0 otherwise.
|
||||
*/
|
||||
extern int user_is_connecting(struct user* user);
|
||||
|
||||
/**
|
||||
* Returns 1 only if the user is in state_cleanup or state_disconnected.
|
||||
*/
|
||||
extern int user_is_disconnecting(struct user* user);
|
||||
|
||||
/**
|
||||
* User supports the protocol extension as given in fourcc.
|
||||
* This is usually set while the user is connecting, but can
|
||||
* also be used to subscribe to a new class of messages from the
|
||||
* hub.
|
||||
*
|
||||
* @see enum user_flags
|
||||
*/
|
||||
extern void user_support_add(struct user* user, int fourcc);
|
||||
|
||||
/**
|
||||
* User no longer supports the protocol extension as given in fourcc.
|
||||
* This can be used to unsubscribe to certain messages generated by
|
||||
* the hub.
|
||||
* @see enum user_flags
|
||||
*/
|
||||
extern void user_support_remove(struct user* user, int fourcc);
|
||||
|
||||
/**
|
||||
* Sets the nat override flag for a user, this allows users on the same
|
||||
* subnet as a natted hub to spoof their IP in order to use active mode
|
||||
* on a natted hub.
|
||||
*/
|
||||
extern void user_set_nat_override(struct user* user);
|
||||
extern int user_is_nat_override(struct user* user);
|
||||
|
||||
/**
|
||||
* Set a flag. @see enum user_flags
|
||||
*/
|
||||
extern void user_flag_set(struct user* user, enum user_flags flag);
|
||||
extern void user_flag_unset(struct user* user, enum user_flags flag);
|
||||
|
||||
/**
|
||||
* Get a flag. @see enum user_flags
|
||||
*/
|
||||
extern int user_flag_get(struct user* user, enum user_flags flag);
|
||||
|
||||
/**
|
||||
* Check if a user supports 'feature' for feature casting (basis for 'Fxxx' messages)
|
||||
* The feature cast is specified as the 'SU' argument to the user's
|
||||
* INF-message.
|
||||
*
|
||||
* @param feature a feature to lookup (example: 'TCP4' or 'UDP4')
|
||||
* @return 1 if 'feature' supported, or 0 otherwise
|
||||
*/
|
||||
extern int user_have_feature_cast_support(struct user* user, char feature[4]);
|
||||
|
||||
/**
|
||||
* Set feature cast support for feature.
|
||||
*
|
||||
* @param feature a feature to lookup (example: 'TCP4' or 'UDP4')
|
||||
* @return 1 if 'feature' supported, or 0 otherwise
|
||||
*/
|
||||
extern int user_set_feature_cast_support(struct user* u, char feature[4]);
|
||||
|
||||
/**
|
||||
* Remove all feature cast support features.
|
||||
*/
|
||||
extern void user_clear_feature_cast_support(struct user* u);
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_USER_H */
|
||||
|
||||
|
222
src/usermanager.c
Normal file
222
src/usermanager.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
/*
|
||||
* This callback function is used to clear user objects from the userlist.
|
||||
* Should only be used in user_manager_shutdown().
|
||||
*/
|
||||
static void clear_user_list_callback(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
struct user* u = (struct user*) ptr;
|
||||
|
||||
/* Mark the user as already being disconnected.
|
||||
* This prevents the hub from trying to send
|
||||
* quit messages to other users.
|
||||
*/
|
||||
u->credentials = cred_none;
|
||||
user_destroy(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void user_manager_stats(struct hub_info* hub)
|
||||
{
|
||||
int factor = 0;
|
||||
struct net_statistics* total;
|
||||
struct net_statistics* intermediate;
|
||||
net_stats_get(&intermediate, &total);
|
||||
|
||||
factor = (time(NULL) - intermediate->timestamp);
|
||||
if (!factor) factor++;
|
||||
|
||||
hub_log(log_info, "Statistics users=%zu, net_tx=%d KB/s, net_rx=%d KB/s",
|
||||
hub->users->count,
|
||||
(int) ((intermediate->tx / factor) / 1024),
|
||||
(int) ((intermediate->rx / factor) / 1024));
|
||||
|
||||
net_stats_reset();
|
||||
}
|
||||
|
||||
|
||||
static void timer_statistics(int fd, short ev, void *arg)
|
||||
{
|
||||
struct hub_info* hub = (struct hub_info*) arg;
|
||||
struct timeval timeout = { TIMEOUT_STATS, 0 };
|
||||
user_manager_stats(hub);
|
||||
evtimer_set(&hub->ev_timer, timer_statistics, hub);
|
||||
evtimer_add(&hub->ev_timer, &timeout);
|
||||
}
|
||||
|
||||
|
||||
int user_manager_init(struct hub_info* hub)
|
||||
{
|
||||
struct user_manager* users = NULL;
|
||||
struct timeval timeout = { TIMEOUT_STATS, 0 };
|
||||
|
||||
users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
|
||||
|
||||
users->list = list_create();
|
||||
users->free_sid = 1;
|
||||
|
||||
if (!users->list)
|
||||
{
|
||||
list_destroy(users->list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub->users = users;
|
||||
|
||||
evtimer_set(&hub->ev_timer, timer_statistics, hub);
|
||||
evtimer_add(&hub->ev_timer, &timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void user_manager_shutdown(struct hub_info* hub)
|
||||
{
|
||||
struct user_manager* users = hub->users;
|
||||
event_del(&hub->ev_timer);
|
||||
|
||||
list_clear(users->list, &clear_user_list_callback);
|
||||
list_destroy(users->list);
|
||||
hub_free(hub->users);
|
||||
}
|
||||
|
||||
|
||||
void user_manager_add(struct user* user)
|
||||
{
|
||||
list_append(user->hub->users->list, user);
|
||||
user->hub->users->count++;
|
||||
user->hub->users->count_peak = MAX(user->hub->users->count, user->hub->users->count_peak);
|
||||
|
||||
user->hub->users->shared_size += user->limits.shared_size;
|
||||
user->hub->users->shared_files += user->limits.shared_files;
|
||||
}
|
||||
|
||||
void user_manager_remove(struct user* user)
|
||||
{
|
||||
list_remove(user->hub->users->list, user);
|
||||
user->hub->users->count--;
|
||||
|
||||
user->hub->users->shared_size -= user->limits.shared_size;
|
||||
user->hub->users->shared_files -= user->limits.shared_files;
|
||||
}
|
||||
|
||||
|
||||
struct user* get_user_by_sid(struct hub_info* hub, sid_t sid)
|
||||
{
|
||||
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users */
|
||||
while (user)
|
||||
{
|
||||
if (user->id.sid == sid)
|
||||
return user;
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct user* get_user_by_cid(struct hub_info* hub, const char* cid)
|
||||
{
|
||||
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
|
||||
while (user)
|
||||
{
|
||||
if (strcmp(user->id.cid, cid) == 0)
|
||||
return user;
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct user* get_user_by_nick(struct hub_info* hub, const char* nick)
|
||||
{
|
||||
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
|
||||
while (user)
|
||||
{
|
||||
if (strcmp(user->id.nick, nick) == 0)
|
||||
return user;
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int send_user_list(struct user* target)
|
||||
{
|
||||
int ret = 1;
|
||||
user_flag_set(target, flag_user_list);
|
||||
struct user* user = (struct user*) list_get_first(target->hub->users->list); /* iterate users - only on INF or PAS msg */
|
||||
while (user)
|
||||
{
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
ret = route_to_user(target, user->info);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
user = (struct user*) list_get_next(user->hub->users->list);
|
||||
}
|
||||
|
||||
if (!target->send_queue_size)
|
||||
{
|
||||
user_flag_unset(target, flag_user_list);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void send_quit_message(struct user* leaving)
|
||||
{
|
||||
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
|
||||
adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));
|
||||
|
||||
if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
|
||||
{
|
||||
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
|
||||
}
|
||||
|
||||
route_to_all(leaving->hub, command);
|
||||
adc_msg_free(command);
|
||||
}
|
||||
|
||||
|
||||
sid_t user_manager_get_free_sid(struct hub_info* hub)
|
||||
{
|
||||
#if 0
|
||||
struct user* user;
|
||||
user = (struct user*) list_get_first(hub->users->list); /* iterate normal users */
|
||||
while (user)
|
||||
{
|
||||
if (user->sid == hub->users->free_sid)
|
||||
{
|
||||
hub->users->free_sid++;
|
||||
if (hub->users->free_sid >= SID_MAX) hub->users->free_sid = 1;
|
||||
break;
|
||||
}
|
||||
user = (struct user*) list_get_next(hub->users->list);
|
||||
}
|
||||
#endif
|
||||
return hub->users->free_sid++;
|
||||
}
|
||||
|
101
src/usermanager.h
Normal file
101
src/usermanager.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, Jan Vidar Krey
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_USER_MANAGER_H
|
||||
#define HAVE_UHUB_USER_MANAGER_H
|
||||
|
||||
struct user_manager
|
||||
{
|
||||
size_t count; /**<< "Number of all fully connected and logged in users" */
|
||||
size_t count_peak; /**<< "Peak number of users" */
|
||||
sid_t free_sid; /**<< "The next available SID." */
|
||||
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
|
||||
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
|
||||
struct linked_list* list; /**<< "Contains all users" */
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the user manager.
|
||||
* @return 0 on success, or -1 if error (out of memory).
|
||||
*/
|
||||
extern int user_manager_init(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Shuts down the user manager.
|
||||
* All users will be disconnected and deleted as part of this.
|
||||
*/
|
||||
extern void user_manager_shutdown(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Generate statistics for logfiles.
|
||||
*/
|
||||
extern void user_manager_stats(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Add a new user to the user manager.
|
||||
*/
|
||||
extern void user_manager_add(struct user* user);
|
||||
|
||||
/**
|
||||
* Remove a user from the user manager.
|
||||
* This user is connected, and will be moved to the leaving queue, pending
|
||||
* all messages in the message queue, and resource cleanup.
|
||||
*/
|
||||
extern void user_manager_remove(struct user* user);
|
||||
|
||||
/**
|
||||
* Returns a free sid for a new user.
|
||||
*/
|
||||
extern sid_t user_manager_get_free_sid(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Lookup a user based on the session ID (sid).
|
||||
* NOTE: This will only search connected users.
|
||||
* @return a user if found, or NULL if not found
|
||||
*/
|
||||
extern struct user* get_user_by_sid(struct hub_info* hub, sid_t sid);
|
||||
|
||||
/**
|
||||
* Lookup a user based on the client ID (cid).
|
||||
* @return a user if found, or NULL if not found
|
||||
*/
|
||||
extern struct user* get_user_by_cid(struct hub_info* hub, const char* cid);
|
||||
|
||||
/**
|
||||
* Lookup a user based on the nick name.
|
||||
* @return a user if found, or NULL if not found
|
||||
*/
|
||||
extern struct user* get_user_by_nick(struct hub_info* hub, const char* nick);
|
||||
|
||||
/**
|
||||
* Send the user list of connected clients to 'user'.
|
||||
* Usually part of the login process.
|
||||
*
|
||||
* @return 1 if sending the user list succeeded, 0 otherwise.
|
||||
*/
|
||||
extern int send_user_list(struct user* user);
|
||||
|
||||
/**
|
||||
* Send a quit message to all connected users when 'user' is
|
||||
* leaving the hub (for whatever reason).
|
||||
*/
|
||||
extern void send_quit_message(struct user* user);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_USER_MANAGER_H */
|
15
version.h
Normal file
15
version.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PRODUCT
|
||||
#define PRODUCT "uHub"
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT_TITLE
|
||||
#define PRODUCT_TITLE "(micro-Hub)"
|
||||
#endif
|
||||
|
||||
#ifndef VERSION
|
||||
#define VERSION "0.2.6-alpha"
|
||||
#endif
|
||||
|
||||
#ifndef COPYRIGHT
|
||||
#define COPYRIGHT "Copyright (c) 2007-2009, Jan Vidar Krey <janvidar@extatic.org>"
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user