@@ -0,0 +1 @@ | |||||
Christian Grothoff |
@@ -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>. |
@@ -0,0 +1,14 @@ | |||||
2012-03-07 gettextize <bug-gnu-gettext@gnu.org> | |||||
* m4/gettext.m4: New file, from gettext-0.18.1. | |||||
* m4/iconv.m4: New file, from gettext-0.18.1. | |||||
* m4/lib-ld.m4: New file, from gettext-0.18.1. | |||||
* m4/lib-link.m4: New file, from gettext-0.18.1. | |||||
* m4/lib-prefix.m4: New file, from gettext-0.18.1. | |||||
* m4/nls.m4: New file, from gettext-0.18.1. | |||||
* m4/po.m4: New file, from gettext-0.18.1. | |||||
* m4/progtest.m4: New file, from gettext-0.18.1. | |||||
* Makefile.am (SUBDIRS): Add po. | |||||
* configure.ac (AC_OUTPUT): Add po/Makefile.in. | |||||
(AM_GNU_GETTEXT_VERSION): Bump to 0.18.1. | |||||
@@ -0,0 +1,365 @@ | |||||
Installation Instructions | |||||
************************* | |||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, | |||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc. | |||||
Copying and distribution of this file, with or without modification, | |||||
are permitted in any medium without royalty provided the copyright | |||||
notice and this notice are preserved. This file is offered as-is, | |||||
without warranty of any kind. | |||||
Basic Installation | |||||
================== | |||||
Briefly, the shell commands `./configure; make; make install' should | |||||
configure, build, and install this package. The following | |||||
more-detailed instructions are generic; see the `README' file for | |||||
instructions specific to this package. Some packages provide this | |||||
`INSTALL' file but do not implement all of the features documented | |||||
below. The lack of an optional feature in a given package is not | |||||
necessarily a bug. More recommendations for GNU packages can be found | |||||
in *note Makefile Conventions: (standards)Makefile Conventions. | |||||
The `configure' shell script attempts to guess correct values for | |||||
various system-dependent variables used during compilation. It uses | |||||
those values to create a `Makefile' in each directory of the package. | |||||
It may also create one or more `.h' files containing system-dependent | |||||
definitions. Finally, it creates a shell script `config.status' that | |||||
you can run in the future to recreate the current configuration, and a | |||||
file `config.log' containing compiler output (useful mainly for | |||||
debugging `configure'). | |||||
It can also use an optional file (typically called `config.cache' | |||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves | |||||
the results of its tests to speed up reconfiguring. Caching is | |||||
disabled by default to prevent problems with accidental use of stale | |||||
cache files. | |||||
If you need to do unusual things to compile the package, please try | |||||
to figure out how `configure' could check whether to do them, and mail | |||||
diffs or instructions to the address given in the `README' so they can | |||||
be considered for the next release. If you are using the cache, and at | |||||
some point `config.cache' contains results you don't want to keep, you | |||||
may remove or edit it. | |||||
The file `configure.ac' (or `configure.in') is used to create | |||||
`configure' by a program called `autoconf'. You need `configure.ac' if | |||||
you want to change it or regenerate `configure' using a newer version | |||||
of `autoconf'. | |||||
The simplest way to compile this package is: | |||||
1. `cd' to the directory containing the package's source code and type | |||||
`./configure' to configure the package for your system. | |||||
Running `configure' might take a while. While running, it prints | |||||
some messages telling which features it is checking for. | |||||
2. Type `make' to compile the package. | |||||
3. Optionally, type `make check' to run any self-tests that come with | |||||
the package, generally using the just-built uninstalled binaries. | |||||
4. Type `make install' to install the programs and any data files and | |||||
documentation. When installing into a prefix owned by root, it is | |||||
recommended that the package be configured and built as a regular | |||||
user, and only the `make install' phase executed with root | |||||
privileges. | |||||
5. Optionally, type `make installcheck' to repeat any self-tests, but | |||||
this time using the binaries in their final installed location. | |||||
This target does not install anything. Running this target as a | |||||
regular user, particularly if the prior `make install' required | |||||
root privileges, verifies that the installation completed | |||||
correctly. | |||||
6. You can remove the program binaries and object files from the | |||||
source code directory by typing `make clean'. To also remove the | |||||
files that `configure' created (so you can compile the package for | |||||
a different kind of computer), type `make distclean'. There is | |||||
also a `make maintainer-clean' target, but that is intended mainly | |||||
for the package's developers. If you use it, you may have to get | |||||
all sorts of other programs in order to regenerate files that came | |||||
with the distribution. | |||||
7. Often, you can also type `make uninstall' to remove the installed | |||||
files again. In practice, not all packages have tested that | |||||
uninstallation works correctly, even though it is required by the | |||||
GNU Coding Standards. | |||||
8. Some packages, particularly those that use Automake, provide `make | |||||
distcheck', which can by used by developers to test that all other | |||||
targets like `make install' and `make uninstall' work correctly. | |||||
This target is generally not run by end users. | |||||
Compilers and Options | |||||
===================== | |||||
Some systems require unusual options for compilation or linking that | |||||
the `configure' script does not know about. Run `./configure --help' | |||||
for details on some of the pertinent environment variables. | |||||
You can give `configure' initial values for configuration parameters | |||||
by setting variables in the command line or in the environment. Here | |||||
is an example: | |||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix | |||||
*Note Defining Variables::, for more details. | |||||
Compiling For Multiple Architectures | |||||
==================================== | |||||
You can compile the package for more than one kind of computer at the | |||||
same time, by placing the object files for each architecture in their | |||||
own directory. To do this, you can use GNU `make'. `cd' to the | |||||
directory where you want the object files and executables to go and run | |||||
the `configure' script. `configure' automatically checks for the | |||||
source code in the directory that `configure' is in and in `..'. This | |||||
is known as a "VPATH" build. | |||||
With a non-GNU `make', it is safer to compile the package for one | |||||
architecture at a time in the source code directory. After you have | |||||
installed the package for one architecture, use `make distclean' before | |||||
reconfiguring for another architecture. | |||||
On MacOS X 10.5 and later systems, you can create libraries and | |||||
executables that work on multiple system types--known as "fat" or | |||||
"universal" binaries--by specifying multiple `-arch' options to the | |||||
compiler but only a single `-arch' option to the preprocessor. Like | |||||
this: | |||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | |||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | |||||
CPP="gcc -E" CXXCPP="g++ -E" | |||||
This is not guaranteed to produce working output in all cases, you | |||||
may have to build one architecture at a time and combine the results | |||||
using the `lipo' tool if you have problems. | |||||
Installation Names | |||||
================== | |||||
By default, `make install' installs the package's commands under | |||||
`/usr/local/bin', include files under `/usr/local/include', etc. You | |||||
can specify an installation prefix other than `/usr/local' by giving | |||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an | |||||
absolute file name. | |||||
You can specify separate installation prefixes for | |||||
architecture-specific files and architecture-independent files. If you | |||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses | |||||
PREFIX as the prefix for installing programs and libraries. | |||||
Documentation and other data files still use the regular prefix. | |||||
In addition, if you use an unusual directory layout you can give | |||||
options like `--bindir=DIR' to specify different values for particular | |||||
kinds of files. Run `configure --help' for a list of the directories | |||||
you can set and what kinds of files go in them. In general, the | |||||
default for these options is expressed in terms of `${prefix}', so that | |||||
specifying just `--prefix' will affect all of the other directory | |||||
specifications that were not explicitly provided. | |||||
The most portable way to affect installation locations is to pass the | |||||
correct locations to `configure'; however, many packages provide one or | |||||
both of the following shortcuts of passing variable assignments to the | |||||
`make install' command line to change installation locations without | |||||
having to reconfigure or recompile. | |||||
The first method involves providing an override variable for each | |||||
affected directory. For example, `make install | |||||
prefix=/alternate/directory' will choose an alternate location for all | |||||
directory configuration variables that were expressed in terms of | |||||
`${prefix}'. Any directories that were specified during `configure', | |||||
but not in terms of `${prefix}', must each be overridden at install | |||||
time for the entire installation to be relocated. The approach of | |||||
makefile variable overrides for each directory variable is required by | |||||
the GNU Coding Standards, and ideally causes no recompilation. | |||||
However, some platforms have known limitations with the semantics of | |||||
shared libraries that end up requiring recompilation when using this | |||||
method, particularly noticeable in packages that use GNU Libtool. | |||||
The second method involves providing the `DESTDIR' variable. For | |||||
example, `make install DESTDIR=/alternate/directory' will prepend | |||||
`/alternate/directory' before all installation names. The approach of | |||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and | |||||
does not work on platforms that have drive letters. On the other hand, | |||||
it does better at avoiding recompilation issues, and works well even | |||||
when some directory options were not specified in terms of `${prefix}' | |||||
at `configure' time. | |||||
Optional Features | |||||
================= | |||||
If the package supports it, you can cause programs to be installed | |||||
with an extra prefix or suffix on their names by giving `configure' the | |||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | |||||
Some packages pay attention to `--enable-FEATURE' options to | |||||
`configure', where FEATURE indicates an optional part of the package. | |||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE | |||||
is something like `gnu-as' or `x' (for the X Window System). The | |||||
`README' should mention any `--enable-' and `--with-' options that the | |||||
package recognizes. | |||||
For packages that use the X Window System, `configure' can usually | |||||
find the X include and library files automatically, but if it doesn't, | |||||
you can use the `configure' options `--x-includes=DIR' and | |||||
`--x-libraries=DIR' to specify their locations. | |||||
Some packages offer the ability to configure how verbose the | |||||
execution of `make' will be. For these packages, running `./configure | |||||
--enable-silent-rules' sets the default to minimal output, which can be | |||||
overridden with `make V=1'; while running `./configure | |||||
--disable-silent-rules' sets the default to verbose, which can be | |||||
overridden with `make V=0'. | |||||
Particular systems | |||||
================== | |||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU | |||||
CC is not installed, it is recommended to use the following options in | |||||
order to use an ANSI C compiler: | |||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500" | |||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX. | |||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot | |||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as | |||||
a workaround. If GNU CC is not installed, it is therefore recommended | |||||
to try | |||||
./configure CC="cc" | |||||
and if that doesn't work, try | |||||
./configure CC="cc -nodtk" | |||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This | |||||
directory contains several dysfunctional programs; working variants of | |||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb' | |||||
in your `PATH', put it _after_ `/usr/bin'. | |||||
On Haiku, software installed for all users goes in `/boot/common', | |||||
not `/usr/local'. It is recommended to use the following options: | |||||
./configure --prefix=/boot/common | |||||
Specifying the System Type | |||||
========================== | |||||
There may be some features `configure' cannot figure out | |||||
automatically, but needs to determine by the type of machine the package | |||||
will run on. Usually, assuming the package is built to be run on the | |||||
_same_ architectures, `configure' can figure that out, but if it prints | |||||
a message saying it cannot guess the machine type, give it the | |||||
`--build=TYPE' option. TYPE can either be a short name for the system | |||||
type, such as `sun4', or a canonical name which has the form: | |||||
CPU-COMPANY-SYSTEM | |||||
where SYSTEM can have one of these forms: | |||||
OS | |||||
KERNEL-OS | |||||
See the file `config.sub' for the possible values of each field. If | |||||
`config.sub' isn't included in this package, then this package doesn't | |||||
need to know the machine type. | |||||
If you are _building_ compiler tools for cross-compiling, you should | |||||
use the option `--target=TYPE' to select the type of system they will | |||||
produce code for. | |||||
If you want to _use_ a cross compiler, that generates code for a | |||||
platform different from the build platform, you should specify the | |||||
"host" platform (i.e., that on which the generated programs will | |||||
eventually be run) with `--host=TYPE'. | |||||
Sharing Defaults | |||||
================ | |||||
If you want to set default values for `configure' scripts to share, | |||||
you can create a site shell script called `config.site' that gives | |||||
default values for variables like `CC', `cache_file', and `prefix'. | |||||
`configure' looks for `PREFIX/share/config.site' if it exists, then | |||||
`PREFIX/etc/config.site' if it exists. Or, you can set the | |||||
`CONFIG_SITE' environment variable to the location of the site script. | |||||
A warning: not all `configure' scripts look for a site script. | |||||
Defining Variables | |||||
================== | |||||
Variables not defined in a site shell script can be set in the | |||||
environment passed to `configure'. However, some packages may run | |||||
configure again during the build, and the customized values of these | |||||
variables may be lost. In order to avoid this problem, you should set | |||||
them in the `configure' command line, using `VAR=value'. For example: | |||||
./configure CC=/usr/local2/bin/gcc | |||||
causes the specified `gcc' to be used as the C compiler (unless it is | |||||
overridden in the site shell script). | |||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to | |||||
an Autoconf bug. Until the bug is fixed you can use this workaround: | |||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash | |||||
`configure' Invocation | |||||
====================== | |||||
`configure' recognizes the following options to control how it | |||||
operates. | |||||
`--help' | |||||
`-h' | |||||
Print a summary of all of the options to `configure', and exit. | |||||
`--help=short' | |||||
`--help=recursive' | |||||
Print a summary of the options unique to this package's | |||||
`configure', and exit. The `short' variant lists options used | |||||
only in the top level, while the `recursive' variant lists options | |||||
also present in any nested packages. | |||||
`--version' | |||||
`-V' | |||||
Print the version of Autoconf used to generate the `configure' | |||||
script, and exit. | |||||
`--cache-file=FILE' | |||||
Enable the cache: use and save the results of the tests in FILE, | |||||
traditionally `config.cache'. FILE defaults to `/dev/null' to | |||||
disable caching. | |||||
`--config-cache' | |||||
`-C' | |||||
Alias for `--cache-file=config.cache'. | |||||
`--quiet' | |||||
`--silent' | |||||
`-q' | |||||
Do not print messages saying which checks are being made. To | |||||
suppress all normal output, redirect it to `/dev/null' (any error | |||||
messages will still be shown). | |||||
`--srcdir=DIR' | |||||
Look for the package's source code in directory DIR. Usually | |||||
`configure' can determine that directory automatically. | |||||
`--prefix=DIR' | |||||
Use DIR as the installation prefix. *note Installation Names:: | |||||
for more details, including other options available for fine-tuning | |||||
the installation locations. | |||||
`--no-create' | |||||
`-n' | |||||
Run the configure checks, but stop before creating any output | |||||
files. | |||||
`configure' also accepts some other, not widely useful, options. Run | |||||
`configure --help' for more details. | |||||
@@ -0,0 +1,9 @@ | |||||
# This Makefile.am is in the public domain | |||||
## Process this file with automake to produce Makefile.in | |||||
SUBDIRS = src po pkgconfig | |||||
EXTRA_DIST = config.rpath \ | |||||
install-sh | |||||
ACLOCAL_AMFLAGS = -I m4 |
@@ -0,0 +1 @@ | |||||
Experimental code for SecuShare. |
@@ -0,0 +1,8 @@ | |||||
#!/bin/sh | |||||
libtoolize --automake --copy --force | |||||
aclocal -I m4 | |||||
autoheader | |||||
autoconf | |||||
automake --add-missing --copy | |||||
@@ -0,0 +1,672 @@ | |||||
#! /bin/sh | |||||
# Output a system dependent set of variables, describing how to set the | |||||
# run time search path of shared libraries in an executable. | |||||
# | |||||
# Copyright 1996-2010 Free Software Foundation, Inc. | |||||
# Taken from GNU libtool, 2001 | |||||
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 | |||||
# | |||||
# This file is free software; the Free Software Foundation gives | |||||
# unlimited permission to copy and/or distribute it, with or without | |||||
# modifications, as long as this notice is preserved. | |||||
# | |||||
# The first argument passed to this file is the canonical host specification, | |||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM | |||||
# or | |||||
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM | |||||
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld | |||||
# should be set by the caller. | |||||
# | |||||
# The set of defined variables is at the end of this script. | |||||
# Known limitations: | |||||
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer | |||||
# than 256 bytes, otherwise the compiler driver will dump core. The only | |||||
# known workaround is to choose shorter directory names for the build | |||||
# directory and/or the installation directory. | |||||
# All known linkers require a `.a' archive for static linking (except MSVC, | |||||
# which needs '.lib'). | |||||
libext=a | |||||
shrext=.so | |||||
host="$1" | |||||
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` | |||||
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` | |||||
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` | |||||
# Code taken from libtool.m4's _LT_CC_BASENAME. | |||||
for cc_temp in $CC""; do | |||||
case $cc_temp in | |||||
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; | |||||
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; | |||||
\-*) ;; | |||||
*) break;; | |||||
esac | |||||
done | |||||
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` | |||||
# Code taken from libtool.m4's _LT_COMPILER_PIC. | |||||
wl= | |||||
if test "$GCC" = yes; then | |||||
wl='-Wl,' | |||||
else | |||||
case "$host_os" in | |||||
aix*) | |||||
wl='-Wl,' | |||||
;; | |||||
darwin*) | |||||
case $cc_basename in | |||||
xlc*) | |||||
wl='-Wl,' | |||||
;; | |||||
esac | |||||
;; | |||||
mingw* | cygwin* | pw32* | os2* | cegcc*) | |||||
;; | |||||
hpux9* | hpux10* | hpux11*) | |||||
wl='-Wl,' | |||||
;; | |||||
irix5* | irix6* | nonstopux*) | |||||
wl='-Wl,' | |||||
;; | |||||
newsos6) | |||||
;; | |||||
linux* | k*bsd*-gnu) | |||||
case $cc_basename in | |||||
ecc*) | |||||
wl='-Wl,' | |||||
;; | |||||
icc* | ifort*) | |||||
wl='-Wl,' | |||||
;; | |||||
lf95*) | |||||
wl='-Wl,' | |||||
;; | |||||
pgcc | pgf77 | pgf90) | |||||
wl='-Wl,' | |||||
;; | |||||
ccc*) | |||||
wl='-Wl,' | |||||
;; | |||||
como) | |||||
wl='-lopt=' | |||||
;; | |||||
*) | |||||
case `$CC -V 2>&1 | sed 5q` in | |||||
*Sun\ C*) | |||||
wl='-Wl,' | |||||
;; | |||||
esac | |||||
;; | |||||
esac | |||||
;; | |||||
osf3* | osf4* | osf5*) | |||||
wl='-Wl,' | |||||
;; | |||||
rdos*) | |||||
;; | |||||
solaris*) | |||||
wl='-Wl,' | |||||
;; | |||||
sunos4*) | |||||
wl='-Qoption ld ' | |||||
;; | |||||
sysv4 | sysv4.2uw2* | sysv4.3*) | |||||
wl='-Wl,' | |||||
;; | |||||
sysv4*MP*) | |||||
;; | |||||
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) | |||||
wl='-Wl,' | |||||
;; | |||||
unicos*) | |||||
wl='-Wl,' | |||||
;; | |||||
uts4*) | |||||
;; | |||||
esac | |||||
fi | |||||
# Code taken from libtool.m4's _LT_LINKER_SHLIBS. | |||||
hardcode_libdir_flag_spec= | |||||
hardcode_libdir_separator= | |||||
hardcode_direct=no | |||||
hardcode_minus_L=no | |||||
case "$host_os" in | |||||
cygwin* | mingw* | pw32* | cegcc*) | |||||
# FIXME: the MSVC++ port hasn't been tested in a loooong time | |||||
# When not using gcc, we currently assume that we are using | |||||
# Microsoft Visual C++. | |||||
if test "$GCC" != yes; then | |||||
with_gnu_ld=no | |||||
fi | |||||
;; | |||||
interix*) | |||||
# we just hope/assume this is gcc and not c89 (= MSVC++) | |||||
with_gnu_ld=yes | |||||
;; | |||||
openbsd*) | |||||
with_gnu_ld=no | |||||
;; | |||||
esac | |||||
ld_shlibs=yes | |||||
if test "$with_gnu_ld" = yes; then | |||||
# Set some defaults for GNU ld with shared library support. These | |||||
# are reset later if shared libraries are not supported. Putting them | |||||
# here allows them to be overridden if necessary. | |||||
# Unlike libtool, we use -rpath here, not --rpath, since the documented | |||||
# option of GNU ld is called -rpath, not --rpath. | |||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' | |||||
case "$host_os" in | |||||
aix[3-9]*) | |||||
# On AIX/PPC, the GNU linker is very broken | |||||
if test "$host_cpu" != ia64; then | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
amigaos*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
hardcode_minus_L=yes | |||||
# Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports | |||||
# that the semantics of dynamic libraries on AmigaOS, at least up | |||||
# to version 4, is to share data among multiple programs linked | |||||
# with the same dynamic library. Since this doesn't match the | |||||
# behavior of shared libraries on other platforms, we cannot use | |||||
# them. | |||||
ld_shlibs=no | |||||
;; | |||||
beos*) | |||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then | |||||
: | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
cygwin* | mingw* | pw32* | cegcc*) | |||||
# hardcode_libdir_flag_spec is actually meaningless, as there is | |||||
# no search path for DLLs. | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then | |||||
: | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
interix[3-9]*) | |||||
hardcode_direct=no | |||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir' | |||||
;; | |||||
gnu* | linux* | k*bsd*-gnu) | |||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then | |||||
: | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
netbsd*) | |||||
;; | |||||
solaris*) | |||||
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then | |||||
ld_shlibs=no | |||||
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then | |||||
: | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) | |||||
case `$LD -v 2>&1` in | |||||
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) | |||||
ld_shlibs=no | |||||
;; | |||||
*) | |||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then | |||||
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
esac | |||||
;; | |||||
sunos4*) | |||||
hardcode_direct=yes | |||||
;; | |||||
*) | |||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then | |||||
: | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
esac | |||||
if test "$ld_shlibs" = no; then | |||||
hardcode_libdir_flag_spec= | |||||
fi | |||||
else | |||||
case "$host_os" in | |||||
aix3*) | |||||
# Note: this linker hardcodes the directories in LIBPATH if there | |||||
# are no directories specified by -L. | |||||
hardcode_minus_L=yes | |||||
if test "$GCC" = yes; then | |||||
# Neither direct hardcoding nor static linking is supported with a | |||||
# broken collect2. | |||||
hardcode_direct=unsupported | |||||
fi | |||||
;; | |||||
aix[4-9]*) | |||||
if test "$host_cpu" = ia64; then | |||||
# On IA64, the linker does run time linking by default, so we don't | |||||
# have to do anything special. | |||||
aix_use_runtimelinking=no | |||||
else | |||||
aix_use_runtimelinking=no | |||||
# Test if we are trying to use run time linking or normal | |||||
# AIX style linking. If -brtl is somewhere in LDFLAGS, we | |||||
# need to do runtime linking. | |||||
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) | |||||
for ld_flag in $LDFLAGS; do | |||||
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then | |||||
aix_use_runtimelinking=yes | |||||
break | |||||
fi | |||||
done | |||||
;; | |||||
esac | |||||
fi | |||||
hardcode_direct=yes | |||||
hardcode_libdir_separator=':' | |||||
if test "$GCC" = yes; then | |||||
case $host_os in aix4.[012]|aix4.[012].*) | |||||
collect2name=`${CC} -print-prog-name=collect2` | |||||
if test -f "$collect2name" && \ | |||||
strings "$collect2name" | grep resolve_lib_name >/dev/null | |||||
then | |||||
# We have reworked collect2 | |||||
: | |||||
else | |||||
# We have old collect2 | |||||
hardcode_direct=unsupported | |||||
hardcode_minus_L=yes | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
hardcode_libdir_separator= | |||||
fi | |||||
;; | |||||
esac | |||||
fi | |||||
# Begin _LT_AC_SYS_LIBPATH_AIX. | |||||
echo 'int main () { return 0; }' > conftest.c | |||||
${CC} ${LDFLAGS} conftest.c -o conftest | |||||
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } | |||||
}'` | |||||
if test -z "$aix_libpath"; then | |||||
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } | |||||
}'` | |||||
fi | |||||
if test -z "$aix_libpath"; then | |||||
aix_libpath="/usr/lib:/lib" | |||||
fi | |||||
rm -f conftest.c conftest | |||||
# End _LT_AC_SYS_LIBPATH_AIX. | |||||
if test "$aix_use_runtimelinking" = yes; then | |||||
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" | |||||
else | |||||
if test "$host_cpu" = ia64; then | |||||
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' | |||||
else | |||||
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" | |||||
fi | |||||
fi | |||||
;; | |||||
amigaos*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
hardcode_minus_L=yes | |||||
# see comment about different semantics on the GNU ld section | |||||
ld_shlibs=no | |||||
;; | |||||
bsdi[45]*) | |||||
;; | |||||
cygwin* | mingw* | pw32* | cegcc*) | |||||
# When not using gcc, we currently assume that we are using | |||||
# Microsoft Visual C++. | |||||
# hardcode_libdir_flag_spec is actually meaningless, as there is | |||||
# no search path for DLLs. | |||||
hardcode_libdir_flag_spec=' ' | |||||
libext=lib | |||||
;; | |||||
darwin* | rhapsody*) | |||||
hardcode_direct=no | |||||
if test "$GCC" = yes ; then | |||||
: | |||||
else | |||||
case $cc_basename in | |||||
xlc*) | |||||
;; | |||||
*) | |||||
ld_shlibs=no | |||||
;; | |||||
esac | |||||
fi | |||||
;; | |||||
dgux*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
;; | |||||
freebsd1*) | |||||
ld_shlibs=no | |||||
;; | |||||
freebsd2.2*) | |||||
hardcode_libdir_flag_spec='-R$libdir' | |||||
hardcode_direct=yes | |||||
;; | |||||
freebsd2*) | |||||
hardcode_direct=yes | |||||
hardcode_minus_L=yes | |||||
;; | |||||
freebsd* | dragonfly*) | |||||
hardcode_libdir_flag_spec='-R$libdir' | |||||
hardcode_direct=yes | |||||
;; | |||||
hpux9*) | |||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
hardcode_direct=yes | |||||
# hardcode_minus_L: Not really in the search PATH, | |||||
# but as the default location of the library. | |||||
hardcode_minus_L=yes | |||||
;; | |||||
hpux10*) | |||||
if test "$with_gnu_ld" = no; then | |||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
hardcode_direct=yes | |||||
# hardcode_minus_L: Not really in the search PATH, | |||||
# but as the default location of the library. | |||||
hardcode_minus_L=yes | |||||
fi | |||||
;; | |||||
hpux11*) | |||||
if test "$with_gnu_ld" = no; then | |||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
case $host_cpu in | |||||
hppa*64*|ia64*) | |||||
hardcode_direct=no | |||||
;; | |||||
*) | |||||
hardcode_direct=yes | |||||
# hardcode_minus_L: Not really in the search PATH, | |||||
# but as the default location of the library. | |||||
hardcode_minus_L=yes | |||||
;; | |||||
esac | |||||
fi | |||||
;; | |||||
irix5* | irix6* | nonstopux*) | |||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
;; | |||||
netbsd*) | |||||
hardcode_libdir_flag_spec='-R$libdir' | |||||
hardcode_direct=yes | |||||
;; | |||||
newsos6) | |||||
hardcode_direct=yes | |||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
;; | |||||
openbsd*) | |||||
if test -f /usr/libexec/ld.so; then | |||||
hardcode_direct=yes | |||||
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then | |||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir' | |||||
else | |||||
case "$host_os" in | |||||
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) | |||||
hardcode_libdir_flag_spec='-R$libdir' | |||||
;; | |||||
*) | |||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir' | |||||
;; | |||||
esac | |||||
fi | |||||
else | |||||
ld_shlibs=no | |||||
fi | |||||
;; | |||||
os2*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
hardcode_minus_L=yes | |||||
;; | |||||
osf3*) | |||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' | |||||
hardcode_libdir_separator=: | |||||
;; | |||||
osf4* | osf5*) | |||||
if test "$GCC" = yes; then | |||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' | |||||
else | |||||
# Both cc and cxx compiler support -rpath directly | |||||
hardcode_libdir_flag_spec='-rpath $libdir' | |||||
fi | |||||
hardcode_libdir_separator=: | |||||
;; | |||||
solaris*) | |||||
hardcode_libdir_flag_spec='-R$libdir' | |||||
;; | |||||
sunos4*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
hardcode_direct=yes | |||||
hardcode_minus_L=yes | |||||
;; | |||||
sysv4) | |||||
case $host_vendor in | |||||
sni) | |||||
hardcode_direct=yes # is this really true??? | |||||
;; | |||||
siemens) | |||||
hardcode_direct=no | |||||
;; | |||||
motorola) | |||||
hardcode_direct=no #Motorola manual says yes, but my tests say they lie | |||||
;; | |||||
esac | |||||
;; | |||||
sysv4.3*) | |||||
;; | |||||
sysv4*MP*) | |||||
if test -d /usr/nec; then | |||||
ld_shlibs=yes | |||||
fi | |||||
;; | |||||
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) | |||||
;; | |||||
sysv5* | sco3.2v5* | sco5v6*) | |||||
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' | |||||
hardcode_libdir_separator=':' | |||||
;; | |||||
uts4*) | |||||
hardcode_libdir_flag_spec='-L$libdir' | |||||
;; | |||||
*) | |||||
ld_shlibs=no | |||||
;; | |||||
esac | |||||
fi | |||||
# Check dynamic linker characteristics | |||||
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. | |||||
# Unlike libtool.m4, here we don't care about _all_ names of the library, but | |||||
# only about the one the linker finds when passed -lNAME. This is the last | |||||
# element of library_names_spec in libtool.m4, or possibly two of them if the | |||||
# linker has special search rules. | |||||
library_names_spec= # the last element of library_names_spec in libtool.m4 | |||||
libname_spec='lib$name' | |||||
case "$host_os" in | |||||
aix3*) | |||||
library_names_spec='$libname.a' | |||||
;; | |||||
aix[4-9]*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
amigaos*) | |||||
library_names_spec='$libname.a' | |||||
;; | |||||
beos*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
bsdi[45]*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
cygwin* | mingw* | pw32* | cegcc*) | |||||
shrext=.dll | |||||
library_names_spec='$libname.dll.a $libname.lib' | |||||
;; | |||||
darwin* | rhapsody*) | |||||
shrext=.dylib | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
dgux*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
freebsd1*) | |||||
;; | |||||
freebsd* | dragonfly*) | |||||
case "$host_os" in | |||||
freebsd[123]*) | |||||
library_names_spec='$libname$shrext$versuffix' ;; | |||||
*) | |||||
library_names_spec='$libname$shrext' ;; | |||||
esac | |||||
;; | |||||
gnu*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
hpux9* | hpux10* | hpux11*) | |||||
case $host_cpu in | |||||
ia64*) | |||||
shrext=.so | |||||
;; | |||||
hppa*64*) | |||||
shrext=.sl | |||||
;; | |||||
*) | |||||
shrext=.sl | |||||
;; | |||||
esac | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
interix[3-9]*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
irix5* | irix6* | nonstopux*) | |||||
library_names_spec='$libname$shrext' | |||||
case "$host_os" in | |||||
irix5* | nonstopux*) | |||||
libsuff= shlibsuff= | |||||
;; | |||||
*) | |||||
case $LD in | |||||
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; | |||||
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; | |||||
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; | |||||
*) libsuff= shlibsuff= ;; | |||||
esac | |||||
;; | |||||
esac | |||||
;; | |||||
linux*oldld* | linux*aout* | linux*coff*) | |||||
;; | |||||
linux* | k*bsd*-gnu) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
knetbsd*-gnu) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
netbsd*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
newsos6) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
nto-qnx*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
openbsd*) | |||||
library_names_spec='$libname$shrext$versuffix' | |||||
;; | |||||
os2*) | |||||
libname_spec='$name' | |||||
shrext=.dll | |||||
library_names_spec='$libname.a' | |||||
;; | |||||
osf3* | osf4* | osf5*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
rdos*) | |||||
;; | |||||
solaris*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
sunos4*) | |||||
library_names_spec='$libname$shrext$versuffix' | |||||
;; | |||||
sysv4 | sysv4.3*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
sysv4*MP*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
uts4*) | |||||
library_names_spec='$libname$shrext' | |||||
;; | |||||
esac | |||||
sed_quote_subst='s/\(["`$\\]\)/\\\1/g' | |||||
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` | |||||
shlibext=`echo "$shrext" | sed -e 's,^\.,,'` | |||||
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` | |||||
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` | |||||
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` | |||||
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF | |||||
# How to pass a linker flag through the compiler. | |||||
wl="$escaped_wl" | |||||
# Static library suffix (normally "a"). | |||||
libext="$libext" | |||||
# Shared library suffix (normally "so"). | |||||
shlibext="$shlibext" | |||||
# Format of library name prefix. | |||||
libname_spec="$escaped_libname_spec" | |||||
# Library names that the linker finds when passed -lNAME. | |||||
library_names_spec="$escaped_library_names_spec" | |||||
# Flag to hardcode \$libdir into a binary during linking. | |||||
# This must work even if \$libdir does not exist. | |||||
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" | |||||
# Whether we need a single -rpath flag with a separated argument. | |||||
hardcode_libdir_separator="$hardcode_libdir_separator" | |||||
# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the | |||||
# resulting binary. | |||||
hardcode_direct="$hardcode_direct" | |||||
# Set to yes if using the -LDIR flag during linking hardcodes DIR into the | |||||
# resulting binary. | |||||
hardcode_minus_L="$hardcode_minus_L" | |||||
EOF |
@@ -0,0 +1,221 @@ | |||||
# This file is part of GNUnet. | |||||
# (C) 2001-2019 Christian Grothoff (and other contributing authors) | |||||
# | |||||
# GNUnet is free software; you can redistribute it and/or modify | |||||
# it under the terms of the GNU General Public License as published | |||||
# by the Free Software Foundation; either version 2, or (at your | |||||
# option) any later version. | |||||
# | |||||
# GNUnet 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 GNUnet; see the file COPYING. If not, write to the | |||||
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |||||
# Boston, MA 02110-1301, USA. | |||||
# | |||||
# | |||||
# Process this file with autoconf to produce a configure script. | |||||
# | |||||
AC_PREREQ(2.61) | |||||
AC_INIT([gnunet-secushare],[0.0.0],[bug-gnunet@gnu.org]) | |||||
AM_INIT_AUTOMAKE([gnunet-secushare], [0.0.0]) | |||||
AM_CONFIG_HEADER(gnunet_secushare_config.h) | |||||
AH_TOP([#define _GNU_SOURCE 1]) | |||||
AC_ISC_POSIX | |||||
AC_PROG_AWK | |||||
AC_PROG_CC | |||||
AC_PROG_MKDIR_P | |||||
AC_PROG_CPP | |||||
AC_PROG_INSTALL | |||||
AC_PROG_LN_S | |||||
AC_PROG_MAKE_SET | |||||
AC_LIBTOOL_WIN32_DLL | |||||
AC_PROG_CC | |||||
AM_PROG_CC_STDC | |||||
AC_HEADER_STDC | |||||
AC_CANONICAL_HOST | |||||
# dynamic libraries/plugins | |||||
AC_DISABLE_STATIC | |||||
AC_PROG_LIBTOOL | |||||
AC_SYS_LARGEFILE | |||||
AC_FUNC_FSEEKO | |||||
CFLAGS="-Wall $CFLAGS" | |||||
# use '-fno-strict-aliasing', but only if the compiler can take it | |||||
if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; | |||||
then | |||||
CFLAGS="-fno-strict-aliasing $CFLAGS" | |||||
fi | |||||
# Check system type | |||||
case "$host_os" in | |||||
*darwin* | *rhapsody* | *macosx*) | |||||
AC_DEFINE_UNQUOTED(OSX,1,[This is an OS X system]) | |||||
CFLAGS="-no-cpp-precomp $CFLAGS" | |||||
LDFLAGS="-flat_namespace -undefined suppress $LDFLAGS" | |||||
;; | |||||
linux*) | |||||
AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) | |||||
;; | |||||
freebsd*) | |||||
AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) | |||||
AC_DEFINE_UNQUOTED(FREEBSD,1,[This is a FreeBSD system]) | |||||
;; | |||||
openbsd*) | |||||
AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) | |||||
AC_DEFINE_UNQUOTED(OPENBSD,1,[This is an OpenBSD system]) | |||||
;; | |||||
netbsd*) | |||||
AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) | |||||
AC_DEFINE_UNQUOTED(NETBSD,1,[This is a NetBSD system]) | |||||
;; | |||||
*solaris*) | |||||
AC_DEFINE_UNQUOTED(SOLARIS,1,[This is a Solaris system]) | |||||
AC_DEFINE_UNQUOTED(_REENTRANT,1,[Need with solaris or errno doesnt work]) | |||||
build_target="solaris" | |||||
;; | |||||
*arm-linux*) | |||||
AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) | |||||
;; | |||||
*cygwin*) | |||||
AC_DEFINE_UNQUOTED(CYGWIN,1,[This is a Cygwin system]) | |||||
AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) | |||||
AC_CHECK_LIB(intl, gettext) | |||||
LDFLAGS="$LDFLAGS -no-undefined" | |||||
build_target="cygwin" | |||||
;; | |||||
*mingw*) | |||||
AC_DEFINE_UNQUOTED(MINGW,1,[This is a MinGW system]) | |||||
AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) | |||||
AC_DEFINE_UNQUOTED(_WIN32,1,[This is a Windows system]) | |||||
AC_CHECK_LIB(intl, gettext) | |||||
LDFLAGS="$LDFLAGS -no-undefined -Wl,--export-all-symbols -lws2_32" | |||||
CFLAGS="-mms-bitfields $CFLAGS" | |||||
build_target="mingw" | |||||
;; | |||||
*) | |||||
AC_MSG_RESULT(Unrecognised OS $host_os) | |||||
AC_DEFINE_UNQUOTED(OTHEROS,1,[Some strange OS]) | |||||
;; | |||||
esac | |||||
AM_CONDITIONAL(MINGW, test "$build_target" = "mingw") | |||||
# check for gettext | |||||
AM_GNU_GETTEXT_VERSION([0.18.1]) | |||||
AM_GNU_GETTEXT([external]) | |||||
AC_CHECK_HEADERS([errno.h stdio.h unistd.h locale.h sys/stat.h sys/types.h langinfo.h libintl.h unistd.h stddef.h argz.h sys/socket.h netinet/in.h stdarg.h]) | |||||
# test for GNUnet core | |||||
gnunet=0 | |||||
lookin=${prefix} | |||||
backup_LDFLAGS="$LDFLAGS" | |||||
backup_CPPFLAGS="$CPPFLAGS" | |||||
GNUNET_LDFLAGS="" | |||||
GNUNET_CPPFLAGS="" | |||||
AC_MSG_CHECKING(for GNUnet core) | |||||
AC_ARG_WITH(gnunet, | |||||
[ --with-gnunet=PFX Base of GNUnet installation], | |||||
[AC_MSG_RESULT([$with_gnunet]) | |||||
case $with_gnunet in | |||||
no) | |||||
lookin="" | |||||
;; | |||||
yes) | |||||
lookin="${prefix}" | |||||
;; | |||||
*) | |||||
lookin="$with_gnunet" | |||||
;; | |||||
esac | |||||
], | |||||
[ | |||||
AC_MSG_RESULT([--with-gnunet not specified]) | |||||
PKG_CHECK_MODULES([GNUNET], [gnunetutil >= 0.9.0], gnunet=1) | |||||
] | |||||
) | |||||
if test "x$gnunet" == "x0" -a ! "x$lookin" == "x" | |||||
then | |||||
AC_MSG_CHECKING(for GNUnet util library in $lookin) | |||||
GNUNET_LDFLAGS="-L${lookin}/lib" | |||||
GNUNET_CPPFLAGS="-I${lookin}/include" | |||||
LDFLAGS="$GNUNET_LDFLAGS $backup_LDFLAGS" | |||||
CPPFLAGS="$GNUNET_CPPFLAGS $backup_CPPFLAGS" | |||||
AC_CHECK_HEADERS([gnunet/gnunet_util_lib.h], | |||||
AC_CHECK_LIB([gnunetutil], [GNUNET_xfree_], | |||||
[ | |||||
gnunet=1 | |||||
EXT_LIB_PATH="-L${lookin}/lib $EXT_LIB_PATH" | |||||
] | |||||
),,[#include <gnunet/platform.h>] | |||||
) | |||||
fi | |||||
if test "x$gnunet" == "x0" | |||||
then | |||||
AC_MSG_ERROR([gnunet-ext requires GNUnet]) | |||||
fi | |||||
# Linker hardening options | |||||
# Currently these options are ELF specific - you can't use this with MacOSX | |||||
AC_ARG_ENABLE(linker-hardening, | |||||
AS_HELP_STRING(--enable-linker-hardening, enable linker security fixups), | |||||
[if test x$enableval = xyes; then | |||||
LDFLAGS="$LDFLAGS -z relro -z now" | |||||
fi]) | |||||
extra_logging=GNUNET_NO | |||||
AC_ARG_ENABLE([logging], | |||||
AS_HELP_STRING([--enable-logging@<:@=value@:>@],[Enable logging calls. Possible values: yes,no,verbose,veryverbose ('yes' is the default)]), | |||||
[AS_IF([test "x$enableval" = "xyes"], [], | |||||
[test "x$enableval" = "xno"], [AC_DEFINE([GNUNET_CULL_LOGGING],[],[Define to cull all logging calls])], | |||||
[test "x$enableval" = "xverbose"], [extra_logging=GNUNET_YES] | |||||
[test "x$enableval" = "xveryverbose"], [extra_logging=\(GNUNET_YES+1\)]) | |||||
], []) | |||||
AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise]) | |||||
AC_SUBST(GNUNET_CPPFLAGS) | |||||
AC_SUBST(GNUNET_LDFLAGS) | |||||
LDFLAGS="$backup_LDFLAGS" | |||||
CPPFLAGS="$backup_CPPFLAGS" | |||||
AC_DEFINE_DIR([PACKAGE_DATA], [datarootdir], [The directory for installing read-only architecture-independent data]) | |||||
# Set PACKAGE_SOURCE_DIR in gnunet_ext_config.h. | |||||
packagesrcdir=`cd $srcdir && pwd` | |||||
AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}", [source dir]) | |||||
AC_OUTPUT([ po/Makefile.in | |||||
Makefile | |||||
pkgconfig/Makefile | |||||
src/Makefile | |||||
src/include/Makefile | |||||
src/multicast/Makefile | |||||
src/multicast/multicast.conf | |||||
src/psycutil/Makefile | |||||
src/psyc/Makefile | |||||
src/psyc/psyc.conf | |||||
src/psycstore/Makefile | |||||
src/psycstore/psycstore.conf | |||||
src/social/Makefile | |||||
src/social/social.conf | |||||
pkgconfig/gnunetmulticast.pc | |||||
pkgconfig/gnunetpsyc.pc | |||||
pkgconfig/gnunetpsycstore.pc | |||||
pkgconfig/gnunetsocial.pc | |||||
]) |
@@ -0,0 +1,35 @@ | |||||
dnl @synopsis AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION]) | |||||
dnl | |||||
dnl This macro _AC_DEFINEs VARNAME to the expansion of the DIR | |||||
dnl variable, taking care of fixing up ${prefix} and such. | |||||
dnl | |||||
dnl VARNAME is offered as both a C preprocessor symbol, and an output | |||||
dnl variable. | |||||
dnl | |||||
dnl Note that the 3 argument form is only supported with autoconf 2.13 | |||||
dnl and later (i.e. only where _AC_DEFINE supports 3 arguments). | |||||
dnl | |||||
dnl Examples: | |||||
dnl | |||||
dnl AC_DEFINE_DIR(DATADIR, datadir) | |||||
dnl AC_DEFINE_DIR(PROG_PATH, bindir, [Location of installed binaries]) | |||||
dnl | |||||
dnl @category Misc | |||||
dnl @author Stepan Kasal <kasal@ucw.cz> | |||||
dnl @author Andreas Schwab <schwab@suse.de> | |||||
dnl @author Guido Draheim <guidod@gmx.de> | |||||
dnl @author Alexandre Oliva | |||||
dnl @version 2005-01-17 | |||||
dnl @license AllPermissive | |||||
AC_DEFUN([AC_DEFINE_DIR], [ | |||||
prefix_NONE= | |||||
exec_prefix_NONE= | |||||
test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix | |||||
test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix | |||||
eval ac_define_dir="\"[$]$2\"" | |||||
AC_SUBST($1, "$ac_define_dir") | |||||
AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3]) | |||||
test "$prefix_NONE" && prefix=NONE | |||||
test "$exec_prefix_NONE" && exec_prefix=NONE | |||||
]) |
@@ -0,0 +1,383 @@ | |||||
# gettext.m4 serial 63 (gettext-0.18) | |||||
dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl | |||||
dnl This file can can be used in projects which are not available under | |||||
dnl the GNU General Public License or the GNU Library General Public | |||||
dnl License but which still want to provide support for the GNU gettext | |||||
dnl functionality. | |||||
dnl Please note that the actual code of the GNU gettext library is covered | |||||
dnl by the GNU Library General Public License, and the rest of the GNU | |||||
dnl gettext package package is covered by the GNU General Public License. | |||||
dnl They are *not* in the public domain. | |||||
dnl Authors: | |||||
dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | |||||
dnl Bruno Haible <haible@clisp.cons.org>, 2000-2006, 2008-2010. | |||||
dnl Macro to add for using GNU gettext. | |||||
dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). | |||||
dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The | |||||
dnl default (if it is not specified or empty) is 'no-libtool'. | |||||
dnl INTLSYMBOL should be 'external' for packages with no intl directory, | |||||
dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. | |||||
dnl If INTLSYMBOL is 'use-libtool', then a libtool library | |||||
dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, | |||||
dnl depending on --{enable,disable}-{shared,static} and on the presence of | |||||
dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library | |||||
dnl $(top_builddir)/intl/libintl.a will be created. | |||||
dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext | |||||
dnl implementations (in libc or libintl) without the ngettext() function | |||||
dnl will be ignored. If NEEDSYMBOL is specified and is | |||||
dnl 'need-formatstring-macros', then GNU gettext implementations that don't | |||||
dnl support the ISO C 99 <inttypes.h> formatstring macros will be ignored. | |||||
dnl INTLDIR is used to find the intl libraries. If empty, | |||||
dnl the value `$(top_builddir)/intl/' is used. | |||||
dnl | |||||
dnl The result of the configuration is one of three cases: | |||||
dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled | |||||
dnl and used. | |||||
dnl Catalog format: GNU --> install in $(datadir) | |||||
dnl Catalog extension: .mo after installation, .gmo in source tree | |||||
dnl 2) GNU gettext has been found in the system's C library. | |||||
dnl Catalog format: GNU --> install in $(datadir) | |||||
dnl Catalog extension: .mo after installation, .gmo in source tree | |||||
dnl 3) No internationalization, always use English msgid. | |||||
dnl Catalog format: none | |||||
dnl Catalog extension: none | |||||
dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. | |||||
dnl The use of .gmo is historical (it was needed to avoid overwriting the | |||||
dnl GNU format catalogs when building on a platform with an X/Open gettext), | |||||
dnl but we keep it in order not to force irrelevant filename changes on the | |||||
dnl maintainers. | |||||
dnl | |||||
AC_DEFUN([AM_GNU_GETTEXT], | |||||
[ | |||||
dnl Argument checking. | |||||
ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , | |||||
[errprint([ERROR: invalid first argument to AM_GNU_GETTEXT | |||||
])])])])]) | |||||
ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old], | |||||
[AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])]) | |||||
ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , | |||||
[errprint([ERROR: invalid second argument to AM_GNU_GETTEXT | |||||
])])])]) | |||||
define([gt_included_intl], | |||||
ifelse([$1], [external], | |||||
ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), | |||||
[yes])) | |||||
define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) | |||||
gt_NEEDS_INIT | |||||
AM_GNU_GETTEXT_NEED([$2]) | |||||
AC_REQUIRE([AM_PO_SUBDIRS])dnl | |||||
ifelse(gt_included_intl, yes, [ | |||||
AC_REQUIRE([AM_INTL_SUBDIR])dnl | |||||
]) | |||||
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. | |||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | |||||
AC_REQUIRE([AC_LIB_RPATH]) | |||||
dnl Sometimes libintl requires libiconv, so first search for libiconv. | |||||
dnl Ideally we would do this search only after the | |||||
dnl if test "$USE_NLS" = "yes"; then | |||||
dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then | |||||
dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT | |||||
dnl the configure script would need to contain the same shell code | |||||
dnl again, outside any 'if'. There are two solutions: | |||||
dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. | |||||
dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. | |||||
dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not | |||||
dnl documented, we avoid it. | |||||
ifelse(gt_included_intl, yes, , [ | |||||
AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) | |||||
]) | |||||
dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. | |||||
gt_INTL_MACOSX | |||||
dnl Set USE_NLS. | |||||
AC_REQUIRE([AM_NLS]) | |||||
ifelse(gt_included_intl, yes, [ | |||||
BUILD_INCLUDED_LIBINTL=no | |||||
USE_INCLUDED_LIBINTL=no | |||||
]) | |||||
LIBINTL= | |||||
LTLIBINTL= | |||||
POSUB= | |||||
dnl Add a version number to the cache macros. | |||||
case " $gt_needs " in | |||||
*" need-formatstring-macros "*) gt_api_version=3 ;; | |||||
*" need-ngettext "*) gt_api_version=2 ;; | |||||
*) gt_api_version=1 ;; | |||||
esac | |||||
gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" | |||||
gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" | |||||
dnl If we use NLS figure out what method | |||||
if test "$USE_NLS" = "yes"; then | |||||
gt_use_preinstalled_gnugettext=no | |||||
ifelse(gt_included_intl, yes, [ | |||||
AC_MSG_CHECKING([whether included gettext is requested]) | |||||
AC_ARG_WITH([included-gettext], | |||||
[ --with-included-gettext use the GNU gettext library included here], | |||||
nls_cv_force_use_gnu_gettext=$withval, | |||||
nls_cv_force_use_gnu_gettext=no) | |||||
AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext]) | |||||
nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" | |||||
if test "$nls_cv_force_use_gnu_gettext" != "yes"; then | |||||
]) | |||||
dnl User does not insist on using GNU NLS library. Figure out what | |||||
dnl to use. If GNU gettext is available we use this. Else we have | |||||
dnl to fall back to GNU NLS library. | |||||
if test $gt_api_version -ge 3; then | |||||
gt_revision_test_code=' | |||||
#ifndef __GNU_GETTEXT_SUPPORTED_REVISION | |||||
#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) | |||||
#endif | |||||
changequote(,)dnl | |||||
typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; | |||||
changequote([,])dnl | |||||
' | |||||
else | |||||
gt_revision_test_code= | |||||
fi | |||||
if test $gt_api_version -ge 2; then | |||||
gt_expression_test_code=' + * ngettext ("", "", 0)' | |||||
else | |||||
gt_expression_test_code= | |||||
fi | |||||
AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], | |||||
[AC_TRY_LINK([#include <libintl.h> | |||||
$gt_revision_test_code | |||||
extern int _nl_msg_cat_cntr; | |||||
extern int *_nl_domain_bindings;], | |||||
[bindtextdomain ("", ""); | |||||
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], | |||||
[eval "$gt_func_gnugettext_libc=yes"], | |||||
[eval "$gt_func_gnugettext_libc=no"])]) | |||||
if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then | |||||
dnl Sometimes libintl requires libiconv, so first search for libiconv. | |||||
ifelse(gt_included_intl, yes, , [ | |||||
AM_ICONV_LINK | |||||
]) | |||||
dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL | |||||
dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) | |||||
dnl because that would add "-liconv" to LIBINTL and LTLIBINTL | |||||
dnl even if libiconv doesn't exist. | |||||
AC_LIB_LINKFLAGS_BODY([intl]) | |||||
AC_CACHE_CHECK([for GNU gettext in libintl], | |||||
[$gt_func_gnugettext_libintl], | |||||
[gt_save_CPPFLAGS="$CPPFLAGS" | |||||
CPPFLAGS="$CPPFLAGS $INCINTL" | |||||
gt_save_LIBS="$LIBS" | |||||
LIBS="$LIBS $LIBINTL" | |||||
dnl Now see whether libintl exists and does not depend on libiconv. | |||||
AC_TRY_LINK([#include <libintl.h> | |||||
$gt_revision_test_code | |||||
extern int _nl_msg_cat_cntr; | |||||
extern | |||||
#ifdef __cplusplus | |||||
"C" | |||||
#endif | |||||
const char *_nl_expand_alias (const char *);], | |||||
[bindtextdomain ("", ""); | |||||
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], | |||||
[eval "$gt_func_gnugettext_libintl=yes"], | |||||
[eval "$gt_func_gnugettext_libintl=no"]) | |||||
dnl Now see whether libintl exists and depends on libiconv. | |||||
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then | |||||
LIBS="$LIBS $LIBICONV" | |||||
AC_TRY_LINK([#include <libintl.h> | |||||
$gt_revision_test_code | |||||
extern int _nl_msg_cat_cntr; | |||||
extern | |||||
#ifdef __cplusplus | |||||
"C" | |||||
#endif | |||||
const char *_nl_expand_alias (const char *);], | |||||
[bindtextdomain ("", ""); | |||||
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], | |||||
[LIBINTL="$LIBINTL $LIBICONV" | |||||
LTLIBINTL="$LTLIBINTL $LTLIBICONV" | |||||
eval "$gt_func_gnugettext_libintl=yes" | |||||
]) | |||||
fi | |||||
CPPFLAGS="$gt_save_CPPFLAGS" | |||||
LIBS="$gt_save_LIBS"]) | |||||
fi | |||||
dnl If an already present or preinstalled GNU gettext() is found, | |||||
dnl use it. But if this macro is used in GNU gettext, and GNU | |||||
dnl gettext is already preinstalled in libintl, we update this | |||||
dnl libintl. (Cf. the install rule in intl/Makefile.in.) | |||||
if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ | |||||
|| { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ | |||||
&& test "$PACKAGE" != gettext-runtime \ | |||||
&& test "$PACKAGE" != gettext-tools; }; then | |||||
gt_use_preinstalled_gnugettext=yes | |||||
else | |||||
dnl Reset the values set by searching for libintl. | |||||
LIBINTL= | |||||
LTLIBINTL= | |||||
INCINTL= | |||||
fi | |||||
ifelse(gt_included_intl, yes, [ | |||||
if test "$gt_use_preinstalled_gnugettext" != "yes"; then | |||||
dnl GNU gettext is not found in the C library. | |||||
dnl Fall back on included GNU gettext library. | |||||
nls_cv_use_gnu_gettext=yes | |||||
fi | |||||
fi | |||||
if test "$nls_cv_use_gnu_gettext" = "yes"; then | |||||
dnl Mark actions used to generate GNU NLS library. | |||||
BUILD_INCLUDED_LIBINTL=yes | |||||
USE_INCLUDED_LIBINTL=yes | |||||
LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" | |||||
LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" | |||||
LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` | |||||
fi | |||||
CATOBJEXT= | |||||
if test "$gt_use_preinstalled_gnugettext" = "yes" \ | |||||
|| test "$nls_cv_use_gnu_gettext" = "yes"; then | |||||
dnl Mark actions to use GNU gettext tools. | |||||
CATOBJEXT=.gmo | |||||
fi | |||||
]) | |||||
if test -n "$INTL_MACOSX_LIBS"; then | |||||
if test "$gt_use_preinstalled_gnugettext" = "yes" \ | |||||
|| test "$nls_cv_use_gnu_gettext" = "yes"; then | |||||
dnl Some extra flags are needed during linking. | |||||
LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" | |||||
LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" | |||||
fi | |||||
fi | |||||
if test "$gt_use_preinstalled_gnugettext" = "yes" \ | |||||
|| test "$nls_cv_use_gnu_gettext" = "yes"; then | |||||
AC_DEFINE([ENABLE_NLS], [1], | |||||
[Define to 1 if translation of program messages to the user's native language | |||||
is requested.]) | |||||
else | |||||
USE_NLS=no | |||||
fi | |||||
fi | |||||
AC_MSG_CHECKING([whether to use NLS]) | |||||
AC_MSG_RESULT([$USE_NLS]) | |||||
if test "$USE_NLS" = "yes"; then | |||||
AC_MSG_CHECKING([where the gettext function comes from]) | |||||
if test "$gt_use_preinstalled_gnugettext" = "yes"; then | |||||
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then | |||||
gt_source="external libintl" | |||||
else | |||||
gt_source="libc" | |||||
fi | |||||
else | |||||
gt_source="included intl directory" | |||||
fi | |||||
AC_MSG_RESULT([$gt_source]) | |||||
fi | |||||
if test "$USE_NLS" = "yes"; then | |||||
if test "$gt_use_preinstalled_gnugettext" = "yes"; then | |||||
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then | |||||
AC_MSG_CHECKING([how to link with libintl]) | |||||
AC_MSG_RESULT([$LIBINTL]) | |||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) | |||||
fi | |||||
dnl For backward compatibility. Some packages may be using this. | |||||
AC_DEFINE([HAVE_GETTEXT], [1], | |||||
[Define if the GNU gettext() function is already present or preinstalled.]) | |||||
AC_DEFINE([HAVE_DCGETTEXT], [1], | |||||
[Define if the GNU dcgettext() function is already present or preinstalled.]) | |||||
fi | |||||
dnl We need to process the po/ directory. | |||||
POSUB=po | |||||
fi | |||||
ifelse(gt_included_intl, yes, [ | |||||
dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL | |||||
dnl to 'yes' because some of the testsuite requires it. | |||||
if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then | |||||
BUILD_INCLUDED_LIBINTL=yes | |||||
fi | |||||
dnl Make all variables we use known to autoconf. | |||||
AC_SUBST([BUILD_INCLUDED_LIBINTL]) | |||||
AC_SUBST([USE_INCLUDED_LIBINTL]) | |||||
AC_SUBST([CATOBJEXT]) | |||||
dnl For backward compatibility. Some configure.ins may be using this. | |||||
nls_cv_header_intl= | |||||
nls_cv_header_libgt= | |||||
dnl For backward compatibility. Some Makefiles may be using this. | |||||
DATADIRNAME=share | |||||
AC_SUBST([DATADIRNAME]) | |||||
dnl For backward compatibility. Some Makefiles may be using this. | |||||
INSTOBJEXT=.mo | |||||
AC_SUBST([INSTOBJEXT]) | |||||
dnl For backward compatibility. Some Makefiles may be using this. | |||||
GENCAT=gencat | |||||
AC_SUBST([GENCAT]) | |||||
dnl For backward compatibility. Some Makefiles may be using this. | |||||
INTLOBJS= | |||||
if test "$USE_INCLUDED_LIBINTL" = yes; then | |||||
INTLOBJS="\$(GETTOBJS)" | |||||
fi | |||||
AC_SUBST([INTLOBJS]) | |||||
dnl Enable libtool support if the surrounding package wishes it. | |||||
INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix | |||||
AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) | |||||
]) | |||||
dnl For backward compatibility. Some Makefiles may be using this. | |||||
INTLLIBS="$LIBINTL" | |||||
AC_SUBST([INTLLIBS]) | |||||
dnl Make all documented variables known to autoconf. | |||||
AC_SUBST([LIBINTL]) | |||||
AC_SUBST([LTLIBINTL]) | |||||
AC_SUBST([POSUB]) | |||||
]) | |||||
dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. | |||||
m4_define([gt_NEEDS_INIT], | |||||
[ | |||||
m4_divert_text([DEFAULTS], [gt_needs=]) | |||||
m4_define([gt_NEEDS_INIT], []) | |||||
]) | |||||
dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) | |||||
AC_DEFUN([AM_GNU_GETTEXT_NEED], | |||||
[ | |||||
m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) | |||||
]) | |||||
dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) | |||||
AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) |
@@ -0,0 +1,214 @@ | |||||
# iconv.m4 serial 11 (gettext-0.18.1) | |||||
dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl From Bruno Haible. | |||||
AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], | |||||
[ | |||||
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. | |||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | |||||
AC_REQUIRE([AC_LIB_RPATH]) | |||||
dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV | |||||
dnl accordingly. | |||||
AC_LIB_LINKFLAGS_BODY([iconv]) | |||||
]) | |||||
AC_DEFUN([AM_ICONV_LINK], | |||||
[ | |||||
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and | |||||
dnl those with the standalone portable GNU libiconv installed). | |||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles | |||||
dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV | |||||
dnl accordingly. | |||||
AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) | |||||
dnl Add $INCICONV to CPPFLAGS before performing the following checks, | |||||
dnl because if the user has installed libiconv and not disabled its use | |||||
dnl via --without-libiconv-prefix, he wants to use it. The first | |||||
dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. | |||||
am_save_CPPFLAGS="$CPPFLAGS" | |||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) | |||||
AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ | |||||
am_cv_func_iconv="no, consider installing GNU libiconv" | |||||
am_cv_lib_iconv=no | |||||
AC_TRY_LINK([#include <stdlib.h> | |||||
#include <iconv.h>], | |||||
[iconv_t cd = iconv_open("",""); | |||||
iconv(cd,NULL,NULL,NULL,NULL); | |||||
iconv_close(cd);], | |||||
[am_cv_func_iconv=yes]) | |||||
if test "$am_cv_func_iconv" != yes; then | |||||
am_save_LIBS="$LIBS" | |||||
LIBS="$LIBS $LIBICONV" | |||||
AC_TRY_LINK([#include <stdlib.h> | |||||
#include <iconv.h>], | |||||
[iconv_t cd = iconv_open("",""); | |||||
iconv(cd,NULL,NULL,NULL,NULL); | |||||
iconv_close(cd);], | |||||
[am_cv_lib_iconv=yes] | |||||
[am_cv_func_iconv=yes]) | |||||
LIBS="$am_save_LIBS" | |||||
fi | |||||
]) | |||||
if test "$am_cv_func_iconv" = yes; then | |||||
AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ | |||||
dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10. | |||||
am_save_LIBS="$LIBS" | |||||
if test $am_cv_lib_iconv = yes; then | |||||
LIBS="$LIBS $LIBICONV" | |||||
fi | |||||
AC_TRY_RUN([ | |||||
#include <iconv.h> | |||||
#include <string.h> | |||||
int main () | |||||
{ | |||||
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful | |||||
returns. */ | |||||
{ | |||||
iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); | |||||
if (cd_utf8_to_88591 != (iconv_t)(-1)) | |||||
{ | |||||
static const char input[] = "\342\202\254"; /* EURO SIGN */ | |||||
char buf[10]; | |||||
const char *inptr = input; | |||||
size_t inbytesleft = strlen (input); | |||||
char *outptr = buf; | |||||
size_t outbytesleft = sizeof (buf); | |||||
size_t res = iconv (cd_utf8_to_88591, | |||||
(char **) &inptr, &inbytesleft, | |||||
&outptr, &outbytesleft); | |||||
if (res == 0) | |||||
return 1; | |||||
} | |||||
} | |||||
/* Test against Solaris 10 bug: Failures are not distinguishable from | |||||
successful returns. */ | |||||
{ | |||||
iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); | |||||
if (cd_ascii_to_88591 != (iconv_t)(-1)) | |||||
{ | |||||
static const char input[] = "\263"; | |||||
char buf[10]; | |||||
const char *inptr = input; | |||||
size_t inbytesleft = strlen (input); | |||||
char *outptr = buf; | |||||
size_t outbytesleft = sizeof (buf); | |||||
size_t res = iconv (cd_ascii_to_88591, | |||||
(char **) &inptr, &inbytesleft, | |||||
&outptr, &outbytesleft); | |||||
if (res == 0) | |||||
return 1; | |||||
} | |||||
} | |||||
#if 0 /* This bug could be worked around by the caller. */ | |||||
/* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ | |||||
{ | |||||
iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); | |||||
if (cd_88591_to_utf8 != (iconv_t)(-1)) | |||||
{ | |||||
static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; | |||||
char buf[50]; | |||||
const char *inptr = input; | |||||
size_t inbytesleft = strlen (input); | |||||
char *outptr = buf; | |||||
size_t outbytesleft = sizeof (buf); | |||||
size_t res = iconv (cd_88591_to_utf8, | |||||
(char **) &inptr, &inbytesleft, | |||||
&outptr, &outbytesleft); | |||||
if ((int)res > 0) | |||||
return 1; | |||||
} | |||||
} | |||||
#endif | |||||
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is | |||||
provided. */ | |||||
if (/* Try standardized names. */ | |||||
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) | |||||
/* Try IRIX, OSF/1 names. */ | |||||
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) | |||||
/* Try AIX names. */ | |||||
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) | |||||
/* Try HP-UX names. */ | |||||
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) | |||||
return 1; | |||||
return 0; | |||||
}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], | |||||
[case "$host_os" in | |||||
aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; | |||||
*) am_cv_func_iconv_works="guessing yes" ;; | |||||
esac]) | |||||
LIBS="$am_save_LIBS" | |||||
]) | |||||
case "$am_cv_func_iconv_works" in | |||||
*no) am_func_iconv=no am_cv_lib_iconv=no ;; | |||||
*) am_func_iconv=yes ;; | |||||
esac | |||||
else | |||||
am_func_iconv=no am_cv_lib_iconv=no | |||||
fi | |||||
if test "$am_func_iconv" = yes; then | |||||
AC_DEFINE([HAVE_ICONV], [1], | |||||
[Define if you have the iconv() function and it works.]) | |||||
fi | |||||
if test "$am_cv_lib_iconv" = yes; then | |||||
AC_MSG_CHECKING([how to link with libiconv]) | |||||
AC_MSG_RESULT([$LIBICONV]) | |||||
else | |||||
dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV | |||||
dnl either. | |||||
CPPFLAGS="$am_save_CPPFLAGS" | |||||
LIBICONV= | |||||
LTLIBICONV= | |||||
fi | |||||
AC_SUBST([LIBICONV]) | |||||
AC_SUBST([LTLIBICONV]) | |||||
]) | |||||
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to | |||||
dnl avoid warnings like | |||||
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". | |||||
dnl This is tricky because of the way 'aclocal' is implemented: | |||||
dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. | |||||
dnl Otherwise aclocal's initial scan pass would miss the macro definition. | |||||
dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. | |||||
dnl Otherwise aclocal would emit many "Use of uninitialized value $1" | |||||
dnl warnings. | |||||
m4_define([gl_iconv_AC_DEFUN], | |||||
m4_version_prereq([2.64], | |||||
[[AC_DEFUN_ONCE( | |||||
[$1], [$2])]], | |||||
[[AC_DEFUN( | |||||
[$1], [$2])]])) | |||||
gl_iconv_AC_DEFUN([AM_ICONV], | |||||
[ | |||||
AM_ICONV_LINK | |||||
if test "$am_cv_func_iconv" = yes; then | |||||
AC_MSG_CHECKING([for iconv declaration]) | |||||
AC_CACHE_VAL([am_cv_proto_iconv], [ | |||||
AC_TRY_COMPILE([ | |||||
#include <stdlib.h> | |||||
#include <iconv.h> | |||||
extern | |||||
#ifdef __cplusplus | |||||
"C" | |||||
#endif | |||||
#if defined(__STDC__) || defined(__cplusplus) | |||||
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); | |||||
#else | |||||
size_t iconv(); | |||||
#endif | |||||
], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) | |||||
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) | |||||
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` | |||||
AC_MSG_RESULT([ | |||||
$am_cv_proto_iconv]) | |||||
AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], | |||||
[Define as const if the declaration of iconv() needs const.]) | |||||
fi | |||||
]) |
@@ -0,0 +1,110 @@ | |||||
# lib-ld.m4 serial 4 (gettext-0.18) | |||||
dnl Copyright (C) 1996-2003, 2009-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl Subroutines of libtool.m4, | |||||
dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision | |||||
dnl with libtool.m4. | |||||
dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. | |||||
AC_DEFUN([AC_LIB_PROG_LD_GNU], | |||||
[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], | |||||
[# I'd rather use --version here, but apparently some GNU ld's only accept -v. | |||||
case `$LD -v 2>&1 </dev/null` in | |||||
*GNU* | *'with BFD'*) | |||||
acl_cv_prog_gnu_ld=yes ;; | |||||
*) | |||||
acl_cv_prog_gnu_ld=no ;; | |||||
esac]) | |||||
with_gnu_ld=$acl_cv_prog_gnu_ld | |||||
]) | |||||
dnl From libtool-1.4. Sets the variable LD. | |||||
AC_DEFUN([AC_LIB_PROG_LD], | |||||
[AC_ARG_WITH([gnu-ld], | |||||
[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], | |||||
test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) | |||||
AC_REQUIRE([AC_PROG_CC])dnl | |||||
AC_REQUIRE([AC_CANONICAL_HOST])dnl | |||||
# Prepare PATH_SEPARATOR. | |||||
# The user is always right. | |||||
if test "${PATH_SEPARATOR+set}" != set; then | |||||
echo "#! /bin/sh" >conf$$.sh | |||||
echo "exit 0" >>conf$$.sh | |||||
chmod +x conf$$.sh | |||||
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then | |||||
PATH_SEPARATOR=';' | |||||
else | |||||
PATH_SEPARATOR=: | |||||
fi | |||||
rm -f conf$$.sh | |||||
fi | |||||
ac_prog=ld | |||||
if test "$GCC" = yes; then | |||||
# Check if gcc -print-prog-name=ld gives a path. | |||||
AC_MSG_CHECKING([for ld used by GCC]) | |||||
case $host in | |||||
*-*-mingw*) | |||||
# gcc leaves a trailing carriage return which upsets mingw | |||||
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; | |||||
*) | |||||
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; | |||||
esac | |||||
case $ac_prog in | |||||
# Accept absolute paths. | |||||
[[\\/]* | [A-Za-z]:[\\/]*)] | |||||
[re_direlt='/[^/][^/]*/\.\./'] | |||||
# Canonicalize the path of ld | |||||
ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` | |||||
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do | |||||
ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` | |||||
done | |||||
test -z "$LD" && LD="$ac_prog" | |||||
;; | |||||
"") | |||||
# If it fails, then pretend we aren't using GCC. | |||||
ac_prog=ld | |||||
;; | |||||
*) | |||||
# If it is relative, then search for the first ld in PATH. | |||||
with_gnu_ld=unknown | |||||
;; | |||||
esac | |||||
elif test "$with_gnu_ld" = yes; then | |||||
AC_MSG_CHECKING([for GNU ld]) | |||||
else | |||||
AC_MSG_CHECKING([for non-GNU ld]) | |||||
fi | |||||
AC_CACHE_VAL([acl_cv_path_LD], | |||||
[if test -z "$LD"; then | |||||
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" | |||||
for ac_dir in $PATH; do | |||||
test -z "$ac_dir" && ac_dir=. | |||||
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then | |||||
acl_cv_path_LD="$ac_dir/$ac_prog" | |||||
# Check to see if the program is GNU ld. I'd rather use --version, | |||||
# but apparently some GNU ld's only accept -v. | |||||
# Break only if it was the GNU/non-GNU ld that we prefer. | |||||
case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in | |||||
*GNU* | *'with BFD'*) | |||||
test "$with_gnu_ld" != no && break ;; | |||||
*) | |||||
test "$with_gnu_ld" != yes && break ;; | |||||
esac | |||||
fi | |||||
done | |||||
IFS="$ac_save_ifs" | |||||
else | |||||
acl_cv_path_LD="$LD" # Let the user override the test with a path. | |||||
fi]) | |||||
LD="$acl_cv_path_LD" | |||||
if test -n "$LD"; then | |||||
AC_MSG_RESULT([$LD]) | |||||
else | |||||
AC_MSG_RESULT([no]) | |||||
fi | |||||
test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) | |||||
AC_LIB_PROG_LD_GNU | |||||
]) |
@@ -0,0 +1,774 @@ | |||||
# lib-link.m4 serial 21 (gettext-0.18) | |||||
dnl Copyright (C) 2001-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl From Bruno Haible. | |||||
AC_PREREQ([2.54]) | |||||
dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and | |||||
dnl the libraries corresponding to explicit and implicit dependencies. | |||||
dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and | |||||
dnl augments the CPPFLAGS variable. | |||||
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname | |||||
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | |||||
AC_DEFUN([AC_LIB_LINKFLAGS], | |||||
[ | |||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | |||||
AC_REQUIRE([AC_LIB_RPATH]) | |||||
pushdef([Name],[translit([$1],[./-], [___])]) | |||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ | |||||
AC_LIB_LINKFLAGS_BODY([$1], [$2]) | |||||
ac_cv_lib[]Name[]_libs="$LIB[]NAME" | |||||
ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" | |||||
ac_cv_lib[]Name[]_cppflags="$INC[]NAME" | |||||
ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" | |||||
]) | |||||
LIB[]NAME="$ac_cv_lib[]Name[]_libs" | |||||
LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" | |||||
INC[]NAME="$ac_cv_lib[]Name[]_cppflags" | |||||
LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" | |||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) | |||||
AC_SUBST([LIB]NAME) | |||||
AC_SUBST([LTLIB]NAME) | |||||
AC_SUBST([LIB]NAME[_PREFIX]) | |||||
dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the | |||||
dnl results of this search when this library appears as a dependency. | |||||
HAVE_LIB[]NAME=yes | |||||
popdef([NAME]) | |||||
popdef([Name]) | |||||
]) | |||||
dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message]) | |||||
dnl searches for libname and the libraries corresponding to explicit and | |||||
dnl implicit dependencies, together with the specified include files and | |||||
dnl the ability to compile and link the specified testcode. The missing-message | |||||
dnl defaults to 'no' and may contain additional hints for the user. | |||||
dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} | |||||
dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and | |||||
dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs | |||||
dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. | |||||
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname | |||||
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | |||||
AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], | |||||
[ | |||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | |||||
AC_REQUIRE([AC_LIB_RPATH]) | |||||
pushdef([Name],[translit([$1],[./-], [___])]) | |||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME | |||||
dnl accordingly. | |||||
AC_LIB_LINKFLAGS_BODY([$1], [$2]) | |||||
dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, | |||||
dnl because if the user has installed lib[]Name and not disabled its use | |||||
dnl via --without-lib[]Name-prefix, he wants to use it. | |||||
ac_save_CPPFLAGS="$CPPFLAGS" | |||||
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) | |||||
AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ | |||||
ac_save_LIBS="$LIBS" | |||||
dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS, | |||||
dnl because these -l options might require -L options that are present in | |||||
dnl LIBS. -l options benefit only from the -L options listed before it. | |||||
dnl Otherwise, add it to the front of LIBS, because it may be a static | |||||
dnl library that depends on another static library that is present in LIBS. | |||||
dnl Static libraries benefit only from the static libraries listed after | |||||
dnl it. | |||||
case " $LIB[]NAME" in | |||||
*" -l"*) LIBS="$LIBS $LIB[]NAME" ;; | |||||
*) LIBS="$LIB[]NAME $LIBS" ;; | |||||
esac | |||||
AC_TRY_LINK([$3], [$4], | |||||
[ac_cv_lib[]Name=yes], | |||||
[ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])']) | |||||
LIBS="$ac_save_LIBS" | |||||
]) | |||||
if test "$ac_cv_lib[]Name" = yes; then | |||||
HAVE_LIB[]NAME=yes | |||||
AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.]) | |||||
AC_MSG_CHECKING([how to link with lib[]$1]) | |||||
AC_MSG_RESULT([$LIB[]NAME]) | |||||
else | |||||
HAVE_LIB[]NAME=no | |||||
dnl If $LIB[]NAME didn't lead to a usable library, we don't need | |||||
dnl $INC[]NAME either. | |||||
CPPFLAGS="$ac_save_CPPFLAGS" | |||||
LIB[]NAME= | |||||
LTLIB[]NAME= | |||||
LIB[]NAME[]_PREFIX= | |||||
fi | |||||
AC_SUBST([HAVE_LIB]NAME) | |||||
AC_SUBST([LIB]NAME) | |||||
AC_SUBST([LTLIB]NAME) | |||||
AC_SUBST([LIB]NAME[_PREFIX]) | |||||
popdef([NAME]) | |||||
popdef([Name]) | |||||
]) | |||||
dnl Determine the platform dependent parameters needed to use rpath: | |||||
dnl acl_libext, | |||||
dnl acl_shlibext, | |||||
dnl acl_hardcode_libdir_flag_spec, | |||||
dnl acl_hardcode_libdir_separator, | |||||
dnl acl_hardcode_direct, | |||||
dnl acl_hardcode_minus_L. | |||||
AC_DEFUN([AC_LIB_RPATH], | |||||
[ | |||||
dnl Tell automake >= 1.10 to complain if config.rpath is missing. | |||||
m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) | |||||
AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS | |||||
AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld | |||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host | |||||
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir | |||||
AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ | |||||
CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ | |||||
${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh | |||||
. ./conftest.sh | |||||
rm -f ./conftest.sh | |||||
acl_cv_rpath=done | |||||
]) | |||||
wl="$acl_cv_wl" | |||||
acl_libext="$acl_cv_libext" | |||||
acl_shlibext="$acl_cv_shlibext" | |||||
acl_libname_spec="$acl_cv_libname_spec" | |||||
acl_library_names_spec="$acl_cv_library_names_spec" | |||||
acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" | |||||
acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" | |||||
acl_hardcode_direct="$acl_cv_hardcode_direct" | |||||
acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" | |||||
dnl Determine whether the user wants rpath handling at all. | |||||
AC_ARG_ENABLE([rpath], | |||||
[ --disable-rpath do not hardcode runtime library paths], | |||||
:, enable_rpath=yes) | |||||
]) | |||||
dnl AC_LIB_FROMPACKAGE(name, package) | |||||
dnl declares that libname comes from the given package. The configure file | |||||
dnl will then not have a --with-libname-prefix option but a | |||||
dnl --with-package-prefix option. Several libraries can come from the same | |||||
dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar | |||||
dnl macro call that searches for libname. | |||||
AC_DEFUN([AC_LIB_FROMPACKAGE], | |||||
[ | |||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
define([acl_frompackage_]NAME, [$2]) | |||||
popdef([NAME]) | |||||
pushdef([PACK],[$2]) | |||||
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
define([acl_libsinpackage_]PACKUP, | |||||
m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1]) | |||||
popdef([PACKUP]) | |||||
popdef([PACK]) | |||||
]) | |||||
dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and | |||||
dnl the libraries corresponding to explicit and implicit dependencies. | |||||
dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. | |||||
dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found | |||||
dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | |||||
AC_DEFUN([AC_LIB_LINKFLAGS_BODY], | |||||
[ | |||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | |||||
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) | |||||
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], | |||||
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | |||||
pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) | |||||
dnl Autoconf >= 2.61 supports dots in --with options. | |||||
pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)]) | |||||
dnl By default, look in $includedir and $libdir. | |||||
use_additional=yes | |||||
AC_LIB_WITH_FINAL_PREFIX([ | |||||
eval additional_includedir=\"$includedir\" | |||||
eval additional_libdir=\"$libdir\" | |||||
]) | |||||
AC_ARG_WITH(P_A_C_K[-prefix], | |||||
[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib | |||||
--without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], | |||||
[ | |||||
if test "X$withval" = "Xno"; then | |||||
use_additional=no | |||||
else | |||||
if test "X$withval" = "X"; then | |||||
AC_LIB_WITH_FINAL_PREFIX([ | |||||
eval additional_includedir=\"$includedir\" | |||||
eval additional_libdir=\"$libdir\" | |||||
]) | |||||
else | |||||
additional_includedir="$withval/include" | |||||
additional_libdir="$withval/$acl_libdirstem" | |||||
if test "$acl_libdirstem2" != "$acl_libdirstem" \ | |||||
&& ! test -d "$withval/$acl_libdirstem"; then | |||||
additional_libdir="$withval/$acl_libdirstem2" | |||||
fi | |||||
fi | |||||
fi | |||||
]) | |||||
dnl Search the library and its dependencies in $additional_libdir and | |||||
dnl $LDFLAGS. Using breadth-first-seach. | |||||
LIB[]NAME= | |||||
LTLIB[]NAME= | |||||
INC[]NAME= | |||||
LIB[]NAME[]_PREFIX= | |||||
dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been | |||||
dnl computed. So it has to be reset here. | |||||
HAVE_LIB[]NAME= | |||||
rpathdirs= | |||||
ltrpathdirs= | |||||
names_already_handled= | |||||
names_next_round='$1 $2' | |||||
while test -n "$names_next_round"; do | |||||
names_this_round="$names_next_round" | |||||
names_next_round= | |||||
for name in $names_this_round; do | |||||
already_handled= | |||||
for n in $names_already_handled; do | |||||
if test "$n" = "$name"; then | |||||
already_handled=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$already_handled"; then | |||||
names_already_handled="$names_already_handled $name" | |||||
dnl See if it was already located by an earlier AC_LIB_LINKFLAGS | |||||
dnl or AC_LIB_HAVE_LINKFLAGS call. | |||||
uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` | |||||
eval value=\"\$HAVE_LIB$uppername\" | |||||
if test -n "$value"; then | |||||
if test "$value" = yes; then | |||||
eval value=\"\$LIB$uppername\" | |||||
test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" | |||||
eval value=\"\$LTLIB$uppername\" | |||||
test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" | |||||
else | |||||
dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined | |||||
dnl that this library doesn't exist. So just drop it. | |||||
: | |||||
fi | |||||
else | |||||
dnl Search the library lib$name in $additional_libdir and $LDFLAGS | |||||
dnl and the already constructed $LIBNAME/$LTLIBNAME. | |||||
found_dir= | |||||
found_la= | |||||
found_so= | |||||
found_a= | |||||
eval libname=\"$acl_libname_spec\" # typically: libname=lib$name | |||||
if test -n "$acl_shlibext"; then | |||||
shrext=".$acl_shlibext" # typically: shrext=.so | |||||
else | |||||
shrext= | |||||
fi | |||||
if test $use_additional = yes; then | |||||
dir="$additional_libdir" | |||||
dnl The same code as in the loop below: | |||||
dnl First look for a shared library. | |||||
if test -n "$acl_shlibext"; then | |||||
if test -f "$dir/$libname$shrext"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$libname$shrext" | |||||
else | |||||
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then | |||||
ver=`(cd "$dir" && \ | |||||
for f in "$libname$shrext".*; do echo "$f"; done \ | |||||
| sed -e "s,^$libname$shrext\\\\.,," \ | |||||
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | |||||
| sed 1q ) 2>/dev/null` | |||||
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$libname$shrext.$ver" | |||||
fi | |||||
else | |||||
eval library_names=\"$acl_library_names_spec\" | |||||
for f in $library_names; do | |||||
if test -f "$dir/$f"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$f" | |||||
break | |||||
fi | |||||
done | |||||
fi | |||||
fi | |||||
fi | |||||
dnl Then look for a static library. | |||||
if test "X$found_dir" = "X"; then | |||||
if test -f "$dir/$libname.$acl_libext"; then | |||||
found_dir="$dir" | |||||
found_a="$dir/$libname.$acl_libext" | |||||
fi | |||||
fi | |||||
if test "X$found_dir" != "X"; then | |||||
if test -f "$dir/$libname.la"; then | |||||
found_la="$dir/$libname.la" | |||||
fi | |||||
fi | |||||
fi | |||||
if test "X$found_dir" = "X"; then | |||||
for x in $LDFLAGS $LTLIB[]NAME; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
case "$x" in | |||||
-L*) | |||||
dir=`echo "X$x" | sed -e 's/^X-L//'` | |||||
dnl First look for a shared library. | |||||
if test -n "$acl_shlibext"; then | |||||
if test -f "$dir/$libname$shrext"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$libname$shrext" | |||||
else | |||||
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then | |||||
ver=`(cd "$dir" && \ | |||||
for f in "$libname$shrext".*; do echo "$f"; done \ | |||||
| sed -e "s,^$libname$shrext\\\\.,," \ | |||||
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | |||||
| sed 1q ) 2>/dev/null` | |||||
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$libname$shrext.$ver" | |||||
fi | |||||
else | |||||
eval library_names=\"$acl_library_names_spec\" | |||||
for f in $library_names; do | |||||
if test -f "$dir/$f"; then | |||||
found_dir="$dir" | |||||
found_so="$dir/$f" | |||||
break | |||||
fi | |||||
done | |||||
fi | |||||
fi | |||||
fi | |||||
dnl Then look for a static library. | |||||
if test "X$found_dir" = "X"; then | |||||
if test -f "$dir/$libname.$acl_libext"; then | |||||
found_dir="$dir" | |||||
found_a="$dir/$libname.$acl_libext" | |||||
fi | |||||
fi | |||||
if test "X$found_dir" != "X"; then | |||||
if test -f "$dir/$libname.la"; then | |||||
found_la="$dir/$libname.la" | |||||
fi | |||||
fi | |||||
;; | |||||
esac | |||||
if test "X$found_dir" != "X"; then | |||||
break | |||||
fi | |||||
done | |||||
fi | |||||
if test "X$found_dir" != "X"; then | |||||
dnl Found the library. | |||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" | |||||
if test "X$found_so" != "X"; then | |||||
dnl Linking with a shared library. We attempt to hardcode its | |||||
dnl directory into the executable's runpath, unless it's the | |||||
dnl standard /usr/lib. | |||||
if test "$enable_rpath" = no \ | |||||
|| test "X$found_dir" = "X/usr/$acl_libdirstem" \ | |||||
|| test "X$found_dir" = "X/usr/$acl_libdirstem2"; then | |||||
dnl No hardcoding is needed. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | |||||
else | |||||
dnl Use an explicit option to hardcode DIR into the resulting | |||||
dnl binary. | |||||
dnl Potentially add DIR to ltrpathdirs. | |||||
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. | |||||
haveit= | |||||
for x in $ltrpathdirs; do | |||||
if test "X$x" = "X$found_dir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
ltrpathdirs="$ltrpathdirs $found_dir" | |||||
fi | |||||
dnl The hardcoding into $LIBNAME is system dependent. | |||||
if test "$acl_hardcode_direct" = yes; then | |||||
dnl Using DIR/libNAME.so during linking hardcodes DIR into the | |||||
dnl resulting binary. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | |||||
else | |||||
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then | |||||
dnl Use an explicit option to hardcode DIR into the resulting | |||||
dnl binary. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | |||||
dnl Potentially add DIR to rpathdirs. | |||||
dnl The rpathdirs will be appended to $LIBNAME at the end. | |||||
haveit= | |||||
for x in $rpathdirs; do | |||||
if test "X$x" = "X$found_dir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
rpathdirs="$rpathdirs $found_dir" | |||||
fi | |||||
else | |||||
dnl Rely on "-L$found_dir". | |||||
dnl But don't add it if it's already contained in the LDFLAGS | |||||
dnl or the already constructed $LIBNAME | |||||
haveit= | |||||
for x in $LDFLAGS $LIB[]NAME; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-L$found_dir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" | |||||
fi | |||||
if test "$acl_hardcode_minus_L" != no; then | |||||
dnl FIXME: Not sure whether we should use | |||||
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" | |||||
dnl here. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | |||||
else | |||||
dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH | |||||
dnl here, because this doesn't fit in flags passed to the | |||||
dnl compiler. So give up. No hardcoding. This affects only | |||||
dnl very old systems. | |||||
dnl FIXME: Not sure whether we should use | |||||
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" | |||||
dnl here. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
else | |||||
if test "X$found_a" != "X"; then | |||||
dnl Linking with a static library. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" | |||||
else | |||||
dnl We shouldn't come here, but anyway it's good to have a | |||||
dnl fallback. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" | |||||
fi | |||||
fi | |||||
dnl Assume the include files are nearby. | |||||
additional_includedir= | |||||
case "$found_dir" in | |||||
*/$acl_libdirstem | */$acl_libdirstem/) | |||||
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` | |||||
if test "$name" = '$1'; then | |||||
LIB[]NAME[]_PREFIX="$basedir" | |||||
fi | |||||
additional_includedir="$basedir/include" | |||||
;; | |||||
*/$acl_libdirstem2 | */$acl_libdirstem2/) | |||||
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` | |||||
if test "$name" = '$1'; then | |||||
LIB[]NAME[]_PREFIX="$basedir" | |||||
fi | |||||
additional_includedir="$basedir/include" | |||||
;; | |||||
esac | |||||
if test "X$additional_includedir" != "X"; then | |||||
dnl Potentially add $additional_includedir to $INCNAME. | |||||
dnl But don't add it | |||||
dnl 1. if it's the standard /usr/include, | |||||
dnl 2. if it's /usr/local/include and we are using GCC on Linux, | |||||
dnl 3. if it's already present in $CPPFLAGS or the already | |||||
dnl constructed $INCNAME, | |||||
dnl 4. if it doesn't exist as a directory. | |||||
if test "X$additional_includedir" != "X/usr/include"; then | |||||
haveit= | |||||
if test "X$additional_includedir" = "X/usr/local/include"; then | |||||
if test -n "$GCC"; then | |||||
case $host_os in | |||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;; | |||||
esac | |||||
fi | |||||
fi | |||||
if test -z "$haveit"; then | |||||
for x in $CPPFLAGS $INC[]NAME; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-I$additional_includedir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
if test -d "$additional_includedir"; then | |||||
dnl Really add $additional_includedir to $INCNAME. | |||||
INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
dnl Look for dependencies. | |||||
if test -n "$found_la"; then | |||||
dnl Read the .la file. It defines the variables | |||||
dnl dlname, library_names, old_library, dependency_libs, current, | |||||
dnl age, revision, installed, dlopen, dlpreopen, libdir. | |||||
save_libdir="$libdir" | |||||
case "$found_la" in | |||||
*/* | *\\*) . "$found_la" ;; | |||||
*) . "./$found_la" ;; | |||||
esac | |||||
libdir="$save_libdir" | |||||
dnl We use only dependency_libs. | |||||
for dep in $dependency_libs; do | |||||
case "$dep" in | |||||
-L*) | |||||
additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` | |||||
dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. | |||||
dnl But don't add it | |||||
dnl 1. if it's the standard /usr/lib, | |||||
dnl 2. if it's /usr/local/lib and we are using GCC on Linux, | |||||
dnl 3. if it's already present in $LDFLAGS or the already | |||||
dnl constructed $LIBNAME, | |||||
dnl 4. if it doesn't exist as a directory. | |||||
if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ | |||||
&& test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then | |||||
haveit= | |||||
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ | |||||
|| test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then | |||||
if test -n "$GCC"; then | |||||
case $host_os in | |||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;; | |||||
esac | |||||
fi | |||||
fi | |||||
if test -z "$haveit"; then | |||||
haveit= | |||||
for x in $LDFLAGS $LIB[]NAME; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-L$additional_libdir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
if test -d "$additional_libdir"; then | |||||
dnl Really add $additional_libdir to $LIBNAME. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" | |||||
fi | |||||
fi | |||||
haveit= | |||||
for x in $LDFLAGS $LTLIB[]NAME; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-L$additional_libdir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
if test -d "$additional_libdir"; then | |||||
dnl Really add $additional_libdir to $LTLIBNAME. | |||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
;; | |||||
-R*) | |||||
dir=`echo "X$dep" | sed -e 's/^X-R//'` | |||||
if test "$enable_rpath" != no; then | |||||
dnl Potentially add DIR to rpathdirs. | |||||
dnl The rpathdirs will be appended to $LIBNAME at the end. | |||||
haveit= | |||||
for x in $rpathdirs; do | |||||
if test "X$x" = "X$dir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
rpathdirs="$rpathdirs $dir" | |||||
fi | |||||
dnl Potentially add DIR to ltrpathdirs. | |||||
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. | |||||
haveit= | |||||
for x in $ltrpathdirs; do | |||||
if test "X$x" = "X$dir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
ltrpathdirs="$ltrpathdirs $dir" | |||||
fi | |||||
fi | |||||
;; | |||||
-l*) | |||||
dnl Handle this in the next round. | |||||
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` | |||||
;; | |||||
*.la) | |||||
dnl Handle this in the next round. Throw away the .la's | |||||
dnl directory; it is already contained in a preceding -L | |||||
dnl option. | |||||
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` | |||||
;; | |||||
*) | |||||
dnl Most likely an immediate library name. | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" | |||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" | |||||
;; | |||||
esac | |||||
done | |||||
fi | |||||
else | |||||
dnl Didn't find the library; assume it is in the system directories | |||||
dnl known to the linker and runtime loader. (All the system | |||||
dnl directories known to the linker should also be known to the | |||||
dnl runtime loader, otherwise the system is severely misconfigured.) | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" | |||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" | |||||
fi | |||||
fi | |||||
fi | |||||
done | |||||
done | |||||
if test "X$rpathdirs" != "X"; then | |||||
if test -n "$acl_hardcode_libdir_separator"; then | |||||
dnl Weird platform: only the last -rpath option counts, the user must | |||||
dnl pass all path elements in one option. We can arrange that for a | |||||
dnl single library, but not when more than one $LIBNAMEs are used. | |||||
alldirs= | |||||
for found_dir in $rpathdirs; do | |||||
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" | |||||
done | |||||
dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. | |||||
acl_save_libdir="$libdir" | |||||
libdir="$alldirs" | |||||
eval flag=\"$acl_hardcode_libdir_flag_spec\" | |||||
libdir="$acl_save_libdir" | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" | |||||
else | |||||
dnl The -rpath options are cumulative. | |||||
for found_dir in $rpathdirs; do | |||||
acl_save_libdir="$libdir" | |||||
libdir="$found_dir" | |||||
eval flag=\"$acl_hardcode_libdir_flag_spec\" | |||||
libdir="$acl_save_libdir" | |||||
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" | |||||
done | |||||
fi | |||||
fi | |||||
if test "X$ltrpathdirs" != "X"; then | |||||
dnl When using libtool, the option that works for both libraries and | |||||
dnl executables is -R. The -R options are cumulative. | |||||
for found_dir in $ltrpathdirs; do | |||||
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" | |||||
done | |||||
fi | |||||
popdef([P_A_C_K]) | |||||
popdef([PACKLIBS]) | |||||
popdef([PACKUP]) | |||||
popdef([PACK]) | |||||
popdef([NAME]) | |||||
]) | |||||
dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, | |||||
dnl unless already present in VAR. | |||||
dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes | |||||
dnl contains two or three consecutive elements that belong together. | |||||
AC_DEFUN([AC_LIB_APPENDTOVAR], | |||||
[ | |||||
for element in [$2]; do | |||||
haveit= | |||||
for x in $[$1]; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X$element"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
[$1]="${[$1]}${[$1]:+ }$element" | |||||
fi | |||||
done | |||||
]) | |||||
dnl For those cases where a variable contains several -L and -l options | |||||
dnl referring to unknown libraries and directories, this macro determines the | |||||
dnl necessary additional linker options for the runtime path. | |||||
dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) | |||||
dnl sets LDADDVAR to linker options needed together with LIBSVALUE. | |||||
dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, | |||||
dnl otherwise linking without libtool is assumed. | |||||
AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], | |||||
[ | |||||
AC_REQUIRE([AC_LIB_RPATH]) | |||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | |||||
$1= | |||||
if test "$enable_rpath" != no; then | |||||
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then | |||||
dnl Use an explicit option to hardcode directories into the resulting | |||||
dnl binary. | |||||
rpathdirs= | |||||
next= | |||||
for opt in $2; do | |||||
if test -n "$next"; then | |||||
dir="$next" | |||||
dnl No need to hardcode the standard /usr/lib. | |||||
if test "X$dir" != "X/usr/$acl_libdirstem" \ | |||||
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then | |||||
rpathdirs="$rpathdirs $dir" | |||||
fi | |||||
next= | |||||
else | |||||
case $opt in | |||||
-L) next=yes ;; | |||||
-L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` | |||||
dnl No need to hardcode the standard /usr/lib. | |||||
if test "X$dir" != "X/usr/$acl_libdirstem" \ | |||||
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then | |||||
rpathdirs="$rpathdirs $dir" | |||||
fi | |||||
next= ;; | |||||
*) next= ;; | |||||
esac | |||||
fi | |||||
done | |||||
if test "X$rpathdirs" != "X"; then | |||||
if test -n ""$3""; then | |||||
dnl libtool is used for linking. Use -R options. | |||||
for dir in $rpathdirs; do | |||||
$1="${$1}${$1:+ }-R$dir" | |||||
done | |||||
else | |||||
dnl The linker is used for linking directly. | |||||
if test -n "$acl_hardcode_libdir_separator"; then | |||||
dnl Weird platform: only the last -rpath option counts, the user | |||||
dnl must pass all path elements in one option. | |||||
alldirs= | |||||
for dir in $rpathdirs; do | |||||
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" | |||||
done | |||||
acl_save_libdir="$libdir" | |||||
libdir="$alldirs" | |||||
eval flag=\"$acl_hardcode_libdir_flag_spec\" | |||||
libdir="$acl_save_libdir" | |||||
$1="$flag" | |||||
else | |||||
dnl The -rpath options are cumulative. | |||||
for dir in $rpathdirs; do | |||||
acl_save_libdir="$libdir" | |||||
libdir="$dir" | |||||
eval flag=\"$acl_hardcode_libdir_flag_spec\" | |||||
libdir="$acl_save_libdir" | |||||
$1="${$1}${$1:+ }$flag" | |||||
done | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
AC_SUBST([$1]) | |||||
]) |
@@ -0,0 +1,224 @@ | |||||
# lib-prefix.m4 serial 7 (gettext-0.18) | |||||
dnl Copyright (C) 2001-2005, 2008-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl From Bruno Haible. | |||||
dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and | |||||
dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't | |||||
dnl require excessive bracketing. | |||||
ifdef([AC_HELP_STRING], | |||||
[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], | |||||
[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) | |||||
dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed | |||||
dnl to access previously installed libraries. The basic assumption is that | |||||
dnl a user will want packages to use other packages he previously installed | |||||
dnl with the same --prefix option. | |||||
dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate | |||||
dnl libraries, but is otherwise very convenient. | |||||
AC_DEFUN([AC_LIB_PREFIX], | |||||
[ | |||||
AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) | |||||
AC_REQUIRE([AC_PROG_CC]) | |||||
AC_REQUIRE([AC_CANONICAL_HOST]) | |||||
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | |||||
AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | |||||
dnl By default, look in $includedir and $libdir. | |||||
use_additional=yes | |||||
AC_LIB_WITH_FINAL_PREFIX([ | |||||
eval additional_includedir=\"$includedir\" | |||||
eval additional_libdir=\"$libdir\" | |||||
]) | |||||
AC_LIB_ARG_WITH([lib-prefix], | |||||
[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib | |||||
--without-lib-prefix don't search for libraries in includedir and libdir], | |||||
[ | |||||
if test "X$withval" = "Xno"; then | |||||
use_additional=no | |||||
else | |||||
if test "X$withval" = "X"; then | |||||
AC_LIB_WITH_FINAL_PREFIX([ | |||||
eval additional_includedir=\"$includedir\" | |||||
eval additional_libdir=\"$libdir\" | |||||
]) | |||||
else | |||||
additional_includedir="$withval/include" | |||||
additional_libdir="$withval/$acl_libdirstem" | |||||
fi | |||||
fi | |||||
]) | |||||
if test $use_additional = yes; then | |||||
dnl Potentially add $additional_includedir to $CPPFLAGS. | |||||
dnl But don't add it | |||||
dnl 1. if it's the standard /usr/include, | |||||
dnl 2. if it's already present in $CPPFLAGS, | |||||
dnl 3. if it's /usr/local/include and we are using GCC on Linux, | |||||
dnl 4. if it doesn't exist as a directory. | |||||
if test "X$additional_includedir" != "X/usr/include"; then | |||||
haveit= | |||||
for x in $CPPFLAGS; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-I$additional_includedir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
if test "X$additional_includedir" = "X/usr/local/include"; then | |||||
if test -n "$GCC"; then | |||||
case $host_os in | |||||
linux* | gnu* | k*bsd*-gnu) haveit=yes;; | |||||
esac | |||||
fi | |||||
fi | |||||
if test -z "$haveit"; then | |||||
if test -d "$additional_includedir"; then | |||||
dnl Really add $additional_includedir to $CPPFLAGS. | |||||
CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
dnl Potentially add $additional_libdir to $LDFLAGS. | |||||
dnl But don't add it | |||||
dnl 1. if it's the standard /usr/lib, | |||||
dnl 2. if it's already present in $LDFLAGS, | |||||
dnl 3. if it's /usr/local/lib and we are using GCC on Linux, | |||||
dnl 4. if it doesn't exist as a directory. | |||||
if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then | |||||
haveit= | |||||
for x in $LDFLAGS; do | |||||
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | |||||
if test "X$x" = "X-L$additional_libdir"; then | |||||
haveit=yes | |||||
break | |||||
fi | |||||
done | |||||
if test -z "$haveit"; then | |||||
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then | |||||
if test -n "$GCC"; then | |||||
case $host_os in | |||||
linux*) haveit=yes;; | |||||
esac | |||||
fi | |||||
fi | |||||
if test -z "$haveit"; then | |||||
if test -d "$additional_libdir"; then | |||||
dnl Really add $additional_libdir to $LDFLAGS. | |||||
LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
fi | |||||
]) | |||||
dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, | |||||
dnl acl_final_exec_prefix, containing the values to which $prefix and | |||||
dnl $exec_prefix will expand at the end of the configure script. | |||||
AC_DEFUN([AC_LIB_PREPARE_PREFIX], | |||||
[ | |||||
dnl Unfortunately, prefix and exec_prefix get only finally determined | |||||
dnl at the end of configure. | |||||
if test "X$prefix" = "XNONE"; then | |||||
acl_final_prefix="$ac_default_prefix" | |||||
else | |||||
acl_final_prefix="$prefix" | |||||
fi | |||||
if test "X$exec_prefix" = "XNONE"; then | |||||
acl_final_exec_prefix='${prefix}' | |||||
else | |||||
acl_final_exec_prefix="$exec_prefix" | |||||
fi | |||||
acl_save_prefix="$prefix" | |||||
prefix="$acl_final_prefix" | |||||
eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" | |||||
prefix="$acl_save_prefix" | |||||
]) | |||||
dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the | |||||
dnl variables prefix and exec_prefix bound to the values they will have | |||||
dnl at the end of the configure script. | |||||
AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], | |||||
[ | |||||
acl_save_prefix="$prefix" | |||||
prefix="$acl_final_prefix" | |||||
acl_save_exec_prefix="$exec_prefix" | |||||
exec_prefix="$acl_final_exec_prefix" | |||||
$1 | |||||
exec_prefix="$acl_save_exec_prefix" | |||||
prefix="$acl_save_prefix" | |||||
]) | |||||
dnl AC_LIB_PREPARE_MULTILIB creates | |||||
dnl - a variable acl_libdirstem, containing the basename of the libdir, either | |||||
dnl "lib" or "lib64" or "lib/64", | |||||
dnl - a variable acl_libdirstem2, as a secondary possible value for | |||||
dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or | |||||
dnl "lib/amd64". | |||||
AC_DEFUN([AC_LIB_PREPARE_MULTILIB], | |||||
[ | |||||
dnl There is no formal standard regarding lib and lib64. | |||||
dnl On glibc systems, the current practice is that on a system supporting | |||||
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under | |||||
dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine | |||||
dnl the compiler's default mode by looking at the compiler's library search | |||||
dnl path. If at least one of its elements ends in /lib64 or points to a | |||||
dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. | |||||
dnl Otherwise we use the default, namely "lib". | |||||
dnl On Solaris systems, the current practice is that on a system supporting | |||||
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under | |||||
dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or | |||||
dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. | |||||
AC_REQUIRE([AC_CANONICAL_HOST]) | |||||
acl_libdirstem=lib | |||||
acl_libdirstem2= | |||||
case "$host_os" in | |||||
solaris*) | |||||
dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment | |||||
dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>. | |||||
dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." | |||||
dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the | |||||
dnl symlink is missing, so we set acl_libdirstem2 too. | |||||
AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], | |||||
[AC_EGREP_CPP([sixtyfour bits], [ | |||||
#ifdef _LP64 | |||||
sixtyfour bits | |||||
#endif | |||||
], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) | |||||
]) | |||||
if test $gl_cv_solaris_64bit = yes; then | |||||
acl_libdirstem=lib/64 | |||||
case "$host_cpu" in | |||||
sparc*) acl_libdirstem2=lib/sparcv9 ;; | |||||
i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; | |||||
esac | |||||
fi | |||||
;; | |||||
*) | |||||
searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` | |||||
if test -n "$searchpath"; then | |||||
acl_save_IFS="${IFS= }"; IFS=":" | |||||
for searchdir in $searchpath; do | |||||
if test -d "$searchdir"; then | |||||
case "$searchdir" in | |||||
*/lib64/ | */lib64 ) acl_libdirstem=lib64 ;; | |||||
*/../ | */.. ) | |||||
# Better ignore directories of this form. They are misleading. | |||||
;; | |||||
*) searchdir=`cd "$searchdir" && pwd` | |||||
case "$searchdir" in | |||||
*/lib64 ) acl_libdirstem=lib64 ;; | |||||
esac ;; | |||||
esac | |||||
fi | |||||
done | |||||
IFS="$acl_save_IFS" | |||||
fi | |||||
;; | |||||
esac | |||||
test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" | |||||
]) |
@@ -0,0 +1,437 @@ | |||||
# Helper functions for option handling. -*- Autoconf -*- | |||||
# | |||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software | |||||
# Foundation, Inc. | |||||
# Written by Gary V. Vaughan, 2004 | |||||
# | |||||
# This file is free software; the Free Software Foundation gives | |||||
# unlimited permission to copy and/or distribute it, with or without | |||||
# modifications, as long as this notice is preserved. | |||||
# serial 8 ltoptions.m4 | |||||
# This is to help aclocal find these macros, as it can't see m4_define. | |||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) | |||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) | |||||
# ------------------------------------------ | |||||
m4_define([_LT_MANGLE_OPTION], | |||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) | |||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) | |||||
# --------------------------------------- | |||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a | |||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are | |||||
# saved as a flag. | |||||
m4_define([_LT_SET_OPTION], | |||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl | |||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), | |||||
_LT_MANGLE_DEFUN([$1], [$2]), | |||||
[m4_warning([Unknown $1 option '$2'])])[]dnl | |||||
]) | |||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) | |||||
# ------------------------------------------------------------ | |||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. | |||||
m4_define([_LT_IF_OPTION], | |||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) | |||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) | |||||
# ------------------------------------------------------- | |||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME | |||||
# are set. | |||||
m4_define([_LT_UNLESS_OPTIONS], | |||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), | |||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), | |||||
[m4_define([$0_found])])])[]dnl | |||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 | |||||
])[]dnl | |||||
]) | |||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) | |||||
# ---------------------------------------- | |||||
# OPTION-LIST is a space-separated list of Libtool options associated | |||||
# with MACRO-NAME. If any OPTION has a matching handler declared with | |||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about | |||||
# the unknown option and exit. | |||||
m4_defun([_LT_SET_OPTIONS], | |||||
[# Set options | |||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), | |||||
[_LT_SET_OPTION([$1], _LT_Option)]) | |||||
m4_if([$1],[LT_INIT],[ | |||||
dnl | |||||
dnl Simply set some default values (i.e off) if boolean options were not | |||||
dnl specified: | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no | |||||
]) | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no | |||||
]) | |||||
dnl | |||||
dnl If no reference was made to various pairs of opposing options, then | |||||
dnl we run the default mode handler for the pair. For example, if neither | |||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared | |||||
dnl archives by default: | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], | |||||
[_LT_ENABLE_FAST_INSTALL]) | |||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], | |||||
[_LT_WITH_AIX_SONAME([aix])]) | |||||
]) | |||||
])# _LT_SET_OPTIONS | |||||
## --------------------------------- ## | |||||
## Macros to handle LT_INIT options. ## | |||||
## --------------------------------- ## | |||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) | |||||
# ----------------------------------------- | |||||
m4_define([_LT_MANGLE_DEFUN], | |||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) | |||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) | |||||
# ----------------------------------------------- | |||||
m4_define([LT_OPTION_DEFINE], | |||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl | |||||
])# LT_OPTION_DEFINE | |||||
# dlopen | |||||
# ------ | |||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes | |||||
]) | |||||
AU_DEFUN([AC_LIBTOOL_DLOPEN], | |||||
[_LT_SET_OPTION([LT_INIT], [dlopen]) | |||||
AC_DIAGNOSE([obsolete], | |||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you | |||||
put the 'dlopen' option into LT_INIT's first parameter.]) | |||||
]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) | |||||
# win32-dll | |||||
# --------- | |||||
# Declare package support for building win32 dll's. | |||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll], | |||||
[enable_win32_dll=yes | |||||
case $host in | |||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) | |||||
AC_CHECK_TOOL(AS, as, false) | |||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false) | |||||
AC_CHECK_TOOL(OBJDUMP, objdump, false) | |||||
;; | |||||
esac | |||||
test -z "$AS" && AS=as | |||||
_LT_DECL([], [AS], [1], [Assembler program])dnl | |||||
test -z "$DLLTOOL" && DLLTOOL=dlltool | |||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl | |||||
test -z "$OBJDUMP" && OBJDUMP=objdump | |||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl | |||||
])# win32-dll | |||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL], | |||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl | |||||
_LT_SET_OPTION([LT_INIT], [win32-dll]) | |||||
AC_DIAGNOSE([obsolete], | |||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you | |||||
put the 'win32-dll' option into LT_INIT's first parameter.]) | |||||
]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) | |||||
# _LT_ENABLE_SHARED([DEFAULT]) | |||||
# ---------------------------- | |||||
# implement the --enable-shared flag, and supports the 'shared' and | |||||
# 'disable-shared' LT_INIT options. | |||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. | |||||
m4_define([_LT_ENABLE_SHARED], | |||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl | |||||
AC_ARG_ENABLE([shared], | |||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], | |||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], | |||||
[p=${PACKAGE-default} | |||||
case $enableval in | |||||
yes) enable_shared=yes ;; | |||||
no) enable_shared=no ;; | |||||
*) | |||||
enable_shared=no | |||||
# Look at the argument we got. We use all the common list separators. | |||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, | |||||
for pkg in $enableval; do | |||||
IFS=$lt_save_ifs | |||||
if test "X$pkg" = "X$p"; then | |||||
enable_shared=yes | |||||
fi | |||||
done | |||||
IFS=$lt_save_ifs | |||||
;; | |||||
esac], | |||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT) | |||||
_LT_DECL([build_libtool_libs], [enable_shared], [0], | |||||
[Whether or not to build shared libraries]) | |||||
])# _LT_ENABLE_SHARED | |||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) | |||||
# Old names: | |||||
AC_DEFUN([AC_ENABLE_SHARED], | |||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) | |||||
]) | |||||
AC_DEFUN([AC_DISABLE_SHARED], | |||||
[_LT_SET_OPTION([LT_INIT], [disable-shared]) | |||||
]) | |||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) | |||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AM_ENABLE_SHARED], []) | |||||
dnl AC_DEFUN([AM_DISABLE_SHARED], []) | |||||
# _LT_ENABLE_STATIC([DEFAULT]) | |||||
# ---------------------------- | |||||
# implement the --enable-static flag, and support the 'static' and | |||||
# 'disable-static' LT_INIT options. | |||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. | |||||
m4_define([_LT_ENABLE_STATIC], | |||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl | |||||
AC_ARG_ENABLE([static], | |||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], | |||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], | |||||
[p=${PACKAGE-default} | |||||
case $enableval in | |||||
yes) enable_static=yes ;; | |||||
no) enable_static=no ;; | |||||
*) | |||||
enable_static=no | |||||
# Look at the argument we got. We use all the common list separators. | |||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, | |||||
for pkg in $enableval; do | |||||
IFS=$lt_save_ifs | |||||
if test "X$pkg" = "X$p"; then | |||||
enable_static=yes | |||||
fi | |||||
done | |||||
IFS=$lt_save_ifs | |||||
;; | |||||
esac], | |||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT) | |||||
_LT_DECL([build_old_libs], [enable_static], [0], | |||||
[Whether or not to build static libraries]) | |||||
])# _LT_ENABLE_STATIC | |||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) | |||||
# Old names: | |||||
AC_DEFUN([AC_ENABLE_STATIC], | |||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) | |||||
]) | |||||
AC_DEFUN([AC_DISABLE_STATIC], | |||||
[_LT_SET_OPTION([LT_INIT], [disable-static]) | |||||
]) | |||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) | |||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AM_ENABLE_STATIC], []) | |||||
dnl AC_DEFUN([AM_DISABLE_STATIC], []) | |||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT]) | |||||
# ---------------------------------- | |||||
# implement the --enable-fast-install flag, and support the 'fast-install' | |||||
# and 'disable-fast-install' LT_INIT options. | |||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. | |||||
m4_define([_LT_ENABLE_FAST_INSTALL], | |||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl | |||||
AC_ARG_ENABLE([fast-install], | |||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], | |||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], | |||||
[p=${PACKAGE-default} | |||||
case $enableval in | |||||
yes) enable_fast_install=yes ;; | |||||
no) enable_fast_install=no ;; | |||||
*) | |||||
enable_fast_install=no | |||||
# Look at the argument we got. We use all the common list separators. | |||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, | |||||
for pkg in $enableval; do | |||||
IFS=$lt_save_ifs | |||||
if test "X$pkg" = "X$p"; then | |||||
enable_fast_install=yes | |||||
fi | |||||
done | |||||
IFS=$lt_save_ifs | |||||
;; | |||||
esac], | |||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) | |||||
_LT_DECL([fast_install], [enable_fast_install], [0], | |||||
[Whether or not to optimize for fast installation])dnl | |||||
])# _LT_ENABLE_FAST_INSTALL | |||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) | |||||
# Old names: | |||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL], | |||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) | |||||
AC_DIAGNOSE([obsolete], | |||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put | |||||
the 'fast-install' option into LT_INIT's first parameter.]) | |||||
]) | |||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL], | |||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) | |||||
AC_DIAGNOSE([obsolete], | |||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put | |||||
the 'disable-fast-install' option into LT_INIT's first parameter.]) | |||||
]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) | |||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) | |||||
# _LT_WITH_AIX_SONAME([DEFAULT]) | |||||
# ---------------------------------- | |||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix' | |||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT | |||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. | |||||
m4_define([_LT_WITH_AIX_SONAME], | |||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl | |||||
shared_archive_member_spec= | |||||
case $host,$enable_shared in | |||||
power*-*-aix[[5-9]]*,yes) | |||||
AC_MSG_CHECKING([which variant of shared library versioning to provide]) | |||||
AC_ARG_WITH([aix-soname], | |||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both], | |||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], | |||||
[case $withval in | |||||
aix|svr4|both) | |||||
;; | |||||
*) | |||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname]) | |||||
;; | |||||
esac | |||||
lt_cv_with_aix_soname=$with_aix_soname], | |||||
[AC_CACHE_VAL([lt_cv_with_aix_soname], | |||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) | |||||
with_aix_soname=$lt_cv_with_aix_soname]) | |||||
AC_MSG_RESULT([$with_aix_soname]) | |||||
if test aix != "$with_aix_soname"; then | |||||
# For the AIX way of multilib, we name the shared archive member | |||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', | |||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. | |||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, | |||||
# the AIX toolchain works better with OBJECT_MODE set (default 32). | |||||
if test 64 = "${OBJECT_MODE-32}"; then | |||||
shared_archive_member_spec=shr_64 | |||||
else | |||||
shared_archive_member_spec=shr | |||||
fi | |||||
fi | |||||
;; | |||||
*) | |||||
with_aix_soname=aix | |||||
;; | |||||
esac | |||||
_LT_DECL([], [shared_archive_member_spec], [0], | |||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl | |||||
])# _LT_WITH_AIX_SONAME | |||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) | |||||
# _LT_WITH_PIC([MODE]) | |||||
# -------------------- | |||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' | |||||
# LT_INIT options. | |||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. | |||||
m4_define([_LT_WITH_PIC], | |||||
[AC_ARG_WITH([pic], | |||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], | |||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])], | |||||
[lt_p=${PACKAGE-default} | |||||
case $withval in | |||||
yes|no) pic_mode=$withval ;; | |||||
*) | |||||
pic_mode=default | |||||
# Look at the argument we got. We use all the common list separators. | |||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, | |||||
for lt_pkg in $withval; do | |||||
IFS=$lt_save_ifs | |||||
if test "X$lt_pkg" = "X$lt_p"; then | |||||
pic_mode=yes | |||||
fi | |||||
done | |||||
IFS=$lt_save_ifs | |||||
;; | |||||
esac], | |||||
[pic_mode=m4_default([$1], [default])]) | |||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl | |||||
])# _LT_WITH_PIC | |||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) | |||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) | |||||
# Old name: | |||||
AU_DEFUN([AC_LIBTOOL_PICMODE], | |||||
[_LT_SET_OPTION([LT_INIT], [pic-only]) | |||||
AC_DIAGNOSE([obsolete], | |||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you | |||||
put the 'pic-only' option into LT_INIT's first parameter.]) | |||||
]) | |||||
dnl aclocal-1.4 backwards compatibility: | |||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) | |||||
## ----------------- ## | |||||
## LTDL_INIT Options ## | |||||
## ----------------- ## | |||||
m4_define([_LTDL_MODE], []) | |||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], | |||||
[m4_define([_LTDL_MODE], [nonrecursive])]) | |||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive], | |||||
[m4_define([_LTDL_MODE], [recursive])]) | |||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject], | |||||
[m4_define([_LTDL_MODE], [subproject])]) | |||||
m4_define([_LTDL_TYPE], []) | |||||
LT_OPTION_DEFINE([LTDL_INIT], [installable], | |||||
[m4_define([_LTDL_TYPE], [installable])]) | |||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience], | |||||
[m4_define([_LTDL_TYPE], [convenience])]) |
@@ -0,0 +1,124 @@ | |||||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- | |||||
# | |||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software | |||||
# Foundation, Inc. | |||||
# Written by Gary V. Vaughan, 2004 | |||||
# | |||||
# This file is free software; the Free Software Foundation gives | |||||
# unlimited permission to copy and/or distribute it, with or without | |||||
# modifications, as long as this notice is preserved. | |||||
# serial 6 ltsugar.m4 | |||||
# This is to help aclocal find these macros, as it can't see m4_define. | |||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) | |||||
# lt_join(SEP, ARG1, [ARG2...]) | |||||
# ----------------------------- | |||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their | |||||
# associated separator. | |||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier | |||||
# versions in m4sugar had bugs. | |||||
m4_define([lt_join], | |||||
[m4_if([$#], [1], [], | |||||
[$#], [2], [[$2]], | |||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) | |||||
m4_define([_lt_join], | |||||
[m4_if([$#$2], [2], [], | |||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) | |||||
# lt_car(LIST) | |||||
# lt_cdr(LIST) | |||||
# ------------ | |||||
# Manipulate m4 lists. | |||||
# These macros are necessary as long as will still need to support | |||||
# Autoconf-2.59, which quotes differently. | |||||
m4_define([lt_car], [[$1]]) | |||||
m4_define([lt_cdr], | |||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], | |||||
[$#], 1, [], | |||||
[m4_dquote(m4_shift($@))])]) | |||||
m4_define([lt_unquote], $1) | |||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR]) | |||||
# ------------------------------------------ | |||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. | |||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended | |||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). | |||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different | |||||
# than defined and empty). | |||||
# | |||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier | |||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. | |||||
m4_define([lt_append], | |||||
[m4_define([$1], | |||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) | |||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) | |||||
# ---------------------------------------------------------- | |||||
# Produce a SEP delimited list of all paired combinations of elements of | |||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list | |||||
# has the form PREFIXmINFIXSUFFIXn. | |||||
# Needed until we can rely on m4_combine added in Autoconf 2.62. | |||||
m4_define([lt_combine], | |||||
[m4_if(m4_eval([$# > 3]), [1], | |||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl | |||||
[[m4_foreach([_Lt_prefix], [$2], | |||||
[m4_foreach([_Lt_suffix], | |||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, | |||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) | |||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) | |||||
# ----------------------------------------------------------------------- | |||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited | |||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. | |||||
m4_define([lt_if_append_uniq], | |||||
[m4_ifdef([$1], | |||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], | |||||
[lt_append([$1], [$2], [$3])$4], | |||||
[$5])], | |||||
[lt_append([$1], [$2], [$3])$4])]) | |||||
# lt_dict_add(DICT, KEY, VALUE) | |||||
# ----------------------------- | |||||
m4_define([lt_dict_add], | |||||
[m4_define([$1($2)], [$3])]) | |||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) | |||||
# -------------------------------------------- | |||||
m4_define([lt_dict_add_subkey], | |||||
[m4_define([$1($2:$3)], [$4])]) | |||||
# lt_dict_fetch(DICT, KEY, [SUBKEY]) | |||||
# ---------------------------------- | |||||
m4_define([lt_dict_fetch], | |||||
[m4_ifval([$3], | |||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), | |||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) | |||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) | |||||
# ----------------------------------------------------------------- | |||||
m4_define([lt_if_dict_fetch], | |||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], | |||||
[$5], | |||||
[$6])]) | |||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) | |||||
# -------------------------------------------------------------- | |||||
m4_define([lt_dict_filter], | |||||
[m4_if([$5], [], [], | |||||
[lt_join(m4_quote(m4_default([$4], [[, ]])), | |||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), | |||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl | |||||
]) |
@@ -0,0 +1,23 @@ | |||||
# ltversion.m4 -- version numbers -*- Autoconf -*- | |||||
# | |||||
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. | |||||
# Written by Scott James Remnant, 2004 | |||||
# | |||||
# This file is free software; the Free Software Foundation gives | |||||
# unlimited permission to copy and/or distribute it, with or without | |||||
# modifications, as long as this notice is preserved. | |||||
# @configure_input@ | |||||
# serial 4179 ltversion.m4 | |||||
# This file is part of GNU Libtool | |||||
m4_define([LT_PACKAGE_VERSION], [2.4.6]) | |||||
m4_define([LT_PACKAGE_REVISION], [2.4.6]) | |||||
AC_DEFUN([LTVERSION_VERSION], | |||||
[macro_version='2.4.6' | |||||
macro_revision='2.4.6' | |||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) | |||||
_LT_DECL(, macro_revision, 0) | |||||
]) |
@@ -0,0 +1,99 @@ | |||||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- | |||||
# | |||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software | |||||
# Foundation, Inc. | |||||
# Written by Scott James Remnant, 2004. | |||||
# | |||||
# This file is free software; the Free Software Foundation gives | |||||
# unlimited permission to copy and/or distribute it, with or without | |||||
# modifications, as long as this notice is preserved. | |||||
# serial 5 lt~obsolete.m4 | |||||
# These exist entirely to fool aclocal when bootstrapping libtool. | |||||
# | |||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), | |||||
# which have later been changed to m4_define as they aren't part of the | |||||
# exported API, or moved to Autoconf or Automake where they belong. | |||||
# | |||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN | |||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us | |||||
# using a macro with the same name in our local m4/libtool.m4 it'll | |||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define | |||||
# and doesn't know about Autoconf macros at all.) | |||||
# | |||||
# So we provide this file, which has a silly filename so it's always | |||||
# included after everything else. This provides aclocal with the | |||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything | |||||
# because those macros already exist, or will be overwritten later. | |||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. | |||||
# | |||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. | |||||
# Yes, that means every name once taken will need to remain here until | |||||
# we give up compatibility with versions before 1.7, at which point | |||||
# we need to keep only those names which we still refer to. | |||||
# This is to help aclocal find these macros, as it can't see m4_define. | |||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) | |||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) | |||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) | |||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) | |||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) | |||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) | |||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) | |||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) | |||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) | |||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) | |||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) | |||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) | |||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) | |||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) | |||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) | |||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) | |||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) | |||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) | |||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) | |||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) | |||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) | |||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) | |||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) | |||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) | |||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) | |||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) | |||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) | |||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) | |||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) | |||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) | |||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) | |||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) | |||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) | |||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) | |||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) | |||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) | |||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) | |||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) | |||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) | |||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) | |||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) | |||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) | |||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) | |||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) | |||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) | |||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) | |||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) | |||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) | |||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) | |||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) | |||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) | |||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) | |||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) | |||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) | |||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) | |||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) | |||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) | |||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) | |||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) | |||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) | |||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) | |||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) |
@@ -0,0 +1,32 @@ | |||||
# nls.m4 serial 5 (gettext-0.18) | |||||
dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation, | |||||
dnl Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl | |||||
dnl This file can can be used in projects which are not available under | |||||
dnl the GNU General Public License or the GNU Library General Public | |||||
dnl License but which still want to provide support for the GNU gettext | |||||
dnl functionality. | |||||
dnl Please note that the actual code of the GNU gettext library is covered | |||||
dnl by the GNU Library General Public License, and the rest of the GNU | |||||
dnl gettext package package is covered by the GNU General Public License. | |||||
dnl They are *not* in the public domain. | |||||
dnl Authors: | |||||
dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | |||||
dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. | |||||
AC_PREREQ([2.50]) | |||||
AC_DEFUN([AM_NLS], | |||||
[ | |||||
AC_MSG_CHECKING([whether NLS is requested]) | |||||
dnl Default is enabled NLS | |||||
AC_ARG_ENABLE([nls], | |||||
[ --disable-nls do not use Native Language Support], | |||||
USE_NLS=$enableval, USE_NLS=yes) | |||||
AC_MSG_RESULT([$USE_NLS]) | |||||
AC_SUBST([USE_NLS]) | |||||
]) |
@@ -0,0 +1,57 @@ | |||||
dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) | |||||
dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page | |||||
dnl also defines GSTUFF_PKG_ERRORS on error | |||||
AC_DEFUN([PKG_CHECK_MODULES], [ | |||||
succeeded=no | |||||
if test -z "$PKG_CONFIG"; then | |||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no) | |||||
fi | |||||
if test "$PKG_CONFIG" = "no" ; then | |||||
echo "*** The pkg-config script could not be found. Make sure it is" | |||||
echo "*** in your path, or set the PKG_CONFIG environment variable" | |||||
echo "*** to the full path to pkg-config." | |||||
echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." | |||||
else | |||||
PKG_CONFIG_MIN_VERSION=0.9.0 | |||||
if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then | |||||
AC_MSG_CHECKING(for $2) | |||||
if $PKG_CONFIG --exists "$2" ; then | |||||
AC_MSG_RESULT(yes) | |||||
succeeded=yes | |||||
AC_MSG_CHECKING($1_CFLAGS) | |||||
$1_CFLAGS=`$PKG_CONFIG --cflags "$2"` | |||||
AC_MSG_RESULT($$1_CFLAGS) | |||||
AC_MSG_CHECKING($1_LIBS) | |||||
$1_LIBS=`$PKG_CONFIG --libs "$2"` | |||||
AC_MSG_RESULT($$1_LIBS) | |||||
else | |||||
$1_CFLAGS="" | |||||
$1_LIBS="" | |||||
## If we have a custom action on failure, don't print errors, but | |||||
## do set a variable so people can do so. | |||||
$1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` | |||||
ifelse([$4], ,echo $$1_PKG_ERRORS,) | |||||
fi | |||||
AC_SUBST($1_CFLAGS) | |||||
AC_SUBST($1_LIBS) | |||||
else | |||||
echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." | |||||
echo "*** See http://www.freedesktop.org/software/pkgconfig" | |||||
fi | |||||
fi | |||||
if test $succeeded = yes; then | |||||
ifelse([$3], , :, [$3]) | |||||
else | |||||
ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) | |||||
fi | |||||
]) | |||||
@@ -0,0 +1,449 @@ | |||||
# po.m4 serial 17 (gettext-0.18) | |||||
dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl | |||||
dnl This file can can be used in projects which are not available under | |||||
dnl the GNU General Public License or the GNU Library General Public | |||||
dnl License but which still want to provide support for the GNU gettext | |||||
dnl functionality. | |||||
dnl Please note that the actual code of the GNU gettext library is covered | |||||
dnl by the GNU Library General Public License, and the rest of the GNU | |||||
dnl gettext package package is covered by the GNU General Public License. | |||||
dnl They are *not* in the public domain. | |||||
dnl Authors: | |||||
dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | |||||
dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. | |||||
AC_PREREQ([2.50]) | |||||
dnl Checks for all prerequisites of the po subdirectory. | |||||
AC_DEFUN([AM_PO_SUBDIRS], | |||||
[ | |||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl | |||||
AC_REQUIRE([AC_PROG_INSTALL])dnl | |||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake | |||||
AC_REQUIRE([AM_NLS])dnl | |||||
dnl Release version of the gettext macros. This is used to ensure that | |||||
dnl the gettext macros and po/Makefile.in.in are in sync. | |||||
AC_SUBST([GETTEXT_MACRO_VERSION], [0.18]) | |||||
dnl Perform the following tests also if --disable-nls has been given, | |||||
dnl because they are needed for "make dist" to work. | |||||
dnl Search for GNU msgfmt in the PATH. | |||||
dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. | |||||
dnl The second test excludes FreeBSD msgfmt. | |||||
AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, | |||||
[$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && | |||||
(if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], | |||||
:) | |||||
AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT]) | |||||
dnl Test whether it is GNU msgfmt >= 0.15. | |||||
changequote(,)dnl | |||||
case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; | |||||
*) MSGFMT_015=$MSGFMT ;; | |||||
esac | |||||
changequote([,])dnl | |||||
AC_SUBST([MSGFMT_015]) | |||||
changequote(,)dnl | |||||
case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; | |||||
*) GMSGFMT_015=$GMSGFMT ;; | |||||
esac | |||||
changequote([,])dnl | |||||
AC_SUBST([GMSGFMT_015]) | |||||
dnl Search for GNU xgettext 0.12 or newer in the PATH. | |||||
dnl The first test excludes Solaris xgettext and early GNU xgettext versions. | |||||
dnl The second test excludes FreeBSD xgettext. | |||||
AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, | |||||
[$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && | |||||
(if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], | |||||
:) | |||||
dnl Remove leftover from FreeBSD xgettext call. | |||||
rm -f messages.po | |||||
dnl Test whether it is GNU xgettext >= 0.15. | |||||
changequote(,)dnl | |||||
case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; | |||||
*) XGETTEXT_015=$XGETTEXT ;; | |||||
esac | |||||
changequote([,])dnl | |||||
AC_SUBST([XGETTEXT_015]) | |||||
dnl Search for GNU msgmerge 0.11 or newer in the PATH. | |||||
AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, | |||||
[$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) | |||||
dnl Installation directories. | |||||
dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we | |||||
dnl have to define it here, so that it can be used in po/Makefile. | |||||
test -n "$localedir" || localedir='${datadir}/locale' | |||||
AC_SUBST([localedir]) | |||||
dnl Support for AM_XGETTEXT_OPTION. | |||||
test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= | |||||
AC_SUBST([XGETTEXT_EXTRA_OPTIONS]) | |||||
AC_CONFIG_COMMANDS([po-directories], [[ | |||||
for ac_file in $CONFIG_FILES; do | |||||
# Support "outfile[:infile[:infile...]]" | |||||
case "$ac_file" in | |||||
*:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; | |||||
esac | |||||
# PO directories have a Makefile.in generated from Makefile.in.in. | |||||
case "$ac_file" in */Makefile.in) | |||||
# Adjust a relative srcdir. | |||||
ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` | |||||
ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" | |||||
ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` | |||||
# In autoconf-2.13 it is called $ac_given_srcdir. | |||||
# In autoconf-2.50 it is called $srcdir. | |||||
test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" | |||||
case "$ac_given_srcdir" in | |||||
.) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; | |||||
/*) top_srcdir="$ac_given_srcdir" ;; | |||||
*) top_srcdir="$ac_dots$ac_given_srcdir" ;; | |||||
esac | |||||
# Treat a directory as a PO directory if and only if it has a | |||||
# POTFILES.in file. This allows packages to have multiple PO | |||||
# directories under different names or in different locations. | |||||
if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then | |||||
rm -f "$ac_dir/POTFILES" | |||||
test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" | |||||
cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" | |||||
POMAKEFILEDEPS="POTFILES.in" | |||||
# ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend | |||||
# on $ac_dir but don't depend on user-specified configuration | |||||
# parameters. | |||||
if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then | |||||
# The LINGUAS file contains the set of available languages. | |||||
if test -n "$OBSOLETE_ALL_LINGUAS"; then | |||||
test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" | |||||
fi | |||||
ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` | |||||
# Hide the ALL_LINGUAS assigment from automake < 1.5. | |||||
eval 'ALL_LINGUAS''=$ALL_LINGUAS_' | |||||
POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" | |||||
else | |||||
# The set of available languages was given in configure.in. | |||||
# Hide the ALL_LINGUAS assigment from automake < 1.5. | |||||
eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' | |||||
fi | |||||
# Compute POFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) | |||||
# Compute UPDATEPOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) | |||||
# Compute DUMMYPOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) | |||||
# Compute GMOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) | |||||
case "$ac_given_srcdir" in | |||||
.) srcdirpre= ;; | |||||
*) srcdirpre='$(srcdir)/' ;; | |||||
esac | |||||
POFILES= | |||||
UPDATEPOFILES= | |||||
DUMMYPOFILES= | |||||
GMOFILES= | |||||
for lang in $ALL_LINGUAS; do | |||||
POFILES="$POFILES $srcdirpre$lang.po" | |||||
UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" | |||||
DUMMYPOFILES="$DUMMYPOFILES $lang.nop" | |||||
GMOFILES="$GMOFILES $srcdirpre$lang.gmo" | |||||
done | |||||
# CATALOGS depends on both $ac_dir and the user's LINGUAS | |||||
# environment variable. | |||||
INST_LINGUAS= | |||||
if test -n "$ALL_LINGUAS"; then | |||||
for presentlang in $ALL_LINGUAS; do | |||||
useit=no | |||||
if test "%UNSET%" != "$LINGUAS"; then | |||||
desiredlanguages="$LINGUAS" | |||||
else | |||||
desiredlanguages="$ALL_LINGUAS" | |||||
fi | |||||
for desiredlang in $desiredlanguages; do | |||||
# Use the presentlang catalog if desiredlang is | |||||
# a. equal to presentlang, or | |||||
# b. a variant of presentlang (because in this case, | |||||
# presentlang can be used as a fallback for messages | |||||
# which are not translated in the desiredlang catalog). | |||||
case "$desiredlang" in | |||||
"$presentlang"*) useit=yes;; | |||||
esac | |||||
done | |||||
if test $useit = yes; then | |||||
INST_LINGUAS="$INST_LINGUAS $presentlang" | |||||
fi | |||||
done | |||||
fi | |||||
CATALOGS= | |||||
if test -n "$INST_LINGUAS"; then | |||||
for lang in $INST_LINGUAS; do | |||||
CATALOGS="$CATALOGS $lang.gmo" | |||||
done | |||||
fi | |||||
test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" | |||||
sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" | |||||
for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do | |||||
if test -f "$f"; then | |||||
case "$f" in | |||||
*.orig | *.bak | *~) ;; | |||||
*) cat "$f" >> "$ac_dir/Makefile" ;; | |||||
esac | |||||
fi | |||||
done | |||||
fi | |||||
;; | |||||
esac | |||||
done]], | |||||
[# Capture the value of obsolete ALL_LINGUAS because we need it to compute | |||||
# POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it | |||||
# from automake < 1.5. | |||||
eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' | |||||
# Capture the value of LINGUAS because we need it to compute CATALOGS. | |||||
LINGUAS="${LINGUAS-%UNSET%}" | |||||
]) | |||||
]) | |||||
dnl Postprocesses a Makefile in a directory containing PO files. | |||||
AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], | |||||
[ | |||||
# When this code is run, in config.status, two variables have already been | |||||
# set: | |||||
# - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, | |||||
# - LINGUAS is the value of the environment variable LINGUAS at configure | |||||
# time. | |||||
changequote(,)dnl | |||||
# Adjust a relative srcdir. | |||||
ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` | |||||
ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" | |||||
ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` | |||||
# In autoconf-2.13 it is called $ac_given_srcdir. | |||||
# In autoconf-2.50 it is called $srcdir. | |||||
test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" | |||||
case "$ac_given_srcdir" in | |||||
.) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; | |||||
/*) top_srcdir="$ac_given_srcdir" ;; | |||||
*) top_srcdir="$ac_dots$ac_given_srcdir" ;; | |||||
esac | |||||
# Find a way to echo strings without interpreting backslash. | |||||
if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then | |||||
gt_echo='echo' | |||||
else | |||||
if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then | |||||
gt_echo='printf %s\n' | |||||
else | |||||
echo_func () { | |||||
cat <<EOT | |||||
$* | |||||
EOT | |||||
} | |||||
gt_echo='echo_func' | |||||
fi | |||||
fi | |||||
# A sed script that extracts the value of VARIABLE from a Makefile. | |||||
sed_x_variable=' | |||||
# Test if the hold space is empty. | |||||
x | |||||
s/P/P/ | |||||
x | |||||
ta | |||||
# Yes it was empty. Look if we have the expected variable definition. | |||||
/^[ ]*VARIABLE[ ]*=/{ | |||||
# Seen the first line of the variable definition. | |||||
s/^[ ]*VARIABLE[ ]*=// | |||||
ba | |||||
} | |||||
bd | |||||
:a | |||||
# Here we are processing a line from the variable definition. | |||||
# Remove comment, more precisely replace it with a space. | |||||
s/#.*$/ / | |||||
# See if the line ends in a backslash. | |||||
tb | |||||
:b | |||||
s/\\$// | |||||
# Print the line, without the trailing backslash. | |||||
p | |||||
tc | |||||
# There was no trailing backslash. The end of the variable definition is | |||||
# reached. Clear the hold space. | |||||
s/^.*$// | |||||
x | |||||
bd | |||||
:c | |||||
# A trailing backslash means that the variable definition continues in the | |||||
# next line. Put a nonempty string into the hold space to indicate this. | |||||
s/^.*$/P/ | |||||
x | |||||
:d | |||||
' | |||||
changequote([,])dnl | |||||
# Set POTFILES to the value of the Makefile variable POTFILES. | |||||
sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'` | |||||
POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"` | |||||
# Compute POTFILES_DEPS as | |||||
# $(foreach file, $(POTFILES), $(top_srcdir)/$(file)) | |||||
POTFILES_DEPS= | |||||
for file in $POTFILES; do | |||||
POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file" | |||||
done | |||||
POMAKEFILEDEPS="" | |||||
if test -n "$OBSOLETE_ALL_LINGUAS"; then | |||||
test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" | |||||
fi | |||||
if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then | |||||
# The LINGUAS file contains the set of available languages. | |||||
ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` | |||||
POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" | |||||
else | |||||
# Set ALL_LINGUAS to the value of the Makefile variable LINGUAS. | |||||
sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'` | |||||
ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"` | |||||
fi | |||||
# Hide the ALL_LINGUAS assigment from automake < 1.5. | |||||
eval 'ALL_LINGUAS''=$ALL_LINGUAS_' | |||||
# Compute POFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) | |||||
# Compute UPDATEPOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) | |||||
# Compute DUMMYPOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) | |||||
# Compute GMOFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) | |||||
# Compute PROPERTIESFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties) | |||||
# Compute CLASSFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class) | |||||
# Compute QMFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm) | |||||
# Compute MSGFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) | |||||
# Compute RESOURCESDLLFILES | |||||
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) | |||||
case "$ac_given_srcdir" in | |||||
.) srcdirpre= ;; | |||||
*) srcdirpre='$(srcdir)/' ;; | |||||
esac | |||||
POFILES= | |||||
UPDATEPOFILES= | |||||
DUMMYPOFILES= | |||||
GMOFILES= | |||||
PROPERTIESFILES= | |||||
CLASSFILES= | |||||
QMFILES= | |||||
MSGFILES= | |||||
RESOURCESDLLFILES= | |||||
for lang in $ALL_LINGUAS; do | |||||
POFILES="$POFILES $srcdirpre$lang.po" | |||||
UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" | |||||
DUMMYPOFILES="$DUMMYPOFILES $lang.nop" | |||||
GMOFILES="$GMOFILES $srcdirpre$lang.gmo" | |||||
PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties" | |||||
CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class" | |||||
QMFILES="$QMFILES $srcdirpre$lang.qm" | |||||
frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | |||||
MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg" | |||||
frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | |||||
RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll" | |||||
done | |||||
# CATALOGS depends on both $ac_dir and the user's LINGUAS | |||||
# environment variable. | |||||
INST_LINGUAS= | |||||
if test -n "$ALL_LINGUAS"; then | |||||
for presentlang in $ALL_LINGUAS; do | |||||
useit=no | |||||
if test "%UNSET%" != "$LINGUAS"; then | |||||
desiredlanguages="$LINGUAS" | |||||
else | |||||
desiredlanguages="$ALL_LINGUAS" | |||||
fi | |||||
for desiredlang in $desiredlanguages; do | |||||
# Use the presentlang catalog if desiredlang is | |||||
# a. equal to presentlang, or | |||||
# b. a variant of presentlang (because in this case, | |||||
# presentlang can be used as a fallback for messages | |||||
# which are not translated in the desiredlang catalog). | |||||
case "$desiredlang" in | |||||
"$presentlang"*) useit=yes;; | |||||
esac | |||||
done | |||||
if test $useit = yes; then | |||||
INST_LINGUAS="$INST_LINGUAS $presentlang" | |||||
fi | |||||
done | |||||
fi | |||||
CATALOGS= | |||||
JAVACATALOGS= | |||||
QTCATALOGS= | |||||
TCLCATALOGS= | |||||
CSHARPCATALOGS= | |||||
if test -n "$INST_LINGUAS"; then | |||||
for lang in $INST_LINGUAS; do | |||||
CATALOGS="$CATALOGS $lang.gmo" | |||||
JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties" | |||||
QTCATALOGS="$QTCATALOGS $lang.qm" | |||||
frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | |||||
TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg" | |||||
frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | |||||
CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll" | |||||
done | |||||
fi | |||||
sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp" | |||||
if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then | |||||
# Add dependencies that cannot be formulated as a simple suffix rule. | |||||
for lang in $ALL_LINGUAS; do | |||||
frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | |||||
cat >> "$ac_file.tmp" <<EOF | |||||
$frobbedlang.msg: $lang.po | |||||
@echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \ | |||||
\$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } | |||||
EOF | |||||
done | |||||
fi | |||||
if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then | |||||
# Add dependencies that cannot be formulated as a simple suffix rule. | |||||
for lang in $ALL_LINGUAS; do | |||||
frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | |||||
cat >> "$ac_file.tmp" <<EOF | |||||
$frobbedlang/\$(DOMAIN).resources.dll: $lang.po | |||||
@echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \ | |||||
\$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } | |||||
EOF | |||||
done | |||||
fi | |||||
if test -n "$POMAKEFILEDEPS"; then | |||||
cat >> "$ac_file.tmp" <<EOF | |||||
Makefile: $POMAKEFILEDEPS | |||||
EOF | |||||
fi | |||||
mv "$ac_file.tmp" "$ac_file" | |||||
]) | |||||
dnl Initializes the accumulator used by AM_XGETTEXT_OPTION. | |||||
AC_DEFUN([AM_XGETTEXT_OPTION_INIT], | |||||
[ | |||||
XGETTEXT_EXTRA_OPTIONS= | |||||
]) | |||||
dnl Registers an option to be passed to xgettext in the po subdirectory. | |||||
AC_DEFUN([AM_XGETTEXT_OPTION], | |||||
[ | |||||
AC_REQUIRE([AM_XGETTEXT_OPTION_INIT]) | |||||
XGETTEXT_EXTRA_OPTIONS="$XGETTEXT_EXTRA_OPTIONS $1" | |||||
]) |
@@ -0,0 +1,92 @@ | |||||
# progtest.m4 serial 6 (gettext-0.18) | |||||
dnl Copyright (C) 1996-2003, 2005, 2008-2010 Free Software Foundation, Inc. | |||||
dnl This file is free software; the Free Software Foundation | |||||
dnl gives unlimited permission to copy and/or distribute it, | |||||
dnl with or without modifications, as long as this notice is preserved. | |||||
dnl | |||||
dnl This file can can be used in projects which are not available under | |||||
dnl the GNU General Public License or the GNU Library General Public | |||||
dnl License but which still want to provide support for the GNU gettext | |||||
dnl functionality. | |||||
dnl Please note that the actual code of the GNU gettext library is covered | |||||
dnl by the GNU Library General Public License, and the rest of the GNU | |||||
dnl gettext package package is covered by the GNU General Public License. | |||||
dnl They are *not* in the public domain. | |||||
dnl Authors: | |||||
dnl Ulrich Drepper <drepper@cygnus.com>, 1996. | |||||
AC_PREREQ([2.50]) | |||||
# Search path for a program which passes the given test. | |||||
dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, | |||||
dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) | |||||
AC_DEFUN([AM_PATH_PROG_WITH_TEST], | |||||
[ | |||||
# Prepare PATH_SEPARATOR. | |||||
# The user is always right. | |||||
if test "${PATH_SEPARATOR+set}" != set; then | |||||
echo "#! /bin/sh" >conf$$.sh | |||||
echo "exit 0" >>conf$$.sh | |||||
chmod +x conf$$.sh | |||||
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then | |||||
PATH_SEPARATOR=';' | |||||
else | |||||
PATH_SEPARATOR=: | |||||
fi | |||||
rm -f conf$$.sh | |||||
fi | |||||
# Find out how to test for executable files. Don't use a zero-byte file, | |||||
# as systems may use methods other than mode bits to determine executability. | |||||
cat >conf$$.file <<_ASEOF | |||||
#! /bin/sh | |||||
exit 0 | |||||
_ASEOF | |||||
chmod +x conf$$.file | |||||
if test -x conf$$.file >/dev/null 2>&1; then | |||||
ac_executable_p="test -x" | |||||
else | |||||
ac_executable_p="test -f" | |||||
fi | |||||
rm -f conf$$.file | |||||
# Extract the first word of "$2", so it can be a program name with args. | |||||
set dummy $2; ac_word=[$]2 | |||||
AC_MSG_CHECKING([for $ac_word]) | |||||
AC_CACHE_VAL([ac_cv_path_$1], | |||||
[case "[$]$1" in | |||||
[[\\/]]* | ?:[[\\/]]*) | |||||
ac_cv_path_$1="[$]$1" # Let the user override the test with a path. | |||||
;; | |||||
*) | |||||
ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR | |||||
for ac_dir in ifelse([$5], , $PATH, [$5]); do | |||||
IFS="$ac_save_IFS" | |||||
test -z "$ac_dir" && ac_dir=. | |||||
for ac_exec_ext in '' $ac_executable_extensions; do | |||||
if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then | |||||
echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD | |||||
if [$3]; then | |||||
ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" | |||||
break 2 | |||||
fi | |||||
fi | |||||
done | |||||
done | |||||
IFS="$ac_save_IFS" | |||||
dnl If no 4th arg is given, leave the cache variable unset, | |||||
dnl so AC_PATH_PROGS will keep looking. | |||||
ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" | |||||
])dnl | |||||
;; | |||||
esac])dnl | |||||
$1="$ac_cv_path_$1" | |||||
if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then | |||||
AC_MSG_RESULT([$][$1]) | |||||
else | |||||
AC_MSG_RESULT([no]) | |||||
fi | |||||
AC_SUBST([$1])dnl | |||||
]) |
@@ -0,0 +1,25 @@ | |||||
# This Makefile.am is in the public domain | |||||
pcfiles = \ | |||||
gnunetmulticast.pc \ | |||||
gnunetpsyc.pc \ | |||||
gnunetpsycstore.pc | |||||
all-local: $(pcfiles) | |||||
cp_verbose = $(cp_verbose_$(V)) | |||||
cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY)) | |||||
cp_verbose_0 = @echo " CP $@"; | |||||
%.pc: %.pc | |||||
$(cp_verbose_0)cp $< $@ | |||||
pkgconfigdir = $(libdir)/pkgconfig | |||||
pkgconfig_DATA = $(pcfiles) | |||||
EXTRA_DIST = \ | |||||
gnunetmulticast.pc.in \ | |||||
gnunetpsyc.pc.in \ | |||||
gnunetpsycstore.pc.in | |||||
CLEANFILES = $(pcfiles) | |||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include |
@@ -0,0 +1,12 @@ | |||||
prefix=@prefix@ | |||||
exec_prefix=@exec_prefix@ | |||||
libdir=@libdir@ | |||||
includedir=@includedir@ | |||||
Name: GNUnet MULTICAST | |||||
Description: library to multicast messages to a group of peers | |||||
URL: https://gnunet.org | |||||
Version: @VERSION@ | |||||
Requires: | |||||
Libs: -L${libdir} -lgnunetmulticast | |||||
Cflags: -I${includedir} |
@@ -0,0 +1,12 @@ | |||||
prefix=@prefix@ | |||||
exec_prefix=@exec_prefix@ | |||||
libdir=@libdir@ | |||||
includedir=@includedir@ | |||||
Name: GNUnet PSYC | |||||
Description: library for PSYC multicast channel management | |||||
URL: https://gnunet.org | |||||
Version: @VERSION@ | |||||
Requires: | |||||
Libs: -L${libdir} -lgnunetpsyc | |||||
Cflags: -I${includedir} |
@@ -0,0 +1,12 @@ | |||||
prefix=@prefix@ | |||||
exec_prefix=@exec_prefix@ | |||||
libdir=@libdir@ | |||||
includedir=@includedir@ | |||||
Name: GNUnet PSYCSTORE | |||||
Description: library to for persistent storage of PSYC messages | |||||
URL: https://gnunet.org | |||||
Version: @VERSION@ | |||||
Requires: | |||||
Libs: -L${libdir} -lgnunetpsycstore | |||||
Cflags: -I${includedir} |
@@ -0,0 +1,6 @@ | |||||
Makefile.in | |||||
Makefile | |||||
POTFILES | |||||
gnunet-ext.pot | |||||
remove-potcdate.sed | |||||
stamp-po |
@@ -0,0 +1,12 @@ | |||||
2012-03-07 gettextize <bug-gnu-gettext@gnu.org> | |||||
* Makefile.in.in: New file, from gettext-0.18.1. | |||||
* Rules-quot: New file, from gettext-0.18.1. | |||||
* boldquot.sed: New file, from gettext-0.18.1. | |||||
* en@boldquot.header: New file, from gettext-0.18.1. | |||||
* en@quot.header: New file, from gettext-0.18.1. | |||||
* insert-header.sin: New file, from gettext-0.18.1. | |||||
* quot.sed: New file, from gettext-0.18.1. | |||||
* remove-potcdate.sin: New file, from gettext-0.18.1. | |||||
* POTFILES.in: New file. | |||||
@@ -0,0 +1,444 @@ | |||||
# Makefile for PO directory in any package using GNU gettext. | |||||
# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu> | |||||
# | |||||
# This file can be copied and used freely without restrictions. It can | |||||
# be used in projects which are not available under the GNU General Public | |||||
# License but which still want to provide support for the GNU gettext | |||||
# functionality. | |||||
# Please note that the actual code of GNU gettext is covered by the GNU | |||||
# General Public License and is *not* in the public domain. | |||||
# | |||||
# Origin: gettext-0.18 | |||||
GETTEXT_MACRO_VERSION = 0.18 | |||||
PACKAGE = @PACKAGE@ | |||||
VERSION = @VERSION@ | |||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | |||||
SHELL = /bin/sh | |||||
@SET_MAKE@ | |||||
srcdir = @srcdir@ | |||||
top_srcdir = @top_srcdir@ | |||||
VPATH = @srcdir@ | |||||
prefix = @prefix@ | |||||
exec_prefix = @exec_prefix@ | |||||
datarootdir = @datarootdir@ | |||||
datadir = @datadir@ | |||||
localedir = @localedir@ | |||||
gettextsrcdir = $(datadir)/gettext/po | |||||
INSTALL = @INSTALL@ | |||||
INSTALL_DATA = @INSTALL_DATA@ | |||||
# We use $(mkdir_p). | |||||
# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as | |||||
# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, | |||||
# @install_sh@ does not start with $(SHELL), so we add it. | |||||
# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined | |||||
# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake | |||||
# versions, $(mkinstalldirs) and $(install_sh) are unused. | |||||
mkinstalldirs = $(SHELL) @install_sh@ -d | |||||
install_sh = $(SHELL) @install_sh@ | |||||
MKDIR_P = @MKDIR_P@ | |||||
mkdir_p = @mkdir_p@ | |||||
GMSGFMT_ = @GMSGFMT@ | |||||
GMSGFMT_no = @GMSGFMT@ | |||||
GMSGFMT_yes = @GMSGFMT_015@ | |||||
GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) | |||||
MSGFMT_ = @MSGFMT@ | |||||
MSGFMT_no = @MSGFMT@ | |||||
MSGFMT_yes = @MSGFMT_015@ | |||||
MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) | |||||
XGETTEXT_ = @XGETTEXT@ | |||||
XGETTEXT_no = @XGETTEXT@ | |||||
XGETTEXT_yes = @XGETTEXT_015@ | |||||
XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) | |||||
MSGMERGE = msgmerge | |||||
MSGMERGE_UPDATE = @MSGMERGE@ --update | |||||
MSGINIT = msginit | |||||
MSGCONV = msgconv | |||||
MSGFILTER = msgfilter | |||||
POFILES = @POFILES@ | |||||
GMOFILES = @GMOFILES@ | |||||
UPDATEPOFILES = @UPDATEPOFILES@ | |||||
DUMMYPOFILES = @DUMMYPOFILES@ | |||||
DISTFILES.common = Makefile.in.in remove-potcdate.sin \ | |||||
$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) | |||||
DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ | |||||
$(POFILES) $(GMOFILES) \ | |||||
$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) | |||||
POTFILES = \ | |||||
CATALOGS = @CATALOGS@ | |||||
# Makevars gets inserted here. (Don't remove this line!) | |||||
.SUFFIXES: | |||||
.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update | |||||
.po.mo: | |||||
@echo "$(MSGFMT) -c -o $@ $<"; \ | |||||
$(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ | |||||
.po.gmo: | |||||
@lang=`echo $* | sed -e 's,.*/,,'`; \ | |||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ | |||||
echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ | |||||
cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo | |||||
.sin.sed: | |||||
sed -e '/^#/d' $< > t-$@ | |||||
mv t-$@ $@ | |||||
all: check-macro-version all-@USE_NLS@ | |||||
all-yes: stamp-po | |||||
all-no: | |||||
# Ensure that the gettext macros and this Makefile.in.in are in sync. | |||||
check-macro-version: | |||||
@test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ | |||||
|| { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ | |||||
exit 1; \ | |||||
} | |||||
# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no | |||||
# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because | |||||
# we don't want to bother translators with empty POT files). We assume that | |||||
# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. | |||||
# In this case, stamp-po is a nop (i.e. a phony target). | |||||
# stamp-po is a timestamp denoting the last time at which the CATALOGS have | |||||
# been loosely updated. Its purpose is that when a developer or translator | |||||
# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, | |||||
# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent | |||||
# invocations of "make" will do nothing. This timestamp would not be necessary | |||||
# if updating the $(CATALOGS) would always touch them; however, the rule for | |||||
# $(POFILES) has been designed to not touch files that don't need to be | |||||
# changed. | |||||
stamp-po: $(srcdir)/$(DOMAIN).pot | |||||
test ! -f $(srcdir)/$(DOMAIN).pot || \ | |||||
test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) | |||||
@test ! -f $(srcdir)/$(DOMAIN).pot || { \ | |||||
echo "touch stamp-po" && \ | |||||
echo timestamp > stamp-poT && \ | |||||
mv stamp-poT stamp-po; \ | |||||
} | |||||
# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', | |||||
# otherwise packages like GCC can not be built if only parts of the source | |||||
# have been downloaded. | |||||
# This target rebuilds $(DOMAIN).pot; it is an expensive operation. | |||||
# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. | |||||
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed | |||||
if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \ | |||||
package_gnu='GNU '; \ | |||||
else \ | |||||
package_gnu=''; \ | |||||
fi; \ | |||||
if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ | |||||
msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ | |||||
else \ | |||||
msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ | |||||
fi; \ | |||||
case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ | |||||
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ | |||||
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ | |||||
--files-from=$(srcdir)/POTFILES.in \ | |||||
--copyright-holder='$(COPYRIGHT_HOLDER)' \ | |||||
--msgid-bugs-address="$$msgid_bugs_address" \ | |||||
;; \ | |||||
*) \ | |||||
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ | |||||
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ | |||||
--files-from=$(srcdir)/POTFILES.in \ | |||||
--copyright-holder='$(COPYRIGHT_HOLDER)' \ | |||||
--package-name="$${package_gnu}@PACKAGE@" \ | |||||
--package-version='@VERSION@' \ | |||||
--msgid-bugs-address="$$msgid_bugs_address" \ | |||||
;; \ | |||||
esac | |||||
test ! -f $(DOMAIN).po || { \ | |||||
if test -f $(srcdir)/$(DOMAIN).pot; then \ | |||||
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ | |||||
sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ | |||||
if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ | |||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ | |||||
else \ | |||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ | |||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ | |||||
fi; \ | |||||
else \ | |||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ | |||||
fi; \ | |||||
} | |||||
# This rule has no dependencies: we don't need to update $(DOMAIN).pot at | |||||
# every "make" invocation, only create it when it is missing. | |||||
# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. | |||||
$(srcdir)/$(DOMAIN).pot: | |||||
$(MAKE) $(DOMAIN).pot-update | |||||
# This target rebuilds a PO file if $(DOMAIN).pot has changed. | |||||
# Note that a PO file is not touched if it doesn't need to be changed. | |||||
$(POFILES): $(srcdir)/$(DOMAIN).pot | |||||
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ | |||||
if test -f "$(srcdir)/$${lang}.po"; then \ | |||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ | |||||
echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ | |||||
cd $(srcdir) \ | |||||
&& { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ | |||||
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ | |||||
*) \ | |||||
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ | |||||
esac; \ | |||||
}; \ | |||||
else \ | |||||
$(MAKE) $${lang}.po-create; \ | |||||
fi | |||||
install: install-exec install-data | |||||
install-exec: | |||||
install-data: install-data-@USE_NLS@ | |||||
if test "$(PACKAGE)" = "gettext-tools"; then \ | |||||
$(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ | |||||
for file in $(DISTFILES.common) Makevars.template; do \ | |||||
$(INSTALL_DATA) $(srcdir)/$$file \ | |||||
$(DESTDIR)$(gettextsrcdir)/$$file; \ | |||||
done; \ | |||||
for file in Makevars; do \ | |||||
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ | |||||
done; \ | |||||
else \ | |||||
: ; \ | |||||
fi | |||||
install-data-no: all | |||||
install-data-yes: all | |||||
@catalogs='$(CATALOGS)'; \ | |||||
for cat in $$catalogs; do \ | |||||
cat=`basename $$cat`; \ | |||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ | |||||
dir=$(localedir)/$$lang/LC_MESSAGES; \ | |||||
$(mkdir_p) $(DESTDIR)$$dir; \ | |||||
if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ | |||||
$(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ | |||||
echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ | |||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ | |||||
if test -n "$$lc"; then \ | |||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ | |||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ | |||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ | |||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ | |||||
for file in *; do \ | |||||
if test -f $$file; then \ | |||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ | |||||
fi; \ | |||||
done); \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ | |||||
else \ | |||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ | |||||
:; \ | |||||
else \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
fi; \ | |||||
fi; \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ | |||||
ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ | |||||
ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ | |||||
cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ | |||||
echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ | |||||
fi; \ | |||||
done; \ | |||||
done | |||||
install-strip: install | |||||
installdirs: installdirs-exec installdirs-data | |||||
installdirs-exec: | |||||
installdirs-data: installdirs-data-@USE_NLS@ | |||||
if test "$(PACKAGE)" = "gettext-tools"; then \ | |||||
$(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ | |||||
else \ | |||||
: ; \ | |||||
fi | |||||
installdirs-data-no: | |||||
installdirs-data-yes: | |||||
@catalogs='$(CATALOGS)'; \ | |||||
for cat in $$catalogs; do \ | |||||
cat=`basename $$cat`; \ | |||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ | |||||
dir=$(localedir)/$$lang/LC_MESSAGES; \ | |||||
$(mkdir_p) $(DESTDIR)$$dir; \ | |||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ | |||||
if test -n "$$lc"; then \ | |||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ | |||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ | |||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ | |||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ | |||||
for file in *; do \ | |||||
if test -f $$file; then \ | |||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ | |||||
fi; \ | |||||
done); \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ | |||||
else \ | |||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ | |||||
:; \ | |||||
else \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ | |||||
fi; \ | |||||
fi; \ | |||||
fi; \ | |||||
done; \ | |||||
done | |||||
# Define this as empty until I found a useful application. | |||||
installcheck: | |||||
uninstall: uninstall-exec uninstall-data | |||||
uninstall-exec: | |||||
uninstall-data: uninstall-data-@USE_NLS@ | |||||
if test "$(PACKAGE)" = "gettext-tools"; then \ | |||||
for file in $(DISTFILES.common) Makevars.template; do \ | |||||
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ | |||||
done; \ | |||||
else \ | |||||
: ; \ | |||||
fi | |||||
uninstall-data-no: | |||||
uninstall-data-yes: | |||||
catalogs='$(CATALOGS)'; \ | |||||
for cat in $$catalogs; do \ | |||||
cat=`basename $$cat`; \ | |||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ | |||||
for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ | |||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ | |||||
done; \ | |||||
done | |||||
check: all | |||||
info dvi ps pdf html tags TAGS ctags CTAGS ID: | |||||
mostlyclean: | |||||
rm -f remove-potcdate.sed | |||||
rm -f stamp-poT | |||||
rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po | |||||
rm -fr *.o | |||||
clean: mostlyclean | |||||
distclean: clean | |||||
rm -f Makefile Makefile.in POTFILES *.mo | |||||
maintainer-clean: distclean | |||||
@echo "This command is intended for maintainers to use;" | |||||
@echo "it deletes files that may require special tools to rebuild." | |||||
rm -f stamp-po $(GMOFILES) | |||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) | |||||
dist distdir: | |||||
$(MAKE) update-po | |||||
@$(MAKE) dist2 | |||||
# This is a separate target because 'update-po' must be executed before. | |||||
dist2: stamp-po $(DISTFILES) | |||||
dists="$(DISTFILES)"; \ | |||||
if test "$(PACKAGE)" = "gettext-tools"; then \ | |||||
dists="$$dists Makevars.template"; \ | |||||
fi; \ | |||||
if test -f $(srcdir)/$(DOMAIN).pot; then \ | |||||
dists="$$dists $(DOMAIN).pot stamp-po"; \ | |||||
fi; \ | |||||
if test -f $(srcdir)/ChangeLog; then \ | |||||
dists="$$dists ChangeLog"; \ | |||||
fi; \ | |||||
for i in 0 1 2 3 4 5 6 7 8 9; do \ | |||||
if test -f $(srcdir)/ChangeLog.$$i; then \ | |||||
dists="$$dists ChangeLog.$$i"; \ | |||||
fi; \ | |||||
done; \ | |||||
if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ | |||||
for file in $$dists; do \ | |||||
if test -f $$file; then \ | |||||
cp -p $$file $(distdir) || exit 1; \ | |||||
else \ | |||||
cp -p $(srcdir)/$$file $(distdir) || exit 1; \ | |||||
fi; \ | |||||
done | |||||
update-po: Makefile | |||||
$(MAKE) $(DOMAIN).pot-update | |||||
test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) | |||||
$(MAKE) update-gmo | |||||
# General rule for creating PO files. | |||||
.nop.po-create: | |||||
@lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ | |||||
echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ | |||||
exit 1 | |||||
# General rule for updating PO files. | |||||
.nop.po-update: | |||||
@lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ | |||||
if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ | |||||
tmpdir=`pwd`; \ | |||||
echo "$$lang:"; \ | |||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ | |||||
echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ | |||||
cd $(srcdir); \ | |||||
if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ | |||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ | |||||
$(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ | |||||
*) \ | |||||
$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ | |||||
esac; \ | |||||
}; then \ | |||||
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ | |||||
rm -f $$tmpdir/$$lang.new.po; \ | |||||
else \ | |||||
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ | |||||
:; \ | |||||
else \ | |||||
echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ | |||||
exit 1; \ | |||||
fi; \ | |||||
fi; \ | |||||
else \ | |||||
echo "msgmerge for $$lang.po failed!" 1>&2; \ | |||||
rm -f $$tmpdir/$$lang.new.po; \ | |||||
fi | |||||
$(DUMMYPOFILES): | |||||
update-gmo: Makefile $(GMOFILES) | |||||
@: | |||||
# Recreate Makefile by invoking config.status. Explicitly invoke the shell, | |||||
# because execution permission bits may not work on the current file system. | |||||
# Use @SHELL@, which is the shell determined by autoconf for the use by its | |||||
# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. | |||||
Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ | |||||
cd $(top_builddir) \ | |||||
&& @SHELL@ ./config.status $(subdir)/$@.in po-directories | |||||
force: | |||||
# Tell versions [3.59,3.63) of GNU make not to export all variables. | |||||
# Otherwise a system limit (for SysV at least) may be exceeded. | |||||
.NOEXPORT: |
@@ -0,0 +1,41 @@ | |||||
# Makefile variables for PO directory in any package using GNU gettext. | |||||
# Usually the message domain is the same as the package name. | |||||
DOMAIN = $(PACKAGE) | |||||
# These two variables depend on the location of this directory. | |||||
subdir = po | |||||
top_builddir = .. | |||||
# These options get passed to xgettext. | |||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ | |||||
# This is the copyright holder that gets inserted into the header of the | |||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding | |||||
# package. (Note that the msgstr strings, extracted from the package's | |||||
# sources, belong to the copyright holder of the package.) Translators are | |||||
# expected to transfer the copyright for their translations to this person | |||||
# or entity, or to disclaim their copyright. The empty string stands for | |||||
# the public domain; in this case the translators are expected to disclaim | |||||
# their copyright. | |||||
COPYRIGHT_HOLDER = Free Software Foundation, Inc. | |||||
# This is the email address or URL to which the translators shall report | |||||
# bugs in the untranslated strings: | |||||
# - Strings which are not entire sentences, see the maintainer guidelines | |||||
# in the GNU gettext documentation, section 'Preparing Strings'. | |||||
# - Strings which use unclear terms or require additional context to be | |||||
# understood. | |||||
# - Strings which make invalid assumptions about notation of date, time or | |||||
# money. | |||||
# - Pluralisation problems. | |||||
# - Incorrect English spelling. | |||||
# - Incorrect formatting. | |||||
# It can be your email address, or a mailing list address where translators | |||||
# can write to without being subscribed, or the URL of a web page through | |||||
# which the translators can contact you. | |||||
MSGID_BUGS_ADDRESS = | |||||
# This is the list of locale categories, beyond LC_MESSAGES, for which the | |||||
# message catalogs shall be used. It is usually empty. | |||||
EXTRA_LOCALE_CATEGORIES = |
@@ -0,0 +1,2 @@ | |||||
# List of source files which contain translatable strings. | |||||
src/ext/gnunet-ext.c |
@@ -0,0 +1,47 @@ | |||||
# Special Makefile rules for English message catalogs with quotation marks. | |||||
DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot | |||||
.SUFFIXES: .insert-header .po-update-en | |||||
en@quot.po-create: | |||||
$(MAKE) en@quot.po-update | |||||
en@boldquot.po-create: | |||||
$(MAKE) en@boldquot.po-update | |||||
en@quot.po-update: en@quot.po-update-en | |||||
en@boldquot.po-update: en@boldquot.po-update-en | |||||
.insert-header.po-update-en: | |||||
@lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ | |||||
if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ | |||||
tmpdir=`pwd`; \ | |||||
echo "$$lang:"; \ | |||||
ll=`echo $$lang | sed -e 's/@.*//'`; \ | |||||
LC_ALL=C; export LC_ALL; \ | |||||
cd $(srcdir); \ | |||||
if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ | |||||
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ | |||||
rm -f $$tmpdir/$$lang.new.po; \ | |||||
else \ | |||||
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ | |||||
:; \ | |||||
else \ | |||||
echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ | |||||
exit 1; \ | |||||
fi; \ | |||||
fi; \ | |||||
else \ | |||||
echo "creation of $$lang.po failed!" 1>&2; \ | |||||
rm -f $$tmpdir/$$lang.new.po; \ | |||||
fi | |||||
en@quot.insert-header: insert-header.sin | |||||
sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header | |||||
en@boldquot.insert-header: insert-header.sin | |||||
sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header | |||||
mostlyclean: mostlyclean-quot | |||||
mostlyclean-quot: | |||||
rm -f *.insert-header |
@@ -0,0 +1,10 @@ | |||||
s/"\([^"]*\)"/“\1”/g | |||||
s/`\([^`']*\)'/‘\1’/g | |||||
s/ '\([^`']*\)' / ‘\1’ /g | |||||
s/ '\([^`']*\)'$/ ‘\1’/g | |||||
s/^'\([^`']*\)' /‘\1’ /g | |||||
s/“”/""/g | |||||
s/“/“[1m/g | |||||
s/”/[0m”/g | |||||
s/‘/‘[1m/g | |||||
s/’/[0m’/g |
@@ -0,0 +1,25 @@ | |||||
# All this catalog "translates" are quotation characters. | |||||
# The msgids must be ASCII and therefore cannot contain real quotation | |||||
# characters, only substitutes like grave accent (0x60), apostrophe (0x27) | |||||
# and double quote (0x22). These substitutes look strange; see | |||||
# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html | |||||
# | |||||
# This catalog translates grave accent (0x60) and apostrophe (0x27) to | |||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019). | |||||
# It also translates pairs of apostrophe (0x27) to | |||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019) | |||||
# and pairs of quotation mark (0x22) to | |||||
# left double quotation mark (U+201C) and right double quotation mark (U+201D). | |||||
# | |||||
# When output to an UTF-8 terminal, the quotation characters appear perfectly. | |||||
# When output to an ISO-8859-1 terminal, the single quotation marks are | |||||
# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to | |||||
# grave/acute accent (by libiconv), and the double quotation marks are | |||||
# transliterated to 0x22. | |||||
# When output to an ASCII terminal, the single quotation marks are | |||||
# transliterated to apostrophes, and the double quotation marks are | |||||
# transliterated to 0x22. | |||||
# | |||||
# This catalog furthermore displays the text between the quotation marks in | |||||
# bold face, assuming the VT100/XTerm escape sequences. | |||||
# |
@@ -0,0 +1,22 @@ | |||||
# All this catalog "translates" are quotation characters. | |||||
# The msgids must be ASCII and therefore cannot contain real quotation | |||||
# characters, only substitutes like grave accent (0x60), apostrophe (0x27) | |||||
# and double quote (0x22). These substitutes look strange; see | |||||
# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html | |||||
# | |||||
# This catalog translates grave accent (0x60) and apostrophe (0x27) to | |||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019). | |||||
# It also translates pairs of apostrophe (0x27) to | |||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019) | |||||
# and pairs of quotation mark (0x22) to | |||||
# left double quotation mark (U+201C) and right double quotation mark (U+201D). | |||||
# | |||||
# When output to an UTF-8 terminal, the quotation characters appear perfectly. | |||||
# When output to an ISO-8859-1 terminal, the single quotation marks are | |||||
# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to | |||||
# grave/acute accent (by libiconv), and the double quotation marks are | |||||
# transliterated to 0x22. | |||||
# When output to an ASCII terminal, the single quotation marks are | |||||
# transliterated to apostrophes, and the double quotation marks are | |||||
# transliterated to 0x22. | |||||
# |
@@ -0,0 +1,23 @@ | |||||
# Sed script that inserts the file called HEADER before the header entry. | |||||
# | |||||
# At each occurrence of a line starting with "msgid ", we execute the following | |||||
# commands. At the first occurrence, insert the file. At the following | |||||
# occurrences, do nothing. The distinction between the first and the following | |||||
# occurrences is achieved by looking at the hold space. | |||||
/^msgid /{ | |||||
x | |||||
# Test if the hold space is empty. | |||||
s/m/m/ | |||||
ta | |||||
# Yes it was empty. First occurrence. Read the file. | |||||
r HEADER | |||||
# Output the file's contents by reading the next line. But don't lose the | |||||
# current line while doing this. | |||||
g | |||||
N | |||||
bb | |||||
:a | |||||
# The hold space was nonempty. Following occurrences. Do nothing. | |||||
x | |||||
:b | |||||
} |
@@ -0,0 +1,6 @@ | |||||
s/"\([^"]*\)"/“\1”/g | |||||
s/`\([^`']*\)'/‘\1’/g | |||||
s/ '\([^`']*\)' / ‘\1’ /g | |||||
s/ '\([^`']*\)'$/ ‘\1’/g | |||||
s/^'\([^`']*\)' /‘\1’ /g | |||||
s/“”/""/g |
@@ -0,0 +1,19 @@ | |||||
# Sed script that remove the POT-Creation-Date line in the header entry | |||||
# from a POT file. | |||||
# | |||||
# The distinction between the first and the following occurrences of the | |||||
# pattern is achieved by looking at the hold space. | |||||
/^"POT-Creation-Date: .*"$/{ | |||||
x | |||||
# Test if the hold space is empty. | |||||
s/P/P/ | |||||
ta | |||||
# Yes it was empty. First occurrence. Remove the line. | |||||
g | |||||
d | |||||
bb | |||||
:a | |||||
# The hold space was nonempty. Following occurrences. Do nothing. | |||||
x | |||||
:b | |||||
} |
@@ -0,0 +1,2 @@ | |||||
Makefile | |||||
Makefile.in |
@@ -0,0 +1,7 @@ | |||||
# This Makefile.am is in the public domain | |||||
SUBDIRS = include \ | |||||
multicast \ | |||||
psycutil \ | |||||
psycstore \ | |||||
psyc \ | |||||
social |
@@ -0,0 +1,2 @@ | |||||
Makefile | |||||
Makefile.in |
@@ -0,0 +1,15 @@ | |||||
# This Makefile.am is in the public domain | |||||
SUBDIRS = . | |||||
gnunetincludedir = $(includedir)/gnunet | |||||
gnunetinclude_HEADERS = \ | |||||
gnunet_multicast_service.h \ | |||||
gnunet_psycstore_plugin.h \ | |||||
gnunet_psycstore_service.h \ | |||||
gnunet_psyc_service.h \ | |||||
gnunet_psyc_util_lib.h \ | |||||
gnunet_psyc_env.h \ | |||||
gnunet_psyc_message.h \ | |||||
gnunet_psyc_slicer.h \ | |||||
gnunet_social_service.h |
@@ -0,0 +1,925 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2012, 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* @author Christian Grothoff | |||||
* | |||||
* @file | |||||
* Multicast service; multicast messaging via CADET | |||||
* | |||||
* @defgroup multicast Multicast service | |||||
* Multicast messaging via CADET. | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_MULTICAST_SERVICE_H | |||||
#define GNUNET_MULTICAST_SERVICE_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_transport_service.h" | |||||
/** | |||||
* Version number of GNUnet-multicast API. | |||||
*/ | |||||
#define GNUNET_MULTICAST_VERSION 0x00000000 | |||||
/** | |||||
* Opaque handle for a multicast group member. | |||||
*/ | |||||
struct GNUNET_MULTICAST_Member; | |||||
/** | |||||
* Handle for the origin of a multicast group. | |||||
*/ | |||||
struct GNUNET_MULTICAST_Origin; | |||||
enum GNUNET_MULTICAST_MessageFlags | |||||
{ | |||||
/** | |||||
* First fragment of a message. | |||||
*/ | |||||
GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT = 1 << 0, | |||||
/** | |||||
* Last fragment of a message. | |||||
*/ | |||||
GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT = 1 << 1, | |||||
/** | |||||
* OR'ed flags if message is not fragmented. | |||||
*/ | |||||
GNUNET_MULTICAST_MESSAGE_NOT_FRAGMENTED | |||||
= GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT | |||||
| GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT, | |||||
/** | |||||
* Historic message, used only locally when replaying messages from local | |||||
* storage. | |||||
*/ | |||||
GNUNET_MULTICAST_MESSAGE_HISTORIC = 1 << 30 | |||||
}; | |||||
GNUNET_NETWORK_STRUCT_BEGIN | |||||
/** | |||||
* Header of a multicast message fragment. | |||||
* | |||||
* This format is public as the replay mechanism must replay message fragments using the | |||||
* same format. This is needed as we want to integrity-check message fragments within | |||||
* the multicast layer to avoid multicasting mal-formed messages. | |||||
*/ | |||||
struct GNUNET_MULTICAST_MessageHeader | |||||
{ | |||||
/** | |||||
* Header for all multicast message fragments from the origin. | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Number of hops this message fragment has taken since the origin. | |||||
* | |||||
* Helpful to determine shortest paths to the origin among honest peers for | |||||
* unicast requests from members. Updated at each hop and thus not signed and | |||||
* not secure. | |||||
*/ | |||||
uint32_t hop_counter GNUNET_PACKED; | |||||
/** | |||||
* ECC signature of the message fragment. | |||||
* | |||||
* Signature must match the public key of the multicast group. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaSignature signature; | |||||
/** | |||||
* Purpose for the signature and size of the signed data. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | |||||
/** | |||||
* Number of the message fragment, monotonically increasing starting from 1. | |||||
*/ | |||||
uint64_t fragment_id GNUNET_PACKED; | |||||
/** | |||||
* Byte offset of this @e fragment of the @e message. | |||||
*/ | |||||
uint64_t fragment_offset GNUNET_PACKED; | |||||
/** | |||||
* Number of the message this fragment belongs to. | |||||
* | |||||
* Set in GNUNET_MULTICAST_origin_to_all(). | |||||
*/ | |||||
uint64_t message_id GNUNET_PACKED; | |||||
/** | |||||
* Counter that monotonically increases whenever a member parts the group. | |||||
* | |||||
* Set in GNUNET_MULTICAST_origin_to_all(). | |||||
* | |||||
* It has significance in case of replay requests: when a member has missed | |||||
* messages and gets a replay request: in this case if the @a group_generation | |||||
* is still the same before and after the missed messages, it means that no | |||||
* @e join or @e part operations happened during the missed messages. | |||||
*/ | |||||
uint64_t group_generation GNUNET_PACKED; | |||||
/** | |||||
* Flags for this message fragment. | |||||
* | |||||
* @see enum GNUNET_MULTICAST_MessageFlags | |||||
*/ | |||||
uint32_t flags GNUNET_PACKED; | |||||
/* Followed by message body. */ | |||||
}; | |||||
/** | |||||
* Header of a request from a member to the origin. | |||||
*/ | |||||
struct GNUNET_MULTICAST_RequestHeader | |||||
{ | |||||
/** | |||||
* Header for all requests from a member to the origin. | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Public key of the sending member. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
/** | |||||
* ECC signature of the request fragment. | |||||
* | |||||
* Signature must match the public key of the multicast group. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaSignature signature; | |||||
/** | |||||
* Purpose for the signature and size of the signed data. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | |||||
/** | |||||
* Number of the request fragment. | |||||
* Monotonically increasing from 1. | |||||
*/ | |||||
uint64_t fragment_id GNUNET_PACKED; | |||||
/** | |||||
* Byte offset of this @e fragment of the @e request. | |||||
*/ | |||||
uint64_t fragment_offset GNUNET_PACKED; | |||||
/** | |||||
* Number of the request this fragment belongs to. | |||||
* | |||||
* Set in GNUNET_MULTICAST_origin_to_all(). | |||||
*/ | |||||
uint64_t request_id GNUNET_PACKED; | |||||
/** | |||||
* Flags for this request. | |||||
*/ | |||||
enum GNUNET_MULTICAST_MessageFlags flags GNUNET_PACKED; | |||||
/* Followed by request body. */ | |||||
}; | |||||
GNUNET_NETWORK_STRUCT_END | |||||
/** | |||||
* Maximum size of a multicast message fragment. | |||||
*/ | |||||
#define GNUNET_MULTICAST_FRAGMENT_MAX_SIZE (63 * 1024) | |||||
#define GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ | |||||
(GNUNET_MULTICAST_FRAGMENT_MAX_SIZE \ | |||||
- sizeof (struct GNUNET_MULTICAST_MessageHeader)) | |||||
/** | |||||
* Handle that identifies a join request. | |||||
* | |||||
* Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the | |||||
* corresponding calls to #GNUNET_MULTICAST_join_decision(). | |||||
*/ | |||||
struct GNUNET_MULTICAST_JoinHandle; | |||||
/** | |||||
* Function to call with the decision made for a join request. | |||||
* | |||||
* Must be called once and only once in response to an invocation of the | |||||
* #GNUNET_MULTICAST_JoinRequestCallback. | |||||
* | |||||
* @param jh | |||||
* Join request handle. | |||||
* @param is_admitted | |||||
* #GNUNET_YES if the join is approved, | |||||
* #GNUNET_NO if it is disapproved, | |||||
* #GNUNET_SYSERR if we cannot answer the request. | |||||
* @param relay_count | |||||
* Number of relays given. | |||||
* @param relays | |||||
* Array of suggested peers that might be useful relays to use | |||||
* when joining the multicast group (essentially a list of peers that | |||||
* are already part of the multicast group and might thus be willing | |||||
* to help with routing). If empty, only this local peer (which must | |||||
* be the multicast origin) is a good candidate for building the | |||||
* multicast tree. Note that it is unnecessary to specify our own | |||||
* peer identity in this array. | |||||
* @param join_resp | |||||
* Message to send in response to the joining peer; | |||||
* can also be used to redirect the peer to a different group at the | |||||
* application layer; this response is to be transmitted to the | |||||
* peer that issued the request even if admission is denied. | |||||
*/ | |||||
struct GNUNET_MULTICAST_ReplayHandle * | |||||
GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh, | |||||
int is_admitted, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_resp); | |||||
/** | |||||
* Method called whenever another peer wants to join the multicast group. | |||||
* | |||||
* Implementations of this function must call GNUNET_MULTICAST_join_decision() | |||||
* with the decision. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param member_pub_key | |||||
* Public key of the member requesting join. | |||||
* @param join_msg | |||||
* Application-dependent join message from the new member. | |||||
* @param jh | |||||
* Join handle to pass to GNUNET_MULTICAST_join_decison(). | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_JoinRequestCallback) (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh); | |||||
/** | |||||
* Method called to inform about the decision in response to a join request. | |||||
* | |||||
* If @a is_admitted is not #GNUNET_YES, then the multicast service disconnects | |||||
* the client and the multicast member handle returned by | |||||
* GNUNET_MULTICAST_member_join() is invalidated. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param is_admitted | |||||
* #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR | |||||
* @param peer | |||||
* The peer we are connected to and the join decision is from. | |||||
* @param relay_count | |||||
* Number of peers in the @a relays array. | |||||
* @param relays | |||||
* Peer identities of members of the group, which serve as relays | |||||
* and can be used to join the group at. If empty, only the origin can | |||||
* be used to connect to the group. | |||||
* @param join_msg | |||||
* Application-dependent join message from the origin. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_JoinDecisionCallback) (void *cls, | |||||
int is_admitted, | |||||
const struct GNUNET_PeerIdentity *peer, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_msg); | |||||
/** | |||||
* Function called whenever a group member has transmitted a request | |||||
* to the origin (other than joining or leaving). | |||||
* | |||||
* FIXME: need to distinguish between origin cancelling a message (some fragments | |||||
* were sent, then the rest 'discarded') and the case where we got disconnected; | |||||
* right now, both would mean 'msg' is NULL, but they could be quite different... | |||||
* So the semantics from the receiver side of | |||||
* GNUNET_MULTICAST_member_to_origin_cancel() are not clear here. Maybe we | |||||
* should do something with the flags in this case? | |||||
* | |||||
* @param cls | |||||
* Closure (set from GNUNET_MULTICAST_origin_start). | |||||
* @param sender | |||||
* Identity of the sender. | |||||
* @param req | |||||
* Request to the origin. | |||||
* @param flags | |||||
* Flags for the request. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_RequestCallback) (void *cls, | |||||
const struct GNUNET_MULTICAST_RequestHeader *req); | |||||
/** | |||||
* Function called whenever a group member is receiving a message fragment from | |||||
* the origin. | |||||
* | |||||
* If admission to the group is denied, this function is called once with the | |||||
* response of the @e origin (as given to GNUNET_MULTICAST_join_decision()) and | |||||
* then a second time with NULL to indicate that the connection failed for good. | |||||
* | |||||
* FIXME: need to distinguish between origin cancelling a message (some fragments | |||||
* were sent, then the rest 'discarded') and the case where we got disconnected; | |||||
* right now, both would mean 'msg' is NULL, but they could be quite different... | |||||
* So the semantics from the receiver side of | |||||
* GNUNET_MULTICAST_origin_to_all_cancel() are not clear here. | |||||
* | |||||
* @param cls | |||||
* Closure (set from GNUNET_MULTICAST_member_join()) | |||||
* @param msg | |||||
* Message from the origin, NULL if the origin shut down | |||||
* (or we were kicked out, and we should thus call | |||||
* GNUNET_MULTICAST_member_part() next) | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_MessageCallback) (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg); | |||||
/** | |||||
* Opaque handle to a replay request from the multicast service. | |||||
*/ | |||||
struct GNUNET_MULTICAST_ReplayHandle; | |||||
/** | |||||
* Functions with this signature are called whenever the multicast service needs | |||||
* a message fragment to be replayed by fragment_id. | |||||
* | |||||
* Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE | |||||
* (with a message or an error); however, if the origin is destroyed or the | |||||
* group is left, the replay handle must no longer be used. | |||||
* | |||||
* @param cls | |||||
* Closure (set from GNUNET_MULTICAST_origin_start() | |||||
* or GNUNET_MULTICAST_member_join()). | |||||
* @param member_pub_key | |||||
* The member requesting replay. | |||||
* @param fragment_id | |||||
* Which message fragment should be replayed. | |||||
* @param flags | |||||
* Flags for the replay. | |||||
* @param rh | |||||
* Handle to pass to message transmit function. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_ReplayFragmentCallback) (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
uint64_t fragment_id, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh); | |||||
/** | |||||
* Functions with this signature are called whenever the multicast service needs | |||||
* a message fragment to be replayed by message_id and fragment_offset. | |||||
* | |||||
* Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE | |||||
* (with a message or an error); however, if the origin is destroyed or the | |||||
* group is left, the replay handle must no longer be used. | |||||
* | |||||
* @param cls | |||||
* Closure (set from GNUNET_MULTICAST_origin_start() | |||||
* or GNUNET_MULTICAST_member_join()). | |||||
* @param member_pub_key | |||||
* The member requesting replay. | |||||
* @param message_id | |||||
* Which message should be replayed. | |||||
* @param fragment_offset | |||||
* Offset of the fragment within of @a message_id to be replayed. | |||||
* @param flags | |||||
* Flags for the replay. | |||||
* @param rh | |||||
* Handle to pass to message transmit function. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_MULTICAST_ReplayMessageCallback) (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh); | |||||
/** | |||||
* Possible error codes during replay. | |||||
*/ | |||||
enum GNUNET_MULTICAST_ReplayErrorCode | |||||
{ | |||||
/** | |||||
* Everything is fine. | |||||
*/ | |||||
GNUNET_MULTICAST_REC_OK = 0, | |||||
/** | |||||
* Message fragment not found in the message store. | |||||
* | |||||
* Either discarded if it is too old, or not arrived yet if this member has | |||||
* missed some messages. | |||||
*/ | |||||
GNUNET_MULTICAST_REC_NOT_FOUND = 1, | |||||
/** | |||||
* Fragment ID counter was larger than the highest counter this | |||||
* replay function has ever encountered; thus it is likely the | |||||
* origin never sent it and we're at the HEAD of the multicast | |||||
* stream as far as this node is concerned. | |||||
* | |||||
* FIXME: needed? | |||||
*/ | |||||
GNUNET_MULTICAST_REC_PAST_HEAD = 2, | |||||
/** | |||||
* Access is denied to the requested fragment, membership test did not pass. | |||||
*/ | |||||
GNUNET_MULTICAST_REC_ACCESS_DENIED = 3, | |||||
/** | |||||
* Internal error (i.e. database error). Try some other peer. | |||||
*/ | |||||
GNUNET_MULTICAST_REC_INTERNAL_ERROR = 4 | |||||
}; | |||||
/** | |||||
* Replay a message fragment for the multicast group. | |||||
* | |||||
* @param rh | |||||
* Replay handle identifying which replay operation was requested. | |||||
* @param msg | |||||
* Replayed message fragment, NULL if not found / an error occurred. | |||||
* @param ec | |||||
* Error code. See enum GNUNET_MULTICAST_ReplayErrorCode | |||||
* If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh, | |||||
const struct GNUNET_MessageHeader *msg, | |||||
enum GNUNET_MULTICAST_ReplayErrorCode ec); | |||||
/** | |||||
* Indicate the end of the replay session. | |||||
* | |||||
* Invalidates the replay handle. | |||||
* | |||||
* @param rh Replay session to end. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh); | |||||
/** | |||||
* Function called to provide data for a transmission for a replay. | |||||
* | |||||
* @see GNUNET_MULTICAST_replay2() | |||||
*/ | |||||
typedef int | |||||
(*GNUNET_MULTICAST_ReplayTransmitNotify) (void *cls, | |||||
size_t *data_size, | |||||
void *data); | |||||
/** | |||||
* Replay a message for the multicast group. | |||||
* | |||||
* @param rh | |||||
* Replay handle identifying which replay operation was requested. | |||||
* @param notify | |||||
* Function to call to get the message. | |||||
* @param notify_cls | |||||
* Closure for @a notify. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh, | |||||
GNUNET_MULTICAST_ReplayTransmitNotify notify, | |||||
void *notify_cls); | |||||
/** | |||||
* Start a multicast group. | |||||
* | |||||
* Peers that issue GNUNET_MULTICAST_member_join() can transmit a join request | |||||
* to either an existing group member or to the origin. If the joining is | |||||
* approved, the member is cleared for @e replay and will begin to receive | |||||
* messages transmitted to the group. If joining is disapproved, the failed | |||||
* candidate will be given a response. Members in the group can send messages | |||||
* to the origin. | |||||
* | |||||
* TODO: This function could optionally offer to advertise the origin in the | |||||
* P2P overlay network(where?) under the respective public key so that other | |||||
* peers can find an alternate PeerId to join it. Higher level protocols may | |||||
* however provide other means of solving the problem of the offline host | |||||
* (see secushare specs about that) and therefore merely need a way to provide | |||||
* a list of possible PeerIds. | |||||
* | |||||
* @param cfg | |||||
* Configuration to use. | |||||
* @param priv_key | |||||
* ECC key that will be used to sign messages for this | |||||
* multicast session; public key is used to identify the multicast group; | |||||
* @param max_fragment_id | |||||
* Maximum fragment ID already sent to the group. | |||||
* 0 for a new group. | |||||
* @param join_request_cb | |||||
* Function called to approve / disapprove joining of a peer. | |||||
* @param replay_frag_cb | |||||
* Function that can be called to replay a message fragment. | |||||
* @param replay_msg_cb | |||||
* Function that can be called to replay a message. | |||||
* @param request_cb | |||||
* Function called with message fragments from group members. | |||||
* @param message_cb | |||||
* Function called with the message fragments sent to the | |||||
* network by GNUNET_MULTICAST_origin_to_all(). These message fragments | |||||
* should be stored for answering replay requests later. | |||||
* @param cls | |||||
* Closure for the various callbacks that follow. | |||||
* | |||||
* @return Handle for the origin, NULL on error. | |||||
*/ | |||||
struct GNUNET_MULTICAST_Origin * | |||||
GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||||
const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key, | |||||
uint64_t max_fragment_id, | |||||
GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | |||||
GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | |||||
GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | |||||
GNUNET_MULTICAST_RequestCallback request_cb, | |||||
GNUNET_MULTICAST_MessageCallback message_cb, | |||||
void *cls); | |||||
/** | |||||
* Function called to provide data for a transmission from the origin to all | |||||
* members. | |||||
* | |||||
* Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) | |||||
* invalidates the respective transmission handle. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param[in,out] data_size | |||||
* Initially set to the number of bytes available in | |||||
* @a data, should be set to the number of bytes written to data. | |||||
* @param[out] data | |||||
* Where to write the body of the message to give to the | |||||
* method. The function must copy at most @a data_size bytes to @a data. | |||||
* | |||||
* @return #GNUNET_SYSERR on error (fatal, aborts transmission) | |||||
* #GNUNET_NO on success, if more data is to be transmitted later. | |||||
* Should be used if @a data_size was not big enough to take all the | |||||
* data. If 0 is returned in @a data_size the transmission is paused, | |||||
* and can be resumed with GNUNET_MULTICAST_origin_to_all_resume(). | |||||
* #GNUNET_YES if this completes the transmission (all data supplied) | |||||
* @deprecated should move to MQ-style API! | |||||
*/ | |||||
typedef int | |||||
(*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls, | |||||
size_t *data_size, | |||||
void *data); | |||||
/** | |||||
* Handle for a request to send a message to all multicast group members | |||||
* (from the origin). | |||||
*/ | |||||
struct GNUNET_MULTICAST_OriginTransmitHandle; | |||||
/** | |||||
* Send a message to the multicast group. | |||||
* | |||||
* @param origin | |||||
* Handle to the multicast group. | |||||
* @param message_id | |||||
* Application layer ID for the message. Opaque to multicast. | |||||
* @param group_generation | |||||
* Group generation of the message. Documented in | |||||
* struct GNUNET_MULTICAST_MessageHeader. | |||||
* @param notify | |||||
* Function to call to get the message. | |||||
* @param notify_cls | |||||
* Closure for @a notify. | |||||
* | |||||
* @return NULL on error (i.e. request already pending). | |||||
* @deprecated should move to MQ-style API! | |||||
*/ | |||||
struct GNUNET_MULTICAST_OriginTransmitHandle * | |||||
GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin, | |||||
uint64_t message_id, | |||||
uint64_t group_generation, | |||||
GNUNET_MULTICAST_OriginTransmitNotify notify, | |||||
void *notify_cls); | |||||
/** | |||||
* Resume message transmission to multicast group. | |||||
* | |||||
* @param th Transmission to cancel. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th); | |||||
/** | |||||
* Cancel request for message transmission to multicast group. | |||||
* | |||||
* @param th Transmission to cancel. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th); | |||||
/** | |||||
* Stop a multicast group. | |||||
* | |||||
* @param origin Multicast group to stop. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin, | |||||
GNUNET_ContinuationCallback stop_cb, | |||||
void *stop_cls); | |||||
/** | |||||
* Join a multicast group. | |||||
* | |||||
* The entity joining is always the local peer. Further information about the | |||||
* candidate can be provided in @a join_msg. If the join fails, the | |||||
* @a message_cb is invoked with a (failure) response and then with NULL. If | |||||
* the join succeeds, outstanding (state) messages and ongoing multicast | |||||
* messages will be given to the @a message_cb until the member decides to part | |||||
* the group. The @a mem_test_cb and @a replay_cb functions may be called at | |||||
* anytime by the multicast service to support relaying messages to other | |||||
* members of the group. | |||||
* | |||||
* @param cfg | |||||
* Configuration to use. | |||||
* @param group_key | |||||
* ECC public key that identifies the group to join. | |||||
* @param member_pub_key | |||||
* ECC key that identifies the member | |||||
* and used to sign requests sent to the origin. | |||||
* @param origin | |||||
* Peer ID of the origin to send unicast requsets to. If NULL, | |||||
* unicast requests are sent back via multiple hops on the reverse path | |||||
* of multicast messages. | |||||
* @param relay_count | |||||
* Number of peers in the @a relays array. | |||||
* @param relays | |||||
* Peer identities of members of the group, which serve as relays | |||||
* and can be used to join the group at. and send the @a join_request to. | |||||
* If empty, the @a join_request is sent directly to the @a origin. | |||||
* @param join_msg | |||||
* Application-dependent join message to be passed to the peer @a origin. | |||||
* @param join_request_cb | |||||
* Function called to approve / disapprove joining of a peer. | |||||
* @param join_decision_cb | |||||
* Function called to inform about the join decision. | |||||
* @param replay_frag_cb | |||||
* Function that can be called to replay message fragments | |||||
* this peer already knows from this group. NULL if this | |||||
* client is unable to support replay. | |||||
* @param replay_msg_cb | |||||
* Function that can be called to replay message fragments | |||||
* this peer already knows from this group. NULL if this | |||||
* client is unable to support replay. | |||||
* @param message_cb | |||||
* Function to be called for all message fragments we | |||||
* receive from the group, excluding those our @a replay_cb | |||||
* already has. | |||||
* @param cls | |||||
* Closure for callbacks. | |||||
* | |||||
* @return Handle for the member, NULL on error. | |||||
*/ | |||||
struct GNUNET_MULTICAST_Member * | |||||
GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *group_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_pub_key, | |||||
const struct GNUNET_PeerIdentity *origin, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_request, | |||||
GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | |||||
GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb, | |||||
GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | |||||
GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | |||||
GNUNET_MULTICAST_MessageCallback message_cb, | |||||
void *cls); | |||||
/** | |||||
* Handle for a replay request. | |||||
*/ | |||||
struct GNUNET_MULTICAST_MemberReplayHandle; | |||||
/** | |||||
* Request a fragment to be replayed by fragment ID. | |||||
* | |||||
* Useful if messages below the @e max_known_fragment_id given when joining are | |||||
* needed and not known to the client. | |||||
* | |||||
* @param member | |||||
* Membership handle. | |||||
* @param fragment_id | |||||
* ID of a message fragment that this client would like to see replayed. | |||||
* @param flags | |||||
* Additional flags for the replay request. | |||||
* It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback | |||||
* | |||||
* @return Replay request handle, NULL on error. | |||||
*/ | |||||
struct GNUNET_MULTICAST_MemberReplayHandle * | |||||
GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member, | |||||
uint64_t fragment_id, | |||||
uint64_t flags); | |||||
/** | |||||
* Request a message fr to be replayed. | |||||
* | |||||
* Useful if messages below the @e max_known_fragment_id given when joining are | |||||
* needed and not known to the client. | |||||
* | |||||
* @param member | |||||
* Membership handle. | |||||
* @param message_id | |||||
* ID of the message this client would like to see replayed. | |||||
* @param fragment_offset | |||||
* Offset of the fragment within the message to replay. | |||||
* @param flags | |||||
* Additional flags for the replay request. | |||||
* It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback | |||||
* | |||||
* @return Replay request handle, NULL on error. | |||||
*/ | |||||
struct GNUNET_MULTICAST_MemberReplayHandle * | |||||
GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
uint64_t flags); | |||||
/** | |||||
* Cancel a replay request. | |||||
* | |||||
* @param rh | |||||
* Request to cancel. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh); | |||||
/** | |||||
* Part a multicast group. | |||||
* | |||||
* Disconnects from all group members and invalidates the @a member handle. | |||||
* | |||||
* An application-dependent part message can be transmitted beforehand using | |||||
* #GNUNET_MULTICAST_member_to_origin()) | |||||
* | |||||
* @param member | |||||
* Membership handle. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member, | |||||
GNUNET_ContinuationCallback part_cb, | |||||
void *part_cls); | |||||
/** | |||||
* Function called to provide data for a transmission from a member to the origin. | |||||
* | |||||
* Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) | |||||
* invalidates the respective transmission handle. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param[in,out] data_size | |||||
* Initially set to the number of bytes available in | |||||
* @a data, should be set to the number of bytes written to data. | |||||
* @param[out] data | |||||
* Where to write the body of the message to give to the | |||||
* method. The function must copy at most @a data_size bytes to @a data. | |||||
* | |||||
* @return #GNUNET_SYSERR on error (fatal, aborts transmission) | |||||
* #GNUNET_NO on success, if more data is to be transmitted later. | |||||
* Should be used if @a data_size was not big enough to take all the | |||||
* data. If 0 is returned in @a data_size the transmission is paused, | |||||
* and can be resumed with GNUNET_MULTICAST_member_to_origin_resume(). | |||||
* #GNUNET_YES if this completes the transmission (all data supplied) | |||||
* @deprecated should move to MQ-style API! | |||||
*/ | |||||
typedef int | |||||
(*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls, | |||||
size_t *data_size, | |||||
void *data); | |||||
/** | |||||
* Handle for a message to be delivered from a member to the origin. | |||||
*/ | |||||
struct GNUNET_MULTICAST_MemberTransmitHandle; | |||||
/** | |||||
* Send a message to the origin of the multicast group. | |||||
* | |||||
* @param member | |||||
* Membership handle. | |||||
* @param request_id | |||||
* Application layer ID for the request. Opaque to multicast. | |||||
* @param notify | |||||
* Callback to call to get the message. | |||||
* @param notify_cls | |||||
* Closure for @a notify. | |||||
* | |||||
* @return Handle to cancel request, NULL on error (i.e. request already pending). | |||||
* @deprecated should move to MQ-style API! | |||||
*/ | |||||
struct GNUNET_MULTICAST_MemberTransmitHandle * | |||||
GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member, | |||||
uint64_t request_id, | |||||
GNUNET_MULTICAST_MemberTransmitNotify notify, | |||||
void *notify_cls); | |||||
/** | |||||
* Resume message transmission to origin. | |||||
* | |||||
* @param th | |||||
* Transmission to cancel. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th); | |||||
/** | |||||
* Cancel request for message transmission to origin. | |||||
* | |||||
* @param th | |||||
* Transmission to cancel. | |||||
*/ | |||||
void | |||||
GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th); | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_MULTICAST_SERVICE_H */ | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,340 @@ | |||||
/* | |||||
* This file is part of GNUnet. | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* PSYC Environment library | |||||
* | |||||
* @defgroup psyc-util-env PSYC Utilities library: Environment | |||||
* Environment data structure operations for PSYC and Social messages. | |||||
* | |||||
* Library providing operations for the @e environment of | |||||
* PSYC and Social messages, and for (de)serializing variable values. | |||||
* | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_PSYC_ENV_H | |||||
#define GNUNET_PSYC_ENV_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
/** | |||||
* Possible operations on PSYC state (persistent) and transient variables (per message). | |||||
*/ | |||||
enum GNUNET_PSYC_Operator | |||||
{ | |||||
/** | |||||
* Set value of a transient variable. | |||||
*/ | |||||
GNUNET_PSYC_OP_SET = ':', | |||||
/** | |||||
* Assign value for a persistent state variable. | |||||
* | |||||
* If an assigned value is NULL, the variable is deleted. | |||||
*/ | |||||
GNUNET_PSYC_OP_ASSIGN = '=', | |||||
/** | |||||
* Augment state variable. | |||||
* | |||||
* Used for appending strings, adding numbers, and adding new items to a list or dictionary. | |||||
*/ | |||||
GNUNET_PSYC_OP_AUGMENT = '+', | |||||
/** | |||||
* Diminish state variable. | |||||
* | |||||
* Used for subtracting numbers, and removing items from a list or dictionary. | |||||
*/ | |||||
GNUNET_PSYC_OP_DIMINISH = '-', | |||||
/** | |||||
* Update state variable. | |||||
* | |||||
* Used for modifying a single item of a list or dictionary. | |||||
*/ | |||||
GNUNET_PSYC_OP_UPDATE = '@', | |||||
}; | |||||
/** | |||||
* PSYC variable types. | |||||
*/ | |||||
enum GNUNET_PSYC_Type | |||||
{ | |||||
GNUNET_PSYC_TYPE_DATA = 0, | |||||
GNUNET_PSYC_TYPE_NUMBER, | |||||
GNUNET_PSYC_TYPE_LIST, | |||||
GNUNET_PSYC_TYPE_DICT | |||||
}; | |||||
/** | |||||
* PSYC state modifier. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier | |||||
{ | |||||
/** | |||||
* State operation. | |||||
*/ | |||||
enum GNUNET_PSYC_Operator oper; | |||||
/** | |||||
* Variable name. | |||||
*/ | |||||
const char *name; | |||||
/** | |||||
* Size of @a value. | |||||
*/ | |||||
size_t value_size; | |||||
/** | |||||
* Value of variable. | |||||
*/ | |||||
const void *value; | |||||
/** | |||||
* Next modifier. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier *next; | |||||
/** | |||||
* Previous modifier. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier *prev; | |||||
}; | |||||
/** | |||||
* Environment for a message. | |||||
* | |||||
* Contains modifiers. | |||||
*/ | |||||
struct GNUNET_PSYC_Environment; | |||||
/** | |||||
* Create an environment. | |||||
* | |||||
* @return A newly allocated environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Environment * | |||||
GNUNET_PSYC_env_create (); | |||||
/** | |||||
* Add a modifier to the environment. | |||||
* | |||||
* @param env The environment. | |||||
* @param oper Operation to perform. | |||||
* @param name Name of the variable. | |||||
* @param value Value of the variable. | |||||
* @param value_size Size of @a value. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, | |||||
enum GNUNET_PSYC_Operator oper, const char *name, | |||||
const void *value, size_t value_size); | |||||
/** | |||||
* Get the first modifier of the environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier * | |||||
GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env); | |||||
/** | |||||
* Get the last modifier of the environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier * | |||||
GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env); | |||||
/** | |||||
* Remove a modifier from the environment. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, | |||||
struct GNUNET_PSYC_Modifier *mod); | |||||
/** | |||||
* Remove a modifier at the beginning of the environment. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, | |||||
enum GNUNET_PSYC_Operator *oper, const char **name, | |||||
const void **value, size_t *value_size); | |||||
/** | |||||
* Iterator for modifiers in the environment. | |||||
* | |||||
* @param cls Closure. | |||||
* @param mod Modifier. | |||||
* | |||||
* @return #GNUNET_YES to continue iterating, | |||||
* #GNUNET_NO to stop. | |||||
*/ | |||||
typedef int | |||||
(*GNUNET_PSYC_Iterator) (void *cls, enum GNUNET_PSYC_Operator oper, | |||||
const char *name, const char *value, | |||||
uint32_t value_size); | |||||
/** | |||||
* Iterate through all modifiers in the environment. | |||||
* | |||||
* @param env The environment. | |||||
* @param it Iterator. | |||||
* @param it_cls Closure for iterator. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, | |||||
GNUNET_PSYC_Iterator it, void *it_cls); | |||||
/** | |||||
* Get the number of modifiers in the environment. | |||||
* | |||||
* @param env The environment. | |||||
* | |||||
* @return Number of modifiers. | |||||
*/ | |||||
size_t | |||||
GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env); | |||||
/** | |||||
* Destroy an environment. | |||||
* | |||||
* @param env The environment to destroy. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env); | |||||
/** | |||||
* Get the type of variable. | |||||
* | |||||
* @param name Name of the variable. | |||||
* | |||||
* @return Variable type. | |||||
*/ | |||||
enum GNUNET_PSYC_Type | |||||
GNUNET_PSYC_var_get_type (char *name); | |||||
/** | |||||
* Perform an operation on a variable. | |||||
* | |||||
* @param name Name of variable. | |||||
* @param current_value Current value of variable. | |||||
* @param current_value_size Size of @a current_value. | |||||
* @param oper Operator. | |||||
* @param args Arguments for the operation. | |||||
* @param args_size Size of @a args. | |||||
* @param return_value Return value. | |||||
* @param return_value_size Size of @a return_value. | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_operation (char *name, void *current_value, size_t current_value_size, | |||||
enum GNUNET_PSYC_Operator oper, void *args, size_t args_size, | |||||
void **return_value, size_t *return_value_size); | |||||
/** | |||||
* Get the variable's value as an integer. | |||||
* | |||||
* @param size Size of value. | |||||
* @param value Raw value of variable. | |||||
* @param[out] number Value converted to a 64-bit integer. | |||||
* | |||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_value_to_number (size_t size, const void *value, int64_t *number); | |||||
/** | |||||
* Get the variable's value as a dictionary. | |||||
* | |||||
* @param size Size of value. | |||||
* @param value Raw value of variable. | |||||
* @param[out] dict A newly created hashmap holding the elements of the dictionary. | |||||
* | |||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_value_to_dict (size_t size, const void *value, struct GNUNET_CONTAINER_MultiHashMap **dict); | |||||
/** | |||||
* Create a PSYC variable value from an integer. | |||||
* | |||||
* @param number The number to convert. | |||||
* @param[out] value_size Size of returned value. | |||||
* | |||||
* @return A newly allocated value or NULL on error. | |||||
*/ | |||||
void * | |||||
GNUNET_PSYC_value_from_number (int64_t number, size_t *value_size); | |||||
/** | |||||
* Create a PSYC variable value from a dictionary. | |||||
* | |||||
* @param dict The dict to convert. | |||||
* @param[out] value_size Size of returned value. | |||||
* | |||||
* @return A newly allocated value or NULL on error. | |||||
*/ | |||||
void * | |||||
GNUNET_PSYC_value_from_dict (struct GNUNET_CONTAINER_MultiHashMap *dict, size_t *value_size); | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_PSYC_ENV_H */ | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,278 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2012, 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* PSYC message utilities; receiving/transmitting/logging PSYC messages | |||||
* | |||||
* @defgroup psyc-util-message PSYC Utilities library: Messages | |||||
* Receiving, transmitting, logging PSYC messages. | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_PSYC_MESSAGE_H | |||||
#define GNUNET_PSYC_MESSAGE_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
#include "gnunet_psyc_service.h" | |||||
/** | |||||
* Create a PSYC message. | |||||
* | |||||
* @param method_name | |||||
* PSYC method for the message. | |||||
* @param env | |||||
* Environment for the message. | |||||
* @param data | |||||
* Data payload for the message. | |||||
* @param data_size | |||||
* Size of @a data. | |||||
* | |||||
* @return Message header with size information, | |||||
* followed by the message parts. | |||||
* | |||||
* FIXME: arg order | |||||
*/ | |||||
struct GNUNET_PSYC_Message * | |||||
GNUNET_PSYC_message_create (const char *method_name, | |||||
const struct GNUNET_PSYC_Environment *env, | |||||
const void *data, | |||||
size_t data_size); | |||||
/** | |||||
* Parse PSYC message. | |||||
* | |||||
* @param msg | |||||
* The PSYC message to parse. | |||||
* @param env | |||||
* The environment for the message with a list of modifiers. | |||||
* @param[out] method_name | |||||
* Pointer to the method name inside @a pmsg. | |||||
* @param[out] data | |||||
* Pointer to data inside @a pmsg. | |||||
* @param[out] data_size | |||||
* Size of @data is written here. | |||||
* | |||||
* @return #GNUNET_OK on success, | |||||
* #GNUNET_SYSERR on parse error. | |||||
* | |||||
* FIXME: arg order | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const char **method_name, | |||||
struct GNUNET_PSYC_Environment *env, | |||||
const void **data, | |||||
uint16_t *data_size); | |||||
void | |||||
GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, | |||||
const struct GNUNET_MessageHeader *msg); | |||||
struct GNUNET_PSYC_TransmitHandle; | |||||
/** | |||||
* Create a transmission handle. | |||||
*/ | |||||
struct GNUNET_PSYC_TransmitHandle * | |||||
GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq); | |||||
/** | |||||
* Destroy a transmission handle. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit); | |||||
/** | |||||
* Transmit a message. | |||||
* | |||||
* @param tmit | |||||
* Transmission handle. | |||||
* @param method_name | |||||
* Which method should be invoked. | |||||
* @param env | |||||
* Environment for the message. | |||||
* Should stay available until the first call to notify_data. | |||||
* Can be NULL if there are no modifiers or @a notify_mod is | |||||
* provided instead. | |||||
* @param notify_mod | |||||
* Function to call to obtain modifiers. | |||||
* Can be NULL if there are no modifiers or @a env is provided instead. | |||||
* @param notify_data | |||||
* Function to call to obtain fragments of the data. | |||||
* @param notify_cls | |||||
* Closure for @a notify_mod and @a notify_data. | |||||
* @param flags | |||||
* Flags for the message being transmitted. | |||||
* | |||||
* @return #GNUNET_OK if the transmission was started. | |||||
* #GNUNET_SYSERR if another transmission is already going on. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit, | |||||
const char *method_name, | |||||
const struct GNUNET_PSYC_Environment *env, | |||||
GNUNET_PSYC_TransmitNotifyModifier notify_mod, | |||||
GNUNET_PSYC_TransmitNotifyData notify_data, | |||||
void *notify_cls, | |||||
uint32_t flags); | |||||
/** | |||||
* Resume transmission. | |||||
* | |||||
* @param tmit Transmission handle. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit); | |||||
/** | |||||
* Abort transmission request. | |||||
* | |||||
* @param tmit Transmission handle. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit); | |||||
/** | |||||
* Got acknowledgement of a transmitted message part, continue transmission. | |||||
* | |||||
* @param tmit Transmission handle. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit); | |||||
struct GNUNET_PSYC_ReceiveHandle; | |||||
/** | |||||
* Create handle for receiving messages. | |||||
*/ | |||||
struct GNUNET_PSYC_ReceiveHandle * | |||||
GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, | |||||
GNUNET_PSYC_MessagePartCallback message_part_cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Destroy handle for receiving messages. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv); | |||||
/** | |||||
* Reset stored data related to the last received message. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv); | |||||
/** | |||||
* Handle incoming PSYC message. | |||||
* | |||||
* @param recv | |||||
* Receive handle. | |||||
* @param msg | |||||
* The message. | |||||
* | |||||
* @return #GNUNET_OK on success, | |||||
* #GNUNET_SYSERR on receive error. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv, | |||||
const struct GNUNET_PSYC_MessageHeader *msg); | |||||
/** | |||||
* Check if @a data contains a series of valid message parts. | |||||
* | |||||
* @param data_size | |||||
* Size of @a data. | |||||
* @param data | |||||
* Data. | |||||
* @param[out] first_ptype | |||||
* Type of first message part. | |||||
* @param[out] last_ptype | |||||
* Type of last message part. | |||||
* | |||||
* @return Number of message parts found in @a data. | |||||
* or GNUNET_SYSERR if the message contains invalid parts. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data, | |||||
uint16_t *first_ptype, uint16_t *last_ptype); | |||||
/** | |||||
* Initialize PSYC message header. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg, | |||||
const struct GNUNET_MULTICAST_MessageHeader *mmsg, | |||||
uint32_t flags); | |||||
/** | |||||
* Create a new PSYC message header from a multicast message for sending it to clients. | |||||
*/ | |||||
struct GNUNET_PSYC_MessageHeader * | |||||
GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg, | |||||
uint32_t flags); | |||||
/** | |||||
* Create a new PSYC message header from a PSYC message. | |||||
*/ | |||||
struct GNUNET_PSYC_MessageHeader * | |||||
GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg); | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_PSYC_MESSAGE_H */ | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,378 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* @author Christian Grothoff | |||||
* | |||||
* @file | |||||
* PSYC Slicer library | |||||
* | |||||
* @defgroup psyc-util-slicer PSYC Utilities library: Slicer | |||||
* Try-and-slice processing of PSYC method names and environment. | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_PSYC_SLICER_H | |||||
#define GNUNET_PSYC_SLICER_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
#include "gnunet_util_lib.h" | |||||
/** | |||||
* Handle to an implementation of try-and-slice. | |||||
*/ | |||||
struct GNUNET_PSYC_Slicer; | |||||
/** | |||||
* Function called upon receiving a message indicating a call to a @e method. | |||||
* | |||||
* This function is called one or more times for each message until all data | |||||
* fragments arrive from the network. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param msg | |||||
* Message part, as it arrived from the network. | |||||
* @param message_id | |||||
* Message counter, monotonically increasing from 1. | |||||
* @param flags | |||||
* OR'ed GNUNET_PSYC_MessageFlags | |||||
* @param fragment_offset | |||||
* Multicast message fragment offset. | |||||
* @param tmit_flags | |||||
* OR'ed GNUNET_PSYC_MasterTransmitFlags | |||||
* @param nym | |||||
* The sender of the message. | |||||
* Can be NULL if the message is not connected to a pseudonym. | |||||
* @param method_name | |||||
* Original method name from PSYC. | |||||
* May be more specific than the registered method name due to | |||||
* try-and-slice matching. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYC_MethodCallback) (void *cls, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_PSYC_MessageMethod *meth, | |||||
uint64_t message_id, | |||||
const char *method_name); | |||||
/** | |||||
* Function called upon receiving a modifier of a message. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param message_id | |||||
* Message ID this data fragment belongs to. | |||||
* @param flags | |||||
* OR'ed GNUNET_PSYC_MessageFlags | |||||
* @param fragment_offset | |||||
* Multicast message fragment offset. | |||||
* @param msg | |||||
* Message part, as it arrived from the network. | |||||
* @param oper | |||||
* Operation to perform. | |||||
* 0 in case of a modifier continuation. | |||||
* @param name | |||||
* Name of the modifier. | |||||
* NULL in case of a modifier continuation. | |||||
* @param value | |||||
* Value of the modifier. | |||||
* @param value_size | |||||
* Size of @value. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYC_ModifierCallback) (void *cls, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_MessageHeader *pmsg, | |||||
uint64_t message_id, | |||||
enum GNUNET_PSYC_Operator oper, | |||||
const char *name, | |||||
const void *value, | |||||
uint16_t value_size, | |||||
uint16_t full_value_size); | |||||
/** | |||||
* Function called upon receiving a data fragment of a message. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param msg | |||||
* Message part, as it arrived from the network. | |||||
* @param message_id | |||||
* Message ID this data fragment belongs to. | |||||
* @param flags | |||||
* OR'ed GNUNET_PSYC_MessageFlags | |||||
* @param fragment_offset | |||||
* Multicast message fragment offset. | |||||
* @param data | |||||
* Data stream given to the method. | |||||
* @param data_size | |||||
* Number of bytes in @a data. | |||||
* @param end | |||||
* End of message? | |||||
* #GNUNET_NO if there are further fragments, | |||||
* #GNUNET_YES if this is the last fragment, | |||||
* #GNUNET_SYSERR indicates the message was cancelled by the sender. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYC_DataCallback) (void *cls, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_MessageHeader *pmsg, | |||||
uint64_t message_id, | |||||
const void *data, | |||||
uint16_t data_size); | |||||
/** | |||||
* End of message. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param msg | |||||
* Message part, as it arrived from the network. | |||||
* @param message_id | |||||
* Message ID this data fragment belongs to. | |||||
* @param flags | |||||
* OR'ed GNUNET_PSYC_MessageFlags | |||||
* @param fragment_offset | |||||
* Multicast message fragment offset. | |||||
* @param cancelled | |||||
* #GNUNET_YES if the message was cancelled, | |||||
* #GNUNET_NO if the message is complete. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYC_EndOfMessageCallback) (void *cls, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_MessageHeader *pmsg, | |||||
uint64_t message_id, | |||||
uint8_t is_cancelled); | |||||
/** | |||||
* Create a try-and-slice instance. | |||||
* | |||||
* A slicer processes incoming messages and notifies callbacks about matching | |||||
* methods or modifiers encountered. | |||||
* | |||||
* @return A new try-and-slice construct. | |||||
*/ | |||||
struct GNUNET_PSYC_Slicer * | |||||
GNUNET_PSYC_slicer_create (void); | |||||
/** | |||||
* Add a method to the try-and-slice instance. | |||||
* | |||||
* The callbacks are called for messages with a matching @a method_name prefix. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance to extend. | |||||
* @param method_name | |||||
* Name of the given method, use empty string to match all. | |||||
* @param method_cb | |||||
* Method handler invoked upon a matching message. | |||||
* @param modifier_cb | |||||
* Modifier handler, invoked after @a method_cb | |||||
* for each modifier in the message. | |||||
* @param data_cb | |||||
* Data handler, invoked after @a modifier_cb for each data fragment. | |||||
* @param eom_cb | |||||
* Invoked upon reaching the end of a matching message. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *method_name, | |||||
GNUNET_PSYC_MessageCallback msg_cb, | |||||
GNUNET_PSYC_MethodCallback method_cb, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
GNUNET_PSYC_DataCallback data_cb, | |||||
GNUNET_PSYC_EndOfMessageCallback eom_cb, | |||||
void *cls); | |||||
/** | |||||
* Remove a registered method from the try-and-slice instance. | |||||
* | |||||
* Removes one matching handler registered with the given | |||||
* @a method_name and callbacks. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param method_name | |||||
* Name of the method to remove. | |||||
* @param method_cb | |||||
* Only remove matching method handler, or NULL. | |||||
* @param modifier_cb | |||||
* Only remove matching modifier handler, or NULL. | |||||
* @param data_cb | |||||
* Only remove matching data handler, or NULL. | |||||
* @param eom_cb | |||||
* Only remove matching End of Message handler, or NULL. | |||||
* | |||||
* @return #GNUNET_OK if a method handler was removed, | |||||
* #GNUNET_NO if no handler matched the given method name and callbacks. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *method_name, | |||||
GNUNET_PSYC_MessageCallback msg_cb, | |||||
GNUNET_PSYC_MethodCallback method_cb, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
GNUNET_PSYC_DataCallback data_cb, | |||||
GNUNET_PSYC_EndOfMessageCallback eom_cb); | |||||
/** | |||||
* Watch a place for changed objects. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param object_filter | |||||
* Object prefix to match. | |||||
* @param modifier_cb | |||||
* Function to call when encountering a state modifier. | |||||
* @param cls | |||||
* Closure for callback. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *object_filter, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
void *cls); | |||||
/** | |||||
* Remove a registered modifier from the try-and-slice instance. | |||||
* | |||||
* Removes one matching handler registered with the given | |||||
* @a object_filter and callback. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param object_filter | |||||
* Object prefix to match. | |||||
* @param modifier_cb | |||||
* Function to call when encountering a state modifier changes. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *object_filter, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb); | |||||
/** | |||||
* Process an incoming message and call matching handlers. | |||||
* | |||||
* @param slicer | |||||
* The slicer to use. | |||||
* @param msg | |||||
* The message as it arrived from the network. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, | |||||
const struct GNUNET_PSYC_MessageHeader *msg); | |||||
/** | |||||
* Process an incoming message part and call matching handlers. | |||||
* | |||||
* @param slicer | |||||
* The slicer to use. | |||||
* @param message_id | |||||
* ID of the message. | |||||
* @param flags | |||||
* Flags for the message. | |||||
* @see enum GNUNET_PSYC_MessageFlags | |||||
* @param fragment offset | |||||
* Fragment offset of the message. | |||||
* @param msg | |||||
* The message part as it arrived from the network. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_MessageHeader *pmsg); | |||||
/** | |||||
* Remove all registered method handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer); | |||||
/** | |||||
* Remove all registered modifier handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer); | |||||
/** | |||||
* Remove all registered method & modifier handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer); | |||||
/** | |||||
* Destroy a given try-and-slice instance. | |||||
* | |||||
* @param slicer | |||||
* Slicer to destroy | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer); | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_PSYC_SLICER_H */ | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,53 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2012, 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* PSYC utilities: messages, environment, slicer | |||||
*/ | |||||
#ifndef GNUNET_PSYC_UTIL_LIB_H | |||||
#define GNUNET_PSYC_UTIL_LIB_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
#include "gnunet_psyc_env.h" | |||||
#include "gnunet_psyc_message.h" | |||||
#include "gnunet_psyc_slicer.h" | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_PSYC_UTIL_LIB_H */ | |||||
#endif |
@@ -0,0 +1,383 @@ | |||||
/* | |||||
This file is part of GNUnet | |||||
Copyright (C) 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* Plugin API for the PSYCstore database backend | |||||
* | |||||
* @defgroup psycstore-plugin PSYC Store plugin API | |||||
* Plugin API for the PSYC Store database backend | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_PSYCSTORE_PLUGIN_H | |||||
#define GNUNET_PSYCSTORE_PLUGIN_H | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_psycstore_service.h" | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
/** | |||||
* Struct returned by the initialization function of the plugin. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_PluginFunctions | |||||
{ | |||||
/** | |||||
* Closure to pass to all plugin functions. | |||||
*/ | |||||
void *cls; | |||||
/** | |||||
* Store join/leave events for a PSYC channel in order to be able to answer | |||||
* membership test queries later. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_membership_store() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*membership_store) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
int did_join, | |||||
uint64_t announced_at, | |||||
uint64_t effective_since, | |||||
uint64_t group_generation); | |||||
/** | |||||
* Test if a member was admitted to the channel at the given message ID. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_membership_test() | |||||
* | |||||
* @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, | |||||
* #GNUNET_SYSERR if there was en error. | |||||
*/ | |||||
int | |||||
(*membership_test) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t message_id); | |||||
/** | |||||
* Store a message fragment sent to a channel. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_fragment_store() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*fragment_store) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_MULTICAST_MessageHeader *message, | |||||
uint32_t psycstore_flags); | |||||
/** | |||||
* Set additional flags for a given message. | |||||
* | |||||
* They are OR'd with any existing flags set. | |||||
* | |||||
* @param cls Closure. | |||||
* @param channel_key Public key of the channel. | |||||
* @param message_id ID of the message. | |||||
* @param psycstore_flags OR'd GNUNET_PSYCSTORE_MessageFlags. | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*message_add_flags) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id, | |||||
uint32_t psycstore_flags); | |||||
/** | |||||
* Retrieve a message fragment range by fragment ID. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_fragment_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*fragment_get) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t first_fragment_id, | |||||
uint64_t last_fragment_id, | |||||
uint64_t *returned_fragments, | |||||
GNUNET_PSYCSTORE_FragmentCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve latest message fragments. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_fragment_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*fragment_get_latest) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t fragment_limit, | |||||
uint64_t *returned_fragments, | |||||
GNUNET_PSYCSTORE_FragmentCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve all fragments of a message ID range. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_message_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*message_get) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t first_fragment_id, | |||||
uint64_t last_fragment_id, | |||||
uint64_t fragment_limit, | |||||
uint64_t *returned_fragments, | |||||
GNUNET_PSYCSTORE_FragmentCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve all fragments of the latest messages. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_message_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*message_get_latest) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t fragment_limit, | |||||
uint64_t *returned_fragments, | |||||
GNUNET_PSYCSTORE_FragmentCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve a fragment of message specified by its message ID and fragment | |||||
* offset. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_message_get_fragment() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*message_get_fragment) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
GNUNET_PSYCSTORE_FragmentCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve the max. values of message counters for a channel. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_counters_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*counters_message_get) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t *max_fragment_id, | |||||
uint64_t *max_message_id, | |||||
uint64_t *max_group_generation); | |||||
/** | |||||
* Retrieve the max. values of state counters for a channel. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_counters_get() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*counters_state_get) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t *max_state_message_id); | |||||
/** | |||||
* Begin modifying current state. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_modify() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_modify_begin) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id, uint64_t state_delta); | |||||
/** | |||||
* Set the current value of a state variable. | |||||
* | |||||
* The state modification process is started with state_modify_begin(), | |||||
* which is followed by one or more calls to this function, | |||||
* and finished with state_modify_end(). | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_modify() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_modify_op) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
enum GNUNET_PSYC_Operator op, | |||||
const char *name, const void *value, size_t value_size); | |||||
/** | |||||
* End modifying current state. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_modify() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_modify_end) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id); | |||||
/** | |||||
* Begin synchronizing state. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_sync() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_sync_begin) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | |||||
/** | |||||
* Assign value of a state variable while synchronizing state. | |||||
* | |||||
* The state synchronization process is started with state_sync_begin(), | |||||
* which is followed by one or more calls to this function, | |||||
* and finished using state_sync_end(). | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_sync() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_sync_assign) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const char *name, const void *value, size_t value_size); | |||||
/** | |||||
* End synchronizing state. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_sync() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_sync_end) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t max_state_message_id, | |||||
uint64_t state_hash_message_id); | |||||
/** | |||||
* Reset the state of a channel. | |||||
* | |||||
* Delete all state variables stored for the given channel. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_reset() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_reset) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | |||||
/** | |||||
* Update signed state values from the current ones. | |||||
* | |||||
* Sets value_signed = value_current for each variable for the given channel. | |||||
*/ | |||||
int | |||||
(*state_update_signed) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | |||||
/** | |||||
* Retrieve a state variable by name (exact match). | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_get) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const char *name, | |||||
GNUNET_PSYCSTORE_StateCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve all state variables for a channel with the given prefix. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_state_get_prefix() | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_get_prefix) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const char *name, | |||||
GNUNET_PSYCSTORE_StateCallback cb, | |||||
void *cb_cls); | |||||
/** | |||||
* Retrieve all signed state variables for a channel. | |||||
* | |||||
* @return #GNUNET_OK on success, else #GNUNET_SYSERR | |||||
*/ | |||||
int | |||||
(*state_get_signed) (void *cls, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
GNUNET_PSYCSTORE_StateCallback cb, | |||||
void *cb_cls); | |||||
}; | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,701 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* @author Christian Grothoff | |||||
* | |||||
* @file | |||||
* PSYCstore service; implements persistent storage for the PSYC service | |||||
* | |||||
* @defgroup psycstore PSYC Store service | |||||
* Persistent storage for the PSYC service. | |||||
* @{ | |||||
*/ | |||||
#ifndef GNUNET_PSYCSTORE_SERVICE_H | |||||
#define GNUNET_PSYCSTORE_SERVICE_H | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
} | |||||
#endif | |||||
#endif | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
#include "gnunet_multicast_service.h" | |||||
#include "gnunet_psyc_service.h" | |||||
/** | |||||
* Version number of GNUnet PSYCstore API. | |||||
*/ | |||||
#define GNUNET_PSYCSTORE_VERSION 0x00000000 | |||||
/** | |||||
* Membership test failed. | |||||
*/ | |||||
#define GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED -2 | |||||
/** | |||||
* Flags for stored messages. | |||||
*/ | |||||
enum GNUNET_PSYCSTORE_MessageFlags | |||||
{ | |||||
/** | |||||
* The message contains state modifiers. | |||||
*/ | |||||
GNUNET_PSYCSTORE_MESSAGE_STATE = 1 << 0, | |||||
/** | |||||
* The state modifiers have been applied to the state store. | |||||
*/ | |||||
GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED = 1 << 1, | |||||
/** | |||||
* The message contains a state hash. | |||||
*/ | |||||
GNUNET_PSYCSTORE_MESSAGE_STATE_HASH = 1 << 2 | |||||
}; | |||||
/** | |||||
* Handle for a PSYCstore | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_Handle; | |||||
/** | |||||
* Connect to the PSYCstore service. | |||||
* | |||||
* @param cfg Configuration to use. | |||||
* | |||||
* @return Handle for the connecton. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_Handle * | |||||
GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); | |||||
/** | |||||
* Disconnect from the PSYCstore service. | |||||
* | |||||
* @param h Handle for the connection. | |||||
*/ | |||||
void | |||||
GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h); | |||||
/** | |||||
* Handle for an operation on the PSYCSTORE (useful to cancel the operation). | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle; | |||||
/** | |||||
* Function called with the result of an asynchronous operation. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param result | |||||
* Result of the operation. | |||||
* @param err_msg | |||||
* Error message, or NULL if there's no error. | |||||
* @param err_msg_size | |||||
* Size of @a err_msg | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYCSTORE_ResultCallback) (void *cls, | |||||
int64_t result, | |||||
const char *err_msg, | |||||
uint16_t err_msg_size); | |||||
/** | |||||
* Store join/leave events for a PSYC channel in order to be able to answer | |||||
* membership test queries later. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel where the event happened. | |||||
* @param slave_key | |||||
* Public key of joining/leaving slave. | |||||
* @param did_join | |||||
* #GNUNET_YES on join, #GNUNET_NO on part. | |||||
* @param announced_at | |||||
* ID of the message that announced the membership change. | |||||
* @param effective_since | |||||
* Message ID this membership change is in effect since. | |||||
* For joins it is <= announced_at, for parts it is always 0. | |||||
* @param group_generation | |||||
* In case of a part, the last group generation the slave has access to. | |||||
* It has relevance when a larger message have fragments with different | |||||
* group generations. | |||||
* @param result_cb | |||||
* Callback to call with the result of the storage operation. | |||||
* @param cls | |||||
* Closure for the callback. | |||||
* | |||||
* @return Operation handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
int did_join, | |||||
uint64_t announced_at, | |||||
uint64_t effective_since, | |||||
uint64_t group_generation, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Test if a member was admitted to the channel at the given message ID. | |||||
* | |||||
* This is useful when relaying and replaying messages to check if a particular | |||||
* slave has access to the message fragment with a given group generation. It | |||||
* is also used when handling join requests to determine whether the slave is | |||||
* currently admitted to the channel. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* Public key of slave whose membership to check. | |||||
* @param message_id | |||||
* Message ID for which to do the membership test. | |||||
* @param group_generation | |||||
* Group generation of the fragment of the message to test. | |||||
* It has relevance if the message consists of multiple fragments with | |||||
* different group generations. | |||||
* @param result_cb | |||||
* Callback to call with the test result. | |||||
* @param cls | |||||
* Closure for the callback. | |||||
* | |||||
* @return Operation handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t message_id, | |||||
uint64_t group_generation, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Store a message fragment sent to a channel. | |||||
* | |||||
* @param h Handle for the PSYCstore. | |||||
* @param channel_key The channel the message belongs to. | |||||
* @param msg Message to store. | |||||
* @param psycstore_flags Flags indicating whether the PSYC message contains | |||||
* state modifiers. | |||||
* @param result_cb Callback to call with the result of the operation. | |||||
* @param cls Closure for the callback. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg, | |||||
enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Function called with one message fragment, as the result of a | |||||
* GNUNET_PSYCSTORE_fragment_get() or GNUNET_PSYCSTORE_message_get() call. | |||||
* | |||||
* @param cls Closure. | |||||
* @param message The retrieved message fragment. A NULL value indicates that | |||||
* there are no more results to be returned. | |||||
* @param psycstore_flags Flags stored with the message. | |||||
* | |||||
* @return #GNUNET_NO to stop calling this callback with further fragments, | |||||
* #GNUNET_YES to continue. | |||||
*/ | |||||
typedef int | |||||
(*GNUNET_PSYCSTORE_FragmentCallback) (void *cls, | |||||
struct GNUNET_MULTICAST_MessageHeader *message, | |||||
enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags); | |||||
/** | |||||
* Retrieve message fragments by fragment ID range. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* The slave requesting the fragment. If not NULL, a membership test is | |||||
* performed first and the fragment is only returned if the slave has | |||||
* access to it. | |||||
* @param first_fragment_id | |||||
* First fragment ID to retrieve. | |||||
* Use 0 to get the latest message fragment. | |||||
* @param last_fragment_id | |||||
* Last consecutive fragment ID to retrieve. | |||||
* Use 0 to get the latest message fragment. | |||||
* @param fragment_cb | |||||
* Callback to call with the retrieved fragments. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t first_message_id, | |||||
uint64_t last_message_id, | |||||
GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Retrieve latest message fragments. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* The slave requesting the fragment. If not NULL, a membership test is | |||||
* performed first and the fragment is only returned if the slave has | |||||
* access to it. | |||||
* @param first_fragment_id | |||||
* First fragment ID to retrieve. | |||||
* Use 0 to get the latest message fragment. | |||||
* @param last_fragment_id | |||||
* Last consecutive fragment ID to retrieve. | |||||
* Use 0 to get the latest message fragment. | |||||
* @param fragment_limit | |||||
* Maximum number of fragments to retrieve. | |||||
* @param fragment_cb | |||||
* Callback to call with the retrieved fragments. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t fragment_limit, | |||||
GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Retrieve all fragments of messages in a message ID range. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* The slave requesting the message. | |||||
* If not NULL, a membership test is performed first | |||||
* and the message is only returned if the slave has access to it. | |||||
* @param first_message_id | |||||
* First message ID to retrieve. | |||||
* @param last_message_id | |||||
* Last consecutive message ID to retrieve. | |||||
* @param fragment_limit | |||||
* Maximum number of fragments to retrieve. | |||||
* @param method_prefix | |||||
* Retrieve only messages with a matching method prefix. | |||||
* @param fragment_cb | |||||
* Callback to call with the retrieved fragments. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t first_message_id, | |||||
uint64_t last_message_id, | |||||
uint64_t fragment_limit, | |||||
const char *method_prefix, | |||||
GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Retrieve all fragments of the latest messages. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* The slave requesting the message. | |||||
* If not NULL, a membership test is performed first | |||||
* and the message is only returned if the slave has access to it. | |||||
* @param message_limit | |||||
* Maximum number of messages to retrieve. | |||||
* @param method_prefix | |||||
* Retrieve only messages with a matching method prefix. | |||||
* @param fragment_cb | |||||
* Callback to call with the retrieved fragments. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t message_limit, | |||||
const char *method_prefix, | |||||
GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Retrieve a fragment of message specified by its message ID and fragment | |||||
* offset. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param slave_key | |||||
* The slave requesting the message fragment. If not NULL, a membership | |||||
* test is performed first and the message fragment is only returned | |||||
* if the slave has access to it. | |||||
* @param message_id | |||||
* Message ID to retrieve. Use 0 to get the latest message. | |||||
* @param fragment_offset | |||||
* Offset of the fragment to retrieve. | |||||
* @param fragment_cb | |||||
* Callback to call with the retrieved fragments. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Callback used to return the latest value of counters for the channel master. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_counters_get() | |||||
* | |||||
* @param cls Closure. | |||||
* @param result_code | |||||
* Status code for the operation: | |||||
* #GNUNET_OK: success, counter values are returned. | |||||
* #GNUNET_NO: no message has been sent to the channel yet. | |||||
* #GNUNET_SYSERR: an error occurred. | |||||
* @param max_fragment_id | |||||
* Latest message fragment ID, used by multicast. | |||||
* @param max_message_id | |||||
* Latest message ID, used by PSYC. | |||||
* @param max_group_generation | |||||
* Latest group generation, used by PSYC. | |||||
* @param max_state_message_id | |||||
* Latest message ID containing state modifiers that | |||||
* was applied to the state store. Used for the state sync process. | |||||
*/ | |||||
typedef void | |||||
(*GNUNET_PSYCSTORE_CountersCallback) (void *cls, | |||||
int result_code, | |||||
uint64_t max_fragment_id, | |||||
uint64_t max_message_id, | |||||
uint64_t max_group_generation, | |||||
uint64_t max_state_message_id); | |||||
/** | |||||
* Retrieve latest values of counters for a channel. | |||||
* | |||||
* The current value of counters are needed | |||||
* - when a channel master is restarted, so that it can continue incrementing | |||||
* the counters from their last value. | |||||
* - when a channel slave rejoins and starts the state synchronization process. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* Public key that identifies the channel. | |||||
* @param counters_cb | |||||
* Callback to call with the result. | |||||
* @param cls | |||||
* Closure for the @a ccb callback. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, | |||||
struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
GNUNET_PSYCSTORE_CountersCallback counters_cb, | |||||
void *cls); | |||||
/** | |||||
* Apply modifiers of a message to the current channel state. | |||||
* | |||||
* An error is returned if there are missing messages containing state | |||||
* operations before the current one. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param message_id | |||||
* ID of the message that contains the @a modifiers. | |||||
* @param state_delta | |||||
* Value of the @e state_delta PSYC header variable of the message. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the @a result_cb callback. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id, | |||||
uint64_t state_delta, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Store synchronized state. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param max_state_message_id | |||||
* ID of the last stateful message before @a state_hash_message_id. | |||||
* @param state_hash_message_id | |||||
* ID of the message that contains the state_hash PSYC header variable. | |||||
* @param modifier_count | |||||
* Number of elements in the @a modifiers array. | |||||
* @param modifiers | |||||
* Full state to store. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callback. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t max_state_message_id, | |||||
uint64_t state_hash_message_id, | |||||
size_t modifier_count, | |||||
const struct GNUNET_PSYC_Modifier *modifiers, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Reset the state of a channel. | |||||
* | |||||
* Delete all state variables stored for the given channel. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callback. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey | |||||
*channel_key, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Update signed values of state variables in the state store. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param message_id | |||||
* Message ID that contained the state @a hash. | |||||
* @param hash | |||||
* Hash of the serialized full state. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callback. | |||||
* | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
uint64_t message_id, | |||||
const struct GNUNET_HashCode *hash, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Function called with the value of a state variable. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param name | |||||
* Name of the state variable. A NULL value indicates that there are no more | |||||
* state variables to be returned. | |||||
* @param value | |||||
* Value of the state variable. | |||||
* @param value_size | |||||
* Number of bytes in @a value. | |||||
* | |||||
* @return #GNUNET_NO to stop calling this callback with further variables, | |||||
* #GNUNET_YES to continue. | |||||
*/; | |||||
typedef int | |||||
(*GNUNET_PSYCSTORE_StateCallback) (void *cls, const char *name, | |||||
const void *value, uint32_t value_size); | |||||
/** | |||||
* Retrieve the best matching state variable. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param name | |||||
* Name of variable to match, the returned variable might be less specific. | |||||
* @param state_cb | |||||
* Callback to return the matching state variable. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const char *name, | |||||
GNUNET_PSYCSTORE_StateCallback state_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Retrieve all state variables for a channel with the given prefix. | |||||
* | |||||
* @param h | |||||
* Handle for the PSYCstore. | |||||
* @param channel_key | |||||
* The channel we are interested in. | |||||
* @param name_prefix | |||||
* Prefix of state variable names to match. | |||||
* @param state_cb | |||||
* Callback to return matching state variables. | |||||
* @param result_cb | |||||
* Callback to call with the result of the operation. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
* | |||||
* @return Handle that can be used to cancel the operation. | |||||
*/ | |||||
struct GNUNET_PSYCSTORE_OperationHandle * | |||||
GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, | |||||
const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | |||||
const char *name_prefix, | |||||
GNUNET_PSYCSTORE_StateCallback state_cb, | |||||
GNUNET_PSYCSTORE_ResultCallback result_cb, | |||||
void *cls); | |||||
/** | |||||
* Cancel an operation. | |||||
* | |||||
* @param op Handle for the operation to cancel. | |||||
*/ | |||||
int | |||||
GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op); | |||||
#if 0 /* keep Emacsens' auto-indent happy */ | |||||
{ | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
/* ifndef GNUNET_PSYCSTORE_SERVICE_H */ | |||||
#endif | |||||
/** @} */ /* end of group */ |
@@ -0,0 +1,7 @@ | |||||
gnunet-service-multicast | |||||
gnunet-multicast | |||||
test_multicast | |||||
test_multicast_multipeer | |||||
test_multicast_2peers | |||||
test_multicast_multipeer_line | |||||
test_multicast_multipeer_star |
@@ -0,0 +1,79 @@ | |||||
# This Makefile.am is in the public domain | |||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include | |||||
pkgcfgdir= $(pkgdatadir)/config.d/ | |||||
libexecdir= $(pkglibdir)/libexec/ | |||||
pkgcfg_DATA = \ | |||||
multicast.conf | |||||
if MINGW | |||||
WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | |||||
endif | |||||
if USE_COVERAGE | |||||
AM_CFLAGS = -fprofile-arcs -ftest-coverage | |||||
endif | |||||
lib_LTLIBRARIES = libgnunetmulticast.la | |||||
libgnunetmulticast_la_SOURCES = \ | |||||
multicast_api.c multicast.h | |||||
libgnunetmulticast_la_LIBADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(GN_LIBINTL) $(XLIB) | |||||
libgnunetmulticast_la_LDFLAGS = \ | |||||
$(GN_LIB_LDFLAGS) $(WINFLAGS) \ | |||||
-version-info 0:0:0 | |||||
bin_PROGRAMS = \ | |||||
gnunet-multicast | |||||
libexec_PROGRAMS = \ | |||||
gnunet-service-multicast \ | |||||
$(EXP_LIBEXEC) | |||||
gnunet_multicast_SOURCES = \ | |||||
gnunet-multicast.c | |||||
gnunet_multicast_LDADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(GN_LIBINTL) | |||||
gnunet_service_multicast_SOURCES = \ | |||||
gnunet-service-multicast.c | |||||
gnunet_service_multicast_LDADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(top_builddir)/src/cadet/libgnunetcadet.la \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(GN_LIBINTL) | |||||
check_PROGRAMS = \ | |||||
test_multicast \ | |||||
test_multicast_multipeer_star \ | |||||
test_multicast_multipeer_line | |||||
if ENABLE_TEST_RUN | |||||
AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; | |||||
TESTS = $(check_PROGRAMS) | |||||
endif | |||||
test_multicast_SOURCES = \ | |||||
test_multicast.c | |||||
test_multicast_LDADD = \ | |||||
libgnunetmulticast.la \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
test_multicast_multipeer_star_SOURCES = \ | |||||
test_multicast_multipeer.c | |||||
test_multicast_multipeer_star_LDADD = \ | |||||
libgnunetmulticast.la \ | |||||
$(top_builddir)/src/testbed/libgnunettestbed.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
test_multicast_multipeer_line_SOURCES = \ | |||||
test_multicast_multipeer.c | |||||
test_multicast_multipeer_line_LDADD = \ | |||||
libgnunetmulticast.la \ | |||||
$(top_builddir)/src/testbed/libgnunettestbed.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la |
@@ -0,0 +1,79 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file multicast/gnunet-multicast.c | |||||
* @brief multicast for writing a tool | |||||
* @author Christian Grothoff | |||||
*/ | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
/* #include "gnunet_multicast_service.h" */ | |||||
/** | |||||
* Final status code. | |||||
*/ | |||||
static int ret; | |||||
/** | |||||
* Main function that will be run by the scheduler. | |||||
* | |||||
* @param cls closure | |||||
* @param args remaining command-line arguments | |||||
* @param cfgfile name of the configuration file used (for saving, can be NULL!) | |||||
* @param cfg configuration | |||||
*/ | |||||
static void | |||||
run (void *cls, char *const *args, const char *cfgfile, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
/* main code here */ | |||||
puts( gettext_noop ("This command doesn't do anything yet.") ); | |||||
ret = -1; | |||||
} | |||||
/** | |||||
* The main function. | |||||
* | |||||
* @param argc number of arguments from the command line | |||||
* @param argv command line arguments | |||||
* @return 0 ok, 1 on error | |||||
*/ | |||||
int | |||||
main (int argc, char *const *argv) | |||||
{ | |||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = { | |||||
/* FIMXE: add options here */ | |||||
GNUNET_GETOPT_OPTION_END | |||||
}; | |||||
if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | |||||
return 2; | |||||
ret = (GNUNET_OK == | |||||
GNUNET_PROGRAM_run (argc, argv, "gnunet-multicast", | |||||
gettext_noop ("This command doesn't do anything yet."), | |||||
options, &run, | |||||
NULL)) ? ret : 1; | |||||
GNUNET_free ((void*) argv); | |||||
return ret; | |||||
} | |||||
/* end of gnunet-multicast.c */ |
@@ -0,0 +1,22 @@ | |||||
[multicast] | |||||
START_ON_DEMAND = @START_ON_DEMAND@ | |||||
BINARY = gnunet-service-multicast | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | |||||
UNIX_MATCH_UID = YES | |||||
UNIX_MATCH_GID = YES | |||||
@UNIXONLY@PORT = 2109 | |||||
HOSTNAME = localhost | |||||
ACCEPT_FROM = 127.0.0.1; | |||||
ACCEPT_FROM6 = ::1; | |||||
# DISABLE_SOCKET_FORWARDING = NO | |||||
# USERNAME = | |||||
# MAXBUF = | |||||
# TIMEOUT = | |||||
# DISABLEV6 = | |||||
# BINDTO = | |||||
# REJECT_FROM = | |||||
# REJECT_FROM6 = | |||||
# PREFIX = |
@@ -0,0 +1,303 @@ | |||||
/* | |||||
This file is part of GNUnet. | |||||
Copyright (C) 2012, 2013 GNUnet e.V. | |||||
GNUnet is free software: you can redistribute it and/or modify it | |||||
under the terms of the GNU Affero General Public License as published | |||||
by the Free Software Foundation, either version 3 of the License, | |||||
or (at your option) any later version. | |||||
GNUnet 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 | |||||
Affero General Public License for more details. | |||||
You should have received a copy of the GNU Affero General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file multicast/multicast.h | |||||
* @brief multicast IPC messages | |||||
* @author Christian Grothoff | |||||
* @author Gabor X Toth | |||||
*/ | |||||
#ifndef MULTICAST_H | |||||
#define MULTICAST_H | |||||
#include "platform.h" | |||||
#include "gnunet_multicast_service.h" | |||||
GNUNET_NETWORK_STRUCT_BEGIN | |||||
/** | |||||
* Header of a join request sent to the origin or another member. | |||||
*/ | |||||
struct MulticastJoinRequestMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Always zero. | |||||
*/ | |||||
uint32_t reserved; | |||||
/** | |||||
* ECC signature of the rest of the fields of the join request. | |||||
* | |||||
* Signature must match the public key of the joining member. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaSignature signature; | |||||
/** | |||||
* Purpose for the signature and size of the signed data. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | |||||
/** | |||||
* Public key of the target group. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | |||||
/** | |||||
* Public key of the joining member. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
/** | |||||
* Peer identity of the joining member. | |||||
*/ | |||||
struct GNUNET_PeerIdentity peer; | |||||
/* Followed by struct GNUNET_MessageHeader join_message */ | |||||
}; | |||||
/** | |||||
* Header of a join decision message sent to a peer requesting join. | |||||
*/ | |||||
struct MulticastJoinDecisionMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* #GNUNET_YES if the peer was admitted | |||||
* #GNUNET_NO if entry was refused, | |||||
* #GNUNET_SYSERR if the request could not be answered. | |||||
*/ | |||||
int32_t is_admitted; | |||||
/** | |||||
* Number of relays given. | |||||
*/ | |||||
uint32_t relay_count; | |||||
/* Followed by relay_count peer identities */ | |||||
/* Followed by the join response message */ | |||||
}; | |||||
/** | |||||
* Header added to a struct MulticastJoinDecisionMessage | |||||
* when sent between the client and service. | |||||
*/ | |||||
struct MulticastJoinDecisionMessageHeader | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* C->S: Peer to send the join decision to. | |||||
* S->C: Peer we received the join decision from. | |||||
*/ | |||||
struct GNUNET_PeerIdentity peer; | |||||
/** | |||||
* C->S: Public key of the member requesting join. | |||||
* S->C: Unused. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
/* Followed by struct MulticastJoinDecisionMessage */ | |||||
}; | |||||
/** | |||||
* Message sent from the client to the service to notify the service | |||||
* about the result of a membership test. | |||||
*/ | |||||
struct MulticastMembershipTestResultMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBERSHIP_TEST_RESULT | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Unique ID that identifies the associated membership test. | |||||
*/ | |||||
uint32_t uid; | |||||
/** | |||||
* #GNUNET_YES if the peer is a member | |||||
* #GNUNET_NO if peer is not a member, | |||||
* #GNUNET_SYSERR if the test could not be answered. | |||||
*/ | |||||
int32_t is_admitted; | |||||
}; | |||||
/** | |||||
* Message sent from the client to the service OR the service to the | |||||
* client asking for a message fragment to be replayed. | |||||
*/ | |||||
struct MulticastReplayRequestMessage | |||||
{ | |||||
/** | |||||
* The message type should be | |||||
* #GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST. | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* S->C: Public key of the member requesting replay. | |||||
* C->S: Unused. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
/** | |||||
* ID of the message that is being requested. | |||||
*/ | |||||
uint64_t fragment_id; | |||||
/** | |||||
* ID of the message that is being requested. | |||||
*/ | |||||
uint64_t message_id; | |||||
/** | |||||
* Offset of the fragment that is being requested. | |||||
*/ | |||||
uint64_t fragment_offset; | |||||
/** | |||||
* Additional flags for the request. | |||||
*/ | |||||
uint64_t flags; | |||||
/** | |||||
* Replay request ID. | |||||
*/ | |||||
uint32_t uid; | |||||
}; | |||||
/** | |||||
* Message sent from the client to the service to give the service | |||||
* a replayed message. | |||||
*/ | |||||
struct MulticastReplayResponseMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE | |||||
* or GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* ID of the message that is being requested. | |||||
*/ | |||||
uint64_t fragment_id; | |||||
/** | |||||
* ID of the message that is being requested. | |||||
*/ | |||||
uint64_t message_id; | |||||
/** | |||||
* Offset of the fragment that is being requested. | |||||
*/ | |||||
uint64_t fragment_offset; | |||||
/** | |||||
* Additional flags for the request. | |||||
*/ | |||||
uint64_t flags; | |||||
/** | |||||
* An `enum GNUNET_MULTICAST_ReplayErrorCode` identifying issues (in NBO). | |||||
*/ | |||||
int32_t error_code; | |||||
/* followed by replayed message */ | |||||
}; | |||||
/** | |||||
* Message sent from the client to the service to notify the service | |||||
* about the starting of a multicast group with this peers as its origin. | |||||
*/ | |||||
struct MulticastOriginStartMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Always zero. | |||||
*/ | |||||
uint32_t reserved; | |||||
/** | |||||
* Private, non-ephemeral key for the multicast group. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPrivateKey group_key; | |||||
/** | |||||
* Last fragment ID sent to the group, used to continue counting fragments if | |||||
* we resume operating * a group. | |||||
*/ | |||||
uint64_t max_fragment_id; | |||||
}; | |||||
struct MulticastMemberJoinMessage | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t relay_count GNUNET_PACKED; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | |||||
struct GNUNET_CRYPTO_EcdsaPrivateKey member_key; | |||||
struct GNUNET_PeerIdentity origin; | |||||
/* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ | |||||
/* Followed by struct GNUNET_MessageHeader join_msg */ | |||||
}; | |||||
GNUNET_NETWORK_STRUCT_END | |||||
#endif | |||||
/* end of multicast.h */ |
@@ -0,0 +1,758 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file multicast/test_multicast.c | |||||
* @brief Tests for the Multicast API. | |||||
* @author Gabor X Toth | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_crypto_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testing_lib.h" | |||||
#include "gnunet_multicast_service.h" | |||||
#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | |||||
/** | |||||
* Return value from 'main'. | |||||
*/ | |||||
static int res; | |||||
/** | |||||
* Handle for task for timeout termination. | |||||
*/ | |||||
static struct GNUNET_SCHEDULER_Task * end_badly_task; | |||||
static const struct GNUNET_CONFIGURATION_Handle *cfg; | |||||
struct GNUNET_PeerIdentity this_peer; | |||||
struct GNUNET_MULTICAST_Origin *origin; | |||||
struct GNUNET_MULTICAST_Member *member; | |||||
struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | |||||
struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
struct TransmitClosure { | |||||
struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit; | |||||
struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit; | |||||
char * data[16]; | |||||
uint8_t data_delay[16]; | |||||
uint8_t data_count; | |||||
uint8_t paused; | |||||
uint8_t n; | |||||
} tmit_cls; | |||||
struct OriginClosure { | |||||
uint8_t msgs_expected; | |||||
uint8_t n; | |||||
} origin_cls; | |||||
struct MemberClosure { | |||||
uint8_t msgs_expected; | |||||
size_t n; | |||||
} member_cls; | |||||
struct GNUNET_MessageHeader *join_req, *join_resp; | |||||
enum | |||||
{ | |||||
TEST_NONE = 0, | |||||
TEST_ORIGIN_START = 1, | |||||
TEST_MEMBER_JOIN_REFUSE = 2, | |||||
TEST_MEMBER_JOIN_ADMIT = 3, | |||||
TEST_ORIGIN_TO_ALL = 4, | |||||
TEST_ORIGIN_TO_ALL_RECV = 5, | |||||
TEST_MEMBER_TO_ORIGIN = 6, | |||||
TEST_MEMBER_REPLAY_ERROR = 7, | |||||
TEST_MEMBER_REPLAY_OK = 8, | |||||
TEST_MEMBER_PART = 9, | |||||
TEST_ORIGIN_STOP = 10, | |||||
} test; | |||||
uint64_t replay_fragment_id; | |||||
uint64_t replay_flags; | |||||
static void | |||||
member_join (int t); | |||||
/** | |||||
* Clean up all resources used. | |||||
*/ | |||||
static void | |||||
cleanup () | |||||
{ | |||||
if (NULL != member) | |||||
{ | |||||
GNUNET_MULTICAST_member_part (member, NULL, NULL); | |||||
member = NULL; | |||||
} | |||||
if (NULL != origin) | |||||
{ | |||||
GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); | |||||
origin = NULL; | |||||
} | |||||
} | |||||
/** | |||||
* Terminate the test case (failure). | |||||
* | |||||
* @param cls NULL | |||||
*/ | |||||
static void | |||||
end_badly (void *cls) | |||||
{ | |||||
res = 1; | |||||
cleanup (); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n"); | |||||
} | |||||
/** | |||||
* Terminate the test case (success). | |||||
* | |||||
* @param cls NULL | |||||
*/ | |||||
static void | |||||
end_normally (void *cls) | |||||
{ | |||||
res = 0; | |||||
cleanup (); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n"); | |||||
} | |||||
/** | |||||
* Finish the test case (successfully). | |||||
*/ | |||||
static void | |||||
end () | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n"); | |||||
if (end_badly_task != NULL) | |||||
{ | |||||
GNUNET_SCHEDULER_cancel (end_badly_task); | |||||
end_badly_task = NULL; | |||||
} | |||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | |||||
&end_normally, NULL); | |||||
} | |||||
static void | |||||
tmit_resume (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n"); | |||||
struct TransmitClosure *tmit = cls; | |||||
if (NULL != tmit->orig_tmit) | |||||
GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit); | |||||
else if (NULL != tmit->mem_tmit) | |||||
GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit); | |||||
} | |||||
static int | |||||
tmit_notify (void *cls, size_t *data_size, void *data) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Test #%u: origin_tmit_notify()\n", test); | |||||
struct TransmitClosure *tmit = cls; | |||||
if (0 == tmit->data_count) | |||||
{ | |||||
*data_size = 0; | |||||
return GNUNET_YES; | |||||
} | |||||
uint16_t size = strlen (tmit->data[tmit->n]); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n", | |||||
(unsigned int) *data_size, | |||||
tmit->n + 1, | |||||
tmit->data_count, | |||||
size); | |||||
if (*data_size < size) | |||||
{ | |||||
*data_size = 0; | |||||
GNUNET_assert (0); | |||||
return GNUNET_SYSERR; | |||||
} | |||||
if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n"); | |||||
tmit->paused = GNUNET_YES; | |||||
GNUNET_SCHEDULER_add_delayed ( | |||||
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | |||||
tmit->data_delay[tmit->n]), | |||||
tmit_resume, tmit); | |||||
*data_size = 0; | |||||
return GNUNET_NO; | |||||
} | |||||
tmit->paused = GNUNET_NO; | |||||
*data_size = size; | |||||
GNUNET_memcpy (data, tmit->data[tmit->n], size); | |||||
return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; | |||||
} | |||||
static void | |||||
member_recv_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_recv_join_request()\n", test); | |||||
} | |||||
static void | |||||
origin_stopped (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_stopped()\n", test); | |||||
end (); | |||||
} | |||||
static void | |||||
schedule_origin_stop (void *cls) | |||||
{ | |||||
test = TEST_ORIGIN_STOP; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_stop()\n", test); | |||||
GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL); | |||||
origin = NULL; | |||||
} | |||||
static void | |||||
member_parted (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_parted()\n", test); | |||||
member = NULL; | |||||
switch (test) | |||||
{ | |||||
case TEST_MEMBER_JOIN_REFUSE: | |||||
// Test 3 starts here | |||||
member_join (TEST_MEMBER_JOIN_ADMIT); | |||||
break; | |||||
case TEST_MEMBER_PART: | |||||
GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL); | |||||
break; | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in member_parted()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
} | |||||
static void | |||||
schedule_member_part (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: schedule_member_part()\n", test); | |||||
GNUNET_MULTICAST_member_part (member, member_parted, NULL); | |||||
} | |||||
static void | |||||
member_part () | |||||
{ | |||||
test = TEST_MEMBER_PART; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_part()\n", test); | |||||
// Test 10 starts here | |||||
GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); | |||||
} | |||||
static void | |||||
member_replay_ok () | |||||
{ | |||||
// Execution of test 8 here | |||||
test = TEST_MEMBER_REPLAY_OK; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_replay_ok()\n", test); | |||||
replay_fragment_id = 1; | |||||
replay_flags = 1 | 1<<11; | |||||
GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, | |||||
replay_flags); | |||||
} | |||||
static void | |||||
member_replay_error () | |||||
{ | |||||
test = TEST_MEMBER_REPLAY_ERROR; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_replay_error()\n", test); | |||||
replay_fragment_id = 1234; | |||||
replay_flags = 11 | 1<<11; | |||||
GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, | |||||
replay_flags); | |||||
} | |||||
static void | |||||
origin_recv_replay_msg (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_recv_replay_msg()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
static void | |||||
member_recv_replay_msg (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_recv_replay_msg()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
static void | |||||
origin_recv_replay_frag (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | |||||
uint64_t fragment_id, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_recv_replay_frag()" | |||||
" - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n", | |||||
test, fragment_id, flags); | |||||
GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags); | |||||
switch (test) | |||||
{ | |||||
case TEST_MEMBER_REPLAY_ERROR: | |||||
// Test 8 starts here | |||||
GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR); | |||||
member_replay_ok (); | |||||
break; | |||||
case TEST_MEMBER_REPLAY_OK: | |||||
{ | |||||
struct GNUNET_MULTICAST_MessageHeader mmsg = { | |||||
.header = { | |||||
.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE), | |||||
.size = htons (sizeof (mmsg)), | |||||
}, | |||||
.fragment_id = GNUNET_htonll (1), | |||||
.message_id = GNUNET_htonll (1), | |||||
.fragment_offset = 0, | |||||
.group_generation = GNUNET_htonll (1), | |||||
.flags = 0, | |||||
}; | |||||
member_cls.n = 0; | |||||
member_cls.msgs_expected = 1; | |||||
GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK); | |||||
GNUNET_MULTICAST_replay_response_end (rh); | |||||
break; | |||||
} | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in origin_recv_replay_frag()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
} | |||||
static void | |||||
member_recv_replay_frag (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | |||||
uint64_t fragment_id, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_recv_replay_frag()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
static void | |||||
origin_recv_request (void *cls, | |||||
const struct GNUNET_MULTICAST_RequestHeader *req) | |||||
{ | |||||
struct OriginClosure *ocls = cls; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_recv_request()\n", test); | |||||
if (++ocls->n != ocls->msgs_expected) | |||||
return; | |||||
GNUNET_assert (0 == memcmp (&req->member_pub_key, | |||||
&member_pub_key, sizeof (member_pub_key))); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Test #%u: verify message content, take first 3 bytes: %.3s\n", | |||||
test, (char *)&req[1]); | |||||
GNUNET_assert (0 == memcmp (&req[1], "abc", 3)); | |||||
// Test 7 starts here | |||||
member_replay_error (); | |||||
} | |||||
static void | |||||
member_to_origin () | |||||
{ | |||||
test = TEST_MEMBER_TO_ORIGIN; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_to_origin()\n", test); | |||||
struct TransmitClosure *tmit = &tmit_cls; | |||||
*tmit = (struct TransmitClosure) {}; | |||||
tmit->data[0] = "abc def"; | |||||
tmit->data[1] = "ghi jkl mno"; | |||||
tmit->data_delay[1] = 2; | |||||
tmit->data[2] = "pqr stuw xyz"; | |||||
tmit->data_count = 3; | |||||
origin_cls.n = 0; | |||||
origin_cls.msgs_expected = 1; | |||||
tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1, | |||||
tmit_notify, tmit); | |||||
} | |||||
static void | |||||
member_recv_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
struct MemberClosure *mcls = cls; | |||||
// Test 5 starts here after message has been received from origin | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Test #%u: member_recv_message() %u/%u\n", | |||||
test, | |||||
(unsigned int) (mcls->n + 1), | |||||
mcls->msgs_expected); | |||||
if (++mcls->n != mcls->msgs_expected) | |||||
return; | |||||
// FIXME: check message content | |||||
switch (test) | |||||
{ | |||||
case TEST_ORIGIN_TO_ALL: | |||||
test = TEST_ORIGIN_TO_ALL_RECV; | |||||
break; | |||||
case TEST_ORIGIN_TO_ALL_RECV: | |||||
// Test 6 starts here | |||||
member_to_origin (); | |||||
break; | |||||
case TEST_MEMBER_REPLAY_OK: | |||||
// Test 9 starts here | |||||
GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id)); | |||||
member_part (); | |||||
break; | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in origin_recv_message()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
} | |||||
static void | |||||
origin_recv_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
struct OriginClosure *ocls = cls; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_recv_message() %u/%u\n", | |||||
test, ocls->n + 1, ocls->msgs_expected); | |||||
if (++ocls->n != ocls->msgs_expected) | |||||
return; | |||||
// FIXME: check message content | |||||
switch (test) | |||||
{ | |||||
case TEST_ORIGIN_TO_ALL: | |||||
// Prepare to execute test 5 | |||||
test = TEST_ORIGIN_TO_ALL_RECV; | |||||
break; | |||||
case TEST_ORIGIN_TO_ALL_RECV: | |||||
// Test 6 starts here | |||||
member_to_origin (); | |||||
break; | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in origin_recv_message()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
} | |||||
static void | |||||
origin_to_all () | |||||
{ | |||||
test = TEST_ORIGIN_TO_ALL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_to_all()\n", test); | |||||
struct TransmitClosure *tmit = &tmit_cls; | |||||
*tmit = (struct TransmitClosure) {}; | |||||
tmit->data[0] = "ABC DEF"; | |||||
tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1); | |||||
uint16_t i; | |||||
for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++) | |||||
tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_'; | |||||
tmit->data[2] = "GHI JKL MNO"; | |||||
tmit->data_delay[2] = 2; | |||||
tmit->data[3] = "PQR STUW XYZ"; | |||||
tmit->data_count = 4; | |||||
origin_cls.n = member_cls.n = 0; | |||||
origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count; | |||||
tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1, | |||||
tmit_notify, tmit); | |||||
} | |||||
static void | |||||
member_recv_join_decision (void *cls, | |||||
int is_admitted, | |||||
const struct GNUNET_PeerIdentity *peer, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_msg) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_recv_join_decision() - is_admitted: %d\n", | |||||
test, is_admitted); | |||||
GNUNET_assert (join_msg->size == join_resp->size); | |||||
GNUNET_assert (join_msg->type == join_resp->type); | |||||
GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size))); | |||||
switch (test) | |||||
{ | |||||
case TEST_MEMBER_JOIN_REFUSE: | |||||
GNUNET_assert (0 == relay_count); | |||||
// Test 3 starts here | |||||
GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); | |||||
break; | |||||
case TEST_MEMBER_JOIN_ADMIT: | |||||
GNUNET_assert (1 == relay_count); | |||||
GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer))); | |||||
// Test 4 starts here | |||||
origin_to_all (); | |||||
break; | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in member_recv_join_decision()\n", test); | |||||
GNUNET_assert (0); | |||||
} | |||||
} | |||||
/** | |||||
* Test: origin receives join request | |||||
*/ | |||||
static void | |||||
origin_recv_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_recv_join_request()\n", test); | |||||
GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key))); | |||||
GNUNET_assert (join_msg->size == join_req->size); | |||||
GNUNET_assert (join_msg->type == join_req->type); | |||||
GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size))); | |||||
char data[] = "here's the decision"; | |||||
uint8_t data_size = strlen (data) + 1; | |||||
join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | |||||
join_resp->size = htons (sizeof (join_resp) + data_size); | |||||
join_resp->type = htons (456); | |||||
GNUNET_memcpy (&join_resp[1], data, data_size); | |||||
switch (test) | |||||
{ | |||||
case TEST_MEMBER_JOIN_REFUSE: | |||||
// Test 3 starts here | |||||
GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp); | |||||
break; | |||||
case TEST_MEMBER_JOIN_ADMIT: | |||||
// Test 3 is running | |||||
GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp); | |||||
break; | |||||
default: | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Invalid test #%d in origin_recv_join_request()\n", test); | |||||
GNUNET_assert (0); | |||||
break; | |||||
} | |||||
} | |||||
/** | |||||
* Test: member joins multicast group | |||||
*/ | |||||
static void | |||||
member_join (int t) | |||||
{ | |||||
test = t; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: member_join()\n", test); | |||||
member_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); | |||||
if (NULL != join_req) | |||||
GNUNET_free (join_req); | |||||
char data[] = "let me in!"; | |||||
uint8_t data_size = strlen (data) + 1; | |||||
join_req = GNUNET_malloc (sizeof (join_req) + data_size); | |||||
join_req->size = htons (sizeof (join_req) + data_size); | |||||
join_req->type = htons (123); | |||||
GNUNET_memcpy (&join_req[1], data, data_size); | |||||
member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key, | |||||
&this_peer, 1, &this_peer, join_req, | |||||
member_recv_join_request, | |||||
member_recv_join_decision, | |||||
member_recv_replay_frag, | |||||
member_recv_replay_msg, | |||||
member_recv_message, | |||||
&member_cls); | |||||
} | |||||
/** | |||||
* Test: Start a multicast group as origin | |||||
*/ | |||||
static void | |||||
origin_start () | |||||
{ | |||||
test = TEST_ORIGIN_START; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Test #%u: origin_start()\n", test); | |||||
group_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | |||||
origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0, | |||||
origin_recv_join_request, | |||||
origin_recv_replay_frag, | |||||
origin_recv_replay_msg, | |||||
origin_recv_request, | |||||
origin_recv_message, | |||||
&origin_cls); | |||||
// Test 2 starts here | |||||
member_join (TEST_MEMBER_JOIN_REFUSE); | |||||
} | |||||
/** | |||||
* Main function of the test, run from scheduler. | |||||
* | |||||
* @param cls NULL | |||||
* @param cfg configuration we use (also to connect to Multicast service) | |||||
* @param peer handle to access more of the peer (not used) | |||||
*/ | |||||
static void | |||||
#if DEBUG_TEST_MULTICAST | |||||
run (void *cls, | |||||
char *const *args, | |||||
const char *cfgfile, | |||||
const struct GNUNET_CONFIGURATION_Handle *c) | |||||
#else | |||||
run (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *c, | |||||
struct GNUNET_TESTING_Peer *peer) | |||||
#endif | |||||
{ | |||||
cfg = c; | |||||
end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | |||||
&end_badly, NULL); | |||||
GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | |||||
// Test 1 starts here | |||||
origin_start (); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
res = 1; | |||||
#if DEBUG_TEST_MULTICAST | |||||
const struct GNUNET_GETOPT_CommandLineOption opts[] = { | |||||
GNUNET_GETOPT_OPTION_END | |||||
}; | |||||
if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast", | |||||
"test-multicast [options]", | |||||
opts, &run, NULL)) | |||||
return 1; | |||||
#else | |||||
if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL)) | |||||
return 1; | |||||
#endif | |||||
return res; | |||||
} | |||||
/* end of test_multicast.c */ |
@@ -0,0 +1,56 @@ | |||||
[testbed] | |||||
HOSTNAME = localhost | |||||
[arm] | |||||
GLOBAL_POSTFIX=-L ERROR | |||||
[multicast] | |||||
#PREFIX = tmux new-window gdb -x ./cmd.gdb --args | |||||
#PREFIX = valgrind --leak-check=full | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | |||||
[vpn] | |||||
START_ON_DEMAND = NO | |||||
[peerinfo] | |||||
# Do not use shipped gnunet HELLOs | |||||
USE_INCLUDED_HELLOS = NO | |||||
# Option to disable all disk IO; only useful for testbed runs | |||||
# (large-scale experiments); disables persistence of HELLOs! | |||||
NO_IO = YES | |||||
[hostlist] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[nat] | |||||
ENABLE_UPNP = NO | |||||
[fs] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[vpn] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[revocation] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[gns] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namestore] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namecache] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[topology] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO |
@@ -0,0 +1,520 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file multicast/test_multicast_2peers.c | |||||
* @brief Tests for the Multicast API with two peers doing the ping | |||||
* pong test. | |||||
* @author xrs | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_crypto_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testbed_service.h" | |||||
#include "gnunet_multicast_service.h" | |||||
#define NUM_PEERS 2 | |||||
static struct GNUNET_TESTBED_Operation *op0; | |||||
static struct GNUNET_TESTBED_Operation *op1; | |||||
static struct GNUNET_TESTBED_Operation *pi_op0; | |||||
static struct GNUNET_TESTBED_Operation *pi_op1; | |||||
static struct GNUNET_TESTBED_Peer **peers; | |||||
const struct GNUNET_PeerIdentity *peer_id[2]; | |||||
static struct GNUNET_SCHEDULER_Task *timeout_tid; | |||||
static struct GNUNET_MULTICAST_Origin *origin; | |||||
static struct GNUNET_MULTICAST_Member *member; | |||||
struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | |||||
struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | |||||
/** | |||||
* Global result for testcase. | |||||
*/ | |||||
static int result; | |||||
/** | |||||
* Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). | |||||
* Cleans up. | |||||
*/ | |||||
static void | |||||
shutdown_task (void *cls) | |||||
{ | |||||
if (NULL != op0) | |||||
{ | |||||
GNUNET_TESTBED_operation_done (op0); | |||||
op0 = NULL; | |||||
} | |||||
if (NULL != op1) | |||||
{ | |||||
GNUNET_TESTBED_operation_done (op1); | |||||
op1 = NULL; | |||||
} | |||||
if (NULL != pi_op0) | |||||
{ | |||||
GNUNET_TESTBED_operation_done (pi_op0); | |||||
pi_op0 = NULL; | |||||
} | |||||
if (NULL != pi_op1) | |||||
{ | |||||
GNUNET_TESTBED_operation_done (pi_op1); | |||||
pi_op1 = NULL; | |||||
} | |||||
if (NULL != timeout_tid) | |||||
{ | |||||
GNUNET_SCHEDULER_cancel (timeout_tid); | |||||
timeout_tid = NULL; | |||||
} | |||||
} | |||||
static void | |||||
timeout_task (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Timeout!\n"); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
member_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Member sent a join request.\n"); | |||||
} | |||||
static int | |||||
notify (void *cls, | |||||
size_t *data_size, | |||||
void *data) | |||||
{ | |||||
char text[] = "ping"; | |||||
*data_size = strlen(text)+1; | |||||
GNUNET_memcpy(data, text, *data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Member sents message to origin: %s\n", text); | |||||
return GNUNET_YES; | |||||
} | |||||
static void | |||||
member_join_decision (void *cls, | |||||
int is_admitted, | |||||
const struct GNUNET_PeerIdentity *peer, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_msg) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Member received a decision from origin: %s\n", | |||||
(GNUNET_YES == is_admitted) | |||||
? "accepted" | |||||
: "rejected"); | |||||
if (GNUNET_YES == is_admitted) | |||||
{ | |||||
struct GNUNET_MULTICAST_MemberTransmitHandle *req; | |||||
// FIXME: move to MQ-style API! | |||||
req = GNUNET_MULTICAST_member_to_origin (member, | |||||
0, | |||||
¬ify, | |||||
NULL); | |||||
} | |||||
} | |||||
static void | |||||
member_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
if (0 != strncmp ("pong", (char *)&msg[1], 4)) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n"); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"member receives: %s\n", (char *)&msg[1]); | |||||
// Testcase ends here. | |||||
result = GNUNET_YES; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
origin_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
struct GNUNET_MessageHeader *join_resp; | |||||
uint8_t data_size = ntohs (join_msg->size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin got a join request...\n"); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin receives: '%s'\n", (char *)&join_msg[1]); | |||||
const char data[] = "Come in!"; | |||||
data_size = strlen (data) + 1; | |||||
join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | |||||
join_resp->size = htons (sizeof (join_resp) + data_size); | |||||
join_resp->type = htons (123); | |||||
GNUNET_memcpy (&join_resp[1], data, data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin sends: '%s'\n", data); | |||||
GNUNET_MULTICAST_join_decision (jh, | |||||
GNUNET_YES, | |||||
0, | |||||
NULL, | |||||
join_resp); | |||||
GNUNET_free (join_resp); | |||||
result = GNUNET_OK; | |||||
} | |||||
int | |||||
origin_notify (void *cls, | |||||
size_t *data_size, | |||||
void *data) | |||||
{ | |||||
char text[] = "pong"; | |||||
*data_size = strlen(text)+1; | |||||
GNUNET_memcpy (data, | |||||
text, | |||||
*data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text); | |||||
return GNUNET_YES; | |||||
} | |||||
static void | |||||
origin_request (void *cls, | |||||
const struct GNUNET_MULTICAST_RequestHeader *req) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]); | |||||
if (0 != strncmp ("ping", (char *)&req[1], 4)) | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); | |||||
GNUNET_MULTICAST_origin_to_all (origin, | |||||
0, | |||||
0, | |||||
origin_notify, | |||||
NULL); | |||||
} | |||||
static void | |||||
origin_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); | |||||
} | |||||
static void | |||||
service_connect1 (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg) | |||||
{ | |||||
member = ca_result; | |||||
if (NULL == member) | |||||
{ | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
else | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n"); | |||||
} | |||||
} | |||||
static void | |||||
multicast_da1 (void *cls, | |||||
void * op_result) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Member parting from multicast group\n"); | |||||
GNUNET_MULTICAST_member_part (member, NULL, NULL); | |||||
} | |||||
static void * | |||||
multicast_ca1 (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct GNUNET_MessageHeader *join_msg; | |||||
void *ret; | |||||
// Get members keys | |||||
member_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); | |||||
char data[] = "Hi, can I enter?"; | |||||
uint8_t data_size = strlen (data) + 1; | |||||
join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); | |||||
join_msg->size = htons (sizeof (join_msg) + data_size); | |||||
join_msg->type = htons (123); | |||||
GNUNET_memcpy (&join_msg[1], data, data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Members tries to join multicast group\n"); | |||||
ret = GNUNET_MULTICAST_member_join (cfg, | |||||
&group_pub_key, | |||||
member_key, | |||||
peer_id[0], | |||||
0, | |||||
NULL, | |||||
join_msg, /* join message */ | |||||
member_join_request, | |||||
member_join_decision, | |||||
NULL, /* no test for member_replay_frag */ | |||||
NULL, /* no test for member_replay_msg */ | |||||
member_message, | |||||
NULL); | |||||
GNUNET_free (join_msg); | |||||
return ret; | |||||
} | |||||
static void | |||||
peer_information_cb (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
const struct GNUNET_TESTBED_PeerInformation *pinfo, | |||||
const char *emsg) | |||||
{ | |||||
int i = (int) (long) cls; | |||||
if (NULL == pinfo) | |||||
{ | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
peer_id[i] = pinfo->result.id; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id)); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Create member peer\n"); | |||||
if (0 == i) | |||||
{ | |||||
/* connect to multicast service of member */ | |||||
op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ | |||||
peers[1], /* The peer whose service to connect to */ | |||||
"multicast", /* The name of the service */ | |||||
service_connect1, /* callback to call after a handle to service | |||||
is opened */ | |||||
NULL, /* closure for the above callback */ | |||||
multicast_ca1, /* callback to call with peer's configuration; | |||||
this should open the needed service connection */ | |||||
multicast_da1, /* callback to be called when closing the | |||||
opened service connection */ | |||||
NULL); /* closure for the above two callbacks */ | |||||
} | |||||
} | |||||
/** | |||||
* Test logic of peer "0" being origin starts here. | |||||
* | |||||
* @param cls closure, for the example: NULL | |||||
* @param op should be equal to "dht_op" | |||||
* @param ca_result result of the connect operation, the | |||||
* connection to the DHT service | |||||
* @param emsg error message, if testbed somehow failed to | |||||
* connect to the DHT. | |||||
*/ | |||||
static void | |||||
service_connect0 (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg) | |||||
{ | |||||
origin = ca_result; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Connected to multicast service of origin\n"); | |||||
// Get GNUnet identity of origin | |||||
pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0], | |||||
GNUNET_TESTBED_PIT_IDENTITY, | |||||
peer_information_cb, | |||||
(void *) 0); | |||||
// Get GNUnet identity of member | |||||
pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1], | |||||
GNUNET_TESTBED_PIT_IDENTITY, | |||||
peer_information_cb, | |||||
(void *) 1); | |||||
/* Connection to service successful. Here we'd usually do something with | |||||
* the service. */ | |||||
result = GNUNET_OK; | |||||
//GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */ | |||||
} | |||||
/** | |||||
* Function run when service multicast has started and is providing us | |||||
* with a configuration file. | |||||
*/ | |||||
static void * | |||||
multicast_ca0 (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
group_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | |||||
return GNUNET_MULTICAST_origin_start (cfg, | |||||
group_key, | |||||
0, | |||||
origin_join_request, | |||||
NULL, /* no test for origin_replay_frag */ | |||||
NULL, /* no test for origin_replay_msg */ | |||||
origin_request, | |||||
origin_message, | |||||
NULL); | |||||
} | |||||
static void | |||||
multicast_da0 (void *cls, | |||||
void *op_result) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Origin closes multicast group\n"); | |||||
GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); | |||||
} | |||||
/** | |||||
* Main function inovked from TESTBED once all of the | |||||
* peers are up and running. This one then connects | |||||
* just to the multicast service of peer 0 and 1. | |||||
* Peer 0 is going to be origin. | |||||
* Peer 1 is going to be one member. | |||||
* Origin will start a multicast group and the member will try to join it. | |||||
* After that we execute some multicast test. | |||||
* | |||||
* @param cls closure | |||||
* @param h the run handle | |||||
* @param peers started peers for the test | |||||
* @param num_peers size of the 'peers' array | |||||
* @param links_succeeded number of links between peers that were created | |||||
* @param links_failed number of links testbed was unable to establish | |||||
*/ | |||||
static void | |||||
testbed_master (void *cls, | |||||
struct GNUNET_TESTBED_RunHandle *h, | |||||
unsigned int num_peers, | |||||
struct GNUNET_TESTBED_Peer **p, | |||||
unsigned int links_succeeded, | |||||
unsigned int links_failed) | |||||
{ | |||||
/* Testbed is ready with peers running and connected in a pre-defined overlay | |||||
topology (FIXME) */ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Connected to testbed_master()\n"); | |||||
peers = p; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Create origin peer\n"); | |||||
op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ | |||||
peers[0], /* The peer whose service to connect to */ | |||||
"multicast", /* The name of the service */ | |||||
service_connect0, /* callback to call after a handle to service | |||||
is opened */ | |||||
NULL, /* closure for the above callback */ | |||||
multicast_ca0, /* callback to call with peer's configuration; | |||||
this should open the needed service connection */ | |||||
multicast_da0, /* callback to be called when closing the | |||||
opened service connection */ | |||||
NULL); /* closure for the above two callbacks */ | |||||
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */ | |||||
/* Schedule the shutdown task with a delay of a few Seconds */ | |||||
timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50), | |||||
&timeout_task, NULL); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
int ret; | |||||
result = GNUNET_SYSERR; | |||||
ret = GNUNET_TESTBED_test_run | |||||
("test-multicast-2peers", /* test case name */ | |||||
"test_multicast.conf", /* template configuration */ | |||||
NUM_PEERS, /* number of peers to start */ | |||||
0LL, /* Event mask - set to 0 for no event notifications */ | |||||
NULL, /* Controller event callback */ | |||||
NULL, /* Closure for controller event callback */ | |||||
testbed_master, /* continuation callback to be called when testbed setup is complete */ | |||||
NULL); /* Closure for the test_master callback */ | |||||
if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
/* end of test_multicast_2peers.c */ |
@@ -0,0 +1,63 @@ | |||||
[testbed] | |||||
HOSTNAME = localhost | |||||
OVERLAY_TOPOLOGY = LINE | |||||
[arm] | |||||
GLOBAL_POSTFIX=-L ERROR | |||||
[multicast] | |||||
#PREFIX = tmux new-window gdb -x ./cmd.gdb --args | |||||
#PREFIX = valgrind --leak-check=full | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | |||||
[vpn] | |||||
START_ON_DEMAND = NO | |||||
[peerinfo] | |||||
# Do not use shipped gnunet HELLOs | |||||
USE_INCLUDED_HELLOS = NO | |||||
# Option to disable all disk IO; only useful for testbed runs | |||||
# (large-scale experiments); disables persistence of HELLOs! | |||||
NO_IO = YES | |||||
[cadet] | |||||
ID_ANNOUNCE_TIME = 5 s | |||||
[hostlist] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[nat] | |||||
ENABLE_UPNP = NO | |||||
[fs] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[vpn] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[revocation] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[gns] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namestore] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namecache] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[topology] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[nse] | |||||
WORKBITS = 0 |
@@ -0,0 +1,643 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file multicast/test_multicast_multipeers.c | |||||
* @brief Tests for the Multicast API with multiple peers. | |||||
* @author xrs | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_crypto_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testbed_service.h" | |||||
#include "gnunet_multicast_service.h" | |||||
#define PEERS_REQUESTED 12 | |||||
struct MulticastPeerContext | |||||
{ | |||||
int peer; /* peer number */ | |||||
struct GNUNET_CRYPTO_EcdsaPrivateKey *key; | |||||
const struct GNUNET_PeerIdentity *id; | |||||
struct GNUNET_TESTBED_Operation *op; /* not yet in use */ | |||||
struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */ | |||||
int test_ok; | |||||
}; | |||||
enum pingpong | |||||
{ | |||||
PING = 1, | |||||
PONG = 2 | |||||
}; | |||||
struct pingpong_msg | |||||
{ | |||||
int peer; | |||||
enum pingpong msg; | |||||
}; | |||||
static void service_connect (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg); | |||||
static struct MulticastPeerContext **multicast_peers; | |||||
static struct GNUNET_TESTBED_Peer **peers; | |||||
static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED]; | |||||
static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED]; | |||||
static struct GNUNET_MULTICAST_Origin *origin; | |||||
static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */ | |||||
static struct GNUNET_SCHEDULER_Task *timeout_tid; | |||||
static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | |||||
static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | |||||
static struct GNUNET_HashCode group_pub_key_hash; | |||||
/** | |||||
* Global result for testcase. | |||||
*/ | |||||
static int result; | |||||
/** | |||||
* Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). | |||||
* Cleans up. | |||||
*/ | |||||
static void | |||||
shutdown_task (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"shutdown_task!\n"); | |||||
for (int i=0;i<PEERS_REQUESTED;i++) | |||||
{ | |||||
if (NULL != op[i]) | |||||
{ | |||||
GNUNET_TESTBED_operation_done(op[i]); | |||||
op[i] = NULL; | |||||
} | |||||
if (NULL != pi_op[i]) | |||||
{ | |||||
GNUNET_TESTBED_operation_done (pi_op[i]); | |||||
pi_op[i] = NULL; | |||||
} | |||||
} | |||||
if (NULL != multicast_peers) | |||||
{ | |||||
for (int i=0; i < PEERS_REQUESTED; i++) | |||||
{ | |||||
GNUNET_free_non_null (multicast_peers[i]->key); | |||||
GNUNET_free (multicast_peers[i]); | |||||
multicast_peers[i] = NULL; | |||||
} | |||||
GNUNET_free (multicast_peers); | |||||
multicast_peers = NULL; | |||||
} | |||||
if (NULL != timeout_tid) | |||||
{ | |||||
GNUNET_SCHEDULER_cancel (timeout_tid); | |||||
timeout_tid = NULL; | |||||
} | |||||
} | |||||
static void | |||||
timeout_task (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
"Timeout!\n"); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
member_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u (%s) sent a join request.\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | |||||
} | |||||
static int | |||||
notify (void *cls, | |||||
size_t *data_size, | |||||
void *data) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); | |||||
pp_msg->peer = mc_peer->peer; | |||||
pp_msg->msg = PING; | |||||
*data_size = sizeof (struct pingpong_msg); | |||||
GNUNET_memcpy(data, pp_msg, *data_size); | |||||
GNUNET_free (pp_msg); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u sents ping to origin\n", mc_peer->peer); | |||||
return GNUNET_YES; | |||||
} | |||||
static void | |||||
member_join_decision (void *cls, | |||||
int is_admitted, | |||||
const struct GNUNET_PeerIdentity *peer, | |||||
uint16_t relay_count, | |||||
const struct GNUNET_PeerIdentity *relays, | |||||
const struct GNUNET_MessageHeader *join_msg) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u (%s) received a decision from origin: %s\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id), | |||||
(GNUNET_YES == is_admitted)?"accepted":"rejected"); | |||||
if (GNUNET_YES == is_admitted) | |||||
{ | |||||
GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer], | |||||
0, | |||||
notify, | |||||
cls); | |||||
} | |||||
} | |||||
static void | |||||
member_replay_frag () | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"member replay frag...\n"); | |||||
} | |||||
static void | |||||
member_replay_msg () | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"member replay msg...\n"); | |||||
} | |||||
static void | |||||
origin_disconnected_cb (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Origin disconnected. Shutting down.\n"); | |||||
result = GNUNET_YES; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
member_disconnected_cb (void *cls) | |||||
{ | |||||
for (int i = 1; i < PEERS_REQUESTED; ++i) | |||||
if (GNUNET_NO == multicast_peers[i]->test_ok) | |||||
return; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
"All member disconnected. Stopping origin.\n"); | |||||
GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls); | |||||
} | |||||
static void | |||||
member_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]); | |||||
if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"peer #%i (%s) receives a pong\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | |||||
mc_peer->test_ok = GNUNET_OK; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"peer #%u (%s) parting from multicast group\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | |||||
GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls); | |||||
} | |||||
} | |||||
static void | |||||
origin_join_request (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
const struct GNUNET_MessageHeader *join_msg, | |||||
struct GNUNET_MULTICAST_JoinHandle *jh) | |||||
{ | |||||
struct GNUNET_MessageHeader *join_resp; | |||||
uint8_t data_size = ntohs (join_msg->size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin got a join request...\n"); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin receives: '%s'\n", (char *)&join_msg[1]); | |||||
char data[] = "Come in!"; | |||||
data_size = strlen (data) + 1; | |||||
join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | |||||
join_resp->size = htons (sizeof (join_resp) + data_size); | |||||
join_resp->type = htons (123); | |||||
GNUNET_memcpy (&join_resp[1], data, data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"origin sends: '%s'\n", data); | |||||
GNUNET_MULTICAST_join_decision (jh, | |||||
GNUNET_YES, | |||||
0, | |||||
NULL, | |||||
join_resp); | |||||
result = GNUNET_OK; | |||||
} | |||||
static void | |||||
origin_replay_frag (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
uint64_t fragment_id, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n"); | |||||
} | |||||
static void | |||||
origin_replay_msg (void *cls, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | |||||
uint64_t message_id, | |||||
uint64_t fragment_offset, | |||||
uint64_t flags, | |||||
struct GNUNET_MULTICAST_ReplayHandle *rh) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n"); | |||||
} | |||||
static int | |||||
origin_notify (void *cls, | |||||
size_t *data_size, | |||||
void *data) | |||||
{ | |||||
struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls; | |||||
struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); | |||||
pp_msg->peer = rcv_pp_msg->peer; | |||||
pp_msg->msg = PONG; | |||||
*data_size = sizeof (struct pingpong_msg); | |||||
GNUNET_memcpy(data, pp_msg, *data_size); | |||||
GNUNET_free (pp_msg); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n"); | |||||
return GNUNET_YES; | |||||
} | |||||
static void | |||||
origin_request (void *cls, | |||||
const struct GNUNET_MULTICAST_RequestHeader *req) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n"); | |||||
req++; | |||||
struct pingpong_msg *pp_msg = (struct pingpong_msg *) req; | |||||
if (1 != pp_msg->msg) { | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); | |||||
} | |||||
GNUNET_MULTICAST_origin_to_all (origin, | |||||
0, | |||||
0, | |||||
origin_notify, | |||||
pp_msg); | |||||
} | |||||
static void | |||||
origin_message (void *cls, | |||||
const struct GNUNET_MULTICAST_MessageHeader *msg) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); | |||||
} | |||||
static void | |||||
multicast_disconnect (void *cls, | |||||
void *op_result) | |||||
{ | |||||
} | |||||
static void * | |||||
multicast_connect (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct MulticastPeerContext *multicast_peer = cls; | |||||
struct GNUNET_MessageHeader *join_msg; | |||||
char data[64]; | |||||
if (0 == multicast_peer->peer) | |||||
{ | |||||
group_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | |||||
GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash); | |||||
origin = GNUNET_MULTICAST_origin_start (cfg, | |||||
group_key, | |||||
0, | |||||
origin_join_request, | |||||
origin_replay_frag, | |||||
origin_replay_msg, | |||||
origin_request, | |||||
origin_message, | |||||
cls); | |||||
if (NULL == origin) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u could not create a multicast group", | |||||
multicast_peer->peer); | |||||
return NULL; | |||||
} | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u connected as origin to group %s\n", | |||||
multicast_peer->peer, | |||||
GNUNET_h2s (&group_pub_key_hash)); | |||||
return origin; | |||||
} | |||||
else | |||||
{ | |||||
multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
sprintf(data, "Hi, I am peer #%u (%s). Can I enter?", | |||||
multicast_peer->peer, | |||||
GNUNET_i2s (multicast_peers[multicast_peer->peer]->id)); | |||||
uint8_t data_size = strlen (data) + 1; | |||||
join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); | |||||
join_msg->size = htons (sizeof (join_msg) + data_size); | |||||
join_msg->type = htons (123); | |||||
GNUNET_memcpy (&join_msg[1], data, data_size); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Peer #%u (%s) tries to join multicast group %s\n", | |||||
multicast_peer->peer, | |||||
GNUNET_i2s (multicast_peers[multicast_peer->peer]->id), | |||||
GNUNET_h2s (&group_pub_key_hash)); | |||||
members[multicast_peer->peer] = | |||||
GNUNET_MULTICAST_member_join (cfg, | |||||
&group_pub_key, | |||||
multicast_peer->key, | |||||
multicast_peers[0]->id, | |||||
0, | |||||
NULL, | |||||
join_msg, /* join message */ | |||||
member_join_request, | |||||
member_join_decision, | |||||
member_replay_frag, | |||||
member_replay_msg, | |||||
member_message, | |||||
cls); | |||||
return members[multicast_peer->peer]; | |||||
} | |||||
} | |||||
static void | |||||
peer_information_cb (void *cls, | |||||
struct GNUNET_TESTBED_Operation *operation, | |||||
const struct GNUNET_TESTBED_PeerInformation *pinfo, | |||||
const char *emsg) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
if (NULL == pinfo) { | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n"); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
multicast_peers[mc_peer->peer]->id = pinfo->result.id; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Got peer information of %s (%s)\n", | |||||
(0 == mc_peer->peer)? "origin" : "member", | |||||
GNUNET_i2s (pinfo->result.id)); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Create peer #%u (%s)\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | |||||
if (0 != mc_peer->peer) | |||||
{ | |||||
/* connect to multicast service of members */ | |||||
op[mc_peer->peer] = | |||||
GNUNET_TESTBED_service_connect (/* Closure for operation */ | |||||
NULL, | |||||
/* The peer whose service to connect to */ | |||||
peers[mc_peer->peer], | |||||
/* The name of the service */ | |||||
"multicast", | |||||
/* called after a handle to service is opened */ | |||||
service_connect, | |||||
/* closure for the above callback */ | |||||
cls, | |||||
/* called when opening the service connection */ | |||||
multicast_connect, | |||||
/* called when closing the service connection */ | |||||
multicast_disconnect, | |||||
/* closure for the above two callbacks */ | |||||
cls); | |||||
} | |||||
} | |||||
static void | |||||
service_connect (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg) | |||||
{ | |||||
struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | |||||
if (NULL == ca_result) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Connection adapter not created for peer #%u (%s)\n", | |||||
mc_peer->peer, | |||||
GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown(); | |||||
} | |||||
if (0 == mc_peer->peer) | |||||
{ | |||||
// Get GNUnet identity of members | |||||
for (int i = 0; i<PEERS_REQUESTED; i++) | |||||
{ | |||||
pi_op[i] = GNUNET_TESTBED_peer_get_information (peers[i], | |||||
GNUNET_TESTBED_PIT_IDENTITY, | |||||
peer_information_cb, | |||||
multicast_peers[i]); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Main function inovked from TESTBED once all of the | |||||
* peers are up and running. This one then connects | |||||
* just to the multicast service of peer 0 and 1. | |||||
* Peer 0 is going to be origin. | |||||
* Peer 1 is going to be one member. | |||||
* Origin will start a multicast group and the member will try to join it. | |||||
* After that we execute some multicast test. | |||||
* | |||||
* @param cls closure | |||||
* @param h the run handle | |||||
* @param peers started peers for the test | |||||
* @param PEERS_REQUESTED size of the 'peers' array | |||||
* @param links_succeeded number of links between peers that were created | |||||
* @param links_failed number of links testbed was unable to establish | |||||
*/ | |||||
static void | |||||
testbed_master (void *cls, | |||||
struct GNUNET_TESTBED_RunHandle *h, | |||||
unsigned int num_peers, | |||||
struct GNUNET_TESTBED_Peer **p, | |||||
unsigned int links_succeeded, | |||||
unsigned int links_failed) | |||||
{ | |||||
/* Testbed is ready with peers running and connected in a pre-defined overlay | |||||
topology (FIXME) */ | |||||
peers = p; | |||||
multicast_peers = GNUNET_new_array (PEERS_REQUESTED, struct MulticastPeerContext*); | |||||
// Create test contexts for members | |||||
for (int i = 0; i<PEERS_REQUESTED; i++) | |||||
{ | |||||
multicast_peers[i] = GNUNET_new (struct MulticastPeerContext); | |||||
multicast_peers[i]->peer = i; | |||||
multicast_peers[i]->test_ok = GNUNET_NO; | |||||
} | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Create origin peer\n"); | |||||
op[0] = | |||||
GNUNET_TESTBED_service_connect (/* Closure for operation */ | |||||
NULL, | |||||
/* The peer whose service to connect to */ | |||||
peers[0], | |||||
/* The name of the service */ | |||||
"multicast", | |||||
/* called after a handle to service is opened */ | |||||
service_connect, | |||||
/* closure for the above callback */ | |||||
multicast_peers[0], | |||||
/* called when opening the service connection */ | |||||
multicast_connect, | |||||
/* called when closing the service connection */ | |||||
multicast_disconnect, | |||||
/* closure for the above two callbacks */ | |||||
multicast_peers[0]); | |||||
/* Schedule a new task on shutdown */ | |||||
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | |||||
/* Schedule the shutdown task with a delay of a few Seconds */ | |||||
timeout_tid = | |||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | |||||
(GNUNET_TIME_UNIT_SECONDS, 400), | |||||
&timeout_task, | |||||
NULL); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
int ret; | |||||
char const *config_file; | |||||
if (strstr (argv[0], "_line") != NULL) | |||||
{ | |||||
config_file = "test_multicast_line.conf"; | |||||
} | |||||
else if (strstr(argv[0], "_star") != NULL) | |||||
{ | |||||
config_file = "test_multicast_star.conf"; | |||||
} | |||||
else | |||||
{ | |||||
config_file = "test_multicast_star.conf"; | |||||
} | |||||
result = GNUNET_SYSERR; | |||||
ret = | |||||
GNUNET_TESTBED_test_run ("test-multicast-multipeer", | |||||
config_file, | |||||
/* number of peers to start */ | |||||
PEERS_REQUESTED, | |||||
/* Event mask - set to 0 for no event notifications */ | |||||
0LL, | |||||
/* Controller event callback */ | |||||
NULL, | |||||
/* Closure for controller event callback */ | |||||
NULL, | |||||
/* called when testbed setup is complete */ | |||||
testbed_master, | |||||
/* Closure for the test_master callback */ | |||||
NULL); | |||||
if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
/* end of test_multicast_multipeer.c */ |
@@ -0,0 +1,64 @@ | |||||
[testbed] | |||||
HOSTNAME = localhost | |||||
OVERLAY_TOPOLOGY = STAR | |||||
[arm] | |||||
GLOBAL_POSTFIX=-L ERROR | |||||
[multicast] | |||||
#PREFIX = tmux new-window gdb -x ./cmd.gdb --args | |||||
#PREFIX = valgrind --leak-check=full | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | |||||
[vpn] | |||||
START_ON_DEMAND = NO | |||||
[peerinfo] | |||||
# Do not use shipped gnunet HELLOs | |||||
USE_INCLUDED_HELLOS = NO | |||||
# Option to disable all disk IO; only useful for testbed runs | |||||
# (large-scale experiments); disables persistence of HELLOs! | |||||
NO_IO = YES | |||||
[cadet] | |||||
ID_ANNOUNCE_TIME = 5 s | |||||
[hostlist] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[nat] | |||||
ENABLE_UPNP = NO | |||||
[fs] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[vpn] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[revocation] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[gns] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namestore] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[namecache] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[topology] | |||||
IMMEDIATE_START = NO | |||||
START_ON_DEMAND = NO | |||||
[nse] | |||||
WORKBITS = 0 | |||||
@@ -0,0 +1,2 @@ | |||||
gnunet-service-psyc | |||||
test_psyc |
@@ -0,0 +1,77 @@ | |||||
# This Makefile.am is in the public domain | |||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include | |||||
pkgcfgdir= $(pkgdatadir)/config.d/ | |||||
libexecdir= $(pkglibdir)/libexec/ | |||||
pkgcfg_DATA = \ | |||||
psyc.conf | |||||
if MINGW | |||||
WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | |||||
endif | |||||
if USE_COVERAGE | |||||
AM_CFLAGS = --coverage -O0 | |||||
XLIB = -lgcov | |||||
endif | |||||
lib_LTLIBRARIES = libgnunetpsyc.la | |||||
libgnunetpsyc_la_SOURCES = \ | |||||
psyc_api.c psyc.h | |||||
libgnunetpsyc_la_LIBADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | |||||
$(GN_LIBINTL) $(XLIB) | |||||
libgnunetpsyc_la_LDFLAGS = \ | |||||
$(GN_LIB_LDFLAGS) $(WINFLAGS) \ | |||||
-version-info 0:0:0 | |||||
bin_PROGRAMS = | |||||
libexec_PROGRAMS = \ | |||||
gnunet-service-psyc | |||||
gnunet_service_psyc_SOURCES = \ | |||||
gnunet-service-psyc.c | |||||
gnunet_service_psyc_LDADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(top_builddir)/src/multicast/libgnunetmulticast.la \ | |||||
$(top_builddir)/src/psycstore/libgnunetpsycstore.la \ | |||||
$(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | |||||
$(GN_LIBINTL) | |||||
gnunet_service_psyc_CFLAGS = $(AM_CFLAGS) | |||||
if HAVE_TESTING | |||||
check_PROGRAMS = \ | |||||
test_psyc | |||||
# test_psyc2 | |||||
endif | |||||
if ENABLE_TEST_RUN | |||||
AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | |||||
TESTS = $(check_PROGRAMS) | |||||
endif | |||||
test_psyc_SOURCES = \ | |||||
test_psyc.c | |||||
test_psyc_LDADD = \ | |||||
libgnunetpsyc.la \ | |||||
$(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
#test_psyc2_SOURCES = \ | |||||
# test_psyc2.c | |||||
#test_psyc2_LDADD = \ | |||||
# libgnunetpsyc.la \ | |||||
# $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | |||||
# $(top_builddir)/src/testbed/libgnunettestbed.la \ | |||||
# $(top_builddir)/src/util/libgnunetutil.la | |||||
EXTRA_DIST = \ | |||||
test_psyc.conf |
@@ -0,0 +1,12 @@ | |||||
[psyc] | |||||
START_ON_DEMAND = @START_ON_DEMAND@ | |||||
BINARY = gnunet-service-psyc | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psyc.sock | |||||
UNIX_MATCH_UID = YES | |||||
UNIX_MATCH_GID = YES | |||||
@UNIXONLY@PORT = 2115 | |||||
HOSTNAME = localhost | |||||
ACCEPT_FROM = 127.0.0.1; | |||||
ACCEPT_FROM6 = ::1; |
@@ -0,0 +1,178 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psyc/psyc.h | |||||
* @brief Common type definitions for the PSYC service and API. | |||||
* @author Gabor X Toth | |||||
*/ | |||||
#ifndef PSYC_H | |||||
#define PSYC_H | |||||
#include "platform.h" | |||||
#include "gnunet_psyc_service.h" | |||||
int | |||||
GNUNET_PSYC_check_message_parts (uint16_t data_size, const char *data, | |||||
uint16_t *first_ptype, uint16_t *last_ptype); | |||||
void | |||||
GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, | |||||
const struct GNUNET_MessageHeader *msg); | |||||
enum MessageState | |||||
{ | |||||
MSG_STATE_START = 0, | |||||
MSG_STATE_HEADER = 1, | |||||
MSG_STATE_METHOD = 2, | |||||
MSG_STATE_MODIFIER = 3, | |||||
MSG_STATE_MOD_CONT = 4, | |||||
MSG_STATE_DATA = 5, | |||||
MSG_STATE_END = 6, | |||||
MSG_STATE_CANCEL = 7, | |||||
MSG_STATE_ERROR = 8, | |||||
}; | |||||
enum MessageFragmentState | |||||
{ | |||||
MSG_FRAG_STATE_START = 0, | |||||
MSG_FRAG_STATE_HEADER = 1, | |||||
MSG_FRAG_STATE_DATA = 2, | |||||
MSG_FRAG_STATE_END = 3, | |||||
MSG_FRAG_STATE_CANCEL = 4, | |||||
MSG_FRAG_STATE_DROP = 5, | |||||
}; | |||||
GNUNET_NETWORK_STRUCT_BEGIN | |||||
/**** library -> service ****/ | |||||
struct MasterStartRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_START | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t policy GNUNET_PACKED; | |||||
struct GNUNET_CRYPTO_EddsaPrivateKey channel_key; | |||||
}; | |||||
struct SlaveJoinRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t relay_count GNUNET_PACKED; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | |||||
struct GNUNET_CRYPTO_EcdsaPrivateKey slave_key; | |||||
struct GNUNET_PeerIdentity origin; | |||||
uint32_t flags GNUNET_PACKED; | |||||
/* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ | |||||
/* Followed by struct GNUNET_MessageHeader join_msg */ | |||||
}; | |||||
struct ChannelMembershipStoreRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
uint64_t op_id GNUNET_PACKED; | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | |||||
uint64_t announced_at GNUNET_PACKED; | |||||
uint64_t effective_since GNUNET_PACKED; | |||||
uint8_t did_join; | |||||
}; | |||||
struct HistoryRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REQUEST | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* ID for this operation. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
uint64_t start_message_id GNUNET_PACKED; | |||||
uint64_t end_message_id GNUNET_PACKED; | |||||
uint64_t message_limit GNUNET_PACKED; | |||||
}; | |||||
struct StateRequest | |||||
{ | |||||
/** | |||||
* Types: | |||||
* - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET | |||||
* - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* ID for this operation. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/* Followed by NUL-terminated name. */ | |||||
}; | |||||
/**** service -> library ****/ | |||||
GNUNET_NETWORK_STRUCT_END | |||||
#endif |
@@ -0,0 +1,67 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psyc/test_psyc_api_join.c | |||||
* @brief library for writing psyc tests | |||||
* @author xrs | |||||
*/ | |||||
#define MAX_TESTBED_OPS 32 | |||||
struct pctx | |||||
{ | |||||
int idx; | |||||
struct GNUNET_TESTBED_Peer *testbed_peer; | |||||
const struct GNUNET_PeerIdentity *peer_id; | |||||
const struct GNUNET_PeerIdentity *peer_id_master; | |||||
/** | |||||
* Used to simulate egos (not peerid) | |||||
*/ | |||||
const struct GNUNET_CRYPTO_EcdsaPrivateKey *id_key; | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *id_pub_key; | |||||
/** | |||||
* Used to store either GNUNET_PSYC_Master or GNUNET_PSYC_Slave handle | |||||
*/ | |||||
void *psyc; | |||||
struct GNUNET_PSYC_Channel *channel; | |||||
const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key; | |||||
int test_ok; | |||||
}; | |||||
static struct GNUNET_SCHEDULER_Task *timeout_task_id; | |||||
static int result = GNUNET_SYSERR; | |||||
static struct GNUNET_TESTBED_Operation *op[MAX_TESTBED_OPS]; | |||||
static int op_cnt = 0; | |||||
@@ -0,0 +1,284 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psyc/test_psyc2.c | |||||
* @brief Testbed test for the PSYC API. | |||||
* @author xrs | |||||
*/ | |||||
#include "platform.h" | |||||
#include "gnunet_crypto_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testbed_service.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
#include "gnunet_psyc_service.h" | |||||
#define PEERS_REQUESTED 2 | |||||
static int result; | |||||
static struct GNUNET_SCHEDULER_Task *timeout_tid; | |||||
static struct pctx **pctx; | |||||
static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | |||||
static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | |||||
/** | |||||
* Task To perform tests | |||||
*/ | |||||
static struct GNUNET_SCHEDULER_Task *test_task; | |||||
/** | |||||
* Peer id couter | |||||
*/ | |||||
static unsigned int pids; | |||||
struct pctx | |||||
{ | |||||
int idx; | |||||
struct GNUNET_TESTBED_Peer *peer; | |||||
const struct GNUNET_PeerIdentity *id; | |||||
struct GNUNET_TESTBED_Operation *op; | |||||
/** | |||||
* psyc service handle | |||||
*/ | |||||
void *psyc; | |||||
struct GNUNET_PSYC_Master *mst; | |||||
struct GNUNET_PSYC_Slave *slv; | |||||
/** | |||||
* result for test on peer | |||||
*/ | |||||
int test_ok; | |||||
}; | |||||
static void | |||||
shutdown_task (void *cls) | |||||
{ | |||||
if (NULL != pctx) | |||||
{ | |||||
if (NULL != pctx[0]->mst) | |||||
GNUNET_PSYC_master_stop (pctx[0]->mst, GNUNET_NO, NULL, NULL); | |||||
for (int i=0; i < PEERS_REQUESTED; i++) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Operation done.\n"); | |||||
GNUNET_TESTBED_operation_done (pctx[i]->op); | |||||
GNUNET_free_non_null (pctx[i]); | |||||
} | |||||
GNUNET_free (pctx); | |||||
} | |||||
if (NULL != timeout_tid) | |||||
GNUNET_SCHEDULER_cancel (timeout_tid); | |||||
} | |||||
static void | |||||
timeout_task (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout!\n"); | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
start_test (void *cls) | |||||
{ | |||||
} | |||||
static void | |||||
pinfo_cb (void *cls, | |||||
struct GNUNET_TESTBED_Operation *operation, | |||||
const struct GNUNET_TESTBED_PeerInformation *pinfo, | |||||
const char *emsg) | |||||
{ | |||||
struct pctx *pc = (struct pctx*) cls; | |||||
pc->id = pinfo->result.id; | |||||
pids++; | |||||
if (pids < (PEERS_REQUESTED - 1)) | |||||
return; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); | |||||
test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL); | |||||
} | |||||
static void | |||||
mst_start_cb () | |||||
{ | |||||
} | |||||
static void | |||||
join_request_cb () | |||||
{ | |||||
} | |||||
static void | |||||
mst_message_cb () | |||||
{ | |||||
} | |||||
static void | |||||
mst_message_part_cb () | |||||
{ | |||||
} | |||||
static void | |||||
slv_message_cb () | |||||
{ | |||||
} | |||||
static void | |||||
slv_message_part_cb () | |||||
{ | |||||
} | |||||
static void | |||||
slv_connect_cb () | |||||
{ | |||||
} | |||||
static void | |||||
join_decision_cb () | |||||
{ | |||||
} | |||||
static void * | |||||
psyc_ca (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct GNUNET_PSYC_Message *join_msg = NULL; | |||||
struct pctx *pc = (struct pctx *) cls; | |||||
if (0 == pc->idx) | |||||
{ | |||||
pc->mst = GNUNET_PSYC_master_start (cfg, channel_key, | |||||
GNUNET_PSYC_CHANNEL_PRIVATE, | |||||
&mst_start_cb, &join_request_cb, | |||||
&mst_message_cb, &mst_message_part_cb, | |||||
NULL); | |||||
return pc->mst; | |||||
} | |||||
pc->slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, | |||||
GNUNET_PSYC_SLAVE_JOIN_NONE, | |||||
&pid, 0, NULL, &slv_message_cb, | |||||
&slv_message_part_cb, | |||||
&slv_connect_cb, &join_decision_cb, | |||||
NULL, join_msg); | |||||
return pc->slv; | |||||
} | |||||
static void | |||||
psyc_da (void *cls, | |||||
void *op_result) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnected from service.\n"); | |||||
} | |||||
static void | |||||
service_connect (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg) | |||||
{ | |||||
struct pctx *pc = (struct pctx *) cls; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"Connected to service\n"); | |||||
GNUNET_assert (NULL != ca_result); | |||||
// FIXME: we need a simple service handle to connect to the service, then | |||||
// get peer information and AFTER that make PSYC ops. Compare to CADET. | |||||
pc->psyc = ca_result; | |||||
GNUNET_TESTBED_peer_get_information (pc->peer, | |||||
GNUNET_TESTBED_PIT_IDENTITY, | |||||
pinfo_cb, pc); | |||||
} | |||||
static void | |||||
testbed_master (void *cls, | |||||
struct GNUNET_TESTBED_RunHandle *h, | |||||
unsigned int num_peers, | |||||
struct GNUNET_TESTBED_Peer **p, | |||||
unsigned int links_succeeded, | |||||
unsigned int links_failed) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master()\n"); | |||||
// Create ctx for peers | |||||
pctx = GNUNET_new_array (PEERS_REQUESTED, struct pctx*); | |||||
for (int i = 0; i<PEERS_REQUESTED; i++) | |||||
{ | |||||
pctx[i] = GNUNET_new (struct pctx); | |||||
pctx[i]->idx = i; | |||||
pctx[i]->peer = p[i]; | |||||
pctx[i]->id = NULL; | |||||
pctx[i]->mst = NULL; | |||||
pctx[i]->op = NULL; | |||||
pctx[i]->test_ok = GNUNET_NO; | |||||
} | |||||
channel_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); | |||||
GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | |||||
pctx[0]->op = | |||||
GNUNET_TESTBED_service_connect (NULL, p[0], "psyc", service_connect, | |||||
pctx[0], psyc_ca, psyc_da, pctx[0]); | |||||
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | |||||
timeout_tid = | |||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5), | |||||
&timeout_task, NULL); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
int ret; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test\n"); | |||||
result = GNUNET_SYSERR; | |||||
ret = GNUNET_TESTBED_test_run ("test-psyc2", "test_psyc.conf", | |||||
PEERS_REQUESTED, 0LL, NULL, NULL, | |||||
testbed_master, NULL); | |||||
if ((GNUNET_OK != ret) || (GNUNET_OK != result)) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
/* end of test-psyc2.c */ |
@@ -0,0 +1,282 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psyc/test_psyc_api_join.c | |||||
* @brief Testbed test for the PSYC API. | |||||
* @author xrs | |||||
*/ | |||||
/** | |||||
* Lessons Learned: | |||||
* - define topology in config | |||||
* - psyc slave join needs part to end (same with master) | |||||
* - GNUNET_SCHEDULER_add_delayed return value will outdate at call time | |||||
* - main can not contain GNUNET_log() | |||||
*/ | |||||
#include "platform.h" | |||||
#include "gnunet_crypto_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testbed_service.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
#include "gnunet_psyc_service.h" | |||||
#include "psyc_test_lib.h" | |||||
static struct pctx PEERS[2]; | |||||
static int pids; | |||||
static void | |||||
shutdown_task (void *cls) | |||||
{ | |||||
if (NULL != timeout_task_id) { | |||||
GNUNET_SCHEDULER_cancel (timeout_task_id); | |||||
timeout_task_id = NULL; | |||||
} | |||||
for (int i=0;i<2;i++) { | |||||
GNUNET_free (PEERS[i].channel_pub_key); | |||||
if (NULL != PEERS[i].psyc) | |||||
{ | |||||
if (0 == i) | |||||
GNUNET_PSYC_master_stop (PEERS[i].psyc, GNUNET_NO, NULL, NULL); | |||||
else | |||||
GNUNET_PSYC_slave_part (PEERS[i].psyc, GNUNET_NO, NULL, NULL); | |||||
} | |||||
} | |||||
for (int i=0;i<MAX_TESTBED_OPS;i++) | |||||
if (NULL != op[i]) | |||||
GNUNET_TESTBED_operation_done (op[i]); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shut down!\n"); | |||||
} | |||||
static void | |||||
timeout_task (void *cls) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Timeout!\n"); | |||||
timeout_task_id = NULL; | |||||
result = GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
join_decision_cb (void *cls, | |||||
const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, | |||||
int is_admitted, | |||||
const struct GNUNET_PSYC_Message *join_msg) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, | |||||
"slave: got join decision: %s\n", | |||||
(GNUNET_YES == is_admitted) ? "admitted":"rejected"); | |||||
result = (GNUNET_YES == is_admitted) ? GNUNET_OK : GNUNET_SYSERR; | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
static void | |||||
join_request_cb (void *cls, | |||||
const struct GNUNET_PSYC_JoinRequestMessage *req, | |||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | |||||
const struct GNUNET_PSYC_Message *join_msg, | |||||
struct GNUNET_PSYC_JoinHandle *jh) | |||||
{ | |||||
struct GNUNET_HashCode slave_key_hash; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "master: got join request.\n"); | |||||
GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); | |||||
GNUNET_PSYC_join_decision (jh, GNUNET_YES, 0, NULL, NULL); | |||||
} | |||||
static void | |||||
psyc_da () | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "disconnect form PSYC service\n"); | |||||
} | |||||
static void * | |||||
psyc_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct pctx *peer = (struct pctx*) cls; | |||||
// Case: master role | |||||
if (0 == peer->idx) { | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as master ...\n"); | |||||
peer->psyc = (struct GNUNET_PSYC_Master *) | |||||
GNUNET_PSYC_master_start (cfg, | |||||
peer->channel_key, | |||||
GNUNET_PSYC_CHANNEL_PRIVATE, | |||||
NULL, | |||||
join_request_cb, | |||||
NULL, | |||||
NULL, | |||||
cls); | |||||
return peer->psyc; | |||||
} | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as slave ...\n"); | |||||
struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | |||||
GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo", "bar baz", 7); | |||||
GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo_bar", "foo bar baz", 11); | |||||
struct GNUNET_PSYC_Message * | |||||
join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 40); | |||||
peer->psyc = (struct GNUNET_PSYC_Slave *) | |||||
GNUNET_PSYC_slave_join (cfg, | |||||
peer->channel_pub_key, | |||||
peer->id_key, | |||||
GNUNET_PSYC_SLAVE_JOIN_NONE, | |||||
peer->peer_id_master, | |||||
0, | |||||
NULL, | |||||
NULL, | |||||
NULL, | |||||
NULL, | |||||
join_decision_cb, | |||||
cls, | |||||
join_msg); | |||||
GNUNET_free (join_msg); | |||||
peer->channel = GNUNET_PSYC_slave_get_channel (peer->psyc); | |||||
GNUNET_PSYC_env_destroy (env); | |||||
return peer->psyc; | |||||
} | |||||
static void | |||||
service_connect (void *cls, | |||||
struct GNUNET_TESTBED_Operation *op, | |||||
void *ca_result, | |||||
const char *emsg) | |||||
{ | |||||
GNUNET_assert (NULL != ca_result); | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to the service\n"); | |||||
} | |||||
static void | |||||
connect_to_services (void *cls) | |||||
{ | |||||
for (int i = 0; i < 2; i++) | |||||
{ | |||||
PEERS[i].peer_id_master = PEERS[0].peer_id; | |||||
op[op_cnt++] = | |||||
GNUNET_TESTBED_service_connect (NULL, PEERS[i].testbed_peer, "psyc", | |||||
&service_connect, &PEERS[i], &psyc_ca, | |||||
&psyc_da, &PEERS[i]); | |||||
} | |||||
} | |||||
static void | |||||
pinfo_cb (void *cls, | |||||
struct GNUNET_TESTBED_Operation *operation, | |||||
const struct GNUNET_TESTBED_PeerInformation *pinfo, | |||||
const char *emsg) | |||||
{ | |||||
struct pctx *peer = (struct pctx*) cls; | |||||
peer->peer_id = pinfo->result.id; | |||||
pids++; | |||||
if (pids < 2) | |||||
return; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting test\n"); | |||||
GNUNET_SCHEDULER_add_now (&connect_to_services, NULL); | |||||
} | |||||
static void | |||||
testbed_master (void *cls, | |||||
struct GNUNET_TESTBED_RunHandle *h, | |||||
unsigned int num_peers, | |||||
struct GNUNET_TESTBED_Peer **p, | |||||
unsigned int links_succeeded, | |||||
unsigned int links_failed) | |||||
{ | |||||
struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master\n"); | |||||
// Set up shutdown logic | |||||
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | |||||
timeout_task_id = | |||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15), | |||||
&timeout_task, NULL); | |||||
GNUNET_assert (NULL != timeout_task_id); | |||||
// Set up channel key | |||||
channel_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
GNUNET_assert (NULL != channel_key); | |||||
// Set up information contexts for peers | |||||
for (int i=0 ; i < 2 ; i++) | |||||
{ | |||||
PEERS[i].idx = i; | |||||
PEERS[i].testbed_peer = p[i]; | |||||
// Create "egos" | |||||
PEERS[i].id_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
// Set up channel keys shared by master and slave | |||||
PEERS[i].channel_key = channel_key; | |||||
PEERS[i].channel_pub_key = | |||||
GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); | |||||
// Get public key | |||||
GNUNET_CRYPTO_eddsa_key_get_public (PEERS[i].channel_key, | |||||
PEERS[i].channel_pub_key); | |||||
// Get peerinfo | |||||
op[op_cnt++] = | |||||
GNUNET_TESTBED_peer_get_information (p[i], | |||||
GNUNET_TESTBED_PIT_IDENTITY, | |||||
pinfo_cb, &PEERS[i]); | |||||
} | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
int ret; | |||||
ret = GNUNET_TESTBED_test_run ("test_psyc_api_join", "test_psyc.conf", | |||||
2, 0LL, NULL, NULL, | |||||
&testbed_master, NULL); | |||||
if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
/* end of test_psyc_api_join.c */ |
@@ -0,0 +1,5 @@ | |||||
gnunet-service-psycstore | |||||
test_plugin_psycstore_mysql | |||||
test_plugin_psycstore_sqlite | |||||
test_plugin_psycstore_postgres | |||||
test_psycstore |
@@ -0,0 +1,155 @@ | |||||
# This Makefile.am is in the public domain | |||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include | |||||
plugindir = $(libdir)/gnunet | |||||
pkgcfgdir= $(pkgdatadir)/config.d/ | |||||
libexecdir= $(pkglibdir)/libexec/ | |||||
pkgcfg_DATA = \ | |||||
psycstore.conf | |||||
if MINGW | |||||
WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | |||||
endif | |||||
if USE_COVERAGE | |||||
AM_CFLAGS = --coverage -O0 | |||||
XLIB = -lgcov | |||||
endif | |||||
if HAVE_MYSQL | |||||
MYSQL_PLUGIN = libgnunet_plugin_psycstore_mysql.la | |||||
if HAVE_TESTING | |||||
MYSQL_TESTS = test_plugin_psycstore_mysql | |||||
endif | |||||
endif | |||||
if HAVE_POSTGRESQL | |||||
POSTGRES_PLUGIN = libgnunet_plugin_psycstore_postgres.la | |||||
if HAVE_TESTING | |||||
POSTGRES_TESTS = test_plugin_psycstore_postgres | |||||
endif | |||||
endif | |||||
if HAVE_SQLITE | |||||
SQLITE_PLUGIN = libgnunet_plugin_psycstore_sqlite.la | |||||
if HAVE_TESTING | |||||
SQLITE_TESTS = test_plugin_psycstore_sqlite | |||||
endif | |||||
endif | |||||
lib_LTLIBRARIES = libgnunetpsycstore.la | |||||
libgnunetpsycstore_la_SOURCES = \ | |||||
psycstore_api.c \ | |||||
psycstore.h | |||||
libgnunetpsycstore_la_LIBADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(GN_LIBINTL) $(XLIB) | |||||
libgnunetpsycstore_la_LDFLAGS = \ | |||||
$(GN_LIB_LDFLAGS) $(WINFLAGS) \ | |||||
-version-info 0:0:0 | |||||
bin_PROGRAMS = | |||||
libexec_PROGRAMS = \ | |||||
gnunet-service-psycstore | |||||
gnunet_service_psycstore_SOURCES = \ | |||||
gnunet-service-psycstore.c | |||||
gnunet_service_psycstore_LDADD = \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | |||||
$(GN_LIBINTL) | |||||
plugin_LTLIBRARIES = \ | |||||
$(SQLITE_PLUGIN) \ | |||||
$(MYSQL_PLUGIN) \ | |||||
$(POSTGRES_PLUGIN) | |||||
libgnunet_plugin_psycstore_mysql_la_SOURCES = \ | |||||
plugin_psycstore_mysql.c | |||||
libgnunet_plugin_psycstore_mysql_la_LIBADD = \ | |||||
libgnunetpsycstore.la \ | |||||
$(top_builddir)/src/my/libgnunetmy.la \ | |||||
$(top_builddir)/src/mysql/libgnunetmysql.la \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ | |||||
$(LTLIBINTL) | |||||
libgnunet_plugin_psycstore_mysql_la_LDFLAGS = \ | |||||
$(GN_PLUGIN_LDFLAGS) | |||||
libgnunet_plugin_psycstore_postgres_la_SOURCES = \ | |||||
plugin_psycstore_postgres.c | |||||
libgnunet_plugin_psycstore_postgres_la_LIBADD = \ | |||||
libgnunetpsycstore.la \ | |||||
$(top_builddir)/src/pq/libgnunetpq.la \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ | |||||
$(LTLIBINTL) | |||||
libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \ | |||||
$(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) | |||||
libgnunet_plugin_psycstore_postgres_la_CPPFLAGS = \ | |||||
$(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS) | |||||
libgnunet_plugin_psycstore_sqlite_la_SOURCES = \ | |||||
plugin_psycstore_sqlite.c | |||||
libgnunet_plugin_psycstore_sqlite_la_LIBADD = \ | |||||
libgnunetpsycstore.la \ | |||||
$(top_builddir)/src/statistics/libgnunetstatistics.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ | |||||
$(LTLIBINTL) | |||||
libgnunet_plugin_psycstore_sqlite_la_LDFLAGS = \ | |||||
$(GN_PLUGIN_LDFLAGS) | |||||
if HAVE_SQLITE | |||||
if HAVE_TESTING | |||||
check_PROGRAMS = \ | |||||
$(SQLITE_TESTS) \ | |||||
$(MYSQL_TESTS) \ | |||||
$(POSTGRES_TESTS) \ | |||||
test_psycstore | |||||
endif | |||||
endif | |||||
if ENABLE_TEST_RUN | |||||
AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | |||||
TESTS = $(check_PROGRAMS) | |||||
endif | |||||
test_psycstore_SOURCES = \ | |||||
test_psycstore.c | |||||
test_psycstore_LDADD = \ | |||||
libgnunetpsycstore.la \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
EXTRA_DIST = \ | |||||
test_psycstore.conf | |||||
test_plugin_psycstore_sqlite_SOURCES = \ | |||||
test_plugin_psycstore.c | |||||
test_plugin_psycstore_sqlite_LDADD = \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
test_plugin_psycstore_mysql_SOURCES = \ | |||||
test_plugin_psycstore.c | |||||
test_plugin_psycstore_mysql_LDADD = \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
test_plugin_psycstore_postgres_SOURCES = \ | |||||
test_plugin_psycstore.c | |||||
test_plugin_psycstore_postgres_LDADD = \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la | |||||
@@ -0,0 +1,28 @@ | |||||
[psycstore] | |||||
START_ON_DEMAND = @START_ON_DEMAND@ | |||||
BINARY = gnunet-service-psycstore | |||||
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psycstore.sock | |||||
UNIX_MATCH_UID = YES | |||||
UNIX_MATCH_GID = YES | |||||
@UNIXONLY@PORT = 2111 | |||||
HOSTNAME = localhost | |||||
ACCEPT_FROM = 127.0.0.1; | |||||
ACCEPT_FROM6 = ::1; | |||||
DATABASE = sqlite | |||||
[psycstore-sqlite] | |||||
FILENAME = $GNUNET_DATA_HOME/psycstore/sqlite.db | |||||
[psycstore-mysql] | |||||
DATABASE = gnunet | |||||
CONFIG = ~/.my.cnf | |||||
# USER = gnunet | |||||
# PASSWORD = | |||||
# HOST = localhost | |||||
# PORT = 3306 | |||||
[psycstore-postgres] | |||||
CONFIG = connect_timeout=10; dbname=gnunet |
@@ -0,0 +1,520 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psycstore/psycstore.h | |||||
* @brief Common type definitions for the PSYCstore service and API. | |||||
* @author Gabor X Toth | |||||
*/ | |||||
#ifndef GNUNET_PSYCSTORE_H | |||||
#define GNUNET_PSYCSTORE_H | |||||
#include "gnunet_common.h" | |||||
GNUNET_NETWORK_STRUCT_BEGIN | |||||
/** | |||||
* Answer from service to client about last operation. | |||||
*/ | |||||
struct OperationResult | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/**lowed by | |||||
* Status code for the operation. | |||||
*/ | |||||
uint64_t result_code GNUNET_PACKED; | |||||
/* followed by 0-terminated error message (on error) */ | |||||
}; | |||||
/** | |||||
* Answer from service to client about master counters. | |||||
* | |||||
* @see GNUNET_PSYCSTORE_counters_get() | |||||
*/ | |||||
struct CountersResult | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Status code for the operation: | |||||
* #GNUNET_OK: success, counter values are returned. | |||||
* #GNUNET_NO: no message has been sent to the channel yet. | |||||
* #GNUNET_SYSERR: an error occurred. | |||||
*/ | |||||
uint32_t result_code GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
uint64_t max_fragment_id GNUNET_PACKED; | |||||
uint64_t max_message_id GNUNET_PACKED; | |||||
uint64_t max_group_generation GNUNET_PACKED; | |||||
uint64_t max_state_message_id GNUNET_PACKED; | |||||
}; | |||||
/** | |||||
* Answer from service to client containing a message fragment. | |||||
*/ | |||||
struct FragmentResult | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t psycstore_flags GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/* Followed by GNUNET_MULTICAST_MessageHeader */ | |||||
}; | |||||
/** | |||||
* Answer from service to client containing a state variable. | |||||
*/ | |||||
struct StateResult | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint16_t name_size GNUNET_PACKED; | |||||
uint16_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/* Followed by name and value */ | |||||
}; | |||||
/** | |||||
* Generic operation request. | |||||
*/ | |||||
struct OperationRequest | |||||
{ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_membership_store() | |||||
*/ | |||||
struct MembershipStoreRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Slave's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | |||||
uint64_t announced_at GNUNET_PACKED; | |||||
uint64_t effective_since GNUNET_PACKED; | |||||
uint64_t group_generation GNUNET_PACKED; | |||||
uint8_t did_join; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_membership_test() | |||||
*/ | |||||
struct MembershipTestRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Slave's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | |||||
uint64_t message_id GNUNET_PACKED; | |||||
uint64_t group_generation GNUNET_PACKED; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_fragment_store() | |||||
*/ | |||||
struct FragmentStoreRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* enum GNUNET_PSYCSTORE_MessageFlags | |||||
*/ | |||||
uint32_t psycstore_flags GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id; | |||||
/* Followed by fragment */ | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_fragment_get() | |||||
*/ | |||||
struct FragmentGetRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Slave's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | |||||
/** | |||||
* First fragment ID to request. | |||||
*/ | |||||
uint64_t first_fragment_id GNUNET_PACKED; | |||||
/** | |||||
* Last fragment ID to request. | |||||
*/ | |||||
uint64_t last_fragment_id GNUNET_PACKED; | |||||
/** | |||||
* Maximum number of fragments to retrieve. | |||||
*/ | |||||
uint64_t fragment_limit GNUNET_PACKED; | |||||
/** | |||||
* Do membership test with @a slave_key before returning fragment? | |||||
* #GNUNET_YES or #GNUNET_NO | |||||
*/ | |||||
uint8_t do_membership_test; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_message_get() | |||||
*/ | |||||
struct MessageGetRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Slave's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | |||||
/** | |||||
* First message ID to request. | |||||
*/ | |||||
uint64_t first_message_id GNUNET_PACKED; | |||||
/** | |||||
* Last message ID to request. | |||||
*/ | |||||
uint64_t last_message_id GNUNET_PACKED; | |||||
/** | |||||
* Maximum number of messages to retrieve. | |||||
*/ | |||||
uint64_t message_limit GNUNET_PACKED; | |||||
/** | |||||
* Maximum number of fragments to retrieve. | |||||
*/ | |||||
uint64_t fragment_limit GNUNET_PACKED; | |||||
/** | |||||
* Do membership test with @a slave_key before returning fragment? | |||||
* #GNUNET_YES or #GNUNET_NO | |||||
*/ | |||||
uint8_t do_membership_test; | |||||
/* Followed by method_prefix */ | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_message_get_fragment() | |||||
*/ | |||||
struct MessageGetFragmentRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_FRAGMENT_GET | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/** | |||||
* Slave's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | |||||
/** | |||||
* Requested message ID. | |||||
*/ | |||||
uint64_t message_id GNUNET_PACKED; | |||||
/** | |||||
* Requested fragment offset. | |||||
*/ | |||||
uint64_t fragment_offset GNUNET_PACKED; | |||||
/** | |||||
* Do membership test with @a slave_key before returning fragment? | |||||
* #GNUNET_YES or #GNUNET_NO | |||||
*/ | |||||
uint8_t do_membership_test; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_state_hash_update() | |||||
*/ | |||||
struct StateHashUpdateRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
uint32_t reserved GNUNET_PACKED; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
struct GNUNET_HashCode hash; | |||||
}; | |||||
enum StateOpFlags | |||||
{ | |||||
STATE_OP_FIRST = 1 << 0, | |||||
STATE_OP_LAST = 1 << 1 | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_state_modify() | |||||
*/ | |||||
struct StateModifyRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* ID of the message to apply the state changes in. | |||||
*/ | |||||
uint64_t message_id GNUNET_PACKED; | |||||
/** | |||||
* State delta of the message with ID @a message_id. | |||||
*/ | |||||
uint64_t state_delta GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
}; | |||||
/** | |||||
* @see GNUNET_PSYCSTORE_state_sync() | |||||
*/ | |||||
struct StateSyncRequest | |||||
{ | |||||
/** | |||||
* Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC | |||||
*/ | |||||
struct GNUNET_MessageHeader header; | |||||
/** | |||||
* Size of name, including NUL terminator. | |||||
*/ | |||||
uint16_t name_size GNUNET_PACKED; | |||||
/** | |||||
* OR'd StateOpFlags | |||||
*/ | |||||
uint8_t flags; | |||||
uint8_t reserved; | |||||
/** | |||||
* Operation ID. | |||||
*/ | |||||
uint64_t op_id GNUNET_PACKED; | |||||
/** | |||||
* ID of the message that contains the state_hash PSYC header variable. | |||||
*/ | |||||
uint64_t state_hash_message_id GNUNET_PACKED; | |||||
/** | |||||
* ID of the last stateful message before @a state_hash_message_id. | |||||
*/ | |||||
uint64_t max_state_message_id GNUNET_PACKED; | |||||
/** | |||||
* Channel's public key. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | |||||
/* Followed by NUL-terminated name, then the value. */ | |||||
}; | |||||
GNUNET_NETWORK_STRUCT_END | |||||
#endif |
@@ -0,0 +1,532 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* @author Christian Grothoff | |||||
* | |||||
* @file | |||||
* Test for the PSYCstore plugins. | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testing_lib.h" | |||||
#include "gnunet_psycstore_plugin.h" | |||||
#include "gnunet_psycstore_service.h" | |||||
#include "gnunet_multicast_service.h" | |||||
#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING | |||||
#if DEBUG_PSYCSTORE | |||||
# define LOG_LEVEL "DEBUG" | |||||
#else | |||||
# define LOG_LEVEL "WARNING" | |||||
#endif | |||||
#define C2ARG(str) str, (sizeof (str) - 1) | |||||
#define LOG(kind,...) \ | |||||
GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__) | |||||
static int ok; | |||||
/** | |||||
* Name of plugin under test. | |||||
*/ | |||||
static const char *plugin_name; | |||||
static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | |||||
static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | |||||
/** | |||||
* Function called when the service shuts down. Unloads our psycstore | |||||
* plugin. | |||||
* | |||||
* @param api api to unload | |||||
*/ | |||||
static void | |||||
unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api) | |||||
{ | |||||
char *libname; | |||||
GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); | |||||
GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); | |||||
GNUNET_free (libname); | |||||
} | |||||
/** | |||||
* Load the psycstore plugin. | |||||
* | |||||
* @param cfg configuration to pass | |||||
* @return NULL on error | |||||
*/ | |||||
static struct GNUNET_PSYCSTORE_PluginFunctions * | |||||
load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct GNUNET_PSYCSTORE_PluginFunctions *ret; | |||||
char *libname; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"), | |||||
plugin_name); | |||||
GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); | |||||
if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) | |||||
{ | |||||
FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); | |||||
return NULL; | |||||
} | |||||
GNUNET_free (libname); | |||||
return ret; | |||||
} | |||||
#define MAX_MSG 16 | |||||
struct FragmentClosure | |||||
{ | |||||
uint8_t n; | |||||
uint64_t flags[MAX_MSG]; | |||||
struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG]; | |||||
}; | |||||
static int | |||||
fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2, | |||||
enum GNUNET_PSYCSTORE_MessageFlags flags) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
struct GNUNET_MULTICAST_MessageHeader *msg1; | |||||
uint64_t flags1; | |||||
int ret; | |||||
if (fcls->n >= MAX_MSG) | |||||
{ | |||||
GNUNET_break (0); | |||||
return GNUNET_SYSERR; | |||||
} | |||||
msg1 = fcls->msg[fcls->n]; | |||||
flags1 = fcls->flags[fcls->n++]; | |||||
if (NULL == msg1) | |||||
{ | |||||
GNUNET_break (0); | |||||
return GNUNET_SYSERR; | |||||
} | |||||
if (flags1 == flags && msg1->header.size == msg2->header.size | |||||
&& 0 == memcmp (msg1, msg2, ntohs (msg1->header.size))) | |||||
{ | |||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n", | |||||
GNUNET_ntohll (msg1->fragment_id)); | |||||
ret = GNUNET_YES; | |||||
} | |||||
else | |||||
{ | |||||
LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n", | |||||
GNUNET_ntohll (msg1->fragment_id)); | |||||
ret = GNUNET_SYSERR; | |||||
} | |||||
GNUNET_free (msg2); | |||||
return ret; | |||||
} | |||||
struct StateClosure { | |||||
size_t n; | |||||
char *name[16]; | |||||
void *value[16]; | |||||
size_t value_size[16]; | |||||
}; | |||||
static int | |||||
state_cb (void *cls, const char *name, const void *value, uint32_t value_size) | |||||
{ | |||||
struct StateClosure *scls = cls; | |||||
const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST! | |||||
size_t val_size = scls->value_size[scls->n++]; | |||||
/* FIXME: check name */ | |||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | |||||
" name = %s, value_size = %u\n", | |||||
name, value_size); | |||||
return GNUNET_YES; | |||||
return value_size == val_size && 0 == memcmp (value, val, val_size) | |||||
? GNUNET_YES | |||||
: GNUNET_SYSERR; | |||||
} | |||||
static void | |||||
run (void *cls, char *const *args, const char *cfgfile, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
{ | |||||
struct GNUNET_PSYCSTORE_PluginFunctions *db; | |||||
ok = 1; | |||||
db = load_plugin (cfg); | |||||
if (NULL == db) | |||||
{ | |||||
FPRINTF (stderr, | |||||
"%s", | |||||
"Failed to initialize PSYCstore. " | |||||
"Database likely not setup, skipping test.\n"); | |||||
ok = 77; | |||||
return; | |||||
} | |||||
/* Store & test membership */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n"); | |||||
channel_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (channel_key, | |||||
&channel_pub_key); | |||||
GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n"); | |||||
GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key, | |||||
&slave_pub_key, GNUNET_YES, | |||||
4, 2, 1)); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n"); | |||||
GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, | |||||
&slave_pub_key, 4)); | |||||
GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, | |||||
&slave_pub_key, 2)); | |||||
GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key, | |||||
&slave_pub_key, 1)); | |||||
/* Store & get messages */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n"); | |||||
struct GNUNET_MULTICAST_MessageHeader *msg | |||||
= GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
GNUNET_assert (msg != NULL); | |||||
msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | |||||
msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
uint64_t fragment_id = INT64_MAX - 1; | |||||
msg->fragment_id = GNUNET_htonll (fragment_id); | |||||
uint64_t message_id = INT64_MAX - 10; | |||||
msg->message_id = GNUNET_htonll (message_id); | |||||
uint64_t group_generation = INT64_MAX - 3; | |||||
msg->group_generation = GNUNET_htonll (group_generation); | |||||
msg->hop_counter = htonl (9); | |||||
msg->fragment_offset = GNUNET_htonll (0); | |||||
msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); | |||||
GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); | |||||
msg->purpose.size = htonl (ntohs (msg->header.size) | |||||
- sizeof (msg->header) | |||||
- sizeof (msg->hop_counter) | |||||
- sizeof (msg->signature)); | |||||
msg->purpose.purpose = htonl (234); | |||||
GNUNET_assert (GNUNET_OK == | |||||
GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature)); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); | |||||
struct FragmentClosure fcls = { 0 }; | |||||
fcls.n = 0; | |||||
fcls.msg[0] = msg; | |||||
fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg, | |||||
fcls.flags[0])); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); | |||||
uint64_t ret_frags = 0; | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, | |||||
fragment_id, fragment_id, | |||||
&ret_frags, fragment_cb, &fcls)); | |||||
GNUNET_assert (fcls.n == 1); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n"); | |||||
fcls.n = 0; | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key, | |||||
GNUNET_ntohll (msg->message_id), | |||||
GNUNET_ntohll (msg->fragment_offset), | |||||
fragment_cb, &fcls)); | |||||
GNUNET_assert (fcls.n == 1); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n"); | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key, | |||||
GNUNET_ntohll (msg->message_id), | |||||
GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED)); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); | |||||
fcls.n = 0; | |||||
fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, | |||||
fragment_id, fragment_id, | |||||
&ret_frags, fragment_cb, &fcls)); | |||||
GNUNET_assert (fcls.n == 1); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); | |||||
struct GNUNET_MULTICAST_MessageHeader *msg1 | |||||
= GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key)); | |||||
GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key)); | |||||
msg1->fragment_id = GNUNET_htonll (INT64_MAX); | |||||
msg1->fragment_offset = GNUNET_htonll (32768); | |||||
fcls.n = 0; | |||||
fcls.msg[1] = msg1; | |||||
fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; | |||||
GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1, | |||||
fcls.flags[1])); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n"); | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->message_get (db->cls, &channel_pub_key, | |||||
message_id, message_id, 0, | |||||
&ret_frags, fragment_cb, &fcls)); | |||||
GNUNET_assert (fcls.n == 2 && ret_frags == 2); | |||||
/* Message counters */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n"); | |||||
fragment_id = 0; | |||||
message_id = 0; | |||||
group_generation = 0; | |||||
GNUNET_assert ( | |||||
GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key, | |||||
&fragment_id, &message_id, | |||||
&group_generation) | |||||
&& fragment_id == GNUNET_ntohll (msg1->fragment_id) | |||||
&& message_id == GNUNET_ntohll (msg1->message_id) | |||||
&& group_generation == GNUNET_ntohll (msg1->group_generation)); | |||||
/* Modify state */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n"); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); | |||||
message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1; | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, | |||||
message_id, 0)); | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | |||||
GNUNET_PSYC_OP_ASSIGN, | |||||
"_foo", | |||||
C2ARG("one two three"))); | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | |||||
GNUNET_PSYC_OP_ASSIGN, | |||||
"_foo_bar", slave_key, | |||||
sizeof (*slave_key))); | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, | |||||
message_id)); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n"); | |||||
struct StateClosure scls = { 0 }; | |||||
scls.n = 0; | |||||
scls.value[0] = "one two three"; | |||||
scls.value_size[0] = strlen ("one two three"); | |||||
GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo", | |||||
state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 1); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n"); | |||||
scls.n = 0; | |||||
scls.value[1] = slave_key; | |||||
scls.value_size[1] = sizeof (*slave_key); | |||||
GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, | |||||
"_foo", state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 2); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); | |||||
scls.n = 0; | |||||
GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key, | |||||
state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 0); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n"); | |||||
GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls, | |||||
&channel_pub_key)); | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); | |||||
scls.n = 0; | |||||
GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key, | |||||
state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 2); | |||||
/* State counters */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n"); | |||||
uint64_t max_state_msg_id = 0; | |||||
GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key, | |||||
&max_state_msg_id) | |||||
&& max_state_msg_id == message_id); | |||||
/* State sync */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n"); | |||||
scls.n = 0; | |||||
scls.value[0] = channel_key; | |||||
scls.value_size[0] = sizeof (*channel_key); | |||||
scls.value[1] = "three two one"; | |||||
scls.value_size[1] = strlen ("three two one"); | |||||
GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key)); | |||||
GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, | |||||
"_sync_bar", scls.value[0], | |||||
scls.value_size[0])); | |||||
GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, | |||||
"_sync_foo", scls.value[1], | |||||
scls.value_size[1])); | |||||
GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key, | |||||
max_state_msg_id, | |||||
INT64_MAX - 5)); | |||||
GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key, | |||||
"_foo", state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 0); | |||||
GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, | |||||
"_sync", state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 2); | |||||
scls.n = 0; | |||||
GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key, | |||||
state_cb, &scls)); | |||||
GNUNET_assert (scls.n == 2); | |||||
/* Modify state after sync */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); | |||||
message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6; | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, | |||||
message_id, | |||||
message_id - max_state_msg_id)); | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | |||||
GNUNET_PSYC_OP_ASSIGN, | |||||
"_sync_foo", | |||||
C2ARG("five six seven"))); | |||||
GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, | |||||
message_id)); | |||||
/* Reset state */ | |||||
LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n"); | |||||
scls.n = 0; | |||||
GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key)); | |||||
GNUNET_assert (scls.n == 0); | |||||
ok = 0; | |||||
if (NULL != channel_key) | |||||
{ | |||||
GNUNET_free (channel_key); | |||||
channel_key = NULL; | |||||
} | |||||
if (NULL != slave_key) | |||||
{ | |||||
GNUNET_free (slave_key); | |||||
slave_key = NULL; | |||||
} | |||||
unload_plugin (db); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
char cfg_name[128]; | |||||
char *const xargv[] = { | |||||
"test-plugin-psycstore", | |||||
"-c", cfg_name, | |||||
"-L", LOG_LEVEL, | |||||
NULL | |||||
}; | |||||
struct GNUNET_GETOPT_CommandLineOption options[] = { | |||||
GNUNET_GETOPT_OPTION_END | |||||
}; | |||||
GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); | |||||
GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL); | |||||
plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); | |||||
GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf", | |||||
plugin_name); | |||||
GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, | |||||
"test-plugin-psycstore", "nohelp", options, &run, NULL); | |||||
if ( (0 != ok) && | |||||
(77 != ok) ) | |||||
FPRINTF (stderr, "Missed some testcases: %d\n", ok); | |||||
#if ! DEBUG_PSYCSTORE | |||||
GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); | |||||
#endif | |||||
return ok; | |||||
} | |||||
/* end of test_plugin_psycstore.c */ |
@@ -0,0 +1,7 @@ | |||||
[psycstore-mysql] | |||||
DATABASE = test | |||||
# CONFIG = ~/.my.cnf | |||||
# USER = gnunet | |||||
# PASSWORD = | |||||
# HOST = localhost | |||||
# PORT = 3306 |
@@ -0,0 +1,2 @@ | |||||
[psycstore-postgres] | |||||
CONFIG = connect_timeout=10; dbname=template1 |
@@ -0,0 +1,2 @@ | |||||
[psycstore-sqlite] | |||||
FILENAME = $GNUNET_TMP/gnunet-test-plugin-psycstore-sqlite/sqlite.db |
@@ -0,0 +1,586 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @file psycstore/test_psycstore.c | |||||
* @brief Test for the PSYCstore service. | |||||
* @author Gabor X Toth | |||||
* @author Christian Grothoff | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_common.h" | |||||
#include "gnunet_testing_lib.h" | |||||
#include "gnunet_psycstore_service.h" | |||||
#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | |||||
/** | |||||
* Return value from 'main'. | |||||
*/ | |||||
static int res; | |||||
/** | |||||
* Handle to PSYCstore service. | |||||
*/ | |||||
static struct GNUNET_PSYCSTORE_Handle *h; | |||||
/** | |||||
* Handle to PSYCstore operation. | |||||
*/ | |||||
static struct GNUNET_PSYCSTORE_OperationHandle *op; | |||||
/** | |||||
* Handle for task for timeout termination. | |||||
*/ | |||||
static struct GNUNET_SCHEDULER_Task *end_badly_task; | |||||
static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | |||||
static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | |||||
static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | |||||
static struct FragmentClosure | |||||
{ | |||||
uint8_t n; | |||||
uint8_t n_expected; | |||||
uint64_t flags[16]; | |||||
struct GNUNET_MULTICAST_MessageHeader *msg[16]; | |||||
} fcls; | |||||
struct StateClosure { | |||||
size_t n; | |||||
char *name[16]; | |||||
void *value[16]; | |||||
size_t value_size[16]; | |||||
} scls; | |||||
static struct GNUNET_PSYC_Modifier modifiers[16]; | |||||
/** | |||||
* Clean up all resources used. | |||||
*/ | |||||
static void | |||||
cleanup () | |||||
{ | |||||
if (NULL != op) | |||||
{ | |||||
GNUNET_PSYCSTORE_operation_cancel (op); | |||||
op = NULL; | |||||
} | |||||
if (NULL != h) | |||||
{ | |||||
GNUNET_PSYCSTORE_disconnect (h); | |||||
h = NULL; | |||||
} | |||||
if (NULL != channel_key) | |||||
{ | |||||
GNUNET_free (channel_key); | |||||
channel_key = NULL; | |||||
} | |||||
if (NULL != slave_key) | |||||
{ | |||||
GNUNET_free (slave_key); | |||||
slave_key = NULL; | |||||
} | |||||
GNUNET_SCHEDULER_shutdown (); | |||||
} | |||||
/** | |||||
* Terminate the testcase (failure). | |||||
* | |||||
* @param cls NULL | |||||
*/ | |||||
static void | |||||
end_badly (void *cls) | |||||
{ | |||||
res = 1; | |||||
cleanup (); | |||||
} | |||||
/** | |||||
* Terminate the testcase (success). | |||||
* | |||||
* @param cls NULL | |||||
*/ | |||||
static void | |||||
end_normally (void *cls) | |||||
{ | |||||
res = 0; | |||||
cleanup (); | |||||
} | |||||
/** | |||||
* Finish the testcase (successfully). | |||||
*/ | |||||
static void | |||||
end () | |||||
{ | |||||
if (NULL != end_badly_task) | |||||
{ | |||||
GNUNET_SCHEDULER_cancel (end_badly_task); | |||||
end_badly_task = NULL; | |||||
} | |||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | |||||
&end_normally, NULL); | |||||
} | |||||
static void | |||||
state_reset_result (void *cls, | |||||
int64_t result, | |||||
const char *err_msg, | |||||
uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | |||||
"state_reset_result:\t%d\n", | |||||
(int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, | |||||
&state_reset_result, cls); | |||||
GNUNET_PSYCSTORE_operation_cancel (op); | |||||
op = NULL; | |||||
end (); | |||||
} | |||||
static int | |||||
state_result (void *cls, | |||||
const char *name, | |||||
const void *value, | |||||
uint32_t value_size) | |||||
{ | |||||
struct StateClosure *scls = cls; | |||||
const char *nam = scls->name[scls->n]; | |||||
const void *val = scls->value[scls->n]; | |||||
size_t val_size = scls->value_size[scls->n++]; | |||||
if (value_size == val_size | |||||
&& 0 == memcmp (value, val, val_size) | |||||
&& 0 == strcmp (name, nam)) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |||||
" variable %s matches\n", | |||||
name); | |||||
return GNUNET_YES; | |||||
} | |||||
else | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
" variable %s differs\nReceived: %.*s\nExpected: %.*s\n", | |||||
name, (int) value_size, (char*) value, (int) val_size, (char*) val); | |||||
GNUNET_assert (0); | |||||
return GNUNET_SYSERR; | |||||
} | |||||
} | |||||
static void | |||||
state_get_prefix_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct StateClosure *scls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_prefix_result:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result && 2 == scls->n); | |||||
op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, | |||||
&state_reset_result, cls); | |||||
} | |||||
static void | |||||
state_get_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_result:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
scls.n = 0; | |||||
scls.name[0] = "_sync_bar"; | |||||
scls.value[0] = "ten eleven twelve"; | |||||
scls.value_size[0] = sizeof ("ten eleven twelve") - 1; | |||||
scls.name[1] = "_sync_foo"; | |||||
scls.value[1] = "three two one"; | |||||
scls.value_size[1] = sizeof ("three two one") - 1; | |||||
op = GNUNET_PSYCSTORE_state_get_prefix (h, &channel_pub_key, "_sync", | |||||
&state_result, | |||||
&state_get_prefix_result, &scls); | |||||
} | |||||
static void | |||||
counters_result (void *cls, int status, uint64_t max_fragment_id, | |||||
uint64_t max_message_id, uint64_t max_group_generation, | |||||
uint64_t max_state_message_id) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
int result = 0; | |||||
op = NULL; | |||||
if (GNUNET_OK == status | |||||
&& max_fragment_id == GNUNET_ntohll (fcls->msg[2]->fragment_id) | |||||
&& max_message_id == GNUNET_ntohll (fcls->msg[2]->message_id) | |||||
&& max_group_generation == GNUNET_ntohll (fcls->msg[2]->group_generation) | |||||
&& max_state_message_id == GNUNET_ntohll (fcls->msg[0]->message_id)) | |||||
result = 1; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "counters_get:\t%d\n", result); | |||||
GNUNET_assert (result == 1); | |||||
scls.n = 0; | |||||
scls.name[0] = "_sync_bar"; | |||||
scls.value[0] = "ten eleven twelve"; | |||||
scls.value_size[0] = sizeof ("ten eleven twelve") - 1; | |||||
op = GNUNET_PSYCSTORE_state_get (h, &channel_pub_key, "_sync_bar_x_yy_zzz", | |||||
&state_result, &state_get_result, &scls); | |||||
} | |||||
static void | |||||
state_modify_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_modify_result:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
op = GNUNET_PSYCSTORE_counters_get (h, &channel_pub_key, | |||||
&counters_result, cls); | |||||
} | |||||
static void | |||||
state_sync_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_sync_result:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
op = GNUNET_PSYCSTORE_state_modify (h, &channel_pub_key, | |||||
GNUNET_ntohll (fcls->msg[0]->message_id), | |||||
0, state_modify_result, fcls); | |||||
} | |||||
static int | |||||
fragment_result (void *cls, | |||||
struct GNUNET_MULTICAST_MessageHeader *msg, | |||||
enum GNUNET_PSYCSTORE_MessageFlags flags) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
GNUNET_assert (fcls->n < fcls->n_expected); | |||||
struct GNUNET_MULTICAST_MessageHeader *msg0 = fcls->msg[fcls->n]; | |||||
uint64_t flags0 = fcls->flags[fcls->n++]; | |||||
if (flags == flags0 && msg->header.size == msg0->header.size | |||||
&& 0 == memcmp (msg, msg0, ntohs (msg->header.size))) | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " fragment %" PRIu64 " matches\n", | |||||
GNUNET_ntohll (msg->fragment_id)); | |||||
return GNUNET_YES; | |||||
} | |||||
else | |||||
{ | |||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |||||
" fragment differs: expected %" PRIu64 ", got %" PRIu64 "\n", | |||||
GNUNET_ntohll (msg0->fragment_id), | |||||
GNUNET_ntohll (msg->fragment_id)); | |||||
GNUNET_assert (0); | |||||
return GNUNET_SYSERR; | |||||
} | |||||
} | |||||
static void | |||||
message_get_latest_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_latest:\t%ld\n", (long int) result); | |||||
GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | |||||
modifiers[0] = (struct GNUNET_PSYC_Modifier) { | |||||
.oper = '=', | |||||
.name = "_sync_foo", | |||||
.value = "three two one", | |||||
.value_size = sizeof ("three two one") - 1 | |||||
}; | |||||
modifiers[1] = (struct GNUNET_PSYC_Modifier) { | |||||
.oper = '=', | |||||
.name = "_sync_bar", | |||||
.value = "ten eleven twelve", | |||||
.value_size = sizeof ("ten eleven twelve") - 1 | |||||
}; | |||||
op = GNUNET_PSYCSTORE_state_sync (h, &channel_pub_key, | |||||
GNUNET_ntohll (fcls->msg[0]->message_id) + 1, | |||||
GNUNET_ntohll (fcls->msg[0]->message_id) + 2, | |||||
2, modifiers, state_sync_result, fcls); | |||||
} | |||||
static void | |||||
message_get_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get:\t%ld\n", (long int) result); | |||||
GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | |||||
fcls->n = 0; | |||||
fcls->n_expected = 3; | |||||
op = GNUNET_PSYCSTORE_message_get_latest (h, &channel_pub_key, &slave_pub_key, | |||||
1, "", &fragment_result, | |||||
&message_get_latest_result, fcls); | |||||
} | |||||
static void | |||||
message_get_fragment_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_fragment:\t%ld\n", (long int) result); | |||||
GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | |||||
fcls->n = 0; | |||||
fcls->n_expected = 3; | |||||
uint64_t message_id = GNUNET_ntohll (fcls->msg[0]->message_id); | |||||
op = GNUNET_PSYCSTORE_message_get (h, &channel_pub_key, &slave_pub_key, | |||||
message_id, message_id, 0, "", | |||||
&fragment_result, | |||||
&message_get_result, fcls); | |||||
} | |||||
static void | |||||
fragment_get_latest_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_get_latest:\t%ld\n", (long int) result); | |||||
GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | |||||
fcls->n = 1; | |||||
fcls->n_expected = 2; | |||||
op = GNUNET_PSYCSTORE_message_get_fragment (h, &channel_pub_key, &slave_pub_key, | |||||
GNUNET_ntohll (fcls->msg[1]->message_id), | |||||
GNUNET_ntohll (fcls->msg[1]->fragment_offset), | |||||
&fragment_result, | |||||
&message_get_fragment_result, fcls); | |||||
} | |||||
static void | |||||
fragment_get_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
struct FragmentClosure *fcls = cls; | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | |||||
"fragment_get:\t%d\n", | |||||
(int) result); | |||||
GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | |||||
fcls->n = 0; | |||||
fcls->n_expected = 3; | |||||
op = GNUNET_PSYCSTORE_fragment_get_latest (h, &channel_pub_key, | |||||
&slave_pub_key, fcls->n_expected, | |||||
&fragment_result, | |||||
&fragment_get_latest_result, fcls); | |||||
} | |||||
static void | |||||
fragment_store_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_store:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
if ((intptr_t) cls == GNUNET_YES) | |||||
{ /* last fragment */ | |||||
fcls.n = 0; | |||||
fcls.n_expected = 1; | |||||
uint64_t fragment_id = GNUNET_ntohll (fcls.msg[0]->fragment_id); | |||||
op = GNUNET_PSYCSTORE_fragment_get (h, &channel_pub_key, &slave_pub_key, | |||||
fragment_id, fragment_id, | |||||
&fragment_result, | |||||
&fragment_get_result, &fcls); | |||||
} | |||||
} | |||||
static void | |||||
fragment_store () | |||||
{ | |||||
struct GNUNET_MULTICAST_MessageHeader *msg; | |||||
fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; | |||||
fcls.msg[0] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
GNUNET_assert (msg != NULL); | |||||
msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | |||||
msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
msg->hop_counter = htonl (9); | |||||
msg->fragment_id = GNUNET_htonll (INT64_MAX - 8); | |||||
msg->fragment_offset = GNUNET_htonll (0); | |||||
msg->message_id = GNUNET_htonll (INT64_MAX - 10); | |||||
msg->group_generation = GNUNET_htonll (INT64_MAX - 3); | |||||
msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); | |||||
GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); | |||||
msg->purpose.size = htonl (ntohs (msg->header.size) | |||||
- sizeof (msg->header) | |||||
- sizeof (msg->hop_counter) | |||||
- sizeof (msg->signature)); | |||||
msg->purpose.purpose = htonl (234); | |||||
GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, | |||||
&msg->signature)); | |||||
op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[0], | |||||
&fragment_store_result, GNUNET_NO); | |||||
fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; | |||||
fcls.msg[1] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
GNUNET_memcpy (msg, fcls.msg[0], sizeof (*msg) + sizeof (channel_pub_key)); | |||||
msg->fragment_id = GNUNET_htonll (INT64_MAX - 4); | |||||
msg->fragment_offset = GNUNET_htonll (1024); | |||||
op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[1], | |||||
&fragment_store_result, GNUNET_NO); | |||||
fcls.flags[2] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; | |||||
fcls.msg[2] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | |||||
GNUNET_memcpy (msg, fcls.msg[1], sizeof (*msg) + sizeof (channel_pub_key)); | |||||
msg->fragment_id = GNUNET_htonll (INT64_MAX); | |||||
msg->fragment_offset = GNUNET_htonll (16384); | |||||
op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[2], | |||||
&fragment_store_result, (void *) GNUNET_YES); | |||||
} | |||||
static void | |||||
membership_test_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_test:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
fragment_store (); | |||||
} | |||||
static void | |||||
membership_store_result (void *cls, int64_t result, | |||||
const char *err_msg, uint16_t err_msg_size) | |||||
{ | |||||
op = NULL; | |||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_store:\t%ld\n", (long int) result); | |||||
GNUNET_assert (GNUNET_OK == result); | |||||
op = GNUNET_PSYCSTORE_membership_test (h, &channel_pub_key, &slave_pub_key, | |||||
INT64_MAX - 10, 2, | |||||
&membership_test_result, NULL); | |||||
} | |||||
/** | |||||
* Main function of the test, run from scheduler. | |||||
* | |||||
* @param cls NULL | |||||
* @param cfg configuration we use (also to connect to PSYCstore service) | |||||
* @param peer handle to access more of the peer (not used) | |||||
*/ | |||||
static void | |||||
#if DEBUG_TEST_PSYCSTORE | |||||
run (void *cls, char *const *args, const char *cfgfile, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg) | |||||
#else | |||||
run (void *cls, | |||||
const struct GNUNET_CONFIGURATION_Handle *cfg, | |||||
struct GNUNET_TESTING_Peer *peer) | |||||
#endif | |||||
{ | |||||
end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); | |||||
h = GNUNET_PSYCSTORE_connect (cfg); | |||||
GNUNET_assert (NULL != h); | |||||
channel_key = GNUNET_CRYPTO_eddsa_key_create (); | |||||
slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | |||||
GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); | |||||
GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | |||||
op = GNUNET_PSYCSTORE_membership_store (h, &channel_pub_key, &slave_pub_key, | |||||
GNUNET_YES, INT64_MAX - 5, | |||||
INT64_MAX - 10, 2, | |||||
&membership_store_result, NULL); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
res = 1; | |||||
#if DEBUG_TEST_PSYCSTORE | |||||
const struct GNUNET_GETOPT_CommandLineOption opts[] = { | |||||
GNUNET_GETOPT_OPTION_END | |||||
}; | |||||
if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psycstore", | |||||
"test-psycstore [options]", | |||||
opts, &run, NULL)) | |||||
return 1; | |||||
#else | |||||
if (0 != GNUNET_TESTING_service_run ("test-psycstore", "psycstore", | |||||
"test_psycstore.conf", &run, NULL)) | |||||
return 1; | |||||
#endif | |||||
return res; | |||||
} | |||||
/* end of test_psycstore.c */ |
@@ -0,0 +1,8 @@ | |||||
[PATHS] | |||||
GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-psycstore/ | |||||
[psycstore] | |||||
DATABASE = sqlite | |||||
[psycstore-sqlite] | |||||
FILENAME = $GNUNET_TEST_HOME/psycstore/sqlite.db |
@@ -0,0 +1 @@ | |||||
test_psyc_env |
@@ -0,0 +1,45 @@ | |||||
# This Makefile.am is in the public domain | |||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include | |||||
pkgcfgdir= $(pkgdatadir)/config.d/ | |||||
libexecdir= $(pkglibdir)/libexec/ | |||||
if MINGW | |||||
WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | |||||
endif | |||||
if USE_COVERAGE | |||||
AM_CFLAGS = --coverage -O0 | |||||
XLIB = -lgcov | |||||
endif | |||||
lib_LTLIBRARIES = libgnunetpsycutil.la | |||||
libgnunetpsycutil_la_SOURCES = \ | |||||
psyc_env.c \ | |||||
psyc_message.c \ | |||||
psyc_slicer.c | |||||
libgnunetpsycutil_la_LIBADD = \ | |||||
$(top_builddir)/src/util/libgnunetutil.la \ | |||||
$(GN_LIBINTL) $(XLIB) | |||||
libgnunetpsycutil_la_LDFLAGS = \ | |||||
$(GN_LIB_LDFLAGS) $(WINFLAGS) \ | |||||
-version-info 0:0:0 | |||||
if HAVE_TESTING | |||||
check_PROGRAMS = \ | |||||
test_psyc_env | |||||
endif | |||||
if ENABLE_TEST_RUN | |||||
AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | |||||
TESTS = $(check_PROGRAMS) | |||||
endif | |||||
test_psyc_env_SOURCES = \ | |||||
test_psyc_env.c | |||||
test_psyc_env_LDADD = \ | |||||
libgnunetpsycutil.la \ | |||||
$(top_builddir)/src/testing/libgnunettesting.la \ | |||||
$(top_builddir)/src/util/libgnunetutil.la |
@@ -0,0 +1,196 @@ | |||||
/* | |||||
* This file is part of GNUnet. | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* Library providing operations for the @e environment of | |||||
* PSYC and Social messages. | |||||
*/ | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_psyc_env.h" | |||||
/** | |||||
* Environment for a message. | |||||
* | |||||
* Contains modifiers. | |||||
*/ | |||||
struct GNUNET_PSYC_Environment | |||||
{ | |||||
struct GNUNET_PSYC_Modifier *mod_head; | |||||
struct GNUNET_PSYC_Modifier *mod_tail; | |||||
size_t mod_count; | |||||
}; | |||||
/** | |||||
* Create an environment. | |||||
* | |||||
* @return A newly allocated environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Environment * | |||||
GNUNET_PSYC_env_create () | |||||
{ | |||||
return GNUNET_new (struct GNUNET_PSYC_Environment); | |||||
} | |||||
/** | |||||
* Add a modifier to the environment. | |||||
* | |||||
* @param env The environment. | |||||
* @param oper Operation to perform. | |||||
* @param name Name of the variable. | |||||
* @param value Value of the variable. | |||||
* @param value_size Size of @a value. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, | |||||
enum GNUNET_PSYC_Operator oper, const char *name, | |||||
const void *value, size_t value_size) | |||||
{ | |||||
struct GNUNET_PSYC_Modifier *mod = GNUNET_new (struct GNUNET_PSYC_Modifier); | |||||
mod->oper = oper; | |||||
mod->name = name; | |||||
mod->value = value; | |||||
mod->value_size = value_size; | |||||
GNUNET_CONTAINER_DLL_insert_tail (env->mod_head, env->mod_tail, mod); | |||||
env->mod_count++; | |||||
} | |||||
/** | |||||
* Get the first modifier of the environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier * | |||||
GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env) | |||||
{ | |||||
return env->mod_head; | |||||
} | |||||
/** | |||||
* Get the last modifier of the environment. | |||||
*/ | |||||
struct GNUNET_PSYC_Modifier * | |||||
GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env) | |||||
{ | |||||
return env->mod_tail; | |||||
} | |||||
/** | |||||
* Remove a modifier from the environment. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, | |||||
struct GNUNET_PSYC_Modifier *mod) | |||||
{ | |||||
GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); | |||||
} | |||||
/** | |||||
* Get the modifier at the beginning of an environment and remove it. | |||||
* | |||||
* @param env | |||||
* @param oper | |||||
* @param name | |||||
* @param value | |||||
* @param value_size | |||||
* | |||||
* @return | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, | |||||
enum GNUNET_PSYC_Operator *oper, const char **name, | |||||
const void **value, size_t *value_size) | |||||
{ | |||||
if (NULL == env->mod_head) | |||||
return GNUNET_NO; | |||||
struct GNUNET_PSYC_Modifier *mod = env->mod_head; | |||||
*oper = mod->oper; | |||||
*name = mod->name; | |||||
*value = mod->value; | |||||
*value_size = mod->value_size; | |||||
GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); | |||||
GNUNET_free (mod); | |||||
env->mod_count--; | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Iterate through all modifiers in the environment. | |||||
* | |||||
* @param env The environment. | |||||
* @param it Iterator. | |||||
* @param it_cls Closure for iterator. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, | |||||
GNUNET_PSYC_Iterator it, void *it_cls) | |||||
{ | |||||
struct GNUNET_PSYC_Modifier *mod; | |||||
for (mod = env->mod_head; NULL != mod; mod = mod->next) | |||||
it (it_cls, mod->oper, mod->name, mod->value, mod->value_size); | |||||
} | |||||
/** | |||||
* Get the number of modifiers in the environment. | |||||
* | |||||
* @param env The environment. | |||||
* | |||||
* @return Number of modifiers. | |||||
*/ | |||||
size_t | |||||
GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env) | |||||
{ | |||||
return env->mod_count; | |||||
} | |||||
/** | |||||
* Destroy an environment. | |||||
* | |||||
* @param env The environment to destroy. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env) | |||||
{ | |||||
struct GNUNET_PSYC_Modifier *mod, *prev = NULL; | |||||
for (mod = env->mod_head; NULL != mod; mod = mod->next) | |||||
{ | |||||
if (NULL != prev) | |||||
GNUNET_free (prev); | |||||
prev = mod; | |||||
} | |||||
if (NULL != prev) | |||||
GNUNET_free (prev); | |||||
GNUNET_free (env); | |||||
} |
@@ -0,0 +1,711 @@ | |||||
/* | |||||
* This file is part of GNUnet | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* PSYC Slicer API | |||||
*/ | |||||
#include <inttypes.h> | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
#define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__) | |||||
/** | |||||
* Handle for a try-and-slice instance. | |||||
*/ | |||||
struct GNUNET_PSYC_Slicer | |||||
{ | |||||
/** | |||||
* Method handlers: H(method_name) -> SlicerMethodCallbacks | |||||
*/ | |||||
struct GNUNET_CONTAINER_MultiHashMap *method_handlers; | |||||
/** | |||||
* Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks | |||||
*/ | |||||
struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers; | |||||
/** | |||||
* Receive handle for incoming messages. | |||||
*/ | |||||
struct GNUNET_PSYC_ReceiveHandle *recv; | |||||
/** | |||||
* Currently being processed message. | |||||
*/ | |||||
const struct GNUNET_PSYC_MessageHeader *msg; | |||||
/** | |||||
* Currently being processed message part. | |||||
*/ | |||||
const struct GNUNET_MessageHeader *pmsg; | |||||
/** | |||||
* ID of currently being received message. | |||||
*/ | |||||
uint64_t message_id; | |||||
/** | |||||
* Fragment offset of currently being received message. | |||||
*/ | |||||
uint64_t fragment_offset; | |||||
/** | |||||
* Flags of currently being received message. | |||||
*/ | |||||
uint32_t flags; | |||||
/** | |||||
* Method name of currently being received message. | |||||
*/ | |||||
char *method_name; | |||||
/** | |||||
* Name of currently processed modifier. | |||||
*/ | |||||
char *mod_name; | |||||
/** | |||||
* Value of currently processed modifier. | |||||
*/ | |||||
char *mod_value; | |||||
/** | |||||
* Public key of the nym the current message originates from. | |||||
*/ | |||||
struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; | |||||
/** | |||||
* Size of @a method_name (including terminating \0). | |||||
*/ | |||||
uint16_t method_name_size; | |||||
/** | |||||
* Size of @a modifier_name (including terminating \0). | |||||
*/ | |||||
uint16_t mod_name_size; | |||||
/** | |||||
* Size of modifier value fragment. | |||||
*/ | |||||
uint16_t mod_value_size; | |||||
/** | |||||
* Full size of modifier value. | |||||
*/ | |||||
uint16_t mod_full_value_size; | |||||
/** | |||||
* Remaining bytes from the value of the current modifier. | |||||
*/ | |||||
uint16_t mod_value_remaining; | |||||
/** | |||||
* Operator of currently processed modifier. | |||||
*/ | |||||
uint8_t mod_oper; | |||||
}; | |||||
/** | |||||
* Callbacks for a slicer method handler. | |||||
*/ | |||||
struct SlicerMethodCallbacks | |||||
{ | |||||
GNUNET_PSYC_MessageCallback msg_cb; | |||||
GNUNET_PSYC_MethodCallback method_cb; | |||||
GNUNET_PSYC_ModifierCallback modifier_cb; | |||||
GNUNET_PSYC_DataCallback data_cb; | |||||
GNUNET_PSYC_EndOfMessageCallback eom_cb; | |||||
void *cls; | |||||
}; | |||||
struct SlicerMethodRemoveClosure | |||||
{ | |||||
struct GNUNET_PSYC_Slicer *slicer; | |||||
struct SlicerMethodCallbacks rm_cbs; | |||||
}; | |||||
/** | |||||
* Callbacks for a slicer method handler. | |||||
*/ | |||||
struct SlicerModifierCallbacks | |||||
{ | |||||
GNUNET_PSYC_ModifierCallback modifier_cb; | |||||
void *cls; | |||||
}; | |||||
struct SlicerModifierRemoveClosure | |||||
{ | |||||
struct GNUNET_PSYC_Slicer *slicer; | |||||
struct SlicerModifierCallbacks rm_cbs; | |||||
}; | |||||
/** | |||||
* Call a method handler for an incoming message part. | |||||
*/ | |||||
static int | |||||
slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key, | |||||
void *value) | |||||
{ | |||||
struct GNUNET_PSYC_Slicer *slicer = cls; | |||||
const struct GNUNET_MessageHeader *pmsg = slicer->pmsg; | |||||
struct SlicerMethodCallbacks *cbs = value; | |||||
uint16_t ptype = ntohs (pmsg->type); | |||||
switch (ptype) | |||||
{ | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | |||||
{ | |||||
if (NULL != cbs->msg_cb) | |||||
cbs->msg_cb (cbs->cls, slicer->msg); | |||||
if (NULL == cbs->method_cb) | |||||
break; | |||||
struct GNUNET_PSYC_MessageMethod * | |||||
meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; | |||||
cbs->method_cb (cbs->cls, slicer->msg, meth, slicer->message_id, | |||||
slicer->method_name); | |||||
break; | |||||
} | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | |||||
{ | |||||
if (NULL == cbs->modifier_cb) | |||||
break; | |||||
struct GNUNET_PSYC_MessageModifier * | |||||
mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | |||||
cbs->modifier_cb (cbs->cls, slicer->msg, &mod->header, slicer->message_id, | |||||
mod->oper, (const char *) &mod[1], | |||||
(const void *) &mod[1] + ntohs (mod->name_size), | |||||
ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size), | |||||
ntohs (mod->value_size)); | |||||
break; | |||||
} | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | |||||
{ | |||||
if (NULL == cbs->modifier_cb) | |||||
break; | |||||
cbs->modifier_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, | |||||
slicer->mod_oper, slicer->mod_name, &pmsg[1], | |||||
ntohs (pmsg->size) - sizeof (*pmsg), | |||||
slicer->mod_full_value_size); | |||||
break; | |||||
} | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | |||||
{ | |||||
if (NULL == cbs->data_cb) | |||||
break; | |||||
cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, | |||||
&pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg)); | |||||
break; | |||||
} | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | |||||
if (NULL == cbs->eom_cb) | |||||
break; | |||||
cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO); | |||||
break; | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | |||||
if (NULL == cbs->eom_cb) | |||||
break; | |||||
cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES); | |||||
break; | |||||
} | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Call a method handler for an incoming message part. | |||||
*/ | |||||
static int | |||||
slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key, | |||||
void *value) | |||||
{ | |||||
struct GNUNET_PSYC_Slicer *slicer = cls; | |||||
struct SlicerModifierCallbacks *cbs = value; | |||||
cbs->modifier_cb (cbs->cls, slicer->msg, slicer->pmsg, slicer->message_id, | |||||
slicer->mod_oper, slicer->mod_name, slicer->mod_value, | |||||
slicer->mod_value_size, slicer->mod_full_value_size); | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Process an incoming message and call matching handlers. | |||||
* | |||||
* @param slicer | |||||
* The slicer to use. | |||||
* @param msg | |||||
* The message as it arrived from the network. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, | |||||
const struct GNUNET_PSYC_MessageHeader *msg) | |||||
{ | |||||
GNUNET_PSYC_receive_message (slicer->recv, msg); | |||||
} | |||||
/** | |||||
* Process an incoming message part and call matching handlers. | |||||
* | |||||
* @param cls | |||||
* Closure. | |||||
* @param message_id | |||||
* ID of the message. | |||||
* @param flags | |||||
* Flags for the message. | |||||
* @see enum GNUNET_PSYC_MessageFlags | |||||
* @param msg | |||||
* The message part. as it arrived from the network. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, | |||||
const struct GNUNET_PSYC_MessageHeader *msg, | |||||
const struct GNUNET_MessageHeader *pmsg) | |||||
{ | |||||
slicer->msg = msg; | |||||
slicer->pmsg = pmsg; | |||||
uint64_t message_id = GNUNET_ntohll (msg->message_id); | |||||
uint16_t ptype = ntohs (pmsg->type); | |||||
if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) | |||||
{ | |||||
struct GNUNET_PSYC_MessageMethod * | |||||
meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; | |||||
slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth); | |||||
slicer->method_name = GNUNET_malloc (slicer->method_name_size); | |||||
GNUNET_memcpy (slicer->method_name, &meth[1], slicer->method_name_size); | |||||
slicer->message_id = message_id; | |||||
} | |||||
else | |||||
{ | |||||
GNUNET_assert (message_id == slicer->message_id); | |||||
} | |||||
char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key); | |||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | |||||
"Slicer received message of type %u and size %u, " | |||||
"with ID %" PRIu64 " and method %s from %s\n", | |||||
ptype, ntohs (pmsg->size), message_id, slicer->method_name, nym_str); | |||||
GNUNET_free (nym_str); | |||||
/* try-and-slice modifier */ | |||||
switch (ptype) | |||||
{ | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | |||||
{ | |||||
struct GNUNET_PSYC_MessageModifier * | |||||
mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | |||||
slicer->mod_oper = mod->oper; | |||||
slicer->mod_name_size = ntohs (mod->name_size); | |||||
slicer->mod_name = GNUNET_malloc (slicer->mod_name_size); | |||||
GNUNET_memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size); | |||||
slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size; | |||||
slicer->mod_full_value_size = ntohs (mod->value_size); | |||||
slicer->mod_value_remaining = slicer->mod_full_value_size; | |||||
slicer->mod_value_size | |||||
= ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size; | |||||
// fall through | |||||
} | |||||
case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | |||||
if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT) | |||||
{ | |||||
slicer->mod_value = (char *) &pmsg[1]; | |||||
slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg); | |||||
} | |||||
slicer->mod_value_remaining -= slicer->mod_value_size; | |||||
char *name = GNUNET_malloc (slicer->mod_name_size); | |||||
GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size); | |||||
do | |||||
{ | |||||
struct GNUNET_HashCode key; | |||||
uint16_t name_len = strlen (name); | |||||
GNUNET_CRYPTO_hash (name, name_len, &key); | |||||
GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, | |||||
slicer_modifier_handler_notify, | |||||
slicer); | |||||
char *p = strrchr (name, '_'); | |||||
if (NULL == p) | |||||
break; | |||||
*p = '\0'; | |||||
} while (1); | |||||
GNUNET_free (name); | |||||
} | |||||
/* try-and-slice method */ | |||||
char *name = GNUNET_malloc (slicer->method_name_size); | |||||
GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size); | |||||
do | |||||
{ | |||||
struct GNUNET_HashCode key; | |||||
uint16_t name_len = strlen (name); | |||||
GNUNET_CRYPTO_hash (name, name_len, &key); | |||||
GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, | |||||
slicer_method_handler_notify, | |||||
slicer); | |||||
char *p = strrchr (name, '_'); | |||||
if (NULL == p) | |||||
break; | |||||
*p = '\0'; | |||||
} while (1); | |||||
GNUNET_free (name); | |||||
if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) | |||||
GNUNET_free (slicer->method_name); | |||||
if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name) | |||||
{ | |||||
GNUNET_free (slicer->mod_name); | |||||
slicer->mod_name = NULL; | |||||
slicer->mod_name_size = 0; | |||||
slicer->mod_value_size = 0; | |||||
slicer->mod_full_value_size = 0; | |||||
slicer->mod_oper = 0; | |||||
} | |||||
slicer->msg = NULL; | |||||
slicer->pmsg = NULL; | |||||
} | |||||
/** | |||||
* Create a try-and-slice instance. | |||||
* | |||||
* A slicer processes incoming messages and notifies callbacks about matching | |||||
* methods or modifiers encountered. | |||||
* | |||||
* @return A new try-and-slice construct. | |||||
*/ | |||||
struct GNUNET_PSYC_Slicer * | |||||
GNUNET_PSYC_slicer_create (void) | |||||
{ | |||||
struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer)); | |||||
slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | |||||
slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | |||||
slicer->recv = GNUNET_PSYC_receive_create (NULL, | |||||
(GNUNET_PSYC_MessagePartCallback) | |||||
GNUNET_PSYC_slicer_message_part, | |||||
slicer); | |||||
return slicer; | |||||
} | |||||
/** | |||||
* Add a method to the try-and-slice instance. | |||||
* | |||||
* The callbacks are called for messages with a matching @a method_name prefix. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance to extend. | |||||
* @param method_name | |||||
* Name of the given method, use empty string to match all. | |||||
* @param method_cb | |||||
* Method handler invoked upon a matching message. | |||||
* @param modifier_cb | |||||
* Modifier handler, invoked after @a method_cb | |||||
* for each modifier in the message. | |||||
* @param data_cb | |||||
* Data handler, invoked after @a modifier_cb for each data fragment. | |||||
* @param eom_cb | |||||
* Invoked upon reaching the end of a matching message. | |||||
* @param cls | |||||
* Closure for the callbacks. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *method_name, | |||||
GNUNET_PSYC_MessageCallback msg_cb, | |||||
GNUNET_PSYC_MethodCallback method_cb, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
GNUNET_PSYC_DataCallback data_cb, | |||||
GNUNET_PSYC_EndOfMessageCallback eom_cb, | |||||
void *cls) | |||||
{ | |||||
struct GNUNET_HashCode key; | |||||
GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); | |||||
struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs)); | |||||
cbs->msg_cb = msg_cb, | |||||
cbs->method_cb = method_cb; | |||||
cbs->modifier_cb = modifier_cb; | |||||
cbs->data_cb = data_cb; | |||||
cbs->eom_cb = eom_cb; | |||||
cbs->cls = cls; | |||||
GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs, | |||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | |||||
} | |||||
static int | |||||
slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value) | |||||
{ | |||||
struct SlicerMethodRemoveClosure *rm_cls = cls; | |||||
struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; | |||||
struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs; | |||||
struct SlicerMethodCallbacks *cbs = value; | |||||
if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb) | |||||
&& (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb) | |||||
&& (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb) | |||||
&& (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb) | |||||
&& (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb)) | |||||
{ | |||||
GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs); | |||||
GNUNET_free (cbs); | |||||
return GNUNET_NO; | |||||
} | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Remove a registered method from the try-and-slice instance. | |||||
* | |||||
* Removes one matching handler registered with the given | |||||
* @a method_name and callbacks. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param method_name | |||||
* Name of the method to remove. | |||||
* @param method_cb | |||||
* Method handler. | |||||
* @param modifier_cb | |||||
* Modifier handler. | |||||
* @param data_cb | |||||
* Data handler. | |||||
* @param eom_cb | |||||
* End of message handler. | |||||
* | |||||
* @return #GNUNET_OK if a method handler was removed, | |||||
* #GNUNET_NO if no handler matched the given method name and callbacks. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *method_name, | |||||
GNUNET_PSYC_MessageCallback msg_cb, | |||||
GNUNET_PSYC_MethodCallback method_cb, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
GNUNET_PSYC_DataCallback data_cb, | |||||
GNUNET_PSYC_EndOfMessageCallback eom_cb) | |||||
{ | |||||
struct GNUNET_HashCode key; | |||||
GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); | |||||
struct SlicerMethodRemoveClosure rm_cls; | |||||
rm_cls.slicer = slicer; | |||||
struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs; | |||||
rm_cbs->msg_cb = msg_cb; | |||||
rm_cbs->method_cb = method_cb; | |||||
rm_cbs->modifier_cb = modifier_cb; | |||||
rm_cbs->data_cb = data_cb; | |||||
rm_cbs->eom_cb = eom_cb; | |||||
return | |||||
(GNUNET_SYSERR | |||||
== GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, | |||||
slicer_method_remove, | |||||
&rm_cls)) | |||||
? GNUNET_NO | |||||
: GNUNET_OK; | |||||
} | |||||
/** | |||||
* Watch a place for changed objects. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param object_filter | |||||
* Object prefix to match. | |||||
* @param modifier_cb | |||||
* Function to call when encountering a state modifier. | |||||
* @param cls | |||||
* Closure for callback. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *object_filter, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb, | |||||
void *cls) | |||||
{ | |||||
struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs); | |||||
cbs->modifier_cb = modifier_cb; | |||||
cbs->cls = cls; | |||||
struct GNUNET_HashCode key; | |||||
GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); | |||||
GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs, | |||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | |||||
} | |||||
static int | |||||
slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value) | |||||
{ | |||||
struct SlicerModifierRemoveClosure *rm_cls = cls; | |||||
struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; | |||||
struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs; | |||||
struct SlicerModifierCallbacks *cbs = value; | |||||
if (cbs->modifier_cb == rm_cbs->modifier_cb) | |||||
{ | |||||
GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs); | |||||
GNUNET_free (cbs); | |||||
return GNUNET_NO; | |||||
} | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Remove a registered modifier from the try-and-slice instance. | |||||
* | |||||
* Removes one matching handler registered with the given | |||||
* @a object_filter and @a modifier_cb. | |||||
* | |||||
* @param slicer | |||||
* The try-and-slice instance. | |||||
* @param object_filter | |||||
* Object prefix to match. | |||||
* @param modifier_cb | |||||
* Function to call when encountering a state modifier changes. | |||||
*/ | |||||
int | |||||
GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, | |||||
const char *object_filter, | |||||
GNUNET_PSYC_ModifierCallback modifier_cb) | |||||
{ | |||||
struct GNUNET_HashCode key; | |||||
GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); | |||||
struct SlicerModifierRemoveClosure rm_cls; | |||||
rm_cls.slicer = slicer; | |||||
struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs; | |||||
rm_cbs->modifier_cb = modifier_cb; | |||||
return | |||||
(GNUNET_SYSERR | |||||
== GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, | |||||
slicer_modifier_remove, | |||||
&rm_cls)) | |||||
? GNUNET_NO | |||||
: GNUNET_OK; | |||||
} | |||||
static int | |||||
slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value) | |||||
{ | |||||
struct SlicerMethodCallbacks *cbs = value; | |||||
GNUNET_free (cbs); | |||||
return GNUNET_YES; | |||||
} | |||||
static int | |||||
slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value) | |||||
{ | |||||
struct SlicerModifierCallbacks *cbs = value; | |||||
GNUNET_free (cbs); | |||||
return GNUNET_YES; | |||||
} | |||||
/** | |||||
* Remove all registered method handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer) | |||||
{ | |||||
GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers, | |||||
slicer_method_free, NULL); | |||||
GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers); | |||||
} | |||||
/** | |||||
* Remove all registered modifier handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer) | |||||
{ | |||||
GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers, | |||||
slicer_modifier_free, NULL); | |||||
GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers); | |||||
} | |||||
/** | |||||
* Remove all registered method & modifier handlers. | |||||
* | |||||
* @param slicer | |||||
* Slicer to clear. | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer) | |||||
{ | |||||
GNUNET_PSYC_slicer_method_clear (slicer); | |||||
GNUNET_PSYC_slicer_modifier_clear (slicer); | |||||
} | |||||
/** | |||||
* Destroy a given try-and-slice instance. | |||||
* | |||||
* @param slicer | |||||
* Slicer to destroy | |||||
*/ | |||||
void | |||||
GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer) | |||||
{ | |||||
GNUNET_PSYC_slicer_clear (slicer); | |||||
GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers); | |||||
GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers); | |||||
GNUNET_PSYC_receive_destroy (slicer->recv); | |||||
GNUNET_free (slicer); | |||||
} |
@@ -0,0 +1,96 @@ | |||||
/* | |||||
* This file is part of GNUnet. | |||||
* Copyright (C) 2013 GNUnet e.V. | |||||
* | |||||
* GNUnet is free software: you can redistribute it and/or modify it | |||||
* under the terms of the GNU Affero General Public License as published | |||||
* by the Free Software Foundation, either version 3 of the License, | |||||
* or (at your option) any later version. | |||||
* | |||||
* GNUnet 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 | |||||
* Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
SPDX-License-Identifier: AGPL3.0-or-later | |||||
*/ | |||||
/** | |||||
* @author Gabor X Toth | |||||
* | |||||
* @file | |||||
* Tests for the environment library. | |||||
*/ | |||||
#include "platform.h" | |||||
#include "gnunet_util_lib.h" | |||||
#include "gnunet_testing_lib.h" | |||||
#include "gnunet_psyc_util_lib.h" | |||||
struct GNUNET_PSYC_Modifier mods[] = { | |||||
{ .oper = GNUNET_PSYC_OP_SET, | |||||
.name = "_foo", .value = "foo", .value_size = 3 }, | |||||
{ .oper = GNUNET_PSYC_OP_ASSIGN, | |||||
.name = "_foo_bar", .value = "foo bar", .value_size = 7 }, | |||||
{ .oper = GNUNET_PSYC_OP_AUGMENT, | |||||
.name = "_foo_bar_baz", .value = "foo bar baz", .value_size = 11 } | |||||
}; | |||||
struct ItCls | |||||
{ | |||||
size_t n; | |||||
}; | |||||
int | |||||
iterator (void *cls, enum GNUNET_PSYC_Operator oper, | |||||
const char *name, const char *value, uint32_t value_size) | |||||
{ | |||||
struct ItCls *it_cls = cls; | |||||
struct GNUNET_PSYC_Modifier *m = &mods[it_cls->n++]; | |||||
GNUNET_assert (oper == m->oper); | |||||
GNUNET_assert (value_size == m->value_size); | |||||
GNUNET_assert (0 == memcmp (name, m->name, strlen (m->name))); | |||||
GNUNET_assert (0 == memcmp (value, m->value, m->value_size)); | |||||
return GNUNET_YES; | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
GNUNET_log_setup ("test-env", "WARNING", NULL); | |||||
struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | |||||
GNUNET_assert (NULL != env); | |||||
int i, len = 3; | |||||
for (i = 0; i < len; i++) | |||||
{ | |||||
GNUNET_PSYC_env_add (env, mods[i].oper, mods[i].name, | |||||
mods[i].value, mods[i].value_size); | |||||
} | |||||
struct ItCls it_cls = { .n = 0 }; | |||||
GNUNET_PSYC_env_iterate (env, iterator, &it_cls); | |||||
GNUNET_assert (len == it_cls.n); | |||||
for (i = 0; i < len; i++) | |||||
{ | |||||
enum GNUNET_PSYC_Operator oper; | |||||
const char *name; | |||||
const void *value; | |||||
size_t value_size; | |||||
GNUNET_PSYC_env_shift (env, &oper, &name, &value, &value_size); | |||||
GNUNET_assert (len - i - 1 == GNUNET_PSYC_env_get_count (env)); | |||||
} | |||||
GNUNET_PSYC_env_destroy (env); | |||||
return 0; | |||||
} |
@@ -0,0 +1,3 @@ | |||||
gnunet-social | |||||
gnunet-service-social | |||||
test_social |