diff options
author | Alberto Ruiz <alberto.ruiz@sun.com> | 2007-10-30 17:21:07 +0000 |
---|---|---|
committer | Alberto Ruiz <alberto.ruiz@sun.com> | 2007-10-30 17:21:07 +0000 |
commit | aadeffb3f0716ffd231d1146d050847e3be355ee (patch) | |
tree | 9f2ed61a84a37fce5f154498023b28d6bfbf69bf |
2007-30-10 Alberto Ruiz <alberto.ruiz@sun.com>
* Initial commit.
154 files changed, 23034 insertions, 0 deletions
@@ -0,0 +1,680 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + +1. Definitions. + +1.1. Contributor means each individual or entity that creates or +contributes to the creation of Modifications. + +1.2. Contributor Version means the combination of the Original +Software, prior Modifications used by a Contributor (if any), +and the Modifications made by that particular Contributor. + +1.3. Covered Software means (a) the Original Software, or (b) +Modifications, or (c) the combination of files containing +Original Software with files containing Modifications, in each +case including portions thereof. + +1.4. Executable means the Covered Software in any form other +than Source Code. + +1.5. Initial Developer means the individual or entity that first +makes Original Software available under this License. + +1.6. Larger Workmeans a work which combines Covered Software or +portions thereof with code not governed by the terms of this +License. + +1.7. License means this document. + +1.8. Licensable means having the right to grant, to the maximum +extent possible, whether at the time of the initial grant or +subsequently acquired, any and all of the rights conveyed herein. + +1.9. Modifications means the Source Code and Executable form of +any of the following: A. Any file that results from an addition +to, deletion from or modification of the contents of a file +containing Original Software or previous Modifications; B. Any +new file that contains any part of the Original Software or +previous Modification; or C. Any new file that is contributed or +otherwise made available under the terms of this License. + +1.10. Original Software means the Source Code and Executable +form of computer software code that is originally released under +this License. + +1.11. Patent Claims means any patent claim(s), now owned or +hereafter acquired, including without limitation, method, +process, and apparatus claims, in any patent Licensable by +grantor. + +1.12. Source Code means (a) the common form of computer software +code in which modifications are made and (b) associated +documentation included in or with such code. + +1.13. You (or Your) means an individual or a legal entity +exercising rights under, and complying with all of the terms of, +this License. For legal entities, You includes any entity which +controls, is controlled by, or is under common control with You. +For purposes of this definition, control means (a) the power, +direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (b) ownership of +more than fifty percent (50%) of the outstanding shares or +beneficial ownership of such entity. + +2. License Grants. + +2.1. The Initial Developer Grant. Conditioned upon Your +compliance with Section 3.1 below and subject to third party +intellectual property claims, the Initial Developer hereby +grants You a world-wide, royalty-free, non-exclusive license: + +(a) under intellectual property rights (other than patent or +trademark) Licensable by Initial Developer, to use, reproduce, +modify, display, perform, sublicense and distribute the Original +Software (or portions thereof), with or without Modifications, +and/or as part of a Larger Work; and + +(b) under Patent Claims infringed by the making, using or +selling of Original Software, to make, have made, use, practice, +sell, and offer for sale, and/or otherwise dispose of the +Original Software (or portions thereof); + +(c) The licenses granted in Sections 2.1(a) and (b) are +effective on the date Initial Developer first distributes or +otherwise makes the Original Software available to a third party +under the terms of this License; + +(d) Notwithstanding Section 2.1(b) above, no patent license is +granted: (1) for code that You delete from the Original +Software, or (2) for infringements caused by: (i) the +modification of the Original Software, or (ii) the combination +of the Original Software with other software or devices. + +2.2. Contributor Grant. Conditioned upon Your compliance with +Section 3.1 below and subject to third party intellectual +property claims, each Contributor hereby grants You a +world-wide, royalty-free, non-exclusive license: + +(a) under intellectual property rights (other than patent or +trademark) Licensable by Contributor to use, reproduce, modify, +display, perform, sublicense and distribute the Modifications +created by such Contributor (or portions thereof), either on an +unmodified basis, with other Modifications, as Covered Software +and/or as part of a Larger Work; and + +(b) under Patent Claims infringed by the making, using, or +selling of Modifications made by that Contributor either alone +and/or in combination with its Contributor Version (or portions +of such combination), to make, use, sell, offer for sale, have +made, and/or otherwise dispose of: (1) Modifications made by +that Contributor (or portions thereof); and (2) the combination +of Modifications made by that Contributor with its Contributor +Version (or portions of such combination). + +(c) The licenses granted in Sections 2.2(a) and 2.2(b) +areeffective on the date Contributor first distributes or +otherwise makes the Modifications available to a third party. + +(d) Notwithstanding Section 2.2(b) above, no patent license is +granted: (1) for any code that Contributor has deleted from the +Contributor Version; (2) for infringements caused by: (i) third +party modifications of Contributor Version, or (ii) the +combination of Modifications made by that Contributor with other +software (except as part of the Contributor Version) or other +devices; or (3) under Patent Claims infringed by Covered +Software in the absence of Modifications made by that +Contributor. + +3. Distribution Obligations. + +3.1. Availability of Source Code. Any Covered Software that You +distribute or otherwise make available in Executable form must +also be made available in Source Code form and that Source Code +form must be distributed only under the terms of this License. +You must include a copy of this License with every copy of the +Source Code form of the Covered Software You distribute or +otherwise make available. You must inform recipients of any such +Covered Software in Executable form as to how they can obtain +such Covered Software in Source Code form in a reasonable manner +on or through a medium customarily used for software exchange. + +3.2. Modifications. The Modifications that You create or to +which You contribute are governed by the terms of this License. +You represent that You believe Your Modifications are Your +original creation(s) and/or You have sufficient rights to grant +the rights conveyed by this License. + +3.3. Required Notices. You must include a notice in each of Your +Modifications that identifies You as the Contributor of the +Modification. You may not remove or alter any copyright, patent +or trademark notices contained within the Covered Software, or +any notices of licensing or any descriptive text giving +attribution to any Contributor or the Initial Developer. + +3.4. Application of Additional Terms. You may not offer or +impose any terms on any Covered Software in Source Code form +that alters or restricts the applicable version of this License +or the recipients rights hereunder. You may choose to offer, and +to charge a fee for, warranty, support, indemnity or liability +obligations to one or more recipients of Covered +Software. However, you may do so only on Your own behalf, and +not on behalf of the Initial Developer or any Contributor. You +must make it absolutely clear that any such warranty, support, +indemnity or liability obligation is offered by You alone, and +You hereby agree to indemnify the Initial Developer and every +Contributor for any liability incurred by the Initial Developer +or such Contributor as a result of warranty, support, indemnity +or liability terms You offer. + +3.5. Distribution of Executable Versions. You may distribute the +Executable form of the Covered Software under the terms of this +License or under the terms of a license of Your choice, which +may contain terms different from this License, provided that You +are in compliance with the terms of this License and that the +license for the Executable form does not attempt to limit or +alter the recipients rights in the Source Code form from the +rights set forth in this License. If You distribute the Covered +Software in Executable form under a different license, You must +make it absolutely clear that any terms which differ from this +License are offered by You alone, not by the Initial Developer +or Contributor. You hereby agree to indemnify the Initial +Developer and every Contributor for any liability incurred by +the Initial Developer or such Contributor as a result of any +such terms You offer. + +3.6. Larger Works. You may create a Larger Work by combining +Covered Software with other code not governed by the terms of +this License and distribute the Larger Work as a single product. +In such a case, You must make sure the requirements of this +License are fulfilled for the Covered Software. + +4. Versions of the License. + +4.1. New Versions. Sun Microsystems, Inc. is the initial license +steward and may publish revised and/or new versions of this +License from time to time. Each version will be given a +distinguishing version number. Except as provided in Section +4.3, no one other than the license steward has the right to +modify this License. + +4.2. Effect of New Versions. You may always continue to use, +distribute or otherwise make the Covered Software available +under the terms of the version of the License under which You +originally received the Covered Software. If the Initial +Developer includes a notice in the Original Software prohibiting +it from being distributed or otherwise made available under any +subsequent version of the License, You must distribute and make +the Covered Software available under the terms of the version of +the License under which You originally received the Covered +Software. Otherwise, You may also choose to use, distribute or +otherwise make the Covered Software available under the terms of +any subsequent version of the License published by the license +steward. + +4.3. Modified Versions. When You are an Initial Developer and +You want to create a new license for Your Original Software, You +may create and use a modified version of this License if You: +(a) rename the license and remove any references to the name of +the license steward (except to note that the license differs +from this License); and (b) otherwise make it clear that the +license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER +THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, +MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. +THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE +DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY +OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, +REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN +ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE +IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + +6.1. This License and the rights granted hereunder will +terminate automatically if You fail to comply with terms herein +and fail to cure such breach within 30 days of becoming aware of +the breach. Provisions which, by their nature, must remain in +effect beyond the termination of this License shall survive. + +6.2. If You assert a patent infringement claim (excluding +declaratory judgment actions) against Initial Developer or a +Contributor (the Initial Developer or Contributor against whom +You assert such claim is referred to as Participant) alleging +that the Participant Software (meaning the Contributor Version +where the Participant is a Contributor or the Original Software +where the Participant is the Initial Developer) directly or +indirectly infringes any patent, then any and all rights granted +directly or indirectly to You by such Participant, the Initial +Developer (if the Initial Developer is not the Participant) and +all Contributors under Sections 2.1 and/or 2.2 of this License +shall, upon 60 days notice from Participant terminate +prospectively and automatically at the expiration of such 60 day +notice period, unless if within such 60 day period You withdraw +Your claim with respect to the Participant Software against such +Participant either unilaterally or pursuant to a written +agreement with Participant. + +6.3. In the event of termination under Sections 6.1 or 6.2 +above, all end user licenses that have been validly granted by +You or any distributor hereunder prior to termination (excluding +licenses granted to You by any distributor) shall survive +termination. + +7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO +LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR +OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER +CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY +SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY +INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY +CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST +PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR +MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, +EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY +OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO +LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH +PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH +LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS +EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. The Covered Software is a +commercial item, as that term is defined in 48 C.F.R. 2.101 +(Oct. 1995), consisting of commercial computer software (as that +term is defined at 48 C.F.R. 252.227-7014(a)(1)) and commercial +computer software documentation as such terms are used in 48 +C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all +U.S. Government End Users acquire Covered Software with only +those rights set forth herein. This U.S. Government Rights +clause is in lieu of, and supersedes, any other FAR, DFAR, or +other clause or provision that addresses Government rights in +computer software under this License. + +9. MISCELLANEOUS. This License represents the complete agreement +concerning subject matter hereof. If any provision of this +License is held to be unenforceable, such provision shall be +reformed only to the extent necessary to make it enforceable. +This License shall be governed by the law of the jurisdiction +specified in a notice contained within the Original Software +(except to the extent applicable law, if any, provides +otherwise), excluding such jurisdictions conflict-of-law +provisions. Any litigation relating to this License shall be +subject to the jurisdiction of the courts located in the +jurisdiction and venue specified in a notice contained within +the Original Software, with the losing party responsible for +costs, including, without limitation, court costs and reasonable +attorneys fees and expenses. The application of the United +Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. Any law or regulation which +provides that the language of a contract shall be construed +against the drafter shall not apply to this License. You agree +that You alone are responsible for compliance with the United +States export administration regulations (and the export control +laws and regulation of any other countries) when You use, +distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and +the Contributors, each party is responsible for claims and +damages arising, directly or indirectly, out of its utilization +of rights under this License and You agree to work with Initial +Developer and Contributors to distribute such responsibility on +an equitable basis. Nothing herein is intended or shall be +deemed to constitute any admission of liability. + +---------------------------------------------------------------- + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND +DISTRIBUTION LICENSE (CDDL): This code is released under the +CDDL and shall be governed by the laws of the State of +California (excluding conflict-of-law provisions). Any +litigation relating to this License shall be subject to the +jurisdiction of the Federal Courts of the Northern District of +California and the state courts of the State of California, with +venue lying in Santa Clara County, California. + +---------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7c0a25a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,2 @@ +2007-30-10 Alberto Ruiz <alberto.ruiz@sun.com> + * Initial commit. @@ -0,0 +1,44 @@ +------------------- +- Desktop Agent - +------------------- + +The following steps should be completed in the agent sub directory of the root path of the source code. + +Before to continue, make sure you have all the dependencies requeried by this package: + + * The APOC SPI + * Berkeley DB (v4.2) library Java bindings + * Heimdall Generic Security Service libraries and headers + * LibXML2 libraries and headers + + Step 1: Generating the configure script +----------------------------------------- + +NOTE: Tarball releases already include a configure script so this step is unnecessary in that case. + +Type this to generate the configure script: + +$ ./autogen.sh --help + + Step 2: Calling the configure script +-------------------------------------- + +In the root path of the source code, you should execute the configure script. For more information on changing the default paths, execute configure with the --help option. + +$ ./configure --prefix=/usr --with-bdb-path=/path/to/db.jar + +NOTE: You should use the same prefix than the SPI. The db.jar would be looked by default on /usr/share/lib/apoc/db.jar, it can be located elsewhere, use the --with-bdb-path option used in the example for any other location. + + Step 3: Building the sources +------------------------------ + +If the configuration ends successfully, then you should build and install the sources: + +$ make +$ make install + + + Post Installation +------------------- + +To start the daemon the build generates an init.d script (initd/apocd) that should be installed manually. An SMF manifest for SOLARIS is generated and installed under the prefix directory as svc/manifest/network/apocd.xml, the SMF database should be updated manually. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..315abd7 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +SUBDIRS = libfileaccess libapoc apocd src + +apocddir=$(APOCDIR) +apocd_DATA=build/class/apocd.jar + +configdir=$(sysconfdir) +config_DATA= \ + src/com/sun/apoc/daemon/properties/apocd.properties \ + src/com/sun/apoc/daemon/properties/os.properties \ + src/com/sun/apoc/daemon/properties/policymgr.properties + + +if SOLARIS +smfdir=$(localstatedir)/svc/manifest/network +smf_DATA=smf/apocd.xml +endif diff --git a/apocd/Makefile.am b/apocd/Makefile.am new file mode 100644 index 0000000..cd07fc2 --- /dev/null +++ b/apocd/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = \ + -I${top_builddir}/libapoc/ + +apocd_LDADD = ${top_builddir}/libapoc/libapoc.la -lapoc + +bindir = $(APOCD_DIR) +bin_PROGRAMS = apocd + +apocd_SOURCES = apocd.c + +if SOLARIS +apocd_SOURCES += solaris.c +else +apocd_SOURCES += linux.c +endif + diff --git a/apocd/apocd.c b/apocd/apocd.c new file mode 100644 index 0000000..f6c6505 --- /dev/null +++ b/apocd/apocd.c @@ -0,0 +1,659 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include "apocd.h" +#include "config.h" + +#include <papiUtils.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <unistd.h> +#include <netinet/in.h> +#include <netdb.h> + +static int authenticate( PAPISocket inSocket ); +static Status daemonChangeDetect( void ); +static Status daemonReload( void ); +static Status daemonRequest( DaemonOp inOp, int inQuiet ); +static Status daemonRestart( void ); +static Status doOp( DaemonOp inOp ); +static int getDaemonAdminPort( void ); +static int getResponse( int inSocket, char * outResponse ); +static void invalidArg( const char * inArg ); +static Status javaStart( int inWait ); +static void putEnv( void ); +static int sendRequest( int inSocket, const unsigned char * inRequest ); +static DaemonOp stringToDaemonOp( const char * inString ); +static void usage( void ); + +static const char * sArgChangeDetect = "change-detect"; +static const char * sArgDisable = "disable"; +static const char * sArgEnable = "enable"; +static const char * sArgIsEnabled = "is-enabled"; +static const char * sArgReload = "reload"; +static const char * sArgRestart = "restart"; +static const char * sArgStart = "start"; +static const char * sArgStatus = "status"; +static const char * sArgStop = "stop"; +static const char * sArgsvcStart = "svcStart"; +static const char * sArgsvcStop = "svcStop"; + +int main( int inArgc, char ** inArgv ) +{ + Status theRC; + + if ( inArgc == 2 ) + { + DaemonOp theOp = stringToDaemonOp( inArgv[ 1 ] ); + if ( theOp == sOpUndefined ) + { + invalidArg( inArgv[ 1 ] ); + theRC = sErrorInvalidArg; + } + else + { + theRC = doOp( theOp ); + } + } + else + { + usage(); + theRC = sErrorInvalidArg; + } + return theRC; +} + +Status daemonStart( void ) +{ + Status theRC = daemonStatus( 1 ); + writeInitialMessage( sOpStart ); + if ( theRC == sStatusNotRunning ) + { +#ifndef LINUX + theRC = javaStart( 0 ); + if ( theRC == sStatusOK ) + { + theRC = daemonWaitStatus( sStatusOK, 30 ); + } +#else + if ( fork() == 0 ) + { + while ( 1 ) + { + theRC = javaStart( 1 ); + if ( theRC == sStatusOK ) + { + break; + } + if ( osDaemonShouldRestart() == 0 ) + { + theRC = sErrorGeneric; + break; + } + } + return theRC; + } + else + { + theRC = daemonWaitStatus( sStatusOK, 30 ); + } +#endif + } + writeFinalMessage( sOpStart, theRC ); + return theRC; +} + +Status daemonStatus( int inQuiet ) +{ + return daemonRequest( sOpStatus, inQuiet ) == sStatusOK ? + sStatusOK : sStatusNotRunning; +} + +Status daemonStop( void ) +{ + Status theRC; + writeInitialMessage( sOpStop ); + daemonRequest( sOpStop, 1 ); + theRC = + daemonWaitStatus( sStatusNotRunning, 20 ) == sStatusNotRunning ? + sStatusOK : sErrorGeneric; + writeFinalMessage( sOpStop, theRC ); + return theRC; +} + +Status daemonWaitStatus( Status inStatus, int inMaxIterations ) +{ + Status theRC; + int theIteration = 0; + + while ( ( theRC = daemonStatus( 1 ) ) != inStatus && + ++ theIteration <= inMaxIterations ) + { + papiSleep( 1 ); + } + return theRC; +} + +void writeInitialMessage( DaemonOp inOp ) +{ + if ( inOp == sOpChangeDetect ) + { + printf( "Requesting a Configuration Agent change detection ... " ); + } + else if ( inOp == sOpDisable ) + { + printf( "Disabling Configuration Agent ... "); + } + else if ( inOp == sOpEnable ) + { + printf( "Enabling Configuration Agent ... "); + } + else if ( inOp == sOpIsEnabled ) + { + printf( "Checking Configuration Agent enabled status ... " ); + } + else if ( inOp == sOpReload ) + { + printf( "Reloading Configuration Agent ... " ); + } + else if ( inOp == sOpStatus ) + { + printf( "Checking Configuration Agent status ... " ); + } + else if ( inOp == sOpStart ) + { + printf( "Starting Configuration Agent ... " ); + } + else if ( inOp == sOpStop ) + { + printf( "Stopping Configuration Agent ... " ); + } + fflush( stdout ); +} + +void writeAlreadyMessage(DaemonOp inOp) +{ + const char *theMessage = NULL ; + + switch (inOp) { + case sOpStart: + theMessage = "Already started" ; + break ; + case sOpStop: + theMessage = "Already stopped" ; + break ; + case sOpEnable: + theMessage = "Already enabled" ; + break ; + case sOpDisable: + theMessage = "Already disabled" ; + break ; + default: + break ; + } + if (theMessage != NULL) { + printf("%s\n", theMessage) ; + } +} + +void writeFinalMessage( DaemonOp inOp, Status inStatus ) +{ + if ( inStatus == sErrorAuthentication ) + { + printf( "Failed\n" ); + } + else if ( inOp == sOpIsEnabled ) + { + printf( "%s\n", inStatus == sStatusEnabled ? "Enabled" : "Not enabled"); + } + else if ( inOp == sOpStatus ) + { + printf( "%s\n", inStatus == sStatusOK ? "Running" : "Not running" ); + } + else if ( inOp == sOpStop ) + { + printf( inStatus == sStatusOK || inStatus == sErrorNotRunning ? + "OK\n" : "Failed\n" ); + } + else + { + printf( inStatus == sStatusOK ? "OK\n" : "Failed\n" ); + } + fflush( stdout ); +} + +int authenticate( PAPISocket inSocket ) +{ + static int sLocalCredentialsBufferSize = 21; + + int theRC = sErrorAuthentication; + char theChallenge[ BUFSIZ ]; + int theIndex = 0; + + theChallenge[ 0 ] = 0; + while ( recv( inSocket, &theChallenge[ theIndex ++ ], 1, 0 ) != -1 ) + { + if ( theChallenge[ theIndex - 1 ] == 0 ) + { + if ( theChallenge[ 0 ] != 0 ) + { + FILE * theFile = fopen( theChallenge, "r" ); + if ( theFile != 0 ) + { + char * theCredentials = + ( char * )malloc( sLocalCredentialsBufferSize ); + if ( theCredentials != 0 ) + { + if ( fgets( theCredentials, + sLocalCredentialsBufferSize, + theFile ) != 0 ) + { + if ( send( inSocket, + theCredentials, + sLocalCredentialsBufferSize - 1, + 0 ) == ( sLocalCredentialsBufferSize - 1 ) ) + { + char theResponse; + if ( getResponse(inSocket,&theResponse)!= -1 && + theResponse == 0 ) + { + theRC = sStatusOK; + } + } + } + free( ( void * )theCredentials ); + } + fclose( theFile ); + } + } + break; + } + } + return theRC; +} + +Status daemonChangeDetect( void ) +{ + return daemonRequest( sOpChangeDetect, 0 ); +} + +Status daemonReload( void ) +{ + return daemonRequest( sOpReload, 0 ); +} + +Status daemonRequest( DaemonOp inOp, int inQuiet ) +{ + Status theRC = sErrorNotRunning; + PAPISocket theSocket; + PAPIConnectResult theConnectResult = + getConnectedSocket( getDaemonAdminPort(), SOCK_STREAM, 0, &theSocket ); + if ( inQuiet == 0 ) + { + writeInitialMessage( inOp ); + } + if ( theConnectResult == PAPIConnectSuccess ) + { + if ( ( theRC = authenticate( theSocket ) ) == sStatusOK ) + { + unsigned char theOp = ( unsigned char )inOp; + if ( sendRequest( theSocket, &theOp ) != -1 ) + { + char theResponse; + if ( getResponse( theSocket, &theResponse ) == -1 ) + { + theRC = sErrorNotRunning; + } + else if ( theResponse == 0 ) + { + theRC = sStatusOK; + } + else + { + theRC = sErrorGeneric; + } + } + } + papiClose( theSocket ); + } + if ( inQuiet == 0 ) + { + writeFinalMessage( inOp, theRC ); + } + return theRC; +} + +Status daemonRestart( void ) +{ + Status theRC = osDaemonStop(); + if ( theRC == sStatusOK ) + { + theRC = osDaemonStart(); + } + return theRC; +} + +static int checkAlreadyDone(DaemonOp inOp) +{ + int retCode = 0 ; + + switch (inOp) { + case sOpStart: + if (daemonStatus(1) == sStatusRunning) { retCode = 1 ; } + break ; + case sOpStop: + if (daemonStatus(1) == sStatusNotRunning) { retCode = 1 ; } + break ; + case sOpEnable: + if (osDaemonIsEnabled(1) == sStatusEnabled) { retCode = 1 ; } + break ; + case sOpDisable: + if (osDaemonIsEnabled(1) == sStatusNotEnabled) { retCode = 1 ; } + break ; + default: + break ; + } + return retCode ; +} + +Status doOp( DaemonOp inOp ) +{ + Status theStatus = sErrorGeneric; + + if (checkAlreadyDone(inOp)) { + writeInitialMessage(inOp) ; + writeAlreadyMessage(inOp) ; + return sStatusOK ; + } + /* + * Non os specific operations + */ + if ( inOp == sOpChangeDetect ) + { + theStatus = daemonChangeDetect(); + } + else if ( inOp == sOpReload ) + { + theStatus = daemonReload(); + } + else if ( inOp == sOpRestart ) + { + theStatus = daemonRestart(); + } + else if ( inOp == sOpStatus ) + { + theStatus = daemonStatus( 0 ); + } + + /* + * os specific operations + */ + else if ( inOp == sOpDisable ) + { + theStatus = osDaemonDisable(); + } + else if ( inOp == sOpEnable ) + { + theStatus = osDaemonEnable(); + } + else if ( inOp == sOpIsEnabled ) + { + theStatus = osDaemonIsEnabled(0); + } + else if ( inOp == sOpStart ) + { + theStatus = osDaemonStart(); + } + else if ( inOp == sOpStop ) + { + theStatus = osDaemonStop(); + } + else if ( inOp == sOpSvcStart ) + { + theStatus = osDaemonSvcStart(); + } + else if ( inOp == sOpSvcStop ) + { + theStatus = osDaemonSvcStop(); + } + return theStatus; +} + +/* + * 6417539 - Need to use IANA registered port + * + * IANA has registered 3809 for us. We use a udp connection on this port to + * the daemon to ask what port is currently set as the admin port + */ +int getDaemonAdminPort( void ) +{ + static char sByte = 1; + static const char * sLocalHostName = "127.0.0.1"; + + int thePort = -1; + PAPISocket theSocket; + char thePortString[ 6 ]; + struct sockaddr_in theDaemonAddr; + struct hostent * theHostEnt; + int theCount; + + theHostEnt = gethostbyname( sLocalHostName ); + theDaemonAddr.sin_family = AF_INET; + theDaemonAddr.sin_port = htons( getDaemonPort() ); + theDaemonAddr.sin_addr = *( (struct in_addr * )theHostEnt->h_addr ); + memset( ( void * )&( theDaemonAddr.sin_zero ), 0, 8 ); + if ( ( theSocket = socket( AF_INET, SOCK_DGRAM, 0 ) ) != INVALID_SOCKET && + connect( theSocket, + ( struct sockaddr * )&theDaemonAddr, + sizeof( struct sockaddr ) ) == 0 && + send( theSocket, &sByte, 1, 0 ) == 1 && + ( theCount = recv( theSocket, thePortString, 6, 0 ) ) > 1 && + thePortString[ theCount - 1 ] == 0 ) + { + thePort = atoi( thePortString ); + } + papiClose( theSocket ); + return thePort; +} + +int getResponse( int inSocket, char * outResponse ) +{ + return recv( inSocket, + outResponse, + 1, + 0 ); +} + +void invalidArg( const char * inOp ) +{ + if ( inOp != 0 ) + { + fprintf( stderr, "Invalid argument '%s'\n", inOp ); + } + usage(); +} + +Status javaStart( int inWait ) +{ + static char * theFormat = + "java -Djava.library.path=%s%s%s -cp %s%sapocd.jar com.sun.apoc.daemon.apocd.Daemon %s %s"; + static char * theCommand = 0; + Status theRC = sStatusOK; + + putEnv(); + if ( theCommand == 0 ) + { + const char * theDaemonInstallDir = getDaemonInstallDir(); + const char * theDaemonLibraryDir = getDaemonLibraryDir(); + const char * theDaemonPropertiesDir = getDaemonPropertiesDir(); + theCommand = + ( char * )malloc( ( strlen( theDaemonInstallDir ) * 2 ) + + strlen( theDaemonLibraryDir ) + + strlen( PATHSEP ) + + strlen( DBJAVA_LIBDIR ) + + strlen( theDaemonPropertiesDir ) + + strlen( FILESEP ) + + ( strlen( theFormat ) + 6 )); + + if ( theCommand != 0 ) + { + sprintf( theCommand, + theFormat, + theDaemonLibraryDir, PATHSEP, + DBJAVA_LIBDIR, + theDaemonInstallDir, FILESEP, + theDaemonInstallDir, + theDaemonPropertiesDir ); + } + } + if ( theCommand != 0 ) + { + FILE * theStream = papiPopen( theCommand, "r" ); + if ( theStream == 0 ) + { + theRC = sErrorGeneric; + } + else if ( inWait == 1 ) + { + theRC = papiPclose( theStream ) == 0 ? sStatusOK : sErrorGeneric; + } + } + else + { + theRC = sErrorGeneric; + } + return theRC; +} + +void putEnv( void ) +{ + char * theJavaHome = getenv( "JAVA_HOME" ); + + if ( theJavaHome != 0 ) + { + char * theJavaPath = ( char * )malloc( strlen( theJavaHome ) + + 4 + + strlen( FILESEP ) ); + if ( theJavaPath != 0 ) + { + char * thePath = getenv( "PATH" ); + char * theNewPath; + sprintf( theJavaPath, "%s%sbin", theJavaHome, FILESEP ); + theNewPath = ( char * )malloc( strlen( theJavaPath ) + + strlen( PATHSEP ) + + strlen( thePath ) + + 6 ); + if ( theNewPath != 0 ) + { + sprintf( theNewPath, + "PATH=%s%s%s", + theJavaPath, + PATHSEP, + thePath ); + putenv( theNewPath ); + free( ( void * )theJavaPath ); + } + } + } + papiUmask( 022 ); +} + +int sendRequest( int inSocket, + const unsigned char * inRequest ) +{ + return send( inSocket, inRequest, 1, 0 ); +} + +DaemonOp stringToDaemonOp( const char * inString ) +{ + DaemonOp theDaemonOp = sOpUndefined; + if ( strcmp( inString, sArgChangeDetect ) == 0 ) + { + theDaemonOp = sOpChangeDetect; + } + else if ( strcmp( inString, sArgDisable ) == 0 ) + { + theDaemonOp = sOpDisable; + } + else if ( strcmp( inString, sArgEnable ) == 0 ) + { + theDaemonOp = sOpEnable; + } + else if ( strcmp( inString, sArgIsEnabled ) == 0 ) + { + theDaemonOp = sOpIsEnabled; + } + else if ( strcmp( inString, sArgReload ) == 0 ) + { + theDaemonOp = sOpReload; + } + else if ( strcmp( inString, sArgRestart ) == 0 ) + { + theDaemonOp = sOpRestart; + } + else if ( strcmp( inString, sArgStart ) == 0 ) + { + theDaemonOp = sOpStart; + } + else if ( strcmp( inString, sArgStatus ) == 0 ) + { + theDaemonOp = sOpStatus; + } + else if ( strcmp( inString, sArgStop ) == 0 ) + { + theDaemonOp = sOpStop; + } + else if ( strcmp( inString, sArgsvcStart ) == 0 ) + { + theDaemonOp = sOpSvcStart; + } + else if ( strcmp( inString, sArgsvcStop ) == 0 ) + { + theDaemonOp = sOpSvcStop; + } + return theDaemonOp; +} + +void usage( void ) +{ + fprintf( stderr, + "%s", + "Usage: apocd change-detect | disable | enable | is-enabled | reload | restart | start | status | stop\n" ); +} diff --git a/apocd/apocd.h b/apocd/apocd.h new file mode 100644 index 0000000..7f9747e --- /dev/null +++ b/apocd/apocd.h @@ -0,0 +1,97 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef _APOCD_H_ +#define _APOCD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + sOpUndefined, + sOpChangeDetect, + sOpDisable, + sOpEnable, + sDEPRECATED_OpInetdStart, + sOpIsEnabled, + sOpReload, + sOpRestart, + sOpStart, + sOpStatus, + sOpStop, + sOpSvcStart, + sOpSvcStop +} DaemonOp; + +typedef enum +{ + sStatusOK = 0, + sStatusEnabled = 0, + sStatusRunning = 0, + sErrorGeneric = 1, + sStatusNotEnabled = 1, + sErrorInvalidArg, + sStatusNotRunning, + sErrorNotRunning, + sErrorAuthentication +} Status; + +extern Status daemonStart( void ); +extern Status daemonStatus( int inQuiet ); +extern Status daemonStop( void ); +extern Status daemonWaitStatus( Status inStatus, int inMaxIterations ); + +extern Status osDaemonDisable( void ); +extern Status osDaemonEnable( void ); +extern Status osDaemonIsEnabled( int inQuiet ); +extern Status osDaemonStart( void ); +extern Status osDaemonStop( void ); +extern Status osDaemonSvcStart( void ); +extern Status osDaemonSvcStop( void ); +#ifdef LINUX +extern int osDaemonShouldRestart( void ); +#endif + +extern void writeInitialMessage( DaemonOp inOp ); +extern void writeFinalMessage( DaemonOp inOp, Status inStatus ); + + +#ifdef __cplusplus +} +#endif + +#endif /* APOCD_H_ */ diff --git a/apocd/config.h.in b/apocd/config.h.in new file mode 100644 index 0000000..e6c6da3 --- /dev/null +++ b/apocd/config.h.in @@ -0,0 +1,40 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef _HAVE_CONFIG_H +#define _HAVE_CONFIG_H +#define BDBJDK "@BDBJDK@" +#define DBJAVA_LIBDIR "@DBJAVA_LIBDIR@" +#endif diff --git a/apocd/linux.c b/apocd/linux.c new file mode 100644 index 0000000..f3b7752 --- /dev/null +++ b/apocd/linux.c @@ -0,0 +1,178 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include "apocd.h" + +#include <papiUtils.h> + +#include <stdio.h> +#include <sys/types.h> +#include <time.h> +#include <syslog.h> + +#define SCRIPT_DISABLE "#!/bin/sh\n \ +/sbin/chkconfig apocd off\n \ +exit $?\n" + +#define SCRIPT_ENABLE "#!/bin/sh\n \ +/sbin/chkconfig apocd on\n \ +exit $?\n" + +#define SCRIPT_ISENABLED "#!/bin/sh\n \ +/sbin/chkconfig -c apocd\n \ +exit $?\n" + +static int execute( const char * inCommand ); + +Status osDaemonDisable( void ) +{ + Status theRC; + writeInitialMessage( sOpDisable ); + theRC = execute( SCRIPT_DISABLE ) == 0 ? sStatusOK : sErrorGeneric; + writeFinalMessage( sOpDisable, theRC ); + if ( theRC == sStatusOK && daemonStatus( 1 ) == sStatusOK ) + { + theRC = daemonStop(); + } + return theRC; +} + +Status osDaemonEnable( void ) +{ + Status theRC; + writeInitialMessage( sOpEnable ); + theRC = execute( SCRIPT_ENABLE ) == 0 ? sStatusOK : sErrorGeneric; + writeFinalMessage( sOpEnable, theRC ); + if ( theRC == sStatusOK && daemonStatus( 1 ) != sStatusOK ) + { + theRC = daemonStart(); + } + return theRC; +} + +Status osDaemonIsEnabled( inQuiet ) +{ + Status theRC; + if (inQuiet == 0) { writeInitialMessage( sOpIsEnabled ); } + theRC = execute( SCRIPT_ISENABLED ) == 0 ? + sStatusEnabled : sStatusNotEnabled; + if (inQuiet == 0) { writeFinalMessage( sOpIsEnabled, theRC ); } + return theRC; +} + +int osDaemonShouldRestart( void ) +{ + static int sFailureIndex = 0; + static time_t sFailureTimes[ 4 ]; + time_t theFailureTime = time( 0 ); + int bShouldRestart = 1; + + if ( sFailureIndex == 4 ) + { + if ( theFailureTime - sFailureTimes[ 0 ] < 60 ) + { + bShouldRestart = 0; + } + else + { + sFailureTimes[ 0 ] = sFailureTimes[ 1 ]; + sFailureTimes[ 1 ] = sFailureTimes[ 2 ]; + sFailureTimes[ 2 ] = sFailureTimes[ 3 ]; + sFailureTimes[ 3 ] = theFailureTime; + } + } + else + { + sFailureTimes[ sFailureIndex ++ ] = theFailureTime; + } + if ( bShouldRestart == 0 ) + { + syslog( LOG_WARNING, "Too many Configuration Agent failures in the last 60 seconds. Not restarting." ); + } + return bShouldRestart; +} + +Status osDaemonStart( void ) +{ + return daemonStart(); +} + +Status osDaemonStop( void ) +{ + return daemonStop(); +} + +Status osDaemonSvcStart( void ) +{ + close( 0 ); close( 1 ); close( 2 ); + return daemonStart(); +} + +Status osDaemonSvcStop( void ) +{ + return daemonStop(); +} + + +int execute( const char * inCommand ) +{ + int theRC = -1; + char * theFileName = tmpnam( 0 ); + FILE * theFile = fopen( theFileName, "w" ); + + if ( theFile != 0 ) + { + char theBuf[ BUFSIZ ]; + + fprintf( theFile, "%s", inCommand ); + fclose( theFile ); + chmod( theFileName, 0700 ); + + theFile = papiPopen( theFileName, "r" ); + if ( theFile != 0 ) + { + while ( 1 ) + { + if ( fgets( theBuf, BUFSIZ, theFile ) == 0 ) + { + break; + } + } + theRC = papiPclose( theFile ); + unlink( theFileName ); + } + } + return theRC; +} diff --git a/apocd/solaris.c b/apocd/solaris.c new file mode 100644 index 0000000..4552a49 --- /dev/null +++ b/apocd/solaris.c @@ -0,0 +1,178 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include "apocd.h" + +#include <libscf.h> +#include <stdlib.h> +#include <string.h> + +static const char * sInstanceName = "svc:/network/apocd/udp:default"; + +static Status osEnabler( int inEnable, int inOneTime, int inQuiet ); + +Status osDaemonDisable( void ) +{ + return osEnabler( 0, 0, 0 ); +} + +Status osDaemonEnable( void ) +{ + return osEnabler( 1, 0, 0 ); +} + +Status osDaemonIsEnabled( int inQuiet ) +{ + Status isEnabled = sStatusNotEnabled; + scf_handle_t * theHandle = scf_handle_create( SCF_VERSION ); + if (inQuiet == 0) { writeInitialMessage( sOpIsEnabled ); } + if ( theHandle != 0 ) + { + if ( scf_handle_bind( theHandle ) == 0 ) + { + scf_instance_t * theInstance = scf_instance_create( theHandle ); + if ( theInstance != 0 ) + { + if ( scf_handle_decode_fmri( + theHandle, + sInstanceName, + 0, + 0, + theInstance, + 0, + 0, + SCF_DECODE_FMRI_EXACT ) != -1 ) + { + scf_handle_t * theInstanceHandle = + scf_instance_handle( theInstance ); + if ( theInstanceHandle != 0 ) + { + uint8_t theEnabled; + scf_propertygroup_t * theGroup = + scf_pg_create( theInstanceHandle ); + scf_property_t * theProp = + scf_property_create( theInstanceHandle ); + scf_value_t * theValue = + scf_value_create( theInstanceHandle ); + if ( theGroup != 0 && theProp != 0 && theValue != 0 ) + { + if ( scf_instance_get_pg( theInstance, + SCF_PG_GENERAL, + theGroup ) == 0 && + scf_pg_get_property( theGroup, + SCF_PROPERTY_ENABLED, + theProp ) == 0 && + scf_property_get_value( theProp, + theValue ) == 0 && + scf_value_get_boolean( theValue, + &theEnabled ) == 0 ) + { + isEnabled = theEnabled == 1 ? + sStatusEnabled : sStatusNotEnabled; + } + } + scf_pg_destroy( theGroup ); + scf_property_destroy( theProp ); + scf_value_destroy( theValue ); + } + } + scf_instance_destroy( theInstance ); + } + } + scf_handle_destroy( theHandle ); + } + if (inQuiet == 0) { writeFinalMessage( sOpIsEnabled, isEnabled ); } + return isEnabled; +} + +Status osDaemonStart( void ) +{ + Status theRC; + writeInitialMessage( sOpStart ); + osEnabler( 1, 1, 1 ); + theRC = daemonWaitStatus( sStatusOK, 30 ); + writeFinalMessage( sOpStart, theRC ); + return theRC; +} + +Status osDaemonStop( void ) +{ + Status theRC; + writeInitialMessage( sOpStop ); + osEnabler( 0, 1, 1 ); + theRC = daemonWaitStatus( sStatusNotRunning, 20 ) == sStatusNotRunning ? + sStatusOK : sErrorGeneric; + writeFinalMessage( sOpStop, theRC ); + return theRC; +} + +Status osDaemonSvcStart( void ) +{ + return daemonStart(); +} + +Status osDaemonSvcStop( void ) +{ + return daemonStop(); +} + +Status osEnabler( int inEnable, int inOneTime, int inQuiet ) +{ + Status theStatus; + DaemonOp theOp = inEnable == 1 ? sOpEnable : sOpDisable; + int theFlags = inOneTime == 1 ? SMF_TEMPORARY : 0; + + if ( inQuiet == 0 ) + { + writeInitialMessage( theOp ); + } + if ( theOp == sOpEnable ) + { + theStatus = + smf_enable_instance( sInstanceName, theFlags ) == SCF_SUCCESS ? + sStatusOK : sErrorGeneric; + } + else + { + theStatus = + smf_disable_instance( sInstanceName, theFlags ) == SCF_SUCCESS ? + sStatusOK : sErrorGeneric; + } + if ( inQuiet == 0 ) + { + writeFinalMessage( theOp, theStatus ); + } + return theStatus; +} diff --git a/apocd/win32/apocdctl.c b/apocd/win32/apocdctl.c new file mode 100644 index 0000000..3081284 --- /dev/null +++ b/apocd/win32/apocdctl.c @@ -0,0 +1,1393 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include <papi/papiUtils.h> + +#include <stdlib.h> +#include <stdio.h> + +#ifndef WNT +#include <sys/socket.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <inttypes.h> +#include <strings.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/stat.h> +#endif + +typedef unsigned char daemonOp; + +static int authenticate( PAPISocket inSocket ); + +static int doDisable( int inQuite ); + +static int doEnable( void ); + +static int doGeneric( daemonOp inOp, int inQuiet ); + +static int doIsEnabled( void ); + +static int doOp( daemonOp inOp ); + +static int doServiceOp( void * inService, int inOp ); + +#ifndef WNT +static int doStart( int inQuite ); +#else +static int doStart( int inQuite, HANDLE * outHandle ); +#endif + +static int doStop( void ); + +static int doRestart( void ); + +static void * getService( void ); + +static int getResponse( int inSocket, char * outResponse ); + +static void invalidArg( const char * inArg ); + +static void putEnv( void ); + +static int sendRequest( int inSocket, + const unsigned char * inRequest ); + +static daemonOp stringToDaemonOp( const char * inString ); + +static void usage( void ); + +static void writeInitialMessage( daemonOp inOp ); + +static void writeFinalMessage( daemonOp inOp, int inStatus ); + +#ifndef WNT + +static int doInetdDisable( void ); + +static int doInetdEnable( void ); + +static int doInetdStart( void ); + +static pid_t getPid( void ); + +static const char * getPidFile( void ); + +static int isInetdRunning( void ); + +static void killPid( void ); + +static void putPid( void ); + +static const char * sPidFile = ".pid"; + +#ifdef LINUX + +#define SCRIPT_DISABLE "#!/bin/sh\n \ +if [ -f /etc/inetd.conf ] ; then\n \ + grep -v apocd /etc/inetd.conf > /tmp/inetd.conf\n \ + cp /tmp/inetd.conf /etc/inetd.conf\n \ + rm -f /tmp/inetd.conf\n \ + /etc/init.d/inetd status > /dev/null 2>&1\n \ + if [ $? -eq 0 ] ; then\n \ + /etc/init.d/inetd restart\n \ + fi\n \ +fi\n \ +exit 0\n" + +#define SCRIPT_ENABLE "#!/bin/sh\n \ +if [ -f /etc/inetd.conf ] ; then\n \ + grep -v apocd /etc/inetd.conf > /tmp/inetd.conf\n \ + cp /tmp/inetd.conf /etc/inetd.conf\n \ + rm -f /tmp/inetd.conf\n \ + echo \"apocd dgram udp wait root /usr/lib/apoc/apocd apocd inetdStart\" >> /etc/inetd.conf\n\ + /etc/init.d/inetd status > /dev/null 2>&1\n \ + if [ $? -eq 0 ] ; then\n \ + /etc/init.d/inetd restart\n \ + fi\n \ +fi\n \ +exit 0\n" + +#else + +#define SCRIPT_DISABLE "#!/bin/sh\n \ +if [ -f /etc/inetd.conf ] ; then\n \ + grep -v apocd /etc/inetd.conf > /tmp/inetd.conf\n \ + cp /tmp/inetd.conf /etc/inetd.conf\n \ + rm -f /tmp/inetd.conf\n \ + pkill -HUP inetd > /dev/null 2>&1\n \ +fi\n \ +exit 0\n" + +#define SCRIPT_ENABLE "#!/bin/sh\n \ +if [ -f /etc/inetd.conf ] ; then\n \ + grep -v apocd /etc/inetd.conf > /tmp/inetd.conf\n \ + cp /tmp/inetd.conf /etc/inetd.conf\n \ + rm -f /tmp/inetd.conf\n \ + echo \"apocd dgram udp wait root /usr/lib/apoc/apocd apocd inetdStart\" >> /etc/inetd.conf\n\ + pkill -HUP inetd > /dev/null 2>&1\n \ +fi\n \ +exit 0\n" + +#endif + +#else + +#include <windows.h> + +typedef WINADVAPI BOOL ( WINAPI *ChangeServiceConfig2Func )( SC_HANDLE, DWORD, LPVOID ); + +typedef WINADVAPI BOOL ( WINAPI *CloseServiceHandleFunc )( SC_HANDLE ); + +typedef WINADVAPI BOOL ( WINAPI *ControlServiceFunc )( SC_HANDLE, DWORD, LPSERVICE_STATUS ); + +typedef WINADVAPI SC_HANDLE ( WINAPI *CreateServiceFunc )( SC_HANDLE, + LPCTSTR, + LPCTSTR, + DWORD, + DWORD, + DWORD, + DWORD, + LPCTSTR, + LPCTSTR, + LPDWORD, + LPCTSTR, + LPCTSTR, + LPCTSTR ); + +typedef WINADVAPI BOOL ( WINAPI *DeleteServiceFunc )( SC_HANDLE ); + +typedef WINADVAPI SC_HANDLE ( WINAPI *OpenSCManagerFunc )( LPCTSTR, LPCTSTR, DWORD ); + +typedef WINADVAPI SC_HANDLE ( WINAPI *OpenServiceFunc )( SC_HANDLE, LPCTSTR, DWORD ); + +typedef WINADVAPI BOOL ( WINAPI *SetServiceStatusFunc )( SERVICE_STATUS_HANDLE, LPSERVICE_STATUS ); + +typedef WINADVAPI SERVICE_STATUS_HANDLE ( WINAPI *RegisterServiceCtrlHandlerFunc )( LPCTSTR, LPHANDLER_FUNCTION ); + +typedef WINADVAPI BOOL ( WINAPI *StartServiceFunc )( SC_HANDLE, DWORD, LPCTSTR * ); + +typedef WINADVAPI BOOL ( WINAPI *StartServiceCtrlDispatcherFunc )( CONST LPSERVICE_TABLE_ENTRY ); + +ChangeServiceConfig2Func fChangeServiceConfig2; +CloseServiceHandleFunc fCloseServiceHandle; +ControlServiceFunc fControlService; +CreateServiceFunc fCreateService; +DeleteServiceFunc fDeleteService; +OpenSCManagerFunc fOpenSCManager; +OpenServiceFunc fOpenService; +RegisterServiceCtrlHandlerFunc fRegisterServiceCtrlHandler; +SetServiceStatusFunc fSetServiceStatus; +StartServiceFunc fStartService; +StartServiceCtrlDispatcherFunc fStartServiceCtrlDispatcher; + +static int doRegistryDisable( void ); + +static int doRegistryEnable( void ); + +static int doServiceDisable( void ); + +static int doServiceEnable( void ); + +static DWORD getServiceStatus( void ); + +static int loadServiceFuncs( void ); + +static void serviceCtrlHandler( DWORD inOpCode ); + +static void serviceMain( DWORD inArgc, LPTSTR * inArgv ); + +static void serviceRestartLoop( HANDLE inHandle ); + +static void setServiceStatus( DWORD inStatus ); + +static const char * sServiceProgram = "apocd.exe"; + +static const char * sServiceName = "apocd"; + +static const char * sServiceDisplayName = "Configuration Agent"; + +static const char * sServiceDescription = "Maintains locally cached policy data"; + +SERVICE_STATUS_HANDLE gServiceStatusHandle; + +SERVICE_STATUS gServiceStatus; + +PAPIMutex * gServiceStatusMutex; + +#endif + +static const char * sArgChangeDetect = "change-detect"; +static const char * sArgDisable = "disable"; +static const char * sArgEnable = "enable"; +static const char * sArgInetdStart = "inetdStart"; +static const char * sArgIsEnabled = "is-enabled"; +static const char * sArgReload = "reload"; +static const char * sArgRestart = "restart"; +static const char * sArgStart = "start"; +static const char * sArgStatus = "status"; +static const char * sArgStop = "stop"; + +static unsigned char sOpUndefined = 0; +static unsigned char sOpChangeDetect = 1; +static unsigned char sOpDisable = 2; +static unsigned char sOpEnable = 3; +static unsigned char sOpInetdStart = 4; +static unsigned char sOpIsEnabled = 5; +static unsigned char sOpReload = 6; +static unsigned char sOpRestart = 7; +static unsigned char sOpStart = 8; +static unsigned char sOpStatus = 9; +static unsigned char sOpStop = 10; + +static int sStatusOK = 0; +static int sStatusEnabled = 0; +static int sErrorGeneric = 1; +static int sStatusNotEnabled = 1; +static int sErrorInvalidArg = 2; +static int sStatusNotRunning = 3; +static int sStatusEnabledWithWarning = 4; +static int sErrorNotRunning = 7; +static int sErrorAuthentication = 8; + +static int sLocalCredentialsBufferSize = 21; + +int main( int inArgc, char ** inArgv ) +{ + int theRC; + int newerThanWindows98 = 0; + +#ifdef WNT + if ( isNewerThanWindows98() == 1 ) + { + newerThanWindows98 = 1; + loadServiceFuncs(); + gServiceStatusMutex = newMutex(); + } + if ( inArgc == 1 && newerThanWindows98 == 1 ) + { + SERVICE_TABLE_ENTRY theServiceTable[] = + { + { ( char *)sServiceName, ( LPSERVICE_MAIN_FUNCTION )serviceMain }, + { NULL, NULL } + }; + fStartServiceCtrlDispatcher( theServiceTable ); + } +#endif + + if ( inArgc == 2 ) + { + daemonOp theOp = stringToDaemonOp( inArgv[ 1 ] ); + if ( theOp == sOpUndefined ) + { + invalidArg( inArgv[ 1 ] ); + theRC = sErrorInvalidArg; + } + else + { + theRC = doOp( theOp ); + } + } + else + { + usage(); + theRC = sErrorInvalidArg; + } + return theRC; +} + +int authenticate( PAPISocket inSocket ) +{ + int theRC = sErrorAuthentication; + char theChallenge[ BUFSIZ ]; + int theIndex = 0; + + theChallenge[ 0 ] = 0; + while ( recv( inSocket, &theChallenge[ theIndex ++ ], 1, 0 ) != -1 ) + { + if ( theChallenge[ theIndex - 1 ] == 0 ) + { + if ( theChallenge[ 0 ] != 0 ) + { + FILE * theFile = fopen( theChallenge, "r" ); + if ( theFile != 0 ) + { + char * theCredentials = + ( char * )malloc( sLocalCredentialsBufferSize ); + if ( theCredentials != 0 ) + { + if ( fgets( theCredentials, + sLocalCredentialsBufferSize, + theFile ) != 0 ) + { + if ( send( inSocket, + theCredentials, + sLocalCredentialsBufferSize - 1, + 0 ) == ( sLocalCredentialsBufferSize - 1 ) ) + { + char theResponse; + if ( getResponse(inSocket,&theResponse)!= -1 && + theResponse == 0 ) + { + theRC = sStatusOK; + } + } + } + free( ( void * )theCredentials ); + } + fclose( theFile ); +#ifdef WNT + remove( theChallenge ); +#endif + } + } + break; + } + } + return theRC; +} + +int doGeneric( daemonOp inOp, int inQuiet ) +{ + int theRC; + PAPISocket theSocket; + PAPIConnectResult theConnectResult = + getConnectedSocket( getDaemonAdminPort(), SOCK_STREAM, 0, &theSocket ); + + if ( inQuiet != 1 ) + { + writeInitialMessage( inOp ); + } + if ( theConnectResult == PAPIConnectSuccess ) + { + if ( ( theRC = authenticate( theSocket ) ) == sStatusOK ) + { + if ( ( theRC = sendRequest( theSocket, &inOp ) ) != -1 ) + { + char theResponse; + theRC = getResponse( theSocket, &theResponse ); + } + if ( theRC == -1 ) + { + theRC = inOp == sOpStatus ? + sStatusNotRunning : sErrorNotRunning; + } + else + { + theRC = sStatusOK; + } + } + papiClose( theSocket ); + } + else + { + theRC = sStatusNotRunning; + } + if ( inQuiet != 1 ) + { + writeFinalMessage( inOp, theRC ); + } + return theRC; +} + +int doIsEnabled() +{ + int theRC = isDaemonEnabled() == 1 ? sStatusEnabled : sStatusNotEnabled; + writeInitialMessage( sOpIsEnabled ); + writeFinalMessage( sOpIsEnabled, theRC ); + return theRC; +} + +int doOp( daemonOp inOp ) +{ + int theRC; + + if ( inOp == sOpDisable ) + { + theRC = doDisable( 0 ); + } + else if ( inOp == sOpEnable ) + { + theRC = doEnable(); + } +#ifndef WNT + else if ( inOp == sOpInetdStart ) + { + theRC = doInetdStart(); + } +#endif + else if ( inOp == sOpIsEnabled ) + { + theRC = doIsEnabled(); + } + else if ( inOp == sOpStart || inOp == sOpStop || inOp == sOpRestart ) + { + void * theService = getService(); + if ( theService != 0 ) + { + theRC = doServiceOp( theService, inOp ); + } + else + { + if ( inOp == sOpStart ) + { +#ifndef WNT + theRC = doStart( 0 ); +#else + theRC = doStart( 0, 0 ); +#endif + } + else if ( inOp == sOpStop ) + { + theRC = doStop(); + } + else if ( inOp == sOpRestart ) + { + theRC = doRestart(); + } + } + } + else + { + theRC = doGeneric( inOp, 0 ); + } + return theRC; +} + +int doServiceOp( void * inService, int inOp ) +{ + int theRC = sStatusOK; +#ifdef WNT + if ( inOp == sOpStop || inOp == sOpRestart ) + { + SERVICE_STATUS theServiceStatus; + BOOL theStatus; + + writeInitialMessage( sOpStop ); + theStatus = + fControlService( inService, SERVICE_CONTROL_STOP, &theServiceStatus ); + if ( theStatus == 0 && + GetLastError() != ERROR_SERVICE_NOT_ACTIVE ) + { + theRC = sErrorGeneric; + } + writeFinalMessage( sOpStop, theRC ); + } + if ( inOp == sOpStart || ( inOp == sOpRestart && theRC == sStatusOK ) ) + { + BOOL theStatus; + + writeInitialMessage( sOpStart ); + theStatus = fStartService( inService, 0, NULL ); + if ( theStatus == 0 && + GetLastError() != ERROR_SERVICE_ALREADY_RUNNING ) + { + theRC = sErrorGeneric; + } + writeFinalMessage( sOpStart, theRC ); + } +#endif + return theRC; +} + +#ifndef WNT +int doStart( int inQuiet ) +#else +int doStart( int inQuiet, HANDLE * outHandle ) +#endif +{ + static char * theFormat = + "java -Djava.library.path=%s -cp %s%sapocd.jar%s%s%sdb.jar%s%s%sldapjdk.jar%s%s%sspi.jar com.sun.apoc.daemon.apocd.Daemon %s %s"; + static char * theCommand = 0; + int theRC = sStatusOK; + + if ( inQuiet != 1 ) + { + writeInitialMessage( sOpStart ); + } + if ( isDaemonEnabled() == 1 ) + { + putEnv(); + if ( theCommand == 0 ) + { + const char * theDaemonInstallDir = getDaemonInstallDir(); + const char * theDaemonLibraryDir = getDaemonLibraryDir(); + const char * theDaemonPropertiesDir = getDaemonPropertiesDir(); + theCommand = + ( char * )malloc( ( strlen( theDaemonInstallDir ) * 5 ) + + strlen( theDaemonLibraryDir ) + + strlen( theDaemonPropertiesDir ) + + ( strlen( FILESEP ) * 4 ) + + ( strlen( PATHSEP ) * 3 ) + + strlen( theFormat ) + 1 ); + if ( theCommand != 0 ) + { + sprintf( theCommand, + theFormat, + theDaemonLibraryDir, + theDaemonInstallDir, FILESEP, PATHSEP, + theDaemonInstallDir, FILESEP, PATHSEP, + theDaemonInstallDir, FILESEP, PATHSEP, + theDaemonInstallDir, FILESEP, + theDaemonInstallDir, + theDaemonPropertiesDir ); + } + } + if ( theCommand != 0 ) + { +#ifndef WNT + if ( papiPopen( theCommand, "w" ) == 0 ) + { + theRC = sErrorGeneric; + } +#else + STARTUPINFO theStartupInfo; + PROCESS_INFORMATION theProcessInfo; + + + ZeroMemory( &theStartupInfo, sizeof( theStartupInfo ) ); + theStartupInfo.dwFlags = STARTF_USESHOWWINDOW; + theStartupInfo.wShowWindow = SW_HIDE; + theStartupInfo.cb = sizeof( theStartupInfo ); + ZeroMemory( &theProcessInfo, sizeof( theProcessInfo ) ); + if ( CreateProcess( 0, + theCommand, + 0, + 0, + FALSE, + 0, + 0, + 0, + &theStartupInfo, + &theProcessInfo ) == 0 ) + { + theRC = sErrorGeneric; + } + else if ( outHandle != 0 ) + { + *outHandle = theProcessInfo.hProcess; + } +#endif + } + else + { + theRC = sErrorGeneric; + } + } + else + { + theRC = sErrorGeneric; + } + if ( inQuiet != 1 ) + { + writeFinalMessage( sOpStart, theRC ); + } + return theRC; +} + +int doStop( void ) +{ + int theRC; + writeInitialMessage( sOpStop ); + theRC = doGeneric( sOpStatus, 1 ); + if ( theRC != sErrorAuthentication ) + { + if ( theRC == sStatusNotRunning ) + { + theRC = sStatusOK; + } + else + { + theRC = doGeneric( sOpStop, 1 ); + } + } + writeFinalMessage( sOpStop, theRC ); +#ifndef WNT + if ( theRC == sStatusOK ) + { + killPid(); + } +#endif + return theRC; +} + +void * getService( void ) +{ +#ifndef WNT + return 0; +#else + if ( isNewerThanWindows98() == 0 ) + { + return 0; + } + else + { + SC_HANDLE theService = NULL; + SC_HANDLE theServiceManager = + fOpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS ); + if ( theServiceManager != NULL ) + { + theService = fOpenService( theServiceManager, + sServiceName, + GENERIC_EXECUTE ); + } + return theService; + } +#endif +} + +int doRestart( void ) +{ + doGeneric( sOpStop, 0 ); +#ifndef WNT + return doStart( 0 ); +#else + return doStart( 0, 0 ); +#endif +} + +int getResponse( int inSocket, char * outResponse ) +{ + return recv( inSocket, + outResponse, + 1, + 0 ); +} + +void invalidArg( const char * inOp ) +{ + if ( inOp != 0 ) + { + fprintf( stderr, "Invalid argument '%s'\n", inOp ); + } + usage(); +} + +void putEnv( void ) +{ + char * theJavaHome = getenv( "JAVA_HOME" ); + + if ( theJavaHome != 0 ) + { + char * theJavaPath = ( char * )malloc( strlen( theJavaHome ) + + 4 + + strlen( FILESEP ) ); + if ( theJavaPath != 0 ) + { + char * thePath = getenv( "PATH" ); + char * theNewPath; + sprintf( theJavaPath, "%s%sbin", theJavaHome, FILESEP ); + theNewPath = ( char * )malloc( strlen( theJavaPath ) + + strlen( PATHSEP ) + + strlen( thePath ) + + 6 ); + if ( theNewPath != 0 ) + { + sprintf( theNewPath, + "PATH=%s%s%s", + theJavaPath, + PATHSEP, + thePath ); + putenv( theNewPath ); + free( ( void * )theJavaPath ); + } + } + } + papiUmask( 022 ); +} + +int sendRequest( int inSocket, + const unsigned char * inRequest ) +{ + return send( inSocket, inRequest, 1, 0 ); +} + +daemonOp stringToDaemonOp( const char * inString ) +{ + daemonOp theDaemonOp = sOpUndefined; + if ( strcmp( inString, sArgChangeDetect ) == 0 ) + { + theDaemonOp = sOpChangeDetect; + } + else if ( strcmp( inString, sArgDisable ) == 0 ) + { + theDaemonOp = sOpDisable; + } + else if ( strcmp( inString, sArgEnable ) == 0 ) + { + theDaemonOp = sOpEnable; + } + else if ( strcmp( inString, sArgInetdStart ) == 0 ) + { + theDaemonOp = sOpInetdStart; + } + else if ( strcmp( inString, sArgIsEnabled ) == 0 ) + { + theDaemonOp = sOpIsEnabled; + } + else if ( strcmp( inString, sArgReload ) == 0 ) + { + theDaemonOp = sOpReload; + } + else + if ( strcmp( inString, sArgRestart ) == 0 ) + { + theDaemonOp = sOpRestart; + } + else + if ( strcmp( inString, sArgStart ) == 0 ) + { + theDaemonOp = sOpStart; + } + else if ( strcmp( inString, sArgStatus ) == 0 ) + { + theDaemonOp = sOpStatus; + } + else + if ( strcmp( inString, sArgStop ) == 0 ) + { + theDaemonOp = sOpStop; + } + return theDaemonOp; +} + +void usage( void ) +{ + fprintf( stderr, + "%s", + "Usage: apocdctl change-detect | disable | enable | is-enabled | reload | restart | start | status | stop\n" ); +} + +void writeInitialMessage( daemonOp inOp ) +{ + if ( inOp == sOpChangeDetect ) + { + printf( "Requesting a Configuration Agent change detection ... " ); + } + else if ( inOp == sOpDisable ) + { + printf( "Disabling Configuration Agent ... "); + } + else if ( inOp == sOpEnable ) + { + printf( "Enabling Configuration Agent ... "); + } + else if ( inOp == sOpIsEnabled ) + { + printf( "Checking Configuration Agent enabled status ... " ); + } + else if ( inOp == sOpReload ) + { + printf( "Reloading Configuration Agent ... " ); + } + else if ( inOp == sOpStatus ) + { + printf( "Checking Configuration Agent status ... " ); + } + else if ( inOp == sOpStart ) + { + printf( "Starting Configuration Agent ... " ); + } + else if ( inOp == sOpStop ) + { + printf( "Stopping Configuration Agent ... " ); + } +} + +void writeFinalMessage( daemonOp inOp, int inStatus ) +{ + if ( inStatus == sErrorAuthentication ) + { + printf( "Failed\n" ); + } + else if ( inOp == sOpIsEnabled ) + { + printf( "%s\n", inStatus == sStatusEnabled ? "Enabled" : "Not enabled"); + } + else if ( inOp == sOpStatus ) + { + printf( "%s\n", inStatus == sStatusOK ? "Running" : "Not running" ); + } + else if ( inOp == sOpStop ) + { + printf( inStatus == sStatusOK || inStatus == sErrorNotRunning ? + "OK\n" : "Failed\n" ); + } + else + { + printf( inStatus == sStatusOK ? "OK\n" : "Failed\n" ); + } +} + +#ifndef WNT + +int doDisable( int inQuite ) +{ + int theRC; + if ( inQuite != 1 ) + { + writeInitialMessage( sOpDisable ); + } +#ifdef SOLARIS + if ( haveService() != 0 ) + { + theRC = doServiceDisable(); + } + else + { + theRC = doInetdDisable(); + } +#else + theRC = doInetdDisable(); +#endif + if ( inQuite != 1 ) + { + writeFinalMessage( sOpDisable, theRC ); + } + doStop(); + return theRC; +} + +int doInetdDisable() +{ + char * theFileName = tmpnam( 0 ); + FILE * theFile; + int theRC = sErrorGeneric; + + theFile = fopen( theFileName, "w" ); + if ( theFile != 0 ) + { + FILE * theStream; + char theBuf[ BUFSIZ ]; + + fprintf( theFile, "%s", SCRIPT_DISABLE ); + fclose( theFile ); + chmod( theFileName, 0700 ); + theStream = papiPopen( theFileName, "r" ); + if ( theStream != 0 ) + { + while ( 1 ) + { + if ( fgets( theBuf, BUFSIZ, theStream ) == 0 ) + { + break; + } + } + theRC = papiPclose( theStream ); + } + unlink( theFileName ); + } + return theRC; +} + +int doEnable( void ) +{ + int theRC; + + writeInitialMessage( sOpEnable ); +#ifdef SOLARIS + if ( haveService() != 0 ) + { + theRC = doServiceEnable(); + } + else + { + theRC = doInetdEnable(); + } +#else + theRC = doInetdEnable(); +#endif + writeFinalMessage( sOpEnable, theRC ); + if ( theRC == sStatusOK && isInetdRunning() != 1 ) + { + fprintf( stderr, + "%s\n", + "Warning: inetd is not running and must be started if you want the" ); + fprintf( stderr, + "%s\n", + " Configuration Agent to start automatically." ); + theRC = sStatusEnabledWithWarning; + } + return theRC; +} + +int doInetdEnable( void ) +{ + char * theFileName = tmpnam( 0 ); + FILE * theFile; + int theRC = sErrorGeneric; + + theFile = fopen( theFileName, "w" ); + if ( theFile != 0 ) + { + FILE * theStream; + char theBuf[ BUFSIZ ]; + + fprintf( theFile, "%s", SCRIPT_ENABLE ); + fclose( theFile ); + chmod( theFileName, 0700 ); + theStream = papiPopen( theFileName, "r" ); + if ( theStream != 0 ) + { + while ( 1 ) + { + if ( fgets( theBuf, BUFSIZ, theStream ) == 0 ) + { + break; + } + } + theRC = papiPclose( theStream ); + } + unlink( theFileName ); + } + return theRC; +} + +int doInetdStart( void ) +{ + if ( doStart( 1 ) == sStatusOK ) + { + putPid(); + while ( 1 ) + { + getchar(); + } + } + return 0; +} + +pid_t getPid( void ) +{ + pid_t thePid = 0; + const char * thePidFile = getPidFile(); + if ( thePidFile != 0 ) + { + FILE * thePidStream = fopen( thePidFile, "r" ); + if ( thePidStream != 0 ) + { + fscanf( thePidStream, "%d", &thePid ); + fclose( thePidStream ); + } + free( ( void * )thePidFile ); + } + return thePid; +} + +const char * getPidFile( void ) +{ + const char * thePidDir = getDaemonInstallDir(); + char * thePidFile = + ( char * )malloc( strlen( thePidDir ) + + ( 2 * strlen( FILESEP ) ) + + strlen( sPidFile ) + + 4 ); + if ( thePidFile != 0 ) + { + sprintf( thePidFile, + "%s%s%s", + thePidDir, + FILESEP, + sPidFile ); + } + return thePidFile; +} + +int isInetdRunning( void ) +{ + int theRC = 0; + static const char * theCommand = "/bin/ps -e | /bin/grep inetd "; + FILE * theStream = papiPopen( theCommand, "r" ); + + if ( theStream != 0 ) + { + char theBuffer[ BUFSIZ ]; + + while ( fgets( theBuffer, BUFSIZ, theStream ) != 0 ){} + theRC = papiPclose( theStream ) == 0 ? 1 : 0; + } + return theRC; +} + +void killPid( void ) +{ + pid_t thePid = getPid(); + if ( thePid > 0 ) + { + kill( thePid, SIGINT ); + } + unlink( getPidFile() ); +} + +void putPid( void ) +{ + const char * thePidFile = getPidFile(); + if ( thePidFile != 0 ) + { + FILE * thePidStream = fopen( thePidFile, "w" ); + if ( thePidStream != 0 ) + { + chmod( thePidFile, 0600 ); + fprintf( thePidStream, "%d", getpid() ); + fclose( thePidStream ); + } + free( ( void * )thePidFile ); + } +} + +#else + +int doDisable( int inQuiet ) +{ + int theRC; + int newerThanWindows98 = isNewerThanWindows98(); + + if ( newerThanWindows98 == 1 ) + { + doServiceOp( getService(), sOpStop ); + theRC = doServiceDisable(); + } + else + { + theRC = doRegistryDisable(); + doStop(); + } + return theRC; +} + +int doRegistryDisable( void ) +{ + int theRC; + LONG theStatus; + + writeInitialMessage( sOpDisable ); + theStatus = RegDeleteKey( HKEY_LOCAL_MACHINE, APOCENABLEDKEY ); + theRC = theStatus == ERROR_SUCCESS || theStatus == ERROR_FILE_NOT_FOUND ? + sStatusOK : sErrorGeneric; + writeFinalMessage( sOpDisable, theRC ); + return theRC; +} + +int doServiceDisable( void ) +{ + int theRC = sErrorGeneric; + SC_HANDLE theServiceManager; + + if ( isNewerThanWindows98() == 1 ) + { + theServiceManager = fOpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS ); + writeInitialMessage( sOpDisable ); + if ( theServiceManager != 0 ) + { + SC_HANDLE theService = fOpenService( theServiceManager, + sServiceName, + DELETE ); + if ( theService != 0 ) + { + if ( fDeleteService( theService ) == TRUE || + GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE ) + { + theRC = sStatusOK; + } + fCloseServiceHandle( theService ); + } + else + { + if ( GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST ) + { + theRC = sStatusOK; + } + } + fCloseServiceHandle( theServiceManager ); + } + else + { + theRC = sStatusOK; + } + } + writeFinalMessage( sOpDisable, theRC ); + return theRC; +} + +int doEnable( void ) +{ + int theRC; + int newerThanWindows98 = isNewerThanWindows98(); + + writeInitialMessage( sOpEnable ); + theRC = newerThanWindows98 == 1 ? + doServiceEnable() : doRegistryEnable(); + writeFinalMessage( sOpEnable, theRC ); + + if ( newerThanWindows98 == 1 && theRC == sStatusOK ) + { + theRC = doServiceOp( getService(), sOpStart ); + } + return theRC; +} + +int doServiceEnable( void ) +{ + int theRC = sErrorGeneric; + char * theDaemonInstallDir = getDaemonInstallDir(); + char * theServiceProgram = + ( char * )malloc( strlen( theDaemonInstallDir ) + + strlen( FILESEP ) + + strlen( sServiceProgram ) + + 1 ); + if ( theServiceProgram != 0 ) + { + SC_HANDLE theServiceManager; + char * theCP = ( char * )theDaemonInstallDir + + strlen( theDaemonInstallDir ) - 1; + while ( theCP-- != theDaemonInstallDir ) + { + if ( *theCP == '\\' ) + { + *( ++theCP ) = 0; + break; + } + } + sprintf( theServiceProgram, + "%sbin%s%s", + theDaemonInstallDir, + FILESEP, + sServiceProgram ); + theServiceManager = fOpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS ); + if ( theServiceManager != 0 ) + { + SC_HANDLE theService = + fCreateService( theServiceManager, + sServiceName, + sServiceDisplayName, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + theServiceProgram, + 0, + 0, + 0, + 0, + 0 ); + if ( theService != 0 ) + { + fChangeServiceConfig2( theService, + SERVICE_CONFIG_DESCRIPTION, + ( LPVOID )&sServiceDescription ); + theRC = sStatusOK; + fCloseServiceHandle( theService ); + } + else + { + if ( GetLastError() == ERROR_SERVICE_EXISTS ) + { + theRC = sStatusOK; + } + } + fCloseServiceHandle( theServiceManager ); + } + free( ( void * )theServiceProgram ); + } + return theRC; +} + +int doRegistryEnable( void ) +{ + int theRC = sErrorGeneric; + HKEY theKey; + DWORD theDisposition; + + if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, + APOCENABLEDKEY, + 0, + 0, + 0, + KEY_WRITE, + 0, + &theKey, + &theDisposition ) == ERROR_SUCCESS ) + { + RegCloseKey( theKey ); + theRC = sStatusOK; + } + return theRC; +} + +DWORD getServiceStatus( void ) +{ + DWORD theStatus = -1; + if ( lockMutex( gServiceStatusMutex ) == 0 ) + { + theStatus = gServiceStatus.dwCurrentState; + unlockMutex( gServiceStatusMutex ); + } + return theStatus; +} + +int loadServiceFuncs( void ) +{ + HMODULE theModule = GetModuleHandle( "advapi32" ); + if ( theModule != NULL ) + { + fChangeServiceConfig2 = + ( ChangeServiceConfig2Func )GetProcAddress( + theModule, "ChangeServiceConfig2A" ); + fCloseServiceHandle = + ( CloseServiceHandleFunc )GetProcAddress( + theModule, "CloseServiceHandle" ); + fControlService = + ( ControlServiceFunc )GetProcAddress( + theModule, "ControlService" ); + fCreateService = + ( CreateServiceFunc )GetProcAddress( + theModule, "CreateServiceA" ); + fDeleteService = + ( DeleteServiceFunc )GetProcAddress( + theModule, "DeleteService" ); + fOpenSCManager = + ( OpenSCManagerFunc )GetProcAddress( + theModule, "OpenSCManagerA" ); + fOpenService = + ( OpenServiceFunc )GetProcAddress( + theModule, "OpenServiceA" ); + fRegisterServiceCtrlHandler = + ( RegisterServiceCtrlHandlerFunc )GetProcAddress( + theModule, "RegisterServiceCtrlHandlerA" ); + fSetServiceStatus = + ( SetServiceStatusFunc )GetProcAddress( + theModule, "SetServiceStatus" ); + fStartService = + ( StartServiceFunc )GetProcAddress( + theModule, "StartServiceA" ); + fStartServiceCtrlDispatcher = + ( StartServiceCtrlDispatcherFunc )GetProcAddress( + theModule, "StartServiceCtrlDispatcherA" ); + } + return 1; +} + +void serviceCtrlHandler( DWORD inOpcode ) +{ + switch( inOpcode ) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + setServiceStatus( SERVICE_STOPPED ); + doGeneric( sOpStop, 1 ); + break; + + case SERVICE_CONTROL_INTERROGATE: + setServiceStatus( doGeneric( sOpStatus, 1 ) == 0 ? + SERVICE_RUNNING : SERVICE_STOPPED ); + break; + + default: + break; + } + gServiceStatus.dwWin32ExitCode = NO_ERROR; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + fSetServiceStatus( gServiceStatusHandle, &gServiceStatus ); +} + +void serviceMain( DWORD inArgc, LPTSTR * inArgv ) +{ + HANDLE theHandle; + gServiceStatusHandle = + fRegisterServiceCtrlHandler( + sServiceName, + ( LPHANDLER_FUNCTION )serviceCtrlHandler ); + + gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + setServiceStatus( SERVICE_START_PENDING ); + gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + gServiceStatus.dwWin32ExitCode = 0; + gServiceStatus.dwServiceSpecificExitCode = 0; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + fSetServiceStatus( gServiceStatusHandle, &gServiceStatus ); + + if ( doStart( 1, &theHandle ) == 0 ) + { + setServiceStatus( SERVICE_RUNNING ); + gServiceStatus.dwWin32ExitCode = NO_ERROR; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + fSetServiceStatus( gServiceStatusHandle, &gServiceStatus ); + serviceRestartLoop( theHandle ); + } + else + { + setServiceStatus( SERVICE_STOPPED ); + gServiceStatus.dwWin32ExitCode = ERROR_GEN_FAILURE; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + fSetServiceStatus( gServiceStatusHandle, &gServiceStatus ); + } +} + +void serviceRestartLoop( HANDLE inHandle ) +{ + while ( 1 ) + { + WaitForSingleObject( inHandle, INFINITE ); + Sleep( 5000 ); + if ( getServiceStatus() == SERVICE_RUNNING ) + { + doStart( 1, &inHandle ); + } + else + { + break; + } + } +} + +void setServiceStatus( DWORD inStatus ) +{ + if ( lockMutex( gServiceStatusMutex ) == 0 ) + { + gServiceStatus.dwCurrentState = inStatus; + unlockMutex( gServiceStatusMutex ); + } +} + +#endif diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..7893731 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir +PROJECT=AGENT +TEST_TYPE=-f +FILE=apocd/apocd.c + +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $PROJECT." + echo "Install the appropriate package for your distribution," + echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/" + DIE=1 +} + + +if test -x "`which automake-1.9`" +then + AUTOMAKE=`which automake-1.9` + ACLOCAL=`which aclocal-1.9` + ACLOCAL_FLAGS="-I m4" +elif test -x "`which automake-1.10`" +then + AUTOMAKE=`which automake-1.10` + ACLOCAL=`which aclocal-1.10` + ACLOCAL_FLAGS="-I m4" +else + echo + echo "You must have automake 1.10.x or 1.9.x installed to compile $PROJECT." + echo "Install the appropriate package for your distribution," + echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/" + DIE=1 +fi + +if test -x "`which libtoolize`" +then + LIBTOOLIZE=`which libtoolize` + LIBTOOLIZEFLAGS="--force" +else + echo + echo "You must have libtoolize installed to comopile $PROJECT." + echo "Install the appropriate package for your operating system." + DIE=1 +fi + + +if test "$DIE" -eq 1; then + exit 1 +fi + +test $TEST_TYPE $FILE || { + echo "You must run this script in the top-level $PROJECT directory" + exit 1 +} + +if test -z "$AUTOGEN_SUBDIR_MODE"; then + if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." + fi +fi + +rm -rf autom4te.cache + + +$ACLOCAL $ACLOCAL_FLAGS || exit $? +$LIBTOOLIZE $LIBTOOLIZEFLAGS || exit $? +$AUTOMAKE --add-missing || exit $? +autoconf || exit $? +cd $ORIGDIR || exit $? + +if test -z "$AUTOGEN_SUBDIR_MODE"; then + $srcdir/configure --enable-maintainer-mode $AUTOGEN_CONFIGURE_ARGS "$@" || exit $? + + echo + echo "Now type 'make' to compile $PROJECT." +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..293cf7d --- /dev/null +++ b/configure.ac @@ -0,0 +1,287 @@ +AC_INIT(apoc-desktop-agent, 1.0) + +AM_INIT_AUTOMAKE +AC_JAVA_OPTIONS + +AC_PROG_CC +AC_PROG_LIBTOOL + +#Checking and including libXML2 +PKG_CHECK_MODULES(LIBXML2, libxml-2.0) +CFLAGS="$CFLAGS $LIBXML2_CFLAGS" +LDFLAGS="$LDFLAGS $LIBXML2_LIBS" +LIBS="$LIBS $LIBXML2_LIBS" + +# Setting APOC Daemon dir +AC_EXPAND(libdir,NONE,EXPANDED_LIBDIR) + +APOCD_DIR="$EXPANDED_LIBDIR/apoc" + +AC_ARG_WITH(daemon-dir, +AC_HELP_STRING( [--with-daemon-dir=DIR], + [specify the APOC daemon installation path (default=LIBDIR/apoc)]), +[ + if test "$withval" != "no" + then + APOCD_DIR=$withval + fi +]) + +#Java DB 4.2 library directory +DBJAVA_DIR="/usr" +AC_ARG_WITH(db-java-prefix, +AC_HELP_STRING( [--with-db-java-prefix=DIR], + [specify the DB JAVA 4.2 installation prefix (default=/usr)]), +[ + if test "$withval" != "no" + then + BDBJAVA_DIR=$withval + fi +]) + +DBJAVA_LIBDIR=$DBJAVA_DIR/lib +AC_ARG_WITH(db-java-libdir, +AC_HELP_STRING( [--with-db-java-libdir=DIR], + [specify the BDB JAVA 4.2 library installation prefix (default=DBJAVA_DIR/usr)]), +[ + if test "$withval" != "no" + then + DBJAVA_LIBDIR=$withval + fi +]) + +# Check only for the presence of the library, it's only needed +# in runtime by the java bindings. No need to add compiler flags. +TMP_LIBS=$LIBS +TMP_CFLAGS=$CFLAGS +TMP_LDFLAGS=$LDFLAGS +LDFLAGS=-L$DBJAVA_LIBDIR +AC_CHECK_LIB(db_java-4.2, DbEnv_get_version_major, + [], + AC_MSG_ERROR(DB JAVA 4.2 library not found. Check your DBJAVA prefix option. +If it is already installed please use --with-db-java-prefix=DIR or --with-db-java-libdir=DIR options to point to the DB JAVA 4.2 installation prefix or library dir.)) +LDFLAGS=$TMP_LDFLAGS +CFLAGS=$CFLAGS +LIBS=$TMP_LIBS + +# Checking for the GSSAPI +GSSAPI_DIR=/usr +GSSAPI_LIBDIR="$GSSAPI_DIR/lib" +GSSAPI_INCLUDEDIR="$GSSAPI_DIR/include" + +AC_ARG_WITH(gss-prefix, +AC_HELP_STRING( [--with-gss-prefix=DIR], + [specify the GSS API installation prefix (default=/usr)]), +[ + if test "$withval" != "no" + then + GSSAPI_DIR=$withval + fi +]) + +AC_ARG_WITH(gss-libdir, +AC_HELP_STRING( [--with-gss-libdir=DIR], + [specify the GSS API library path (default=GSS_PREFIX/lib)]), +[ + if test "$withval" != "no" + then + GSSAPI_LIBDIR=$withval + fi +]) + +AC_ARG_WITH(gss-includedir, +AC_HELP_STRING( [--with-gss-includedir=DIR], + [specify the GSS API include path (default=GSS_PREFIX/include)]), +[ + if test "$withval" != "no" + then + GSSAPI_INCLUDEDIR=$withval + fi +]) + + +CFLAGS="$CFLAGS -I$GSSAPI_INCLUDEDIR" +LDFLAGS="$LDFLAGS -L$GSSAPI_LIBDIR" + +AC_CHECK_HEADERS(gssapi/gssapi.h, + [GSSAPI_INCLUDES="-I$GSSAPI_INCLUDEDIR/gssapi"]) + +if test -z "$GSSAPI_INCLUDES" +then +AC_CHECK_HEADERS(gssapi.h, + [GSSAPI_INCLUDES="-I$GSSAPI_INCLUDEDIR"]) +fi + +if test -z "$GSSAPI_INCLUDES" +then + AC_MSG_ERROR(GSSAPI development headers not found. +If it is already installed please use --with-gss-prefix=DIR to point to the GSSAPI installation prefix.) +fi + +#Checking the gssapi presence +AC_CHECK_LIB(gss, gss_init_sec_context, + [GSSAPI_LIBS="-L$GSSAPI_LIBDIR -lgss"],) + +if test -z "$GSSAPI_LIBS" +then +AC_CHECK_LIB(gssapi, gss_init_sec_context, + [GSSAPI_LIBS="-L$GSSAPI_LIBDIR -lgssapi"],) +fi + +if test -z "$GSSAPI_LIBS" +then +AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, + [GSSAPI_LIBS="-L$GSSAPI_LIBDIR -lgssapi_krb5"],) +fi + +if test -z "$GSSAPI_LIBS" +then +AC_MSG_ERROR(GSSAPI library not found. Check your GSSAPI prefix option. +If it is already installed please use --with-gss-prefix=DIR to point to the GSSAPI installation prefix.) +fi + + +CFLAGS="$CFLAGS $GSSAPI_INCLUDES" +LDFLAGS="$LDFLAGS $GSSAPI_LIBS" +LIBS="$LIBS $GSSAPI_LIBS" + + +# Setting APOC class path +AC_EXPAND(datadir, NONE, EXPANDED_DATADIR) + +APOCDIR=$EXPANDED_DATADIR'/lib/apoc' + +AC_ARG_WITH(apoc-path, +AC_HELP_STRING( [--with-apoc-path=DIR], + [specify a path to install the apoc libraries (DATADIR/lib/apoc)]), +[ + if test "$withval" != "no" + then + APOCDIR=$withval + fi +]) + +SPIJDK=$APOCDIR/spi.jar + +#Setting Oracle/Sleepycat's BerkeleyDB JDK +BDBJDK=$APOCDIR/db.jar + +AC_ARG_WITH(bdb-path, +AC_HELP_STRING( [--with-bdb-path=DIR], + [specify the Sleepycat's BerkeleyDB JDK path or jar file (APOCDIR/db.jar)]), +[ + if test "$withval" != "no" + then + BDBJDK=$withval + fi +]) + +AC_ARG_ENABLE(debug, +AC_HELP_STRING( [--enable-debug], + [enable debugging symbols]), + [debug="yes"]) + +if test "$debug" == "yes" +then + CFLAGS="$CFLAGS -g " +fi + + +_SAVE_CLASSPATH=$CLASSPATH +export CLASSPATH=$CLASPATH:$SPIJDK:$BDBJDK + +AC_PROG_JAVAC +AC_PROG_JAVA +AC_PROG_JAR + +AC_CHECK_CLASS(com.sleepycat.db.Db, [], [ +echo +AC_MSG_ERROR(Sleepycat's BerkeleyDB JDK +If it is already installed please use --with-bdb-path=DIR to point to the path or jar file.) +]) + +AC_CHECK_CLASS(com.sun.apoc.spi.PolicyManager, [], [ +echo +AC_MSG_ERROR(APOC SPI not found. +If it is already installed please use --with-apoc-path=DIR to point to the path wher the spi.jar file is stored.) +]) + +AC_JNI_INCLUDE_DIR + +if test -z "$JNI_INCLUDE_DIRS" +then + AC_MSG_ERROR(Java Native Interface (JNI) headers not found.) +fi + +for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +do + CFLAGS="$CFLAGS -I$JNI_INCLUDE_DIR" +done + +AC_CHECK_PROG(ANT, ant, ant, no) +if test $ANT == "no" +then + AC_MSG_ERROR(Apache's Ant was not found in path.) +fi + +case "${host}" in + *-*solaris*) PLATFORM=UNX + OS=SOLARIS + CFLAGS="$CFLAGS -xarch=v8 -xspace -xO3" + LIBS="$LIBS -lpthread -lnsl -lsocket -lm -lc -lrt -lscf" + LDFLAGS="-mt -z combreloc -z text -Bdirect -z defs" + ;; + *-*linux*) PLATFORM=UNX + OS=LINUX + ;; +esac + +CFLAGS="$CFLAGS -D$PLATFORM -D$OS" + +AM_CONDITIONAL([SOLARIS], [test "$OS" = "SOLARIS"]) + +#APOC data dir +AC_EXPAND(localstatedir, NONE, EXPANDED_LOCALSTATEDIR) + +APOC_DATADIR="$EXPANDED_LOCALSTATEDIR/apoc" + +AC_ARG_WITH(apoc-datadir, +AC_HELP_STRING( [--with-apoc-data=DIR], + [specify the APOC data dir (default=LOCALSTATEDIR/apoc)]), +[ + if test "$withval" != "no" + then + APOCD_DIR=$withval + fi +]) + +AC_EXPAND(sysconfdir, NONE, EXPANDED_SYSCONFDIR) +AC_EXPAND(libdir, NONE, EXPANDED_LIBDIR) + +AC_SUBST(APOCDIR) +AC_SUBST(SPIJDK) +AC_SUBST(BDBJDK) +AC_SUBST(APOCD_DIR) +AC_SUBST(APOC_DATADIR) +AC_SUBST(EXPANDED_SYSCONFDIR) +AC_SUBST(EXPANDED_LIBDIR) +AC_SUBST(DBJAVA_LIBDIR) + +AC_OUTPUT([ +Makefile +libapoc.pc +libapoc/Makefile +libapoc/config.h +libfileaccess/Makefile +apocd/Makefile +apocd/config.h +smf/apocd.xml +initd/apocd +src/Makefile +src/com/Makefile +src/com/sun/Makefile +src/com/sun/apoc/Makefile +src/com/sun/apoc/daemon/Makefile +src/com/sun/apoc/daemon/build.xml +src/com/sun/apoc/daemon/properties/os.properties +]) diff --git a/initd/apocd.in b/initd/apocd.in new file mode 100755 index 0000000..97b59bd --- /dev/null +++ b/initd/apocd.in @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Copyright (c) 2004 by Sun Microsystems, Inc. +# All rights reserved. +# +# /etc/init.d/apocd +# +### BEGIN INIT INFO +# Provides: apocd +# Required-Start: $network $local_fs +# Required-Stop: $network $local_fs +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Description: Configuration Agent +### END INIT INFO + +APOCD_BIN=@APOCD_DIR@/apocd +test -x $APOCD_BIN || exit 5 + +. /etc/rc.status +rc_reset + +case "$1" in + start) + echo -n "Starting Configuration Agent" + $APOCD_BIN svcStart > /dev/null + rc_status -v + ;; + + stop) + echo -n "Stopping Configuration Agent" + $APOCD_BIN svcStop > /dev/null + rc_status -v + ;; + + try-restart) + $0 status >/dev/null && $0 restart + rc_status + ;; + + restart) + $0 stop + $0 start + rc_status + ;; + + force-reload|reload) + echo -n "Reloading Configuration Agent" + $APOCD_BIN reload > /dev/null + rc_status -v + ;; + + status) + echo -n "Checking Configuration Agent status" + $APOCD_BIN status > /dev/null + rc_status -v + ;; + + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + exit 1 + ;; +esac +rc_exit + diff --git a/libapoc.pc.in b/libapoc.pc.in new file mode 100644 index 0000000..d38e32b --- /dev/null +++ b/libapoc.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +gssapilibs=@GSSAPI_LIBS@ +gssapiincludes=@GSSAPI_INCLUDES@ + +Name: libapoc +Description: library that provides an interface to the APOC desktop agent for applications +Version: @VERSION@ +Requires: libxml-2.0 +Libs: -L${libdir} -lapoc ${gssapilibs} +Cflags: -I${includedir}/apoc ${gssapiincludes} diff --git a/libapoc/Makefile.am b/libapoc/Makefile.am new file mode 100644 index 0000000..1da0d20 --- /dev/null +++ b/libapoc/Makefile.am @@ -0,0 +1,39 @@ +lib_LTLIBRARIES = libapoc.la + +libapocdir = $(includedir)/apoc/papi + +libapoc_HEADERS = \ + papi.h \ + papiTypes.h + +libapoc_la_LDFLAGS = -version-info "1:0:0" + +libapoc_la_SOURCES = \ + papi.c \ + papi.h \ + papiConnection.h \ + papiConnection.c \ + papiDaemon.h \ + papiDaemon.c \ + papiDatabase.c \ + papiDatabase.h \ + papiInternal.c \ + papiInternal.h \ + papiLayerList.c \ + papiLayerList.h \ + papiListenerList.c \ + papiListenerList.h \ + papiMessage.c \ + papiMessage.h \ + papiSAXParserContext.c \ + papiSAXParserContext.h \ + papiStringList.c \ + papiStringList.h \ + papiEntityList.c \ + papiEntityList.h \ + papiUtils.c \ + papiUtils.h \ + papiPort.c \ + papiTypes.h + + diff --git a/libapoc/config.h.in b/libapoc/config.h.in new file mode 100644 index 0000000..74120a7 --- /dev/null +++ b/libapoc/config.h.in @@ -0,0 +1,41 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef _HAVE_CONFIG_H +#define _HAVE_CONFIG_H +#define APOC_INSTALLDIR "@APOCDIR@" +#define APOC_LIBRARYDIR "@EXPANDED_LIBDIR@" +#define APOC_PROPDIR "@EXPANDED_SYSCONFDIR@" +#endif diff --git a/libapoc/papi.c b/libapoc/papi.c new file mode 100644 index 0000000..23e4c8f --- /dev/null +++ b/libapoc/papi.c @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papi.h" +#include "papiInternal.h" + + +PAPI * papiInitialise( const char * inEntityId, + PAPIStatus * outStatus ) +{ + return papiInitialiseWithListener( inEntityId, 0, 0, outStatus ); +} + +PAPI * papiInitialiseWithListener( const char * inEntityId, + PAPIConnectionListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIEntityList theEntity ; + + theEntity.entityType = PAPIEntityUser; + theEntity.entityId = inEntityId; + theEntity.next = 0; + return initialise( &theEntity, inListener, inUserData, outStatus); +} + +void papiDeinitialise( PAPI * inPAPI, PAPIStatus * outStatus ) +{ + deinitialise( inPAPI, outStatus ); +} + +PAPILayerList * papiReadComponentLayers( const PAPI * inPAPI, + const char * inComponentName, + PAPIStatus * outStatus ) +{ + return readComponentLayers( inPAPI, inComponentName, outStatus ); +} + +PAPIStringList * papiListComponentNames( const PAPI * inPAPI, + const char * inFilter, + PAPIStatus * outStatus ) +{ + return listComponentNames( inPAPI, inFilter, outStatus ); +} + +void papiSetOffline( const PAPI * inPAPI, + const char * inComponentName, + int inOffline, + PAPIStatus * outStatus ) +{ + if ( outStatus != 0 ) + { + *outStatus = PAPISuccess; + } +} + +int papiIsOffline( const PAPI * inPAPI, + const char * inComponentName, + int * outIsOffline, + PAPIStatus * outStatus ) +{ + if ( outStatus != 0 ) + { + *outStatus = PAPISuccess; + } + return 0; +} + +PAPIListenerId papiAddListener( const PAPI * inPAPI, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + return addListener( inPAPI, + inComponentName, + inListener, + inUserData, + outStatus ); +} + +void papiRemoveListener( const PAPI * inPAPI, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ) +{ + removeListener( inPAPI, inListenerId, outStatus ); +} + +void papiFreeLayerList( PAPILayerList * inList ) +{ + deleteLayerList( inList ); +} + +void papiFreeStringList( PAPIStringList * inList ) +{ + deleteStringList( inList ); +} diff --git a/libapoc/papi.h b/libapoc/papi.h new file mode 100644 index 0000000..0addec9 --- /dev/null +++ b/libapoc/papi.h @@ -0,0 +1,146 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +/* papi.h - Policy Access API */ + +#ifndef PAPI_H_ +#define PAPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "papiTypes.h" + +#ifdef WIN32 +#ifdef PAPI_EXPORTS +#define PAPI_API __declspec(dllexport) +#else +#define PAPI_API __declspec(dllimport) +#endif +#else +#define PAPI_API +#endif + +/* Main PAPI functions */ + +/* + * Obtain a new PAPI handle for the specified entity + * Specifying inEntityId=NULL will result in the entity id being calculated + * from the current user id. + */ +PAPI_API PAPI * papiInitialise( const char * inEntityId, + PAPIStatus * outStatus ); + +/* + * Same as papiInitialise with the additional possibility of specifying + * a listener function which will be called in the event of a daemon connect or + * disconnect. + */ +PAPI_API PAPI * papiInitialiseWithListener( const char * inEntityId, + PAPIConnectionListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +/* + * Invalidate and free all resoures associated with a PAPI handle + * previously returned by papiInitialise() + */ +PAPI_API void papiDeinitialise( PAPI * inPAPI, PAPIStatus * outStatus ); + +/* + * Retrieve all layers for a specified component + * Returns a PAPILayerList ( See papiTypes.h ) ordered according to mergepath + * + * The caller must "free" the returned PAPILayerList using papiFreeLayerList() + */ +PAPI_API PAPILayerList * papiReadComponentLayers( const PAPI * inPAPI, + const char * inComponentName, + PAPIStatus * outStatus ); + +/* + * List all available components which comply with the specified filter + * Returns a PAPIStringList ( See papiTypes.h ) + * + * The caller must "free" the returned PAPIStringList using papiFreeStringList() + * + * TBD: specify the supported filter syntax + */ +PAPI_API PAPIStringList * papiListComponentNames( const PAPI * inPAPI, + const char * inFilter, + PAPIStatus * outStatus ); + +/* + * Mark the specified component as offline or online + */ +PAPI_API void papiSetOffline( const PAPI * inPAPI, + const char * inComponentName, + int inOffline, + PAPIStatus * outStatus ); + +/* + * Query the online/offline status of a specified component + */ +PAPI_API int papiIsOffline( const PAPI * inPAPI, + const char * inComponentName, + int * outIsOffline, + PAPIStatus * outStatus ); + +/* + * Add a listener for changes to the specified component + */ +PAPI_API PAPIListenerId papiAddListener( const PAPI * inPAPI, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +/* + * Remove a listener previously added by papiAddListener() + */ +PAPI_API void papiRemoveListener( const PAPI * inPAPI, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ); + +/* + * Free all resources associated with the specified list + */ +PAPI_API void papiFreeLayerList( PAPILayerList * inList ); +PAPI_API void papiFreeStringList( PAPIStringList * inList ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPI_H_ */ diff --git a/libapoc/papiConnection.c b/libapoc/papiConnection.c new file mode 100644 index 0000000..7eb4b6e --- /dev/null +++ b/libapoc/papiConnection.c @@ -0,0 +1,747 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiConnection.h" +#include "papiSAXParserContext.h" +#include "papiStringList.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#ifndef WNT +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#endif + +typedef struct NotificationThreadArg +{ + PAPIListener mListener; + PAPIEvent * mEvent; + void * mUserData; +} NotificationThreadArg; + +static PAPIConnection * allocConnection ( + PAPIConnectionListener inListener, + void * inUserDat, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPISocket inFD, + PAPIStatus * outStatus ); + +static int daemonConnect( int inRetryCount ); + +static void createNotificationThread( PAPIListener inListener, + PAPIEventType inType, + const char * inComponentName, + void * inUserData ); + +static PAPIListenerThreadStatus getListenerThreadStatus( + PAPIConnection *inConnection ); + +static PAPIMessage * getResponse( PAPIConnection *inConnection, + PAPIStatus * outStatus ); + +static PAPIMessage * getResponseMessage( PAPIConnection *inConnection, + PAPIStatus * outStatus ); + +static void handleSASLAuth( PAPIConnection *inConnection, + PAPIMessage * inChallenge ); + +static int haveMessage( PAPIConnection *inConnection ); + +static void * listener( void * inConnection ); + +static void * notifier( void * inNotificationThreadArg ); + +static void sendInternalNotification( PAPIConnection *inConnection, + PAPIMessage * inMessage ); + +static void sendNotification( PAPIConnection *inConnection, + PAPIMessage * theMessage ); + +static void setListenerThreadStatus( PAPIConnection *inConnection, + PAPIListenerThreadStatus inStatus ); + +static void startListeningThread( PAPIConnection *inConnection, + PAPIStatus * outStatus ); + +static void stopListeningThread( PAPIConnection *inConnection, + PAPIStatus * outStatus ); + +static void takeFive( void ); + +static int sDefaultDaemonPort = 38900; + +PAPIListenerId connectionAddListener( PAPIConnection * inConnection, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIListenerId theListenerId = 0; + *outStatus = PAPISuccess; + if ( lockMutex( inConnection->mListenersMutex ) == 0 ) + { + theListenerId = addListenerList( &( inConnection->mListeners ), + inComponentName, + inListener, + inUserData ); + *outStatus = theListenerId == 0 ? + PAPIOutOfMemoryFailure : + PAPISuccess; + unlockMutex( inConnection->mListenersMutex ); + } + else + { + *outStatus = PAPIUnknownFailure; + } + return theListenerId; +} + +void connectionRemoveListener( PAPIConnection * inConnection, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ) +{ + *outStatus = PAPISuccess; + if ( lockMutex( inConnection->mListenersMutex ) == 0 ) + { + removeListenerList( & ( inConnection->mListeners ), + ( PAPIListenerList * )inListenerId ); + unlockMutex( inConnection->mListenersMutex ); + } + else + { + *outStatus = PAPIUnknownFailure; + } +} + +void connectionSetSASLAuthHandler( PAPIConnection * inConnection, + PAPIAuthHandler inHandler, + void * inHandlerUserData ) +{ + inConnection->mAuthHandler = inHandler; + inConnection->mAuthHandlerUserData->mUserData = inHandlerUserData; +} + +void deleteConnection( PAPIConnection * inConnection ) +{ + if ( inConnection != 0 ) + { + PAPIStatus theStatus; + stopListeningThread( inConnection, &theStatus ); + deleteListenerList( inConnection->mListeners ); + deleteMutex( inConnection->mListenersMutex ); + deleteMutex( inConnection->mSavedMessageMutex ); + deleteMutex( inConnection->mListenerThreadStatusMutex ); + deleteMutex( inConnection->mConnectionStateChangeMutex ); + if ( inConnection->mAuthHandlerUserData != 0 ) + { + free( ( void * )inConnection->mAuthHandlerUserData ); + } + free( ( void * )inConnection ); + } +} + +PAPIConnection * newConnection( PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPIConnection * theConnection = 0; + int theSocket = daemonConnect( 10 ); + + if ( theSocket == INVALID_SOCKET ) + { + *outStatus = PAPIConnectionFailure; + } + else + { + *outStatus = PAPISuccess; + } + if ( *outStatus == PAPISuccess || isDaemonEnabled() == 1 ) + { + theConnection = allocConnection( inConnectionListener, + inUserData, + inInternalListener, + inInternalListenerData, + theSocket, + &theStatus ); + if ( theStatus == PAPISuccess ) + { + startListeningThread( theConnection, &theStatus ); + } + if ( theStatus != PAPISuccess ) + { + deleteConnection( theConnection ); + theConnection = 0; + *outStatus = theStatus; + } + } + return theConnection; +} + +int readBytes( PAPIConnection * inConnection, char * inBuffer, int inLen ) +{ + int theTotalByteCount = 0; + while ( inLen > 0 ) + { + int theByteCount = -1; + if ( haveMessage( inConnection ) != -1 ) + { + theByteCount = + recv(inConnection->mFD, inBuffer + theTotalByteCount, inLen, 0); + if ( theByteCount == -1 && errno == EINTR ) + { + theByteCount = 0; + } + } + if ( theByteCount == SOCKET_ERROR ) + { + theTotalByteCount = -1; + break; + } + else + { + inLen -= theByteCount; + theTotalByteCount += theByteCount; + } + } + return theTotalByteCount; +} + +int readContentLength( PAPIConnection * inConnection ) +{ + char theBuffer[ 15 ]; + int theIndex; + int theContentLength = -1; + if ( readBytes( inConnection, theBuffer, 15 ) != 15 ) + { + return -1; + } + if ( strncmp( theBuffer, + CONTENTLENGTH, + sizeof( CONTENTLENGTH ) - 1 ) != 0) + { + return -1; + } + theIndex = 0; + while ( readBytes( inConnection, theBuffer + theIndex, 1 ) == 1 ) + { + if ( theBuffer[ theIndex ] == '\n' ) + { + theBuffer[ theIndex - 1 ] = 0; + theContentLength = atoi( theBuffer ); + break; + } + theIndex ++; + } + return theContentLength; +} + +PAPIMessage * sendRequest( PAPIConnection * inConnection, + PAPIMessage * inRequestMessage, + PAPIStatus * outStatus ) +{ + int theContentLength; + char theContentLengthString[ MAX_CONTENT_LENGTH_SIZE ]; + char * theRequest; + PAPIMessage * theResponse = 0; + + *outStatus = PAPISuccess; + + if ( inConnection == 0 || inConnection->mFD == INVALID_SOCKET ) + { + *outStatus = PAPIConnectionFailure; + return 0; + } + + theRequest = messageToString( inRequestMessage ); + if ( theRequest != 0 && ( theContentLength = strlen( theRequest ) ) > 0 ) + { + char * theBuf; + int theSize; + snprintf( theContentLengthString, + MAX_CONTENT_LENGTH_SIZE, + "%s%d\r\n", + CONTENTLENGTH, + theContentLength ); + + deleteMessage( inConnection->mSavedMessage ); + inConnection->mSavedMessage = 0; + theSize = strlen( theContentLengthString ) + theContentLength + 1; + theBuf = ( char * )malloc( theSize ); + if ( theBuf == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + free( ( void * )theRequest ); + return 0; + } + snprintf( theBuf, theSize, "%s%s", theContentLengthString, theRequest ); + if ( send( inConnection->mFD, + ( void * )theBuf, + theSize - 1, + 0 ) == SOCKET_ERROR ) + { + *outStatus = PAPIConnectionFailure; + free( ( void * )theBuf ); + free( ( void * )theRequest ); + return 0; + } + free( ( void * )theBuf ); + free( ( void * )theRequest ); + theResponse = getResponse( inConnection, outStatus ); + } + else + { + free( ( void * )theRequest ); + } + return theResponse; +} + +void setBlocking( PAPIConnection * inConnection, int inIsBlocking ) +{ + inConnection->mFDPollTimeout = inIsBlocking == 1 ? + -1 : getTransactionTimeout(); +} + +PAPIConnection* allocConnection( PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPISocket inSocket, + PAPIStatus * outStatus ) +{ + PAPIConnection * theConnection = + ( PAPIConnection * )malloc( sizeof( PAPIConnection ) ); + if ( theConnection != 0 ) + { + theConnection->mFD = inSocket; + theConnection->mFDPollTimeout = getTransactionTimeout(); + theConnection->mListeners = 0; + theConnection->mSavedMessage = 0; + theConnection->mListenerThreadStatus = NOT_RUNNING; + theConnection->mConnectionListener = inConnectionListener; + theConnection->mUserData = inUserData; + theConnection->mListenersMutex = newMutex(); + theConnection->mSavedMessageMutex = newMutex(); + theConnection->mListenerThreadStatusMutex= newMutex(); + theConnection->mConnectionStateChangeMutex= newMutex(); + theConnection->mInternalListener = inInternalListener; + theConnection->mInternalListenerData = inInternalListenerData; + theConnection->mAuthHandler = 0; + theConnection->mAuthHandlerUserData = + ( PAPIAuthHandlerData * )malloc( sizeof( PAPIAuthHandlerData ) ); + *outStatus = PAPISuccess; + } + else + { + *outStatus = PAPIOutOfMemoryFailure; + } + return theConnection; +} + +PAPISocket daemonConnect( int inRetryCount ) +{ + int thePort = getDaemonPort(); + PAPISocket theSocket; + PAPIConnectResult theRC = + getConnectedSocket( thePort, SOCK_STREAM, 0, &theSocket ); + + if ( theRC == PAPIConnectRejected || + ( theRC == PAPIConnectFailed && startDaemon() == 0 ) ) + { + theRC = + getConnectedSocket( thePort, SOCK_STREAM, inRetryCount, &theSocket); + } + return theSocket; +} + +void createNotificationThread( PAPIListener inListener, + PAPIEventType inType, + const char * inComponentName, + void * inUserData ) +{ + NotificationThreadArg * theArg = + ( NotificationThreadArg * )malloc( sizeof( NotificationThreadArg ) ); + if ( theArg != 0 ) + { + theArg->mEvent = ( PAPIEvent * )malloc( sizeof( PAPIEvent ) ); + if ( theArg->mEvent != 0 ) + { + theArg->mEvent->eventType = inType; + theArg->mEvent->componentName = strdup( inComponentName ); + theArg->mListener = inListener; + theArg->mUserData = inUserData; + + createThread( notifier, ( void *)theArg ); + } + } +} + +PAPIListenerThreadStatus getListenerThreadStatus( + PAPIConnection * inConnection ) +{ + PAPIListenerThreadStatus theListenerThreadStatus = NOT_RUNNING; + if ( lockMutex( inConnection->mListenerThreadStatusMutex ) == 0 ) + { + theListenerThreadStatus = inConnection->mListenerThreadStatus; + unlockMutex( inConnection->mListenerThreadStatusMutex ); + } + return theListenerThreadStatus; +} + +PAPIMessage * getResponse( PAPIConnection * inConnection, + PAPIStatus * outStatus ) +{ + PAPIMessage * theResponse = 0; + *outStatus = PAPISuccess; + while ( theResponse == 0 && inConnection->mFD != INVALID_SOCKET ) + { + if ( lockMutex( inConnection->mSavedMessageMutex ) == 0 ) + { + theResponse = inConnection->mSavedMessage; + inConnection->mSavedMessage = 0; + unlockMutex( inConnection->mSavedMessageMutex ); + } + takeFive(); + } + if ( theResponse == 0 || inConnection->mFD == INVALID_SOCKET ) + { + *outStatus = PAPIConnectionFailure; + } + return theResponse; +} + +PAPIMessage * getResponseMessage( PAPIConnection * inConnection, + PAPIStatus * outStatus ) +{ + PAPISAXUserData theUserData; + PAPISAXParserContext theSAXParserContext; + PAPIMessage * theResponse = 0; + + theUserData.mMessage = 0; + theSAXParserContext = + newSAXParserContext( inConnection, &theUserData ); + if ( parse( theSAXParserContext ) != 0 ) + { + if ( inConnection->mFD == INVALID_SOCKET ) + { + *outStatus = PAPIConnectionFailure; + } + else + { + *outStatus = PAPIUnknownFailure; + } + } + deleteSAXParserContext( theSAXParserContext ); + return theUserData.mMessage; +} + +void handleSASLAuth( PAPIConnection * inConnection, PAPIMessage * inChallenge ) +{ + PAPIAuthHandler theHandler = inConnection->mAuthHandler; + PAPIAuthHandlerData * theData = inConnection->mAuthHandlerUserData; + theData->mChallenge = inChallenge; + /* avoid calling handler repeatedly during sasl auth */ + inConnection->mAuthHandler = 0; + createThread( theHandler, theData ); +} + +int haveMessage( PAPIConnection * inConnection ) +{ + int bHaveMessage = 0; + int theRC; + + theRC = socketPoll( inConnection->mFD, inConnection->mFDPollTimeout ); + if ( theRC == 1 ) + { + char theByte; + if ( recv( inConnection->mFD, &theByte, 1, MSG_PEEK ) != 1 ) + { + if ( errno != EINTR ) + { + bHaveMessage = -1; + } + } + else + { + bHaveMessage = 1; + } + } + else + { + bHaveMessage = -1; + } + return bHaveMessage; +} + +void * listener( void * inConnection ) +{ +#ifndef WNT + sigset_t theSigset; +#endif + PAPIConnection * theConnection = ( PAPIConnection * )inConnection; + +#ifndef WNT + sigemptyset( &theSigset ); + sigaddset( &theSigset, SIGHUP ); + pthread_sigmask( SIG_BLOCK, &theSigset, 0 ); +#endif + setListenerThreadStatus( inConnection, RUNNING ); + while ( getListenerThreadStatus( inConnection ) == RUNNING ) + { + PAPIStatus theStatus; + PAPIMessage * theMessage; + if ( theConnection->mFD != INVALID_SOCKET ) + { + int bHaveMessage = haveMessage( theConnection ); + if ( bHaveMessage == 0 ) + { + continue; + } + else if ( bHaveMessage == -1 ) + { + papiClose( theConnection->mFD ); + theConnection->mFD = INVALID_SOCKET; + if ( lockMutex( theConnection->mConnectionStateChangeMutex ) + == 0 ) + { + theConnection->mConnectionListener( PAPIDisconnected, + theConnection->mUserData ); + unlockMutex( theConnection->mConnectionStateChangeMutex ); + } + if ( isDaemonEnabled() != 1 ) + { + break; + } + continue; + } + theMessage = getResponseMessage( theConnection, &theStatus ); + if ( theMessage != 0 ) + { + if ( theMessage->mName == PAPImodifyNotification || + theMessage->mName == PAPIaddNotification || + theMessage->mName == PAPIremoveNotification ) + { + sendInternalNotification( theConnection, theMessage ); + sendNotification( theConnection, theMessage ); + deleteMessage( theMessage ); + } + else if ( theMessage->mName == PAPIRespSuccessContinueSASLAuth&& + theConnection->mAuthHandler != 0 ) + { + handleSASLAuth( theConnection, theMessage ); + } + else + { + if ( lockMutex( theConnection->mSavedMessageMutex ) == 0 ) + { + theConnection->mSavedMessage = theMessage; + unlockMutex( theConnection->mSavedMessageMutex ); + } + } + } + } + else + { + if ( lockMutex( theConnection->mConnectionStateChangeMutex ) == 0 ) + { + theConnection->mFD = daemonConnect( 1 ); + setBlocking( theConnection, 0 ); + if ( theConnection->mFD != INVALID_SOCKET ) + { + theConnection->mConnectionListener( PAPIConnected, + theConnection->mUserData ); + } + unlockMutex( theConnection->mConnectionStateChangeMutex ); + if ( theConnection->mFD == INVALID_SOCKET ) + { + papiSleep( 10 ); + } + } + } + } + setListenerThreadStatus( inConnection, NOT_RUNNING ); + return 0; +} + +void * notifier( void * inArg ) +{ + NotificationThreadArg * theArg = ( NotificationThreadArg * )inArg; + theArg->mListener( theArg->mEvent, theArg->mUserData ); + free( ( void *)theArg->mEvent->componentName ); + free( ( void *)theArg->mEvent ); + free( ( void *)theArg ); + return 0; +} + +void sendInternalNotification( PAPIConnection * inConnection, + PAPIMessage * inMessage ) +{ + PAPIMessageName theName = inMessage->mName; + if ( theName == PAPIaddNotification || theName == PAPIremoveNotification ) + { + PAPIStringList * theComponentNames = + getParamValue( inMessage, PAPIParamComponentName ); + PAPIStringList * theTmpList = theComponentNames; + while ( theTmpList != 0 ) + { + PAPIEvent theEvent; + theEvent.eventType = + theName == PAPIaddNotification ? + PAPIComponentAdd : PAPIComponentRemove; + theEvent.componentName = theTmpList->data; + inConnection->mInternalListener( + &theEvent, + inConnection->mInternalListenerData ); + theTmpList = theTmpList->next; + } + deleteStringList( theComponentNames ); + } +} + +void sendNotification( PAPIConnection * inConnection, PAPIMessage * inMessage ) +{ + PAPIStringList * theComponentNames = + getParamValue( inMessage, PAPIParamComponentName ); + PAPIStringList * theTmpList = theComponentNames; + while ( theComponentNames != 0 ) + { + PAPIListenerList * theListenerList; + + if ( lockMutex( inConnection->mListenersMutex ) == 0 ) + { + theListenerList = inConnection->mListeners; + while ( theListenerList != 0 ) + { + int theLen = strlen( theListenerList->mComponentName ); + if ( strcmp( theListenerList->mComponentName, + theComponentNames->data ) == 0 || + ( theListenerList->mComponentName[ theLen - 1 ] == '.' && + strncmp( theListenerList->mComponentName, + theComponentNames->data, + theLen ) == 0 ) ) + { + PAPIEventType theEventType; + switch( inMessage->mName ) + { + case PAPImodifyNotification: + theEventType = PAPIComponentModify; + break; + + case PAPIaddNotification: + theEventType = PAPIComponentAdd; + break; + + case PAPIremoveNotification: + theEventType = PAPIComponentRemove; + break; + } + createNotificationThread( theListenerList->mListener, + theEventType, + theComponentNames->data, + theListenerList->mUserData); + } + theListenerList = theListenerList->mNext; + } + theComponentNames = theComponentNames->next; + unlockMutex( inConnection->mListenersMutex ); + } + } + deleteStringList( theTmpList ); +} + +void setListenerThreadStatus( PAPIConnection * inConnection, + PAPIListenerThreadStatus inStatus ) +{ + if ( lockMutex(inConnection->mListenerThreadStatusMutex ) == 0 ) + { + inConnection->mListenerThreadStatus = inStatus; + unlockMutex( inConnection->mListenerThreadStatusMutex ); + } +} + +void startListeningThread( PAPIConnection * inConnection, + PAPIStatus * outStatus ) +{ + inConnection->mListenerThread = createThread( listener, inConnection ); + if ( inConnection->mListenerThread != 0 ) + { + *outStatus = PAPISuccess; + } + else + { + *outStatus = PAPIUnknownFailure; + } +} + +void stopListeningThread( PAPIConnection * inConnection, PAPIStatus * outStatus) +{ + *outStatus = PAPISuccess; + if ( getListenerThreadStatus( inConnection ) == RUNNING ) + { + if ( lockMutex( inConnection->mListenersMutex ) == 0 ) + { + destroyThread( inConnection->mListenerThread ); + papiClose( inConnection->mFD ); + unlockMutex( inConnection->mListenersMutex ); + } + else + { + *outStatus = PAPIUnknownFailure; + } + } +} + +void takeFive( void ) +{ +#ifndef WNT + + struct timespec theTimeout; + + theTimeout.tv_sec = 0; + theTimeout.tv_nsec = 5000000; + nanosleep( &theTimeout, NULL); + +#else + + Sleep( 50 ); + +#endif +} diff --git a/libapoc/papiConnection.h b/libapoc/papiConnection.h new file mode 100644 index 0000000..b973806 --- /dev/null +++ b/libapoc/papiConnection.h @@ -0,0 +1,117 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPICONNECTION_H_ +#define PAPICONNECTION_H_ + +#include "papiListenerList.h" +#include "papiMessage.h" +#include "papiUtils.h" +#include "papiTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { NOT_RUNNING, EXITING, RUNNING } PAPIListenerThreadStatus; + +typedef struct PAPIAuthHandlerData +{ + void * mUserData; + PAPIMessage * mChallenge; +} PAPIAuthHandlerData; + +typedef void * ( *PAPIAuthHandler )( void * inAuthData ); + +typedef struct PAPIConnection +{ + PAPISocket mFD; + int mFDPollTimeout; + PAPIListenerList * mListeners; + PAPIMutex * mListenersMutex; + PAPIMessage * mSavedMessage; + PAPIMutex * mSavedMessageMutex; + PAPIThread mListenerThread; + PAPIListenerThreadStatus mListenerThreadStatus; + PAPIMutex * mListenerThreadStatusMutex; + PAPIConnectionListener mConnectionListener; + PAPIMutex * mConnectionStateChangeMutex; + void * mUserData; + PAPIListener mInternalListener; + void * mInternalListenerData; + PAPIAuthHandler mAuthHandler; + PAPIAuthHandlerData * mAuthHandlerUserData; +} PAPIConnection; + +PAPIListenerId connectionAddListener( PAPIConnection * inConnection, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +void connectionRemoveListener( PAPIConnection * inConnection, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ); + +void connectionSetSASLAuthHandler( PAPIConnection * inConnection, + PAPIAuthHandler inAuthHandler, + void * inUserData ); + +void deleteConnection ( PAPIConnection * inConnection ); + + +PAPIConnection * newConnection( PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPIStatus * outStatus ); + +int readBytes( PAPIConnection * inConnection, + char * inBuffer, + int inLen ); + +int readContentLength( PAPIConnection * inConnection ); + +PAPIMessage * sendRequest( PAPIConnection * inConnection, + PAPIMessage * inRequest, + PAPIStatus * outStatus ); + +void setBlocking( PAPIConnection * inConnection, + int inIsBlocking ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPICONNECTION_H_ */ diff --git a/libapoc/papiDaemon.c b/libapoc/papiDaemon.c new file mode 100644 index 0000000..841ee19 --- /dev/null +++ b/libapoc/papiDaemon.c @@ -0,0 +1,516 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiDaemon.h" +#include "papiMessage.h" +#include "papiUtils.h" +#include "papiEntityList.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static PAPIMessage * createCreateSessionRequest( + const char * inUserId, + const PAPIEntityList * inEntityId, + const char * inCredentials ); + +static void createSession( PAPIDaemon * inDaemon, + PAPIStatus * outStatus ); + +static void daemonReaddListener( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIStatus * outStatus ); + +static void destroySession( PAPIDaemon * inDaemon ); + +static const char * getLocalCreds( const char * inLocalChallengeFile, + PAPIStatus * outStatus ); + +static void * saslAuthHandler( void * inData ); + +static int sLocalCredentialsBufferSize = 21; + +PAPIListenerId daemonAddListener( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIListenerId theListenerId = 0; + daemonReaddListener( inDaemon, inComponentName, outStatus ); + if ( *outStatus == PAPISuccess ) + { + theListenerId = connectionAddListener( inDaemon->mConnection, + inComponentName, + inListener, + inUserData, + outStatus ); + } + return theListenerId; +} + +PAPIStringList * daemonList( PAPIDaemon * inDaemon, PAPIStatus * outStatus ) +{ + PAPIStringList * theList = 0; + if ( inDaemon->mSessionId != 0 ) + { + PAPIMessage * theRequest; + PAPIMessage * theResponse; + + theRequest = newMessage( PAPIReqList ); + if ( theRequest == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return 0; + } + addParam( theRequest, PAPIParamSessionId, inDaemon->mSessionId ); + theResponse = sendRequest( inDaemon->mConnection,theRequest,outStatus ); + if ( theResponse != 0 ) + { + theList = getParamValue( theResponse, PAPIParamComponentName ); + } + + deleteMessage( theRequest ); + deleteMessage( theResponse ); + } + return theList; +} + +PAPIStringList * daemonRead( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIStatus * outStatus ) +{ + PAPIStringList * theLayers = 0; + if ( inDaemon->mSessionId != 0 ) + { + PAPIMessage * theRequest; + PAPIMessage * theResponse; + + theRequest = newMessage( PAPIReqRead ); + if ( theRequest == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return 0; + } + addParam( theRequest, PAPIParamSessionId, inDaemon->mSessionId ); + addParam( theRequest, PAPIParamComponentName, inComponentName ); + theResponse = sendRequest( inDaemon->mConnection,theRequest,outStatus ); + if ( theResponse != 0 ) + { + theLayers = getParamValue( theResponse, PAPIParamLayer ); + } + + deleteMessage( theRequest ); + deleteMessage( theResponse ); + } + return theLayers; +} + +void daemonReconnect( PAPIDaemon * inDaemon, + PAPIStatus * outStatus ) +{ + setBlocking( inDaemon->mConnection, 0 ); + createSession( inDaemon, outStatus ); + if ( *outStatus == PAPISuccess ) + { + PAPIListenerList * theList = inDaemon->mConnection->mListeners; + setBlocking( inDaemon->mConnection, 1 ); + while ( theList != 0 ) + { + daemonReaddListener( inDaemon, theList->mComponentName, outStatus); + theList = theList->mNext; + } + } +} + +void daemonRemoveListener( PAPIDaemon * inDaemon, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ) +{ + *outStatus = PAPISuccess; + if ( inDaemon->mSessionId != 0 && inListenerId != 0 ) + { + PAPIMessage * theRequest; + PAPIMessage * theResponse; + PAPIListenerList * theListenerList = + ( PAPIListenerList * )inListenerId; + const char * theComponentName = theListenerList->mComponentName; + + if ( theComponentName == 0 ) + { + return; + } + + theRequest = newMessage( PAPIReqRemoveListener ); + if ( theRequest == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return; + } + addParam( theRequest, PAPIParamSessionId, inDaemon->mSessionId ); + addParam( theRequest, PAPIParamComponentName, theComponentName ); + theResponse = sendRequest( inDaemon->mConnection,theRequest,outStatus ); + deleteMessage( theRequest ); + deleteMessage( theResponse ); + + if ( *outStatus == PAPISuccess ) + { + connectionRemoveListener( inDaemon->mConnection, + inListenerId, + outStatus ); + } + } +} + +void deleteDaemon( PAPIDaemon * inDaemon ) +{ + if ( inDaemon != 0 ) + { + if ( inDaemon->mUserId != 0 ) + { + free( ( void *)inDaemon->mUserId ); + } + if ( inDaemon->mEntities != 0 ) + { + papiFreeEntityList( inDaemon->mEntities ); + } + if ( inDaemon->mSessionId != 0 ) + { + destroySession( inDaemon ); + free( ( void * )inDaemon->mSessionId ); + } + deleteConnection( inDaemon->mConnection ); + free( inDaemon ); + } +} + +static void fillDaemonEntities( PAPIDaemon * inDaemon ) +{ + PAPIEntityList *theEntity = inDaemon->mEntities; + + while ( theEntity != 0 ) + { + switch ( theEntity->entityType ) + { + case PAPIEntityUser: + if ( theEntity->entityId == 0 ) + { + theEntity->entityId = strdup(inDaemon->mUserId); + } + break ; + default: + break ; + } + theEntity = theEntity->next; + } +} + +PAPIDaemon * newDaemon( const PAPIEntityList * inEntities, + PAPIConnectionListener inListener, + void * inUserData, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPIStatus * outStatus ) +{ + PAPIDaemon * theDaemon = ( PAPIDaemon *)malloc( sizeof( PAPIDaemon ) ); + if ( theDaemon == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return 0; + } + memset( theDaemon, 0, sizeof( PAPIDaemon ) ); + theDaemon->mUserId = getUserName(); + if ( theDaemon->mUserId == 0 ) + { + *outStatus = PAPIUnknownFailure; + deleteDaemon( theDaemon ); + return 0; + } + if ( inEntities != 0 ) + { + theDaemon->mEntities = papiCopyEntityList( inEntities ); + if ( theDaemon->mEntities == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + deleteDaemon( theDaemon ); + return 0; + } + fillDaemonEntities( theDaemon ); + } + + + theDaemon->mConnection = newConnection( inListener, + inUserData, + inInternalListener, + inInternalListenerData, + outStatus ); + if ( *outStatus == PAPISuccess ) + { + daemonReconnect( theDaemon, outStatus ); + } + if ( *outStatus != PAPISuccess && *outStatus != PAPIConnectionFailure ) + { + deleteDaemon( theDaemon ); + theDaemon = 0; + } + return theDaemon; +} + +PAPIMessage * createCreateSessionRequest( const char * inUserId, + const PAPIEntityList * inEntities, + const char * inCredentials ) +{ + PAPIMessage * theRequest = newMessage( PAPIReqCreateSessionExt ); + if ( theRequest != 0 ) + { + const PAPIEntityList * entity = inEntities; + + addParam( theRequest, PAPIParamUserId, inUserId ); + addParam( theRequest, PAPIParamCredentials, inCredentials ); + while ( entity != 0 ) + { + addParam( theRequest, PAPIParamEntityType, + getEntityTypeString( entity->entityType ) ); + addParam( theRequest, PAPIParamEntityId, entity->entityId ); + entity = entity->next; + } + } + return theRequest; +} + +void createSession( PAPIDaemon * inDaemon, + PAPIStatus * outStatus ) +{ + int shouldContinue = 1; + char * theCreds = 0; + void * theSASLContext = 0; + + connectionSetSASLAuthHandler( inDaemon->mConnection, 0, 0 ); + while ( shouldContinue == 1 ) + { + PAPIMessage * theResponse; + PAPIMessage * theRequest = + createCreateSessionRequest( inDaemon->mUserId, + inDaemon->mEntities, + theCreds ); + if ( theCreds != 0 ) + { + free( ( void * )theCreds ); + } + if ( theRequest == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + connectionSetSASLAuthHandler( inDaemon->mConnection, + saslAuthHandler, + inDaemon ); + return; + } + theResponse = sendRequest(inDaemon->mConnection, theRequest, outStatus); + deleteMessage( theRequest ); + if ( *outStatus == PAPISuccess ) + { + PAPIStringList * theValues; + switch( theResponse->mName ) + { + case PAPIRespSuccess: + theValues = getParamValue( theResponse, PAPIParamSessionId); + if ( theValues != 0 ) + { + inDaemon->mSessionId = strdup( theValues->data ); + deleteStringList( theValues ); + } + shouldContinue = 0; + break; + + case PAPIRespSuccessContinueLocalAuth: + case PAPIRespSuccessContinueSASLAuth: + theValues = getParamValue( theResponse, PAPIParamMessage ); + if ( theValues != 0 ) + { + theCreds = + theResponse->mName == PAPIRespSuccessContinueLocalAuth? + ( char * )getLocalCreds( theValues->data, + outStatus ) : + ( char * )getSASLCreds( theValues->data, + outStatus ); + if ( *outStatus != PAPISuccess ) + { + theCreds = 0; + *outStatus = PAPISuccess; + } + deleteStringList( theValues ); + } + else + { + *outStatus = PAPIUnknownFailure; + shouldContinue = 0; + } + break; + + case PAPIRespConnectionFailure: + case PAPIRespAuthenticationFailure: + *outStatus = PAPISuccess; + shouldContinue = 0; + break; + + default: + *outStatus = PAPIUnknownFailure; + shouldContinue = 0; + break; + } + } + else + { + shouldContinue = 0; + } + deleteMessage( theResponse ); + } + connectionSetSASLAuthHandler( inDaemon->mConnection, + saslAuthHandler, + inDaemon ); +} + +void daemonReaddListener( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIStatus * outStatus ) +{ + if ( inDaemon->mSessionId != 0 ) + { + PAPIMessage * theRequest; + PAPIMessage * theResponse; + + theRequest = newMessage( PAPIReqAddListener ); + if ( theRequest == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return; + } + addParam( theRequest, PAPIParamSessionId, inDaemon->mSessionId ); + addParam( theRequest, PAPIParamComponentName, inComponentName ); + theResponse = sendRequest( inDaemon->mConnection,theRequest,outStatus ); + deleteMessage( theRequest ); + deleteMessage( theResponse ); + } + else + { + *outStatus = PAPIAuthenticationFailure; + } +} + +void destroySession( PAPIDaemon * inDaemon ) +{ + if ( inDaemon->mSessionId != 0 ) + { + PAPIMessage * theRequest; + PAPIMessage * theResponse; + PAPIStatus theStatus; + + theRequest = newMessage( PAPIReqDestroySession ); + if ( theRequest == 0 ) + { + return; + } + addParam( theRequest, PAPIParamSessionId, inDaemon->mSessionId ); + theResponse = sendRequest( inDaemon->mConnection,theRequest,&theStatus); + deleteMessage( theRequest ); + deleteMessage( theResponse ); + } +} + +const char * getLocalCreds( const char * inLocalChallengeFile, + PAPIStatus * outStatus ) +{ + char * theCredentials = ( char * )malloc( sLocalCredentialsBufferSize ); + if ( theCredentials == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return theCredentials; + } + if ( inLocalChallengeFile != 0 ) + { + FILE * theFile = fopen( inLocalChallengeFile, "r" ); + if ( theFile != 0 ) + { + fgets( theCredentials, + sLocalCredentialsBufferSize, + theFile ); + fclose( theFile ); + } + else + { + *outStatus = PAPIUnknownFailure; + } + } + else + { + *outStatus = PAPIUnknownFailure; + } + return theCredentials; +} + +void * saslAuthHandler( void * inData ) +{ + PAPIAuthHandlerData * theData = ( PAPIAuthHandlerData * )inData; + PAPIDaemon * theDaemon = ( PAPIDaemon * )theData->mUserData; + PAPIStringList * theValues = getParamValue( theData->mChallenge, + PAPIParamMessage ); + deleteMessage( theData->mChallenge ); + if ( theValues != 0 ) + { + PAPIStatus theStatus; + const char * theCreds = + getSASLCreds( theValues->data, &theStatus ); + PAPIMessage * theRequest = + createCreateSessionRequest( theDaemon->mUserId, + theDaemon->mEntities, + theCreds ); + deleteStringList( theValues ); + if ( theCreds != 0 ) + { + free( ( void * )theCreds ); + } + if ( theRequest != 0 ) + { + PAPIMessage * theResponse = + sendRequest( theDaemon->mConnection, theRequest,&theStatus); + deleteMessage( theResponse ); + deleteMessage( theRequest ); + } + } + connectionSetSASLAuthHandler( theDaemon->mConnection, + saslAuthHandler, + theDaemon ); + return 0; +} diff --git a/libapoc/papiDaemon.h b/libapoc/papiDaemon.h new file mode 100644 index 0000000..b7732b8 --- /dev/null +++ b/libapoc/papiDaemon.h @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +/* papiDaemon.h */ + +#ifndef PAPIDAEMON_H_ +#define PAPIDAEMON_H_ + +#include "papiConnection.h" +#include "papiTypes.h" +#include "papiInternal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PAPIDaemon +{ + const char * mUserId; + PAPIEntityList * mEntities; + PAPIConnection * mConnection; + const char * mSessionId; + PAPIConnectionListener mConnectionListener; + void * mUserData; +} PAPIDaemon; + +PAPIListenerId daemonAddListener( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +PAPIStringList *daemonList( PAPIDaemon * inDaemon, + PAPIStatus * outStatus ); + +PAPIStringList *daemonRead( PAPIDaemon * inDaemon, + const char * inComponentName, + PAPIStatus * outStatus ); + +void daemonReconnect( PAPIDaemon * inDaemon, + PAPIStatus * outStatus ); + +void daemonRemoveListener( PAPIDaemon * inDaemon, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ); + +void deleteDaemon( PAPIDaemon * inDaemon ); + +PAPIDaemon * newDaemon( const PAPIEntityList * inEntities, + PAPIConnectionListener inListener, + void * inUserData, + PAPIListener inInternalListener, + void * inInternalListenerData, + PAPIStatus * outStatus ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPIDAEMON_H_ */ diff --git a/libapoc/papiDatabase.c b/libapoc/papiDatabase.c new file mode 100644 index 0000000..dad61e6 --- /dev/null +++ b/libapoc/papiDatabase.c @@ -0,0 +1,285 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiDatabase.h" +#include "papiInternal.h" +#include "papiUtils.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void connectionListener( PAPIConnectionState inState, + void * inUserData); + +static int componentExists( PAPIDatabase * inDatabase, + const char * inComponentName ); + +static void componentsListener( const PAPIEvent * inEvent, + void * inUserData ); + +static void * onConnect( void * inDatabase ); + +static void * onDisconnect( void * inDatabase ); + +#define TIMESTAMPSIZE 16 + + +PAPIListenerId addListenerToDatabase( PAPIDatabase * inDatabase, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + return daemonAddListener( inDatabase->mDaemon, + inComponentName, + inListener, + inUserData, + outStatus ); +} + +void deleteDatabase( PAPIDatabase * inDatabase ) +{ + if ( inDatabase != 0 ) + { + deleteStringList( inDatabase->mComponents ); + deleteMutex( inDatabase->mComponentsMutex ); + if ( inDatabase->mDaemon != 0 ) + { + deleteDaemon( inDatabase->mDaemon ); + } + deleteMutex( inDatabase->mConnectionStateMutex ); + free( ( void *)inDatabase ); + } +} + +PAPIConnectionState getConnectionState( PAPIDatabase * inDatabase ) +{ + PAPIConnectionState theState = PAPIDisconnected; + if ( lockMutex( inDatabase->mConnectionStateMutex ) == 0 ) + { + theState = inDatabase->mConnectionState; + unlockMutex( inDatabase->mConnectionStateMutex ); + } + return theState; +} + +PAPILayerList * readLayersFromDatabase( PAPIDatabase * inDatabase, + const char * inComponentName, + PAPIStatus * outStatus ) +{ + PAPILayerList * theLayerList = 0; + if ( componentExists( inDatabase, inComponentName ) != 0 ) + { + PAPIStringList * theTmpList = + daemonRead( inDatabase->mDaemon, inComponentName, outStatus ); + PAPIStringList * theList = theTmpList; + while ( theTmpList != 0 ) + { + if ( theTmpList->data != 0 && + strlen( theTmpList->data ) >= TIMESTAMPSIZE ) + { + char theTimestamp[ TIMESTAMPSIZE ]; + snprintf( theTimestamp, TIMESTAMPSIZE, "%s", theTmpList->data); +#ifdef WNT + theTimestamp[ TIMESTAMPSIZE - 1 ] = 0; +#endif + addLayerList( &theLayerList, + theTmpList->data + TIMESTAMPSIZE - 1, + theTimestamp ); + theTmpList = theTmpList->next; + } + } + deleteStringList( theList ); + } + else + { + *outStatus = PAPINoSuchComponentFailure; + } + return theLayerList; +} + +PAPIStringList * readNamesFromDatabase( PAPIDatabase * inDatabase, + const char * inFilter ) +{ + PAPIStringList * theList = 0; + if ( lockMutex( inDatabase->mComponentsMutex ) == 0 ) + { + theList = copyStringList( inDatabase->mComponents ); + unlockMutex( inDatabase->mComponentsMutex ); + } + return theList; +} + +void removeListenerFromDatabase( PAPIDatabase * inDatabase, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ) +{ + daemonRemoveListener( inDatabase->mDaemon, inListenerId, outStatus ); +} + +PAPIDatabase * newDatabase( const PAPIEntityList * inEntities, + PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIDatabase * theDatabase = + ( PAPIDatabase *)malloc( sizeof( PAPIDatabase ) ); + + if ( theDatabase == 0 ) + { + *outStatus = PAPIOutOfMemoryFailure; + return 0; + } + memset( theDatabase, 0, sizeof( PAPIDatabase ) ); + theDatabase->mConnectionListener = inConnectionListener; + theDatabase->mUserData = inUserData; + theDatabase->mConnectionState = PAPIDisconnected; + theDatabase->mConnectionStateMutex = newMutex(); + if ( lockMutex( theDatabase->mConnectionStateMutex ) == 0 ) + { + theDatabase->mDaemon = newDaemon( inEntities, + connectionListener, + theDatabase, + componentsListener, + theDatabase, + outStatus ); + if ( *outStatus != PAPISuccess && + ( *outStatus != PAPIConnectionFailure || isDaemonEnabled() == 0 ) ) + { + unlockMutex( theDatabase->mConnectionStateMutex ); + deleteDatabase( theDatabase ); + theDatabase = 0; + } + else + { + if ( *outStatus == PAPISuccess ) + { + theDatabase->mComponents = + daemonList( theDatabase->mDaemon, outStatus ); + theDatabase->mConnectionState = PAPIConnected; + } + theDatabase->mComponentsMutex = newMutex(); + unlockMutex( theDatabase->mConnectionStateMutex ); + } + } + return theDatabase; +} + +void connectionListener( PAPIConnectionState inState, void * inUserData ) +{ + createThread( inState == PAPIConnected ? onConnect : onDisconnect, + inUserData ); +} + +int componentExists( PAPIDatabase * inDatabase, const char * inComponentName ) +{ + int haveComponent = 0; + if ( lockMutex( inDatabase->mComponentsMutex ) == 0 ) + { + haveComponent = + containsString( inDatabase->mComponents, inComponentName ); + unlockMutex( inDatabase->mComponentsMutex ); + } + return haveComponent; +} + +void componentsListener( const PAPIEvent * inEvent, void * inUserData ) +{ + PAPIDatabase * theDatabase = ( PAPIDatabase * )inUserData; + if ( lockMutex( theDatabase->mComponentsMutex ) == 0 ) + { + if ( inEvent->eventType == PAPIComponentAdd ) + { + addStringList( &theDatabase->mComponents, + ( const char * )inEvent->componentName ); + } + else + { + deleteStringList( + removeStringList( &theDatabase->mComponents, + ( const char * )inEvent->componentName ) ); + } + unlockMutex( theDatabase->mComponentsMutex ); + } +} + +void * onConnect( void * inDatabase ) +{ + PAPIStatus theStatus; + PAPIDatabase * theDatabase = ( PAPIDatabase * )inDatabase; + if ( lockMutex( theDatabase->mConnectionStateMutex ) == 0 ) + { + daemonReconnect( theDatabase->mDaemon, + &theStatus ); + if ( theStatus == PAPISuccess ) + { + theDatabase->mConnectionState = PAPIConnected; + if ( lockMutex( theDatabase->mComponentsMutex ) == 0 ) + { + deleteStringList( theDatabase->mComponents ); + theDatabase->mComponents = + daemonList( theDatabase->mDaemon, &theStatus ); + unlockMutex( theDatabase->mComponentsMutex ); + } + unlockMutex( theDatabase->mConnectionStateMutex ); + if ( theDatabase->mConnectionListener != 0 ) + { + theDatabase->mConnectionListener( PAPIConnected, + theDatabase->mUserData ); + } + } + else + { + unlockMutex( theDatabase->mConnectionStateMutex ); + } + } + return 0; +} + +void * onDisconnect( void * inDatabase ) +{ + PAPIDatabase * theDatabase = ( PAPIDatabase * )inDatabase; + if ( lockMutex( theDatabase->mConnectionStateMutex ) == 0 ) + { + theDatabase->mConnectionState = PAPIDisconnected; + unlockMutex( theDatabase->mConnectionStateMutex ); + if ( theDatabase->mConnectionListener != 0 ) + { + theDatabase->mConnectionListener( PAPIDisconnected, + theDatabase->mUserData ); + } + } + return 0; +} diff --git a/libapoc/papiDatabase.h b/libapoc/papiDatabase.h new file mode 100644 index 0000000..e8e3b86 --- /dev/null +++ b/libapoc/papiDatabase.h @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +/* papiDatabase.h */ + +#ifndef PAPIDATABASE_H_ +#define PAPIDATABASE_H_ + +#include "papiTypes.h" +#include "papiDaemon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PAPIDatabase +{ + PAPIStringList * mComponents; + PAPIMutex * mComponentsMutex; + PAPIDaemon * mDaemon; + PAPIConnectionState mConnectionState; + PAPIMutex * mConnectionStateMutex; + PAPIConnectionListener mConnectionListener; + void * mUserData; +} PAPIDatabase; + +PAPIListenerId addListenerToDatabase( PAPIDatabase * inDatabase, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +void deleteDatabase( PAPIDatabase * inDatabase ); + +PAPIConnectionState getConnectionState( PAPIDatabase * inDatabase ); + +PAPILayerList * readLayersFromDatabase( PAPIDatabase * inDatabase, + const char * inComponentName, + PAPIStatus * outStatus ); + +PAPIStringList * readNamesFromDatabase( PAPIDatabase * inDatabase, + const char * inFilter ); + +void removeListenerFromDatabase( PAPIDatabase * inDatabase, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ); + +PAPIDatabase * newDatabase( const PAPIEntityList * inEntities, + PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIStatus * outStatus ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPIDATABASE_H_ */ diff --git a/libapoc/papiEntityList.c b/libapoc/papiEntityList.c new file mode 100644 index 0000000..3a2249a --- /dev/null +++ b/libapoc/papiEntityList.c @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include "papiEntityList.h" + +#include <stdlib.h> +#include <string.h> + +PAPIEntityList *papiAddEntityItem(PAPIEntityList *aEntities, + PAPIEntityType aEntityType, + const char *aEntityId) +{ + PAPIEntityList *retCode = aEntities ; + + if (aEntityId != NULL) + { + PAPIEntityList *last = retCode ; + PAPIEntityList *newItem = malloc(sizeof(PAPIEntityList)) ; + + newItem->entityType = aEntityType ; + newItem->entityId = strdup(aEntityId) ; + newItem->next = NULL ; + while (last != NULL && last->next != NULL) { last = last->next ; } + if (last != NULL) { last->next = newItem ; } + else { retCode = newItem ; } + } + return retCode ; +} + +PAPIEntityList *papiCopyEntityList(const PAPIEntityList *aEntities) +{ + PAPIEntityList *retCode = NULL ; + + if (aEntities != NULL) + { + retCode = malloc(sizeof(PAPIEntityList)) ; + retCode->entityType = aEntities->entityType ; + if (aEntities->entityId != NULL) + { + retCode->entityId = strdup(aEntities->entityId) ; + } + else { retCode->entityId = NULL ; } + retCode->next = papiCopyEntityList(aEntities->next) ; + } + return retCode ; +} + +void papiFreeEntityList(PAPIEntityList *aEntities) +{ + if (aEntities != NULL) + { + if (aEntities->entityId != NULL) + { + free((void *) aEntities->entityId) ; + } + if (aEntities->next != NULL) { papiFreeEntityList(aEntities->next) ; } + free(aEntities) ; + } +} + diff --git a/libapoc/papiEntityList.h b/libapoc/papiEntityList.h new file mode 100644 index 0000000..6a8b207 --- /dev/null +++ b/libapoc/papiEntityList.h @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef PAPI_ENTITY_LIST_H_ +#define PAPI_ENTITY_LIST_H_ + +/* Recognised entity types. */ +typedef enum { PAPIEntityHost = 0, + PAPIEntityUser } PAPIEntityType; + +typedef struct PAPIEntityList +{ + PAPIEntityType entityType; + const char * entityId; + struct PAPIEntityList * next; +} PAPIEntityList; + +PAPIEntityList * papiAddEntityItem( PAPIEntityList * inEntities, + PAPIEntityType inEntityType, + const char * inEntityId ); +void papiFreeEntityList( PAPIEntityList * inEntities ); +PAPIEntityList *papiCopyEntityList(const PAPIEntityList *aEntities) ; + +#endif /* PAPI_ENTITY_LIST_H_ */ diff --git a/libapoc/papiInternal.c b/libapoc/papiInternal.c new file mode 100644 index 0000000..c2c08e6 --- /dev/null +++ b/libapoc/papiInternal.c @@ -0,0 +1,227 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papi.h" +#include "papiDatabase.h" + +static PAPIMutex * gMutex = 0; + +static int lock( void ) +{ + int theRC = -1; + if ( gMutex == 0 ) + { + gMutex = newMutex(); + } + if ( gMutex != 0 ) + { + theRC = lockMutex( gMutex ); + } + return theRC; +} + +static int unlock( void ) +{ + int theRC = -1; + if ( gMutex != 0 ) + { + theRC = unlockMutex( gMutex ); + } + return theRC; +} + +PAPIListenerId addListener( const PAPI * inPAPI, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPIDatabase * theDatabase = ( PAPIDatabase * )inPAPI; + PAPIListenerId theListenerId; + + if ( theDatabase != 0 && inComponentName != 0 && inListener != 0 ) + { + if ( getConnectionState( theDatabase ) == PAPIDisconnected ) + { + theStatus = PAPIConnectionFailure; + } + else if ( lock() == 0 ) + { + theListenerId = addListenerToDatabase( theDatabase, + inComponentName, + inListener, + inUserData, + &theStatus ); + unlock(); + } + } + else + { + theStatus = PAPIInvalidArg; + } + if ( outStatus != 0 ) + { + *outStatus = theStatus; + } + return theListenerId; +} + +void deinitialise( PAPI * inPAPI, PAPIStatus * outStatus ) +{ + if ( lock() == 0 ) + { + deleteDatabase( ( PAPIDatabase * )inPAPI ); + unlock(); + } + if ( outStatus != 0 ) + { + *outStatus = PAPISuccess; + } +} + +PAPI * initialise( const PAPIEntityList * inEntities, + PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPI * thePAPI = 0; + if ( lock() == 0 ) + { + thePAPI = ( PAPI *)newDatabase( inEntities, + inConnectionListener, + inUserData, + &theStatus ); + unlock(); + } + if ( outStatus != 0 ) + { + *outStatus = theStatus; + } + return thePAPI; +} + +PAPIStringList * listComponentNames( const PAPI * inPAPI, + const char * inFilter, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPIDatabase * theDatabase = ( PAPIDatabase * )inPAPI; + PAPIStringList * theNames = 0; + if ( theDatabase != 0 ) + { + if ( getConnectionState( theDatabase ) == PAPIDisconnected ) + { + theStatus = PAPIConnectionFailure; + } + else if ( lock() == 0 ) + { + theNames = readNamesFromDatabase( theDatabase, inFilter ); + theStatus = PAPISuccess; + unlock(); + } + } + else + { + theStatus = PAPIInvalidArg; + } + if ( outStatus != 0 ) + { + *outStatus = theStatus; + } + return theNames; +} + +PAPILayerList * readComponentLayers( const PAPI * inPAPI, + const char * inComponentName, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPIDatabase * theDatabase = ( PAPIDatabase * )inPAPI; + PAPILayerList * theLayers = 0; + + if ( theDatabase != 0 && inComponentName != 0 ) + { + if ( getConnectionState( theDatabase ) == PAPIDisconnected ) + { + theStatus = PAPIConnectionFailure; + } + else if ( lock() == 0 ) + { + theLayers = readLayersFromDatabase( theDatabase, + inComponentName, + &theStatus ); + unlock(); + } + } + else + { + theStatus = PAPIInvalidArg; + } + if ( outStatus != 0 ) + { + *outStatus = theStatus; + } + return theLayers; +} + +void removeListener( const PAPI * inPAPI, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ) +{ + PAPIStatus theStatus; + PAPIDatabase * theDatabase = ( PAPIDatabase * )inPAPI; + + if ( theDatabase != 0 && inListenerId != 0 ) + { + if ( getConnectionState( theDatabase ) == PAPIDisconnected ) + { + theStatus = PAPIConnectionFailure; + } + else if ( lock() == 0 ) + { + removeListenerFromDatabase( theDatabase, inListenerId, &theStatus ); + unlock(); + } + } + else + { + theStatus = PAPIInvalidArg; + } + if ( outStatus != 0 ) + { + *outStatus = theStatus; + } +} diff --git a/libapoc/papiInternal.h b/libapoc/papiInternal.h new file mode 100644 index 0000000..0b36c17 --- /dev/null +++ b/libapoc/papiInternal.h @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPIINTERNAL_H_ +#define PAPIINTERNAL_H_ + +#include "papi.h" +#include "papiLayerList.h" +#include "papiStringList.h" +#include "papiEntityList.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PAPIListenerId addListener( const PAPI * inPAPI, + const char * inComponentName, + PAPIListener inListener, + void * inUserData, + PAPIStatus * outStatus ); + +void deinitialise( PAPI * inPAPI, + PAPIStatus * outStatus ); + +PAPI * initialise( const PAPIEntityList * inEntities, + PAPIConnectionListener inConnectionListener, + void * inUserData, + PAPIStatus * outStatus ); + +PAPIStringList * listComponentNames( const PAPI * inPAPI, + const char * inFilter, + PAPIStatus * outStatus ); + + + +PAPILayerList * readComponentLayers( const PAPI * inPAPI, + const char * inComponentName, + PAPIStatus * outStatus ); + + + +void removeListener( const PAPI * inPAPI, + PAPIListenerId inListenerId, + PAPIStatus * outStatus ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPIINTERNAL_H_ */ diff --git a/libapoc/papiLayerList.c b/libapoc/papiLayerList.c new file mode 100644 index 0000000..3cb6def --- /dev/null +++ b/libapoc/papiLayerList.c @@ -0,0 +1,104 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiLayerList.h" + +#include <stdlib.h> +#include <string.h> + +static PAPILayerList * newLayerList( void ); + +PAPILayerList * addLayerList( PAPILayerList ** ioPrevious, + const char * inData, + const char * inTimestamp ) +{ + PAPILayerList * theLayerList = ioPrevious[ 0 ]; + + if ( inData != 0 ) + { + if ( ( theLayerList = newLayerList() ) != 0 ) + { + theLayerList->data = ( unsigned char * )strdup( inData ); + theLayerList->size = strlen( inData ); + theLayerList->timestamp = strdup( inTimestamp ); + if ( ioPrevious[ 0 ] == 0 ) + { + ioPrevious[ 0 ] = theLayerList; + } + else + { + PAPILayerList * theTmpList = ioPrevious[ 0 ]; + while ( theTmpList->next != 0 ) + { + theTmpList = theTmpList->next; + } + theTmpList->next = theLayerList; + } + } + } + return theLayerList; +} + +void deleteLayerList( PAPILayerList * inLayerList ) +{ + if ( inLayerList != 0 ) + { + if ( inLayerList->next != 0 ) + { + deleteLayerList( inLayerList->next ); + } + if ( inLayerList->data != 0 ) + { + free( ( void *)inLayerList->data ); + } + if ( inLayerList->timestamp != 0 ) + { + free( ( void *)inLayerList->timestamp ); + } + free( inLayerList ); + } +} + +PAPILayerList * newLayerList( void ) +{ + PAPILayerList * theLayerList = + ( PAPILayerList * )malloc( sizeof( PAPILayerList ) ); + if ( theLayerList != 0 ) + { + theLayerList->data = 0; + theLayerList->size = 0; + theLayerList->next = 0; + } + return theLayerList; +} diff --git a/libapoc/papiLayerList.h b/libapoc/papiLayerList.h new file mode 100644 index 0000000..55fb938 --- /dev/null +++ b/libapoc/papiLayerList.h @@ -0,0 +1,55 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPILAYERLIST_H_ +#define PAPILAYERLIST_H_ + +#include "papiTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PAPILayerList * addLayerList( PAPILayerList ** ioPreviousList, + const char * inData, + const char * inTimestamp ); + +void deleteLayerList( PAPILayerList * inLayerList ); + + +#ifdef __cplusplus +} +#endif + +#endif /* PAPILAYERLIST_H_ */ diff --git a/libapoc/papiListenerList.c b/libapoc/papiListenerList.c new file mode 100644 index 0000000..d7d6222 --- /dev/null +++ b/libapoc/papiListenerList.c @@ -0,0 +1,131 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiListenerList.h" + +#include <stdlib.h> +#include <string.h> + +static PAPIListenerList * newListenerList( void ); + +PAPIListenerList * addListenerList( PAPIListenerList ** ioPrevious, + const char * inComponentName, + PAPIListener inListener, + void * inUserData ) +{ + PAPIListenerList * theListenerList = ioPrevious[ 0 ]; + + if ( inComponentName != 0 && inListener != 0 ) + { + if ( ( theListenerList = newListenerList() ) != 0 ) + { + theListenerList->mComponentName = strdup( inComponentName ); + theListenerList->mListener = inListener; + theListenerList->mUserData = inUserData; + if ( ioPrevious[ 0 ] == 0 ) + { + ioPrevious[ 0 ] = theListenerList; + } + else + { + PAPIListenerList * theTmpList = ioPrevious[ 0 ]; + while ( theTmpList->mNext != 0 ) + { + theTmpList = theTmpList->mNext; + } + theTmpList->mNext = theListenerList; + } + } + } + return theListenerList; +} + +void removeListenerList( PAPIListenerList ** ioPreviousList, + PAPIListenerList * inList ) +{ + if ( inList != 0 && ioPreviousList != 0 ) + { + PAPIListenerList * thePreviousList = 0; + PAPIListenerList * theNextList = ioPreviousList[ 0 ]; + while ( theNextList != 0 ) + { + if ( theNextList == inList ) + { + if ( theNextList == ioPreviousList[ 0 ] ) + { + ioPreviousList[ 0 ] = ioPreviousList[ 0 ]->mNext; + } + else + { + thePreviousList->mNext = theNextList->mNext; + } + inList->mNext = 0; + deleteListenerList( inList ); + break; + } + thePreviousList = theNextList; + theNextList = theNextList->mNext; + } + } +} + +void deleteListenerList( PAPIListenerList * inListenerList ) +{ + if ( inListenerList != 0 ) + { + if ( inListenerList->mNext != 0 ) + { + deleteListenerList( inListenerList->mNext ); + } + if ( inListenerList->mComponentName != 0 ) + { + free( ( void *)inListenerList->mComponentName ); + } + free( inListenerList ); + } +} + +PAPIListenerList * newListenerList( void ) +{ + PAPIListenerList * theListenerList = + ( PAPIListenerList * )malloc( sizeof( PAPIListenerList ) ); + if ( theListenerList != 0 ) + { + theListenerList->mComponentName = 0; + theListenerList->mListener = 0; + theListenerList->mUserData = 0; + theListenerList->mNext = 0; + } + return theListenerList; +} diff --git a/libapoc/papiListenerList.h b/libapoc/papiListenerList.h new file mode 100644 index 0000000..120b0c3 --- /dev/null +++ b/libapoc/papiListenerList.h @@ -0,0 +1,66 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPILISTENERLIST_H_ +#define PAPILISTENERLIST_H_ + +#include "papiTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PAPIListenerList +{ + const char * mComponentName; + PAPIListener mListener; + void * mUserData; + struct PAPIListenerList * mNext; +} PAPIListenerList; + +PAPIListenerList * addListenerList( PAPIListenerList ** ioPreviousList, + const char * inComponentName, + PAPIListener inListener, + void * inUserData ); + +void removeListenerList( PAPIListenerList ** ioPreviousList, + PAPIListenerList * inList ); + +void deleteListenerList( PAPIListenerList * inListenerList ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPILISTENERLIST_H_ */ diff --git a/libapoc/papiMessage.c b/libapoc/papiMessage.c new file mode 100644 index 0000000..da95ef8 --- /dev/null +++ b/libapoc/papiMessage.c @@ -0,0 +1,293 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "papiMessage.h" +#include "papiInternal.h" + +static PAPIParamNameList * newParamNameList( PAPIParamName inParamName ); + +static void deleteParamNameList( PAPIParamNameList * inParamNameList ); + +static PAPIParamNameList * addParamNameList( PAPIParamNameList **ioPreviousList, + PAPIParamName inParamName ); + +static const char *sMessageNames[] = +{ + "success", + "invalidRequest", + "connectionFailure", + "authenticationFailure", + "invalidSessionId", + "noSuchComponent", + "successContinueLocalAuth", + "successContinueSASLAuth", + + "addNotification", + "removeNotification", + "modifyNotification", + + "createSession", + "read", + "list", + "destroySession", + "addListener", + "removeListener", + "createSessionExt" +}; + +static const char *sParamNames[] = +{ + "sessionId", + "userId", + "entityId", + "credentials", + "componentName", + "clientData", + "message", + "layer", + "entityType" +}; + +/* Must be aligned with PAPIEntityType enumeration in papiTypes.h AND + must be the same strings as the SOURCE ones in + spi/environment/EnvironmentConstants. */ +static const char *sEntityTypes[] = +{ + "HOST", + "USER" +}; + +PAPIMessage * newMessage( PAPIMessageName inMessageName ) +{ + PAPIMessage * theMessage = ( PAPIMessage * )malloc( sizeof( PAPIMessage ) ); + if ( theMessage != 0 ) + { + theMessage->mName = inMessageName; + theMessage->mParamNames = 0; + theMessage->mParamValues = 0; + } + return theMessage; +} + +void deleteMessage( PAPIMessage * inMessage ) +{ + if ( inMessage != 0 ) + { + deleteParamNameList( inMessage->mParamNames ); + deleteStringList( inMessage->mParamValues ); + free( ( void * )inMessage ); + } +} + +void addParam( PAPIMessage * inMessage, + PAPIParamName inParamName, + const char * inParamValue ) +{ + if ( inMessage != 0 ) + { + addParamNameList( &inMessage->mParamNames, inParamName ); + addStringList( &inMessage->mParamValues, inParamValue ); + } +} + +char * messageToString( PAPIMessage * inMessage ) +{ + int theStringSize; + char * theString = 0; + if ( inMessage != 0 ) + { + PAPIParamNameList * theNameList = inMessage->mParamNames; + PAPIStringList * theValueList = inMessage->mParamValues; + theStringSize = + ( 2 * strlen( sMessageNames[ ( int )inMessage->mName ] ) ) + 5; + while ( theNameList != 0 ) + { + theStringSize += + ( 2 * strlen( sParamNames[ ( int )theNameList->mName ] ) ) + 5; + if ( theValueList->data != 0 ) + { + theStringSize += strlen( theValueList->data ); + } + theNameList = theNameList->mNext; + theValueList = theValueList->next; + } + + + if ( theStringSize > 0 ) + { + theNameList = inMessage->mParamNames; + theValueList = inMessage->mParamValues; + theString = ( char * )malloc( theStringSize + 1 ); + theString[ 0 ] = 0; + + sprintf( theString, "<%s>", sMessageNames[( int )inMessage->mName]); + while ( theNameList != 0 ) + { + strcat( theString, "<" ); + strcat( theString, sParamNames[ ( int )theNameList->mName ] ); + strcat( theString, ">" ); + + if ( theValueList->data != 0 ) + { + strcat( theString, theValueList->data ); + } + + strcat( theString, "</" ); + strcat( theString, sParamNames[ ( int )theNameList->mName] ); + strcat( theString, ">" ); + + theNameList = theNameList->mNext; + theValueList = theValueList->next; + } + strcat( theString, "</" ); + strcat( theString, sMessageNames[ ( int )inMessage->mName ] ); + strcat( theString, ">" ); + } + } + return theString; +} + +PAPIStringList * getParamValue( PAPIMessage * inMessage, + PAPIParamName inParamName ) +{ + PAPIStringList * theValue = 0; + if ( inMessage != 0 ) + { + PAPIParamNameList * theNames = inMessage->mParamNames; + PAPIStringList * theValues = inMessage->mParamValues; + while ( theNames != 0 ) + { + if ( theNames->mName == inParamName ) + { + addStringList( &theValue, theValues->data ); + } + theNames = theNames->mNext; + theValues = theValues->next; + } + } + return theValue; +} + +PAPIParamNameList * newParamNameList( PAPIParamName inParamName ) +{ + PAPIParamNameList * theList = + ( PAPIParamNameList * )malloc( sizeof( PAPIParamNameList ) ); + if ( theList != 0 ) + { + theList->mName = inParamName; + theList->mNext = 0; + } + return theList; +} + +PAPIMessageName stringToMessageName( const char * inMessageName ) +{ + PAPIMessageName theName = PAPIMessageNameUnused; + if ( inMessageName != 0 ) + { + int theIndex; + for ( theIndex = 0; theIndex < PAPIMessageNameUnused; theIndex ++ ) + { + if ( strcmp( inMessageName, sMessageNames[ theIndex ] ) == 0 ) + { + theName = ( PAPIMessageName )theIndex; + break; + } + } + } + return theName; +} + +PAPIParamName stringToParamName( const char * inParamName ) +{ + PAPIParamName theName = PAPIParamNameUnused; + if ( inParamName != 0 ) + { + int theIndex; + for ( theIndex = 0; theIndex < PAPIParamNameUnused; theIndex ++ ) + { + if ( strcmp( inParamName, sParamNames[ theIndex ] ) == 0 ) + { + theName = ( PAPIParamName )theIndex; + break; + } + } + } + return theName; +} + +static void deleteParamNameList( PAPIParamNameList * inParamNameList ) +{ + if ( inParamNameList != 0 ) + { + if ( inParamNameList->mNext != 0 ) + { + deleteParamNameList( inParamNameList->mNext ); + } + free( ( void * )inParamNameList ); + } +} + +static PAPIParamNameList * addParamNameList( PAPIParamNameList **ioPrevious, + PAPIParamName inParamName ) +{ + PAPIParamNameList * theList = newParamNameList( inParamName ); + if ( theList != 0 ) + { + if ( ioPrevious[ 0 ] == 0 ) + { + ioPrevious[ 0 ] = theList; + } + else + { + PAPIParamNameList * theTmpList = ioPrevious[ 0 ]; + while ( theTmpList->mNext != 0 ) + { + theTmpList = theTmpList->mNext; + } + theTmpList->mNext = theList; + } + } + return theList; +} + +const char * getEntityTypeString( PAPIEntityType inType ) +{ + return sEntityTypes[ inType ]; +} + diff --git a/libapoc/papiMessage.h b/libapoc/papiMessage.h new file mode 100644 index 0000000..988ee99 --- /dev/null +++ b/libapoc/papiMessage.h @@ -0,0 +1,125 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef PAPIMESSAGE_H_ +#define PAPIMESSAGE_H_ + +#include "papiTypes.h" +#include "papiEntityList.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + PAPIRespSuccess = 0, + PAPIRespInvalidRequest, + PAPIRespConnectionFailure, + PAPIRespAuthenticationFailure, + PAPIRespInvalidSessionId, + PAPIRespNoSuchComponent, + PAPIRespSuccessContinueLocalAuth, + PAPIRespSuccessContinueSASLAuth, + + PAPIaddNotification, + PAPIremoveNotification, + PAPImodifyNotification, + + PAPIReqCreateSession, + PAPIReqRead, + PAPIReqList, + PAPIReqDestroySession, + PAPIReqAddListener, + PAPIReqRemoveListener, + PAPIReqCreateSessionExt, + + PAPIMessageNameUnused + +} PAPIMessageName; + +typedef enum +{ + PAPIParamSessionId = 0, + PAPIParamUserId, + PAPIParamEntityId, + PAPIParamCredentials, + PAPIParamComponentName, + PAPIParamClientData, + PAPIParamMessage, + PAPIParamLayer, + PAPIParamEntityType, + PAPIParamNameUnused +} PAPIParamName; + +typedef struct PAPIParamNameList +{ + PAPIParamName mName; + struct PAPIParamNameList * mNext; +} PAPIParamNameList; + +typedef struct PAPIMessage +{ + PAPIMessageName mName; + PAPIParamNameList * mParamNames; + PAPIStringList * mParamValues; +} PAPIMessage; + +PAPIMessage * newMessage( PAPIMessageName inMessageName ); + +void deleteMessage( PAPIMessage * inMessage ); + +void addParam( PAPIMessage * inMessage, + PAPIParamName inParamName, + const char * inParamValue ); + +PAPIStringList *getParamValue( PAPIMessage * inMessage, + PAPIParamName inParamName ); + +char * messageToString( PAPIMessage * inMessage ); + +PAPIMessageName stringToMessageName( const char * inMessageName ); +PAPIParamName stringToParamName( const char * inParamName ); + +const char *getEntityTypeString( PAPIEntityType inType ); + +#define CONTENTLENGTH "CONTENT-LENGTH:" +#define MAX_CONTENT_LENGTH_SIZE 23 + +#ifdef __cplusplus +} +#endif + +#endif /* PAPIMESSAGE_H_ */ diff --git a/libapoc/papiPort.c b/libapoc/papiPort.c new file mode 100644 index 0000000..f19926e --- /dev/null +++ b/libapoc/papiPort.c @@ -0,0 +1,457 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiUtils.h" +#include "config.h" + +#include <gssapi.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <poll.h> +#include <sys/socket.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +#ifdef SOLARIS +#include <libscf.h> +#endif + +static void initGSSAPIContext( const char * inServiceName, + gss_ctx_id_t * outContext, + gss_buffer_desc * outToken, + PAPIStatus * outStatus ); + +static int isDaemonInitdEnabled( void ); + +static void writeGSSAPIAuthId( gss_ctx_id_t * outContext, + gss_buffer_desc * outToken, + PAPIStatus * outStatus ); + +const char * getGSSAPISrcName( gss_ctx_id_t * inContext ); + +static void getTargetService( const char * inServiceName, + gss_name_t * outService, + PAPIStatus * outStatus ); + +static void encodeGSSAPITokens( gss_buffer_desc * inBuffers, + int inBufferCnt, + char ** outB64 ); + +static const char * sInstallDir = APOC_INSTALLDIR; +static const char * sLibraryDir = APOC_LIBRARYDIR; +static const char * sPropertiesDir = APOC_PROPDIR; + + +PAPIThread createThread( PAPIThreadFunc inThreadFunc, void * inArg ) +{ + pthread_attr_t theAttr; + pthread_t * theThread = ( pthread_t * )malloc( sizeof( pthread_t ) ); + + pthread_attr_init( &theAttr ); + pthread_attr_setdetachstate( &theAttr, PTHREAD_CREATE_DETACHED ); + if ( pthread_create( theThread, &theAttr, inThreadFunc, inArg ) != 0 ) + { + free( ( void * )theThread ); + theThread = 0; + } + return theThread; +} + +void destroyThread( PAPIThread inThread ) +{ + pthread_cancel( *inThread ); +} + +void deleteMutex( PAPIMutex * inMutex ) +{ + if ( inMutex != 0 ) + { + pthread_mutex_destroy( inMutex ); + free( ( void * )inMutex ); + } +} + +const char * getSASLCreds( const char * inServiceName, PAPIStatus * outStatus ) +{ + char * theCredentials = 0; + gss_ctx_id_t theContextHandle = GSS_C_NO_CONTEXT; + gss_buffer_desc theOutputTokens[ 3 ]; + + theOutputTokens[ 0 ].length = + theOutputTokens[ 1 ].length = + theOutputTokens[ 2 ].length = 0; + initGSSAPIContext( inServiceName, + &theContextHandle, + &theOutputTokens[ 0 ], + outStatus ); + if ( *outStatus == PAPISuccess ) + { + writeGSSAPIAuthId( &theContextHandle, &theOutputTokens[ 2 ],outStatus ); + if ( *outStatus == PAPISuccess ) + { + OM_uint32 theMinorStatus; + encodeGSSAPITokens( theOutputTokens, + 3, + &theCredentials ); + gss_release_buffer( &theMinorStatus, &theOutputTokens[ 0 ] ); + gss_release_buffer( &theMinorStatus, &theOutputTokens[ 2 ] ); + gss_delete_sec_context( &theMinorStatus, + &theContextHandle, + 0 ); + } + } + return theCredentials; +} + +const char * getInstallDir( void ) +{ + return sInstallDir; +} + +const char * getLibraryDir( void ) +{ + return sLibraryDir; +} + +const char * getPropertiesDir( void ) +{ + return sPropertiesDir; +} + +const char * getUserName( void ) +{ +/* + * no longer using cuserid here as it truncates user name at 8 characters + */ + struct passwd * thePasswd = getpwuid( geteuid() ); + return thePasswd != 0 && thePasswd->pw_name != 0 ? + strdup( thePasswd->pw_name ) : 0; +} + +int isDaemonEnabled( void ) +{ + int isDaemonEnabled = 0; +#ifdef SOLARIS + isDaemonEnabled = isServiceEnabled(); +#else + isDaemonEnabled = isDaemonInitdEnabled(); +#endif + return isDaemonEnabled; +} + +#ifdef SOLARIS +int isServiceEnabled( void ) +{ + static const char * sInstanceName = "svc:/network/apocd/udp:default"; + int isServiceEnabled = 0; + char * theState = smf_get_state( sInstanceName ); + if ( theState != 0 ) + { + if ( strcmp( theState, SCF_STATE_STRING_DISABLED ) != 0 ) + { + isServiceEnabled = 1; + } + free( ( void * )theState ); + } + return isServiceEnabled; +} +#else +int isDaemonInitdEnabled( void ) +{ + static char * theCommand = "/sbin/chkconfig -c apocd"; + FILE * theStream; + int theRC = 0; + + theStream = papiPopen( theCommand, "w" ); + if ( theStream != 0 ) + { + theRC = papiPclose( theStream ) == 0 ? 1 : 0; + } + + return theRC; +} +#endif + +int lockMutex( PAPIMutex * inMutex ) +{ + return pthread_mutex_lock( inMutex ); +} + +PAPIMutex * newMutex( void ) +{ + pthread_mutex_t * theMutex = + ( pthread_mutex_t * )malloc( sizeof( pthread_mutex_t ) ); + if ( theMutex != 0 ) + { + pthread_mutex_init( theMutex, 0 ); + } + return theMutex; +} + +int socketPoll( PAPISocket inSocket, int inMillis ) +{ + struct pollfd thePollFD; + int theRC; + + thePollFD.fd = inSocket; + thePollFD.events = POLLIN; + theRC = poll( &thePollFD, 1, inMillis ); + if ( theRC == 1 && thePollFD.revents & POLLIN != POLLIN ) + { + theRC = 0; + } + else if ( theRC == -1 && thePollFD.revents & POLLHUP == POLLHUP ) + { + theRC = 0; + } + + return theRC; +} + +int startDaemon( void ) +{ + int theRC = 1; + + /* + * apoc2.0: daemon startup via inetd no longer supported + * + if ( isDaemonEnabled() == 1 ) + { + int theSocket = getConnectedSocket( getDaemonPort(), SOCK_DGRAM, 0 ); + if ( theSocket != INVALID_SOCKET ) + { + if ( send( theSocket, ( void *)"\n", 1, 0 ) != -1 ) + { + theRC = 0; + } + close( theSocket ); + } + } + */ + return theRC; +} + +int unlockMutex( PAPIMutex * inMutex ) +{ + return pthread_mutex_unlock( inMutex ); +} + +void encodeGSSAPITokens( gss_buffer_desc * inBuffers, + int inBufferCnt, + char ** outB64Buffer ) +{ + void * theBuffer; + char * theTmpPtr; + int theBufferSize = 0; + int theIndex; + + for ( theIndex = 0; theIndex < inBufferCnt; ++ theIndex ) + { + theBufferSize += inBuffers[ theIndex ].length + 5; + } + + theBuffer = malloc( theBufferSize ); + theTmpPtr = ( char *)theBuffer; + for ( theIndex = 0; theIndex < inBufferCnt; ++ theIndex ) + { + /* Write the token size */ + snprintf( theTmpPtr, 6, "%05d", inBuffers[ theIndex ].length ); + theTmpPtr += 5; + + /* Write the token */ + memcpy( ( void *)theTmpPtr, + inBuffers[ theIndex ].value, + inBuffers[ theIndex ].length); + theTmpPtr += inBuffers[ theIndex ].length; + } + base64_encode( theBuffer, theBufferSize, outB64Buffer ); + free( ( void *)theBuffer ); +} + +void initGSSAPIContext( const char * inServiceName, + gss_ctx_id_t * outContext, + gss_buffer_desc * outToken, + PAPIStatus * outStatus ) +{ + gss_name_t theServiceName; + + getTargetService( inServiceName, &theServiceName, outStatus ); + if ( *outStatus == PAPISuccess ) + { + OM_uint32 theMajorStatus; + OM_uint32 theMinorStatus; + gss_buffer_desc theServiceNameBuf; + OM_uint32 theReqFlags = GSS_C_DELEG_FLAG; + OM_uint32 theRetFlags; + gss_OID theMech; +#ifdef SOLARIS + gss_OID_desc theMechArr = + { 9, "\052\206\110\206\367\022\001\002\002"}; + theMech = &theMechArr; +#else + theMech = GSS_KRB5_MECHANISM; +#endif + + outToken->length = 0; + theMajorStatus = gss_init_sec_context( &theMinorStatus, + GSS_C_NO_CREDENTIAL, + outContext, + theServiceName, + GSS_C_NO_OID, + 0, + 0, + NULL, + GSS_C_NO_BUFFER, + 0, + outToken, + &theRetFlags, + 0 ); + if ( theMajorStatus == GSS_S_COMPLETE ) + { + *outStatus = PAPISuccess; + } + else + { + *outStatus = PAPIAuthenticationFailure; + } + } +} + +const char * getGSSAPISrcName( gss_ctx_id_t * inContext ) +{ + char * theGSSAPISrcName = 0; + OM_uint32 theMajorStatus; + OM_uint32 theMinorStatus; + gss_name_t theSrcName; + + theMajorStatus = gss_inquire_context( &theMinorStatus, + *inContext, + &theSrcName, + 0, + 0, + 0, + 0, + 0, + 0 ); + if ( theMajorStatus == GSS_S_COMPLETE ) + { + gss_buffer_desc theSrcNameBuffer; + theMajorStatus = gss_display_name( &theMinorStatus, + theSrcName, + &theSrcNameBuffer, + 0 ); + if ( theMajorStatus == GSS_S_COMPLETE ) + { + int theSize = theSrcNameBuffer.length + 1; + theGSSAPISrcName = ( char * )malloc( theSize ); + if ( theGSSAPISrcName != 0 ) + { + snprintf( theGSSAPISrcName, + theSize, + "%s", + ( char *)theSrcNameBuffer.value ); + } + gss_release_buffer( &theMinorStatus, &theSrcNameBuffer ); + } + } + return theGSSAPISrcName; +} + +void getTargetService( const char * inServiceName, + gss_name_t * outServiceName, + PAPIStatus * outStatus ) +{ + if ( inServiceName != 0 ) + { + OM_uint32 theMajorStatus; + OM_uint32 theMinorStatus; + gss_buffer_desc theServiceNameBuf; + OM_uint32 theReqFlags = GSS_C_DELEG_FLAG; + OM_uint32 theRetFlags; + + theServiceNameBuf.length = strlen( inServiceName ); + theServiceNameBuf.value = ( char * )inServiceName; + theMajorStatus = + gss_import_name( &theMinorStatus, + &theServiceNameBuf, + GSS_C_NO_OID, + outServiceName ); + *outStatus = theMajorStatus == GSS_S_COMPLETE ? + PAPISuccess : PAPIAuthenticationFailure; + } +} + +void writeGSSAPIAuthId( gss_ctx_id_t * inContext, + gss_buffer_desc * outToken, + PAPIStatus * outStatus ) +{ + /* + * We no longer write the ldap authorisation id as LDAP servers + * can't agree on the format. + * See 6275775 + */ + OM_uint32 theMajorStatus; + OM_uint32 theMinorStatus; + gss_buffer_desc theAuthzIdBuffer; + int theConfState; + + *outStatus = PAPIAuthenticationFailure; + theAuthzIdBuffer.length = 4; + theAuthzIdBuffer.value = malloc( theAuthzIdBuffer.length ); + if ( theAuthzIdBuffer.value != 0 ) + { + char * theCP = ( char *)theAuthzIdBuffer.value; + /* security layer */ + theCP[ 0 ] = ( char )1; + /* message size */ + theCP[ 1 ] = ( char )1; + theCP[ 2 ] = theCP[ 3 ] = ( char )0; + + theMajorStatus = gss_wrap( &theMinorStatus, + *inContext, + 0, + GSS_C_QOP_DEFAULT, + &theAuthzIdBuffer, + &theConfState, + outToken ); + free( theAuthzIdBuffer.value ); + if ( theMajorStatus == GSS_S_COMPLETE ) + { + *outStatus = PAPISuccess; + } + } +} diff --git a/libapoc/papiSAXParserContext.c b/libapoc/papiSAXParserContext.c new file mode 100644 index 0000000..edf60dc --- /dev/null +++ b/libapoc/papiSAXParserContext.c @@ -0,0 +1,182 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include <stdlib.h> + +#include "papiSAXParserContext.h" + +static int saxReader( void * inIOContext, char * inBuffer, int inLen ); + +static int saxCloser( void * inIOContext ); + +static void papiStartElement( void * inUserData, + const xmlChar * inName, + const xmlChar ** inAttrs ); +static void papiCharacters( void * inUserData, + const xmlChar * inChars, + int inLen ); + +static xmlSAXHandler sSAXHandler = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + papiStartElement, + 0, + 0, + papiCharacters, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + }; + +PAPISAXParserContext newSAXParserContext( PAPIConnection * inConnection, + PAPISAXUserData * inUserData ) +{ + PAPISAXParserContext theSAXParserContext; + PAPISAXIOContext * theIOContext = + ( PAPISAXIOContext * )malloc( sizeof( PAPISAXIOContext ) ); + if ( theIOContext != 0 ) + { + theIOContext->mContentLength = -1; + theIOContext->mConnection = inConnection; + + theSAXParserContext = + xmlCreateIOParserCtxt( &sSAXHandler, + ( void *) inUserData, + saxReader, + saxCloser, + ( void *)theIOContext, + XML_CHAR_ENCODING_NONE ); + + } + return theSAXParserContext; +} + +void deleteSAXParserContext( PAPISAXParserContext inParserContext ) +{ + xmlFreeParserCtxt( inParserContext ); +} + +int parse( PAPISAXParserContext inParserContext ) +{ + return xmlParseDocument( inParserContext ); +} + +void papiStartElement( void * inUserData, + const xmlChar * inName, + const xmlChar ** inAttrs ) +{ + PAPISAXUserData * theUserData = ( PAPISAXUserData * )inUserData; + if ( theUserData != 0 && theUserData->mMessage == 0 ) + { + theUserData->mMessage = newMessage( + stringToMessageName( ( const char * )inName ) ); + } + else + { + theUserData->mCurrentParamName = + stringToParamName( ( const char * )inName ); + } +} + +void papiCharacters( void * inUserData, + const xmlChar * inChars, + int inLen ) +{ + PAPISAXUserData * theUserData = ( PAPISAXUserData * )inUserData; + if ( theUserData != 0 && theUserData->mMessage != 0 ) + { + char * theValue = ( char * )malloc( inLen + 1 ); + if ( theValue != 0 ) + { + snprintf( theValue, inLen + 1, "%s", inChars ); + theValue[ inLen ] = 0; + addParam( theUserData->mMessage, + theUserData->mCurrentParamName, + theValue ); + free( ( void *)theValue ); + theUserData->mCurrentParamName = PAPIParamNameUnused; + } + } +} + +int saxReader( void * inIOContext, char * inBuffer, int inLen ) +{ + int theByteCount = EOF; + PAPISAXIOContext * theIOContext = ( PAPISAXIOContext * )inIOContext; + + if ( theIOContext->mContentLength == -1 ) + { + theIOContext->mContentLength = + readContentLength( theIOContext->mConnection ); + } + if ( theIOContext->mContentLength > 0 ) + { + int theLen = inLen < theIOContext->mContentLength ? + inLen : theIOContext->mContentLength; + theByteCount = readBytes( theIOContext->mConnection, + ( void *)inBuffer, + theLen ); + if ( theByteCount > 0 ) + { + theIOContext->mContentLength -= theByteCount; + } + } + return theByteCount == -1 ? 0 : theByteCount; +} + +int saxCloser( void * inIOContext ) +{ + free( inIOContext ); + return 0; +} diff --git a/libapoc/papiSAXParserContext.h b/libapoc/papiSAXParserContext.h new file mode 100644 index 0000000..b36bf99 --- /dev/null +++ b/libapoc/papiSAXParserContext.h @@ -0,0 +1,74 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#ifndef PAPISAXPARSERCONTEXT_H_ +#define PAPISAXPARSERCONTEXT_H_ + +#include <libxml/parser.h> + +#include "papiConnection.h" +#include "papiMessage.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef xmlParserCtxtPtr PAPISAXParserContext; + +typedef struct PAPISAXIOContext +{ + int mContentLength; + PAPIConnection * mConnection; +} PAPISAXIOContext; + +typedef struct PAPISAXUserData +{ + PAPIMessage * mMessage; + PAPIParamName mCurrentParamName; +} PAPISAXUserData; + +PAPISAXParserContext newSAXParserContext( PAPIConnection * inFD, + PAPISAXUserData * inUserData ); + +void deleteSAXParserContext( PAPISAXParserContext inParserContext ); + +int parse( PAPISAXParserContext inParserContext ); + + +#ifdef __cplusplus +} +#endif + +#endif /* PAPISAXPARSERCONTEXT_H_ */ diff --git a/libapoc/papiStringList.c b/libapoc/papiStringList.c new file mode 100644 index 0000000..d992af6 --- /dev/null +++ b/libapoc/papiStringList.c @@ -0,0 +1,176 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiStringList.h" + +#include <stdlib.h> +#include <string.h> + +static PAPIStringList * newStringList( void ); + +PAPIStringList * addStringList( PAPIStringList ** ioPrevious, + const char * inData ) +{ + PAPIStringList * theStringList = newStringList(); + if ( theStringList != 0 ) + { + theStringList->data = inData == 0 ? 0 : strdup( inData ); + if ( ioPrevious[ 0 ] == 0 ) + { + ioPrevious[ 0 ] = theStringList; + } + else + { + PAPIStringList * theTmpList = ioPrevious[ 0 ]; + while ( theTmpList->next != 0 ) + { + theTmpList = theTmpList->next; + } + theTmpList->next = theStringList; + } + } + return theStringList; +} + +int containsString( PAPIStringList * inList, const char * inString ) +{ + int isContained = 0; + if ( inList != 0 && inString != 0 ) + { + while ( inList != 0 ) + { + if ( strcmp( inList->data, inString ) == 0 ) + { + isContained = 1; + break; + } + inList = inList->next; + } + } + return isContained; +} + +PAPIStringList * copyStringList( PAPIStringList * inList ) +{ + PAPIStringList * theList = 0; + while ( inList != 0 ) + { + addStringList( &theList, inList->data ); + inList = inList->next; + } + return theList; +} + +void deleteStringList( PAPIStringList * inStringList ) +{ + if ( inStringList != 0 ) + { + if ( inStringList->next != 0 ) + { + deleteStringList( inStringList->next ); + } + if ( inStringList->data != 0 ) + { + free( ( void *)inStringList->data ); + } + free( inStringList ); + } +} + +PAPIStringList * removeStringList( PAPIStringList ** ioStringList, + const char * inString ) +{ + PAPIStringList * theList = 0; + if ( ioStringList != 0 && inString != 0 ) + { + theList = ioStringList[ 0 ]; + if ( theList != 0 ) + { + PAPIStringList * thePrevList = theList; + while ( theList != 0 ) + { + if ( strcmp( theList->data, inString ) == 0 ) + { + if ( theList == ioStringList[ 0 ] ) + { + ioStringList[ 0 ] = ioStringList[ 0 ]->next; + } + else + { + thePrevList->next = theList->next; + } + theList->next = 0; + break; + } + thePrevList = theList; + theList = theList->next; + } + } + } + return theList; +} + +PAPIStringList * strToStringList( const char * inString ) +{ + PAPIStringList * theList = 0; + if ( inString != 0 ) + { + PAPIStringList * theTmpList; + const char * theString = strdup( inString ); + char * theToken = strtok( ( char *)theString, " " ); + while ( theToken != 0 ) + { + theTmpList = addStringList( &theList, theToken ); + if ( theList == 0 ) + { + theList = theTmpList; + } + theToken = strtok( NULL, " " ); + } + free( ( void * )theString ); + } + return theList; +} + +PAPIStringList * newStringList( void ) +{ + PAPIStringList * theStringList = + ( PAPIStringList * )malloc( sizeof( PAPIStringList ) ); + if ( theStringList != 0 ) + { + theStringList->data = 0; + theStringList->next = 0; + } + return theStringList; +} diff --git a/libapoc/papiStringList.h b/libapoc/papiStringList.h new file mode 100644 index 0000000..52f2526 --- /dev/null +++ b/libapoc/papiStringList.h @@ -0,0 +1,61 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPISTRINGLIST_H_ +#define PAPISTRINGLIST_H_ + +#include "papiTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PAPIStringList * addStringList( PAPIStringList ** ioPreviousList, + const char * inData ); + +int containsString( PAPIStringList * inList, const char * inString ); + +PAPIStringList * copyStringList( PAPIStringList * inList ); + +void deleteStringList( PAPIStringList * inStringList ); + +PAPIStringList * removeStringList( PAPIStringList ** ioStringList, const char * inString ); + +PAPIStringList * strToStringList( const char * inString ); + +#ifdef __cplusplus +} +#endif + +#endif /* PAPISTRINGLIST_H_ */ diff --git a/libapoc/papiTypes.h b/libapoc/papiTypes.h new file mode 100644 index 0000000..f324476 --- /dev/null +++ b/libapoc/papiTypes.h @@ -0,0 +1,96 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +/* papiTypes.h - Policy Access API types */ + +#ifndef PAPITYPES_H_ +#define PAPITYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* opaque PAPI session handle */ +typedef struct PAPI PAPI; + +/* Status returned by PAPI functions */ +typedef enum { PAPISuccess = 0, + PAPIConnectionFailure, + PAPIAuthenticationFailure, + PAPINoSuchComponentFailure, + PAPILDBFailure, + PAPIInvalidArg, + PAPIOutOfMemoryFailure, + PAPIUnknownFailure } PAPIStatus; + +/* Notification stuff */ +typedef enum { PAPIComponentAdd, + PAPIComponentModify, + PAPIComponentRemove } PAPIEventType; + +typedef struct { + PAPIEventType eventType; + const char * componentName; +} PAPIEvent; + +typedef void ( *PAPIListener )( const PAPIEvent * inEvent, void * inUserData ); + +typedef void * PAPIListenerId; + +/* Connection state stuff */ +typedef enum { PAPIConnected, PAPIDisconnected } PAPIConnectionState; + +typedef void ( *PAPIConnectionListener )( PAPIConnectionState inState, + void * inUserData ); + +/* Layer stuff */ +typedef struct PAPILayerList +{ + const unsigned char * data; + int size; + const char * timestamp; + struct PAPILayerList * next; +} PAPILayerList; + +typedef struct PAPIStringList +{ + const char * data; + struct PAPIStringList * next; +} PAPIStringList; + +#ifdef __cplusplus +} +#endif + +#endif /* PAPITYPES_H_ */ diff --git a/libapoc/papiUtils.c b/libapoc/papiUtils.c new file mode 100644 index 0000000..df30a13 --- /dev/null +++ b/libapoc/papiUtils.c @@ -0,0 +1,662 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiUtils.h" + +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#ifndef WNT +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#endif + +typedef struct PAPIConfigList +{ + int mName; + const char * mValue; + struct PAPIConfigList * mNext; +} PAPIConfigList; + +typedef enum +{ + PAPIDaemonInstallDir = 0, + PAPIDaemonPort, + PAPIDaemonDataDir, + PAPITransactionTimeout, + PAPIUnknown +} PAPIConfigName; + +static PAPIConfigList * addConfigList( PAPIConfigList ** inPrevious, + int inName, + char * inValue) ; + +static void deleteConfigList( PAPIConfigList * inList ); + +static unsigned char findNextPair( FILE * inFile, + int * outName, + char ** outValue ); + +static int mapToName( const char * inName ); + +static void loadConfig( void ); + +static void loadConfigFile( const char * inFileName, + PAPIConfigList ** inoutList ); + +static int configLock( void ); + +static PAPIConfigList * newConfigList( void ); + +static int skipComments( FILE * inFile ); + +static int configUnlock( void ); + +static int papiConnect( PAPISocket inSocket, + struct sockaddr * inRemote ); + +static const char * sDaemonInstallDir = 0; +static const char * sDaemonLibraryDir = 0; +static const char * sDaemonPropertiesDir = 0; +static int sDaemonPort = -1; +static const char * sDataDir = 0; +static int sTransactionTimeout = -1; + +static int sDefaultDaemonPort = 3809; +static int sDefaultTransactionTimeout = 10000; +static int sMinimumTransactionTimeout = 1000; + +static PAPIMutex * sConfigMutex = 0; + + +static const char sB64[ 64 ] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define ISWHITESPACE(inChar) ((inChar) == ' ' || (inChar) == '\t') +#define ISRETURN(inChar) ((inChar) == '\r' || (inChar) == '\n') + +int base64_encode( const void * inBuffer, + int inBufferSize, + char ** outB64Buffer ) +{ + char *s, *p; + int i; + int c; + const unsigned char *q; + + p = s = (char *) malloc( inBufferSize * 4 / 3 + 4); + if (p == NULL) + return -1; + q = (const unsigned char *) inBuffer; + i = 0; + for (i = 0; i < inBufferSize;) { + c = q[i++]; + c *= 256; + if (i < inBufferSize) + c += q[i]; + i++; + c *= 256; + if (i < inBufferSize) + c += q[i]; + i++; + p[0] = ( char )sB64[(c & 0x00fc0000) >> 18]; + p[1] = ( char )sB64[(c & 0x0003f000) >> 12]; + p[2] = ( char )sB64[(c & 0x00000fc0) >> 6]; + p[3] = ( char )sB64[(c & 0x0000003f) >> 0]; + if (i > inBufferSize) + p[3] = '='; + if (i > inBufferSize + 1) + p[2] = '='; + p += 4; + } + *p = 0; + *outB64Buffer = s; + return strlen(s); +} + +const char * getDaemonDataDir( void ) +{ + if ( configLock() == 0 ) + { + if ( sDataDir == 0 ) + { + loadConfig(); + } + configUnlock(); + } + return sDataDir; +} + +const char * getDaemonInstallDir( void ) +{ + if ( sDaemonInstallDir == 0 ) + { + sDaemonInstallDir = getInstallDir(); + } + return sDaemonInstallDir; +} + +const char * getDaemonLibraryDir( void ) +{ + if ( sDaemonLibraryDir == 0 ) + { + sDaemonLibraryDir = getLibraryDir(); + } + return sDaemonLibraryDir; +} + +const char * getDaemonPropertiesDir( void ) +{ + if ( sDaemonPropertiesDir == 0 ) + { + sDaemonPropertiesDir = getPropertiesDir(); + } + return sDaemonPropertiesDir; +} + +int getDaemonPort( void ) +{ + if ( configLock() == 0 ) + { + if ( sDaemonPort == -1 ) + { + loadConfig(); + if ( sDaemonPort == -1 ) + { + sDaemonPort = sDefaultDaemonPort; + } + } + configUnlock(); + } + return sDaemonPort; +} + +const char * getTimestamp( void ) +{ + char * theTimestamp = 0; + time_t theTime = time( 0 ); + struct tm * theGMTime = gmtime( &theTime ); + if ( theTime != 0 ) + { + theTimestamp = ( char * )malloc( 16 ); + if ( theTimestamp != 0 ) + { + snprintf( theTimestamp, + 16, + "%d%.2d%.2d%.2d%.2d%.2dZ", + theGMTime->tm_year + 1900, + theGMTime->tm_mon + 1, + theGMTime->tm_mday, + theGMTime->tm_hour, + theGMTime->tm_min, + theGMTime->tm_sec ); + } + } + return theTimestamp; +} + +int getTransactionTimeout( void ) +{ + if ( configLock() == 0 ) + { + if ( sTransactionTimeout == -1 ) + { + loadConfig(); + if ( sTransactionTimeout == -1 ) + { + sTransactionTimeout = sDefaultTransactionTimeout; + } + else + if ( sTransactionTimeout < sMinimumTransactionTimeout ) + { + sTransactionTimeout = sMinimumTransactionTimeout; + } + } + configUnlock(); + } + return sTransactionTimeout; +} + +PAPIConfigList * addConfigList( PAPIConfigList ** inPrevious, + int inName, + char * inValue) +{ + PAPIConfigList * theConfigList = newConfigList(); + if ( theConfigList != 0 ) + { + theConfigList->mName = inName; + theConfigList->mValue = inValue ; + theConfigList->mNext = 0; + if ( inPrevious[ 0 ] == 0 ) + { + inPrevious[ 0 ] = theConfigList; + } + else + { + PAPIConfigList * theTmpList = inPrevious[ 0 ]; + while ( theTmpList->mNext != 0 ) + { + theTmpList = theTmpList->mNext; + } + theTmpList->mNext = theConfigList; + } + } + return theConfigList; +} + +void deleteConfigList( PAPIConfigList * inList ) +{ + if ( inList != 0 ) + { + if ( inList->mNext != 0 ) + { + deleteConfigList( inList->mNext ); + } + if ( inList->mValue ) + { + free( ( void * )inList->mValue ); + } + free( inList ); + } +} + +unsigned char findNextPair(FILE *inFile, int *outName, char **outValue) +{ + char theString [1024] ; + int theChar = -1 ; + int theStringLength = 0 ; + + *outName = PAPIUnknown ; + *outValue = 0 ; + /* Get rid of comments */ + theChar = skipComments(inFile) ; + /* Find name */ + while (theChar != EOF) + { + /* Skip initial whitespace */ + if (theStringLength == 0 && ISWHITESPACE(theChar)) { continue ; } + if (theChar == '\\') + { /* Drop escape character */ + theChar = fgetc(inFile) ; + } + else if (theChar == '=') + { /* Skip initial whitespace for possible value */ + do { theChar = fgetc(inFile) ; } while (ISWHITESPACE(theChar)) ; + break ; + } + /* If we encounter a line break, something's wrong */ + if (ISRETURN(theChar)) + { + theStringLength = 0 ; + break ; + } + /* Else copy into the current string */ + theString [theStringLength ++] = theChar ; + theChar = fgetc(inFile) ; + } + /* Remove trailing whitespace */ + while (theStringLength != 0 && + ISWHITESPACE(theString [theStringLength - 1])) + { + -- theStringLength ; + } + /* Terminate string */ + theString [theStringLength] = 0 ; + *outName = mapToName(theString) ; + if (*outName == PAPIUnknown) + { /* If uncomprehensible name, move to next line */ + while (!ISRETURN(theChar) && theChar != EOF) + { + theChar = fgetc(inFile) ; + } + return theChar != EOF ; + } + theStringLength = 0 ; + /* Find corresponding value */ + while (theChar != EOF) + { + /* Skip initial whitespace */ + if (theStringLength == 0 && ISWHITESPACE(theChar)) { continue ; } + if (theChar == '\\') + { /* Drop escape character */ + theChar = fgetc(inFile) ; + } + if (ISRETURN(theChar)) + { /* If end of line is reached, remove trailing whitespace */ + while (theStringLength != 0 && + ISWHITESPACE(theString [theStringLength - 1])) + { + -- theStringLength ; + } + break ; + } + /* Else copy into the current string */ + theString [theStringLength ++] = theChar ; + theChar = fgetc(inFile) ; + } + /* Terminate and duplicate value */ + theString [theStringLength] = 0 ; + *outValue = strdup(theString) ; + return theChar != EOF ; +} + +PAPIConnectResult getConnectedSocket( + int inPort, int inType, int inRetryCount, PAPISocket * outSocket ) +{ + static char sRejected = 0; + static char sAccepted = 1; + static const char * sLocalHostName = "127.0.0.1"; + PAPIConnectResult theResult; + PAPISocket theSocket; + struct sockaddr_in theDaemonAddr; + struct hostent * theHostEnt; + int bResue = 1; +#ifdef WNT + static int isWSAInitialised = 0; + WSADATA theWSAData; + + if ( isWSAInitialised == 0 ) + { + WSAStartup( MAKEWORD( 2, 2 ), &theWSAData ); + isWSAInitialised = 1; + } +#endif + + *outSocket = INVALID_SOCKET; + + theHostEnt = gethostbyname( sLocalHostName ); + theDaemonAddr.sin_family = AF_INET; + theDaemonAddr.sin_port = htons( inPort ); + theDaemonAddr.sin_addr = *( (struct in_addr * )theHostEnt->h_addr ); + + do + { + memset( ( void * )&( theDaemonAddr.sin_zero ), 0, 8 ); + theResult = PAPIConnectFailed; + if ( ( theSocket = socket( AF_INET, inType, 0 ) ) != INVALID_SOCKET && + papiConnect( theSocket, + ( struct sockaddr * )&theDaemonAddr ) == 0 ) + { + char theInitialByte; + if ( socketPoll( theSocket, getTransactionTimeout() ) != 1 || + recv( theSocket, &theInitialByte, 1, 0 ) != 1 || + ( theInitialByte != sAccepted && theInitialByte != sRejected )) + { + papiClose( theSocket ); + theResult = PAPIConnectWrongService; + break; + } + else + { + theResult = theInitialByte == sAccepted ? + PAPIConnectSuccess : PAPIConnectRejected; + if ( theResult == PAPIConnectSuccess ) + { + *outSocket = theSocket; + break; + } + } + } + papiClose( theSocket ); + if ( inRetryCount > 0 ) + { + papiSleep( 1 ); + } + } while ( --inRetryCount > 0 ); + return theResult; +} + +int mapToName(const char *inName) +{ + if (strcmp(inName, "DaemonPort") == 0) + { return PAPIDaemonPort ; } + else if (strcmp(inName, "DataDir") == 0) + { return PAPIDaemonDataDir ; } + else if (strcmp(inName, "DaemonInstallDir") == 0) + { return PAPIDaemonInstallDir ; } + else if (strcmp(inName, "TransactionTimeout") == 0) + { return PAPITransactionTimeout ; } + else return PAPIUnknown ; +} + +void loadConfig( void ) +{ + static const char * sPropertiesFile = "/apocd.properties"; + static const char * sOsPropertiesFile = "/os.properties" ; + PAPIConfigList * theConfigList = 0 ; + PAPIConfigList * theTmpList = 0 ; + char * thePropertiesFileName = 0; + int theSize; + int prefixLength; + + if ( sDaemonPropertiesDir == 0 ) + { + sDaemonPropertiesDir = getPropertiesDir(); + } + prefixLength = strlen( sDaemonPropertiesDir ); + theSize = prefixLength + strlen( sPropertiesFile ) + 1; + thePropertiesFileName = ( char * )malloc( theSize ); + snprintf( thePropertiesFileName, + theSize, + "%s%s", + sDaemonPropertiesDir, + sPropertiesFile ); + loadConfigFile( thePropertiesFileName, &theConfigList ); + free( ( void * )thePropertiesFileName ); + + theSize = prefixLength + strlen( sOsPropertiesFile ) + 1; + thePropertiesFileName = ( char * )malloc( theSize ); + snprintf( thePropertiesFileName, + theSize, + "%s%s", + sDaemonPropertiesDir, + sOsPropertiesFile ); + loadConfigFile( thePropertiesFileName, &theConfigList ); + free( ( void *)thePropertiesFileName ); + + theTmpList = theConfigList; + while ( theTmpList != 0 ) + { + switch( theTmpList->mName ) + { + case PAPIDaemonPort: + sDaemonPort = atoi( theTmpList->mValue ); + break; + + case PAPIDaemonDataDir: +#ifndef WNT + sDataDir = strdup( theTmpList->mValue ); +#else + sDataDir = convertDataDir( theTmpList->mValue ); +#endif + break; + + case PAPITransactionTimeout: + sTransactionTimeout = 1000 * atoi( theTmpList->mValue ); + break; + + default: + break; + } + theTmpList = theTmpList->mNext; + } + deleteConfigList( theConfigList ); +} + +void loadConfigFile(const char *inFileName, PAPIConfigList **inoutConfigList) +{ + FILE *theFile = 0 ; + int theName = 0 ; + char *theValue = 0 ; + + if (inoutConfigList == 0 || inFileName == 0) { return ; } + theFile = fopen(inFileName, "r") ; + if (theFile == 0) { return ; } + while (findNextPair(theFile, &theName, &theValue)) + { + if (theName != PAPIUnknown) + { + addConfigList(inoutConfigList, theName, theValue) ; + } + } + fclose(theFile) ; +} + +int configLock( void ) +{ + int theRC = -1; + if ( sConfigMutex == 0 ) + { + sConfigMutex = newMutex(); + } + if ( sConfigMutex != 0 ) + { + theRC = lockMutex( sConfigMutex ); + } + return theRC; +} + +PAPIConfigList * newConfigList( void ) +{ + PAPIConfigList * theConfigList = + ( PAPIConfigList * )malloc( sizeof( PAPIConfigList ) ); + if ( theConfigList != 0 ) + { + theConfigList->mName = PAPIUnknown; + theConfigList->mValue = 0; + theConfigList->mNext = 0; + } + return theConfigList; +} + +int skipComments(FILE *inFile) +{ + int theChar = -1 ; + + do + { + theChar = fgetc(inFile) ; + if (ISRETURN(theChar) || ISWHITESPACE(theChar)) { continue ; } + if (theChar == '/') + { + theChar = fgetc(inFile) ; + if (theChar != '*') { ungetc(theChar, inFile) ; } + else + { + do + { + theChar = fgetc(inFile) ; + if (theChar == '*') + { + theChar = fgetc(inFile) ; + if (theChar == '/') { break ; } + } + } while (theChar != EOF) ; + } + } + else + { + ungetc(theChar, inFile) ; + break ; + } + } while (theChar != EOF) ; + return fgetc(inFile) ; +} + +int configUnlock( void ) +{ + int theRC = -1; + if ( sConfigMutex != 0 ) + { + theRC = unlockMutex( sConfigMutex ); + } + return theRC; +} + +static int papiConnect( PAPISocket inSocket, struct sockaddr * inRemote ) +{ + int theRC = -1; + int bReuse = 1; + int theSocketFlags; + if ( setsockopt( inSocket, + SOL_SOCKET, + SO_REUSEADDR, + &bReuse, + sizeof( bReuse ) ) == -1 ) + { + return theRC; + } +#ifdef SOLARIS + theSocketFlags = fcntl( inSocket, F_GETFL, 0); + if ( theSocketFlags >= 0 && + fcntl( inSocket, F_SETFL, theSocketFlags | O_NONBLOCK ) != -1 ) + { + theRC = connect( inSocket, inRemote, sizeof( struct sockaddr ) ); + fcntl( inSocket, F_SETFL, theSocketFlags ); + } +#else + theRC = connect( inSocket, inRemote, sizeof( struct sockaddr ) ); +#endif + if ( theRC == 0 ) + { + /* + * Nasty problem on Linux where connecting to daemon port sometimes + * works even when daemon is not listening. The following is an + * attempt to detect this + */ + struct sockaddr_in theLocal; + socklen_t theSize = sizeof( theLocal ); + if ( getsockname( inSocket, + ( struct sockaddr * )&theLocal, + &theSize ) == 0 ) + { + if ( ntohs( theLocal.sin_port ) == + ntohs( ( ( struct sockaddr_in * )&inRemote )->sin_port ) ) + { + theRC = -1; + } + } + else + { + theRC = -1; + } + } + return theRC; +} diff --git a/libapoc/papiUtils.h b/libapoc/papiUtils.h new file mode 100644 index 0000000..118e48d --- /dev/null +++ b/libapoc/papiUtils.h @@ -0,0 +1,167 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#ifndef PAPIUTILS_H_ +#define PAPIUTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "papiTypes.h" + +#include <sys/types.h> +#include <sys/stat.h> + +typedef enum +{ + PAPIConnectSuccess, + PAPIConnectRejected, + PAPIConnectFailed, + PAPIConnectWrongService +} PAPIConnectResult; + +#ifndef WNT +#include <pthread.h> + +#include <sys/types.h> +#include <sys/stat.h> +typedef pthread_mutex_t PAPIMutex; +typedef int PAPISocket; +typedef pthread_t * PAPIThread; + +#define FILESEP "/" +#define PATHSEP ":" +#define papiClose close +#define papiSleep sleep +#define papiPclose pclose +#define papiPopen popen +#define papiUmask umask +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 + +#ifdef SOLARIS +int isServiceEnabled( void ); +#endif + +#else +#include <windows.h> +#include <io.h> +#include <stdio.h> + +typedef CRITICAL_SECTION PAPIMutex; +typedef SOCKET PAPISocket; +typedef HANDLE PAPIThread; +typedef int socklen_t; + +#define FILESEP "\\\\" +#define PATHSEP ";" +#define snprintf _snprintf +#define papiClose closesocket +#define papiSleep( inSeconds ) Sleep( inSeconds * 1000 ) +#define papiPclose _pclose +#define papiPopen _popen +#define papiUmask _umask + +#define APOCENABLEDKEY "Software\\Sun Microsystems\\apoc\\1.0\\Enabled" + +#define APOCSERVICENAME "apocd" + +const char * convertDataDir( const char * inDir ); + +int isNewerThanWindows98( void ); + +#endif + + +typedef void * ( *PAPIThreadFunc )( void * inArg ); + +int base64_encode( const void * inBuffer, + int inBufferSize, + char ** outB64Buffer ); + +PAPIThread createThread( PAPIThreadFunc inThreadFunc, + void * inArg ); + +void destroyThread( PAPIThread inThread ); + +void deleteMutex( PAPIMutex * inMutex ); + +PAPIConnectResult getConnectedSocket( int inPort, + int inType, + int inRetryCount, + PAPISocket * outSocket ); + +const char * getDaemonDataDir( void ); + +const char * getDaemonInstallDir(void ); + +const char * getDaemonLibraryDir(void ); + +const char * getDaemonPropertiesDir(void ); + +int getDaemonPort( void ); + +const char * getInstallDir( void ); + +const char * getLibraryDir( void ); + +const char * getPropertiesDir( void ); + +const char * getSASLCreds( const char * inServiceName, + PAPIStatus * outStatus ); + +const char * getTimestamp( void ); + +int getTransactionTimeout( void ); + +const char * getUserName( void ); + +int isDaemonEnabled( void ); + +int lockMutex( PAPIMutex * inMutex ); + +int socketPoll( PAPISocket inSocket, + int inMillis ); + +int startDaemon( void ); + +PAPIMutex * newMutex( void ); + +int unlockMutex( PAPIMutex * inMutex ); +#ifdef __cplusplus +} +#endif + +#endif /* PAPIUTILS_H_ */ diff --git a/libapoc/papitool.c b/libapoc/papitool.c new file mode 100644 index 0000000..cfaec0e --- /dev/null +++ b/libapoc/papitool.c @@ -0,0 +1,521 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +#include <papi/papi.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> + +char const * g_appname; +const char * g_entity = NULL; + +void show_version(FILE * target); + +void show_error(char const * fmt, char const * param); +void usage(char const * fmt, char const * param); +void list_usage(); +void show_usage(); +void offline_usage(); + +void test_connect_avail(int argc, char * const argv[]); +void list_components(int argc, char * const argv[]); +void show_components(int argc, char * const argv[]); +void do_offline(int argc, char * const argv[]); + +int match(const char * input, const char * command) +{ + if (!input || !*input) return 0; + + return !strncmp(input,command,strlen(input)); +} + +int main(int argc, char * argv[]) +{ + int argindex = 1; + int subargc; + char * const * subargv; + + if (argv[0] == NULL) + g_appname = "[papitool]"; + else if ( (g_appname = strrchr(argv[0],'/')) != NULL ) + ++g_appname; + else + g_appname = argv[0]; + + if (argc <= argindex) usage("Too few arguments: %s", "Missing Command"); + + /* parse options */ + if (!strcmp(argv[argindex], "--version") || + !strcmp(argv[argindex], "-V") ) + { + show_version(stdout); + if (argc == ++argindex) exit(0); + } + + if ( !strcmp(argv[argindex], "-e") || + (!strcmp(argv[argindex], "-Ve") && (show_version(stdout),1)) ) + { + ++argindex; + if (argc <= argindex) usage("Too few arguments: %s", "Missing Entity and Command"); + + g_entity = argv[argindex++]; + + if (argc <= argindex) usage("Too few arguments: %s", "Missing Command"); + } + + /* do help command/options */ + if (!strcmp(argv[argindex], "help") || + !strcmp(argv[argindex], "--help") || + !strcmp(argv[argindex], "-h") || + !strcmp(argv[argindex], "-?") ) + { + usage(NULL,NULL); + } + + /* end of options */ + subargc = argc - argindex; + subargv = argv + argindex; + + if (match(subargv[0],"test")) + test_connect_avail(subargc,subargv); + + else if (match(subargv[0],"list")) + list_components(subargc,subargv); + + else if (match(subargv[0],"show")) + show_components(subargc,subargv); + + else if (match(subargv[0],"offline")) + do_offline(subargc,subargv); + + else + usage("Unknown command: '%s'",subargv[0]); + + return 0; +} + +/* PAPI helper functions */ + +void checkPapiError(PAPIStatus error) +{ + const char * errmsg; + switch (error) + { + case PAPISuccess: + return; + + case PAPIConnectionFailure: + errmsg = "PAPI: Connection Failure for entity %s"; + break; + + case PAPIAuthenticationFailure: + errmsg = "PAPI: Authentication Failure for entity %s"; + break; + + + case PAPINoSuchComponentFailure: + errmsg = "PAPI: No such component"; + break; + + case PAPILDBFailure: + errmsg = "PAPI: Database (LDB) Failure"; + break; + + case PAPIInvalidArg: + errmsg = "PAPI: Invalid Argument"; + break; + + case PAPIOutOfMemoryFailure: + errmsg = "PAPI: Out of Memory"; + break; + + case PAPIUnknownFailure: + errmsg = "PAPI: Unspecified Failure"; + break; + + default: + errmsg = "PAPI: Unknown PAPI error code"; + break; + } + const char * entity = g_entity ? g_entity : "<default entity>"; + + show_error(errmsg,entity); + fprintf(stderr,"\nTerminating\n"); + + exit(-error); +} + +PAPI * initPapi() +{ + PAPIStatus error = PAPISuccess; + PAPI * result = papiInitialise(g_entity,&error); + + checkPapiError(error); + return result; +} + +void exitPapi(PAPI * papi) +{ + PAPIStatus error = PAPISuccess; + + papiDeinitialise(papi,&error); + + checkPapiError(error); +} + +/* connection test function */ + +void describe_test_usage() +{ + fprintf(stderr,"\n\n\t%s [options] t[est]", g_appname); + fputs( "\n\t\t- Test if a PAPI connection can be established" + , stderr); +} + +void test_connect_avail(int argc, char * const argv[]) +{ + PAPI * papi; + + papi = initPapi(); + + fprintf(stderr,"\nOK. PAPI connection was established successfully"); + if (g_entity) + fprintf(stderr," for entity '%s'", g_entity); + else + fprintf(stderr," for the current user"); + fputs("\n",stderr); + + exitPapi(papi); +} + +/* list components function */ + +void describe_list_usage() +{ + fprintf(stderr,"\n\n\t%s [options] l[ist] [filter]", g_appname); + fputs( "\n\t\t- List components that match a filter" + , stderr); +} + +void list_components(int argc, char * const argv[]) +{ + PAPI * papi; + PAPIStatus error = PAPISuccess; + PAPIStringList * components; + PAPIStringList * component; + const char * filter; + int count = 0; + + if (argc > 2) + { + show_error("Too many arguments for 'list' command",NULL); + list_usage(); + } + + if (argc < 2) + filter = NULL; + else + filter = argv[1]; + + papi = initPapi(); + + components = papiListComponentNames(papi,filter,&error); + + if (error == PAPINoSuchComponentFailure) + { + fprintf(stderr,"\nNo Component for filter '%s'\n",filter ? filter : "<null>"); + goto done; + } + + checkPapiError(error); + + for (component = components; component; component=component->next) + { + ++count; + if (component->data) + printf("%s\n",component->data); + else + fprintf(stderr, "### Data for component #%d is NULL ###\n",count); + } + fprintf(stderr,"\n\n%d component(s) found.\n",count ); + + papiFreeStringList(components); + +done: + exitPapi(papi); +} + +/* show component data function */ + +void describe_show_usage() +{ + fprintf(stderr,"\n\n\t%s [options] s[how] (all|time|count|<N>) <component> ...", g_appname); + + fputs( "\n\t\t- Show data for component(s)." + "\n\t\t Supported operations:" + "\n\t\t all - show entire contents for all layers of each component" + "\n\t\t time - show layer count and timestamp for each component" + "\n\t\t count - show layer count for each component" + "\n\t\t <N> - show Nth layer of component (works best with a single component)" + , stderr); +} + +enum { + SHOW_FULL = -1, + SHOW_TIME = -2, + SHOW_COUNT = -3 +}; + +void dump_layer(PAPILayerList * layer, FILE * tofile) +{ + fputs("\n",tofile); + if (layer && layer->data && layer->size>0) + { + size_t size = layer->size, read; + const unsigned char * data = layer->data; + + while (size > 0) + { + read = fwrite(data,1,size,tofile); + + if (read == 0) + { + fputs("\n### ERROR ###",tofile); + show_error("Error writing output: %s", strerror(errno)); + break; + } + + size -= read; + data += read; + } + } + else + fputs("### No data for this layer ###",tofile); + + fputs("\n",tofile); +} + +void dump_component(const char * component, PAPILayerList * layers, int op) +{ + PAPILayerList * layer; + int count = 0; + + if (op >= SHOW_FULL) + printf("\n========== Start of data for component '%s' ==================", component); + else + printf("\nComponent '%s':", component); + + for (layer = layers; layer; layer=layer->next) + { + ++count; + + if (op == SHOW_FULL || op == SHOW_TIME) + printf("\n- Layer #%d: Timestamp = %s\t***", + count, layer->timestamp ? layer->timestamp : "<null>"); + + if (op == SHOW_FULL || op == count) + dump_layer(layer,stdout); + } + + if (op >= SHOW_FULL) + printf("========== End of data for component '%s' ====================", component); + + printf("\n\t%d layer(s)\n",count); +} + +void show_components(int argc, char * const argv[]) +{ + PAPI * papi; + PAPIStatus error = PAPISuccess; + const char * component; + int argindex = 1; + int op; + + if (argc < 3) + { + show_error("Not enough arguments for 'show' command",NULL); + show_usage(); + } + + if (match(argv[argindex],"all")) + op = SHOW_FULL; + + else if (match(argv[argindex],"time")) + op = SHOW_TIME; + + else if (match(argv[argindex],"count")) + op = SHOW_COUNT; + + else + op = atoi(argv[argindex]); + + if (op == 0) + { + show_error("Invalid operation '%s' for 'show' command",argv[argindex]); + show_usage(); + } + + papi = initPapi(); + + while ( (component = argv[++argindex]) != NULL ) + { + PAPILayerList * layers = papiReadComponentLayers(papi,component,&error); + + if (error == PAPINoSuchComponentFailure) + { + printf("\nNo Such Component '%s'\n",component); + continue; + } + + checkPapiError(error); + + dump_component(component,layers,op); + + papiFreeLayerList(layers); + } + + exitPapi(papi); +} + +/* offline status function */ + +void describe_offline_usage() +{ + fprintf(stderr,"\n\n\t%s [options] o[ffline] (show|add|drop|+|-) <component> ...", g_appname); + + fputs( "\n\t\t- Show or change offline status for component(s)." + "\n\t\t Supported operations:" + "\n\t\t show - show current offline status for each component" + "\n\t\t add - mark each component for offline availability (alias '+')" + "\n\t\t drop - mark each component as not availabile offline (alias '-')" + , stderr); + fputs("\n\t*** NOT YET IMPLEMENTED ***",stderr); +} + +void do_offline(int argc, char * const argv[]) +{ + PAPI * papi; + PAPIStatus error = PAPISuccess; + + offline_usage(); + + papi = initPapi(); + exitPapi(papi); +} + +/* usage reporting */ + +void show_version(FILE * file) +{ + const char * version = "0.1"; + const char * author = "Joerg Barfurth"; + fprintf(file,"\n%s - PAPI dumper tool for APOC",g_appname); + fprintf(file,"\nVersion: %s\tBuild time: %s",version,__TIME__); + fprintf(file,"\nAuthor: %s",author); + fprintf(file,"\nCopyright (C) 2003 Sun Microsystems,Inc.\n"); +} + +void pre_usage() +{ + show_version(stderr); + fprintf(stderr,"\nUsage: "); +} + +void post_usage(int exitcode) +{ + fprintf(stderr,"\n\nOptions:"); + fprintf(stderr,"\n\t-V / --version\t- display information about this tool"); + fprintf(stderr,"\n\t-e <entity>\t- use entity id <entity>"); + fprintf(stderr,"\n"); + + exit(exitcode); +} + +void describe_help_usage() +{ + fprintf(stderr,"\n\n\t%s [options] help\n\t\t- show this help screen", g_appname); +} + +void show_error(char const * fmt, char const * param) +{ + fprintf(stderr,"### %s Error: ", g_appname); + fprintf(stderr,fmt,param); +} + +void usage(char const * fmt, char const * param) +{ + if (fmt) + show_error(fmt,param); + + pre_usage(); + + describe_test_usage(); + describe_list_usage(); + describe_show_usage(); + describe_offline_usage(); + describe_help_usage(); + + post_usage(fmt?1:0); +} + +void list_usage() +{ + pre_usage(); + + describe_list_usage(); + + post_usage(2); +} + +void show_usage() +{ + pre_usage(); + + describe_show_usage(); + + post_usage(3); +} + +void offline_usage() +{ + pre_usage(); + + describe_offline_usage(); + + post_usage(4); +} + + diff --git a/libapoc/w32/Makefile b/libapoc/w32/Makefile new file mode 100644 index 0000000..1d4d88a --- /dev/null +++ b/libapoc/w32/Makefile @@ -0,0 +1,55 @@ +# +#******************************************************************************* +#* $RCSfile: Makefile,v $ +#* +#* Description: +#* +#* Last change: $Date: 2007/04/20 15:01:50 $ $Revision: 1.3 $ +#* +#* Copyright 2003 Sun Microsystems, Inc. All rights reserved. Use of this +#* product is subject to license terms. +#* +#******************************************************************************* +# + + +PRJ=../../.. + +include $(PRJ)/Makefile.common + +ifdef WNT + +APOCSOURCES = papiPort.c +APOCOBJS = $(APOCSOURCES:%.c=$(OBJDIR)/%.o) +APOCINCLUDES = -I../.. $(GSSINCLUDES) $(INCLUDES) + +all: apoc + +clean: apocclean + +apoc: mkdirs $(APOCOBJS) + +apocclean: + rm -f $(APOCOBJS) + +mkdirs: + $(mkoutdirs) + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGSSO) $(APOCINCLUDES) -c $*.c -Fo$(OBJDIR)/$*.o -Fd$(OBJDIR)/$*.pdb + +else + +apoc: + +all: + +clean: + +apoc: + +apocclean: + +mkdirs: + +endif diff --git a/libapoc/w32/Makefile.old b/libapoc/w32/Makefile.old new file mode 100644 index 0000000..c75f42e --- /dev/null +++ b/libapoc/w32/Makefile.old @@ -0,0 +1,110 @@ +# +#******************************************************************************* +#* $RCSfile: Makefile,v $ +#* +#* Description: +#* +#* Last change: $Date: 2006/06/27 09:08:56 $ $Revision: 1.9 $ +#* +#* Copyright 2003 Sun Microsystems, Inc. All rights reserved. Use of this +#* product is subject to license terms. +#* +#******************************************************************************* +# + + +PRJ=../.. + +include $(PRJ)/Makefile.common + +APOCSOURCES = \ + papi.c \ + papiConnection.c \ + papiDaemon.c \ + papiDatabase.c \ + papiInternal.c \ + papiLayerList.c \ + papiListenerList.c \ + papiMessage.c \ + papiSAXParserContext.c \ + papiStringList.c \ + papiEntityList.c \ + papiUtils.c +APOCOBJS = $(APOCSOURCES:%.c=$(OBJDIR)/%.o) $(OBJDIR)/papiPort.o +LIBAPOC = $(LIBDIR)/$(SOPREFIX)apoc$(SOSUFFIX) +APOCINCLUDES = $(LIBXML2INCLUDES) $(INCLUDES) +APOCLIBS = $(LIBXML2LIBS) $(GSSLIBS) $(LIBS) +ifdef SOLARIS +APOCLIBS += -lscf +endif + + +APOCJAVASOURCE = papiJava.c +APOCJAVAOBJS = $(APOCJAVASOURCE:%.c=$(OBJDIR)/%.o) +LIBAPOCJAVA = $(LIBDIR)/$(SOPREFIX)apoc_java$(SOSUFFIX) +ifdef UNX +APOCJAVALIBS = -L$(LIBDIR) -lapoc $(LIBS) +else +APOCJAVALIBS = apoc.lib $(LIBS) +endif + + +APOCWRAPSOURCE = papiWrap.c +APOCWRAPOBJS = $(APOCWRAPSOURCE:%.c=$(OBJDIR)/%.o) +LIBAPOCWRAP = $(LIBDIR)/$(SOPREFIX)apocwrap$(SOSUFFIX) +ifdef UNX +APOCWRAPLIBS = -L$(LIBDIR) -lapoc $(LIBS) -lrt +else +APOCWRAPLIBS = apoc.lib $(LIBS) +endif + +all: apoc apoc-adapter-java + +clean: apocclean apoc-adapter-javaclean + +apoc: mkdirs $(LIBAPOC) + +$(LIBAPOC): $(APOCOBJS) +ifdef UNX + $(CC) $(LDFLAGSSO) -o $(LIBAPOC) $(APOCOBJS) $(APOCLIBS) -ldl +else + $(LINK) $(LDFLAGSSO) $(APOCOBJS) /OUT:$(LIBAPOC) $(APOCLIBS) +endif + +apocclean: + rm -f $(APOCOBJS) $(LIBAPOC) + +apoc-adapter-java: $(LIBAPOCJAVA) + +$(LIBAPOCJAVA): $(APOCJAVAOBJS) +ifdef UNX + $(CC) $(LDFLAGSSO) -o$(LIBAPOCJAVA) $(APOCJAVAOBJS) $(APOCJAVALIBS) +else + $(LINK) $(LDFLAGSSO) $(APOCJAVAOBJS) /OUT:$(LIBAPOCJAVA) $(APOCJAVALIBS) +endif + +apoc-adapter-javaclean: + rm -f $(APOCJAVAOBJS) $(LIBAPOCJAVA) + + +apocwrap: $(LIBAPOCWRAP) + +$(LIBAPOCWRAP): $(APOCWRAPOBJS) +ifdef UNX + $(CC) $(LDFLAGSSO) -o$(LIBAPOCWRAP) $(APOCWRAPOBJS) $(APOCWRAPLIBS) +else + $(LINK) $(LDFLAGSSO) $(APOCWRAPOBJS) /OUT:$(LIBAPOCWRAP) $(APOCWRAPLIBS) +endif + +apocwrapclean: + rm -f $(APOCWRAPOBJS) $(LIBAPOCWRAP) + +mkdirs: + $(mkoutdirs) + +$(OBJDIR)/%.o: %.c +ifdef UNX + $(CC) $(CFLAGSSO) $(APOCINCLUDES) -c $*.c -o $(OBJDIR)/$*.o +else + $(CC) $(CFLAGSSO) -DPAPI_EXPORTS $(APOCINCLUDES) -c $*.c -Fo$(OBJDIR)/$*.o -Fd$(OBJDIR)/$*.pdb +endif diff --git a/libapoc/w32/papiPort.c b/libapoc/w32/papiPort.c new file mode 100755 index 0000000..6383f02 --- /dev/null +++ b/libapoc/w32/papiPort.c @@ -0,0 +1,624 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "papiUtils.h" + +#include <lmcons.h> +#define SECURITY_WIN32 +#include <security.h> +#include <sspi.h> +#include <ntsecapi.h> +#include <stdlib.h> +#include <malloc.h> +#include <shlobj.h> + +typedef WINADVAPI SC_HANDLE ( WINAPI *OpenSCManagerFunc ) + ( LPCTSTR, LPCTSTR, DWORD ); + +typedef WINADVAPI BOOL ( WINAPI * EnumServicesStatusFunc ) + ( SC_HANDLE, DWORD, DWORD, LPENUM_SERVICE_STATUS, DWORD, LPDWORD, LPDWORD, + LPDWORD ); + +static PSecurityFunctionTable getSecurityInterface( int * outMaxTokenSize ); + +static int isRegistryEnabled( void ); + +static int isServiceEnabled( void ); + +static int loadServiceFuncs( void ); + +static void writeGSSAPIAuthId( + PSecurityFunctionTable inSecurityInterface, + CredHandle * inCredentials, + CtxtHandle * inContext, + SecBuffer * outBuffer, + PAPIStatus * outStatus ); + +static void encodeGSSAPITokens( SecBuffer * inBuffers, + int inBufferCount, + char ** outB64Buffer ); + +#define INSTALLDIR "\\Sun\\apoc\\lib" + +const char * convertDataDir( const char * inDataDir ) +{ + char * theDataDir = 0; + if ( inDataDir != 0 ) + { + theDataDir = ( char * )malloc( strlen( inDataDir ) + 1 ); + if ( theDataDir != 0 ) + { + char * theToken = strtok( inDataDir, "\\" ); + theDataDir[ 0 ] = 0; + while ( theToken != 0 ) + { + strcat( theDataDir, theToken ); + theToken = strtok( 0, "\\" ); + if ( theToken != 0 ) + { + strcat( theDataDir, "\\" ); + } + } + } + } + return theDataDir; +} + +int createThread( PAPIThreadFunc inThreadFunc, + void * inArg ) +{ + int theThreadId; + HANDLE theThread = + CreateThread( NULL, + 0, + ( LPTHREAD_START_ROUTINE )inThreadFunc, + inArg, + 0, + ( LPDWORD )&theThreadId ); + return theThread != 0 ? 0 : -1; +} + +const char * getInstallDir( void ) +{ + static char * sInstallDir = 0; + if ( sInstallDir == 0 ) + { + char theProgramFiles[ MAX_PATH ]; + if ( SHGetFolderPath( NULL, + CSIDL_PROGRAM_FILES, + NULL, + SHGFP_TYPE_CURRENT, + ( LPTSTR )&theProgramFiles ) == S_OK ) + { + char theShortPath[ MAX_PATH ]; + DWORD theSize = MAX_PATH; + theSize =GetShortPathName( theProgramFiles, &theShortPath, theSize); + sInstallDir = malloc( theSize + + strlen( INSTALLDIR ) + + 1 ); + if ( sInstallDir != 0 ) + { + sprintf( sInstallDir, "%s%s", theShortPath, INSTALLDIR ); + } + } + } + return sInstallDir; +} + +const char * getLibraryDir( void ) +{ + return getInstallDir(); +} + +const char * getPropertiesDir( void ) +{ + return getInstallDir(); +} + +int isNewerThanWindows98( void ) +{ + if ( GetVersion() < 0x80000000 ) + { + return 1; + } + else + { + return 0; + } +} + +PAPIMutex * newMutex( void ) +{ + PAPIMutex * theMutex = + ( PAPIMutex * )malloc( sizeof( PAPIMutex ) ); + if ( theMutex != 0 ) + { + InitializeCriticalSection( theMutex ); + } + return theMutex; +} + +void deleteMutex( PAPIMutex * inMutex ) +{ + if ( inMutex != 0 ) + { + DeleteCriticalSection( inMutex ); + free( ( void *)inMutex ); + } +} + +const char * getSASLCreds( const char * inServiceName, PAPIStatus * outStatus ) +{ + char * theCredentials; + static int sMaxTokenSize; + PSecurityFunctionTable theSecurityInterface = + getSecurityInterface( &sMaxTokenSize ); + + *outStatus = PAPIAuthenticationFailure; + if ( theSecurityInterface != 0 ) + { + if ( inServiceName != 0 ) + { + CredHandle theCredHandle; + TimeStamp theCredLifetime; + SECURITY_STATUS theStatus = + ( theSecurityInterface->AcquireCredentialsHandle ) + ( + 0, + "Kerberos", + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + &theCredHandle, + &theCredLifetime + ); + if ( theStatus == SEC_E_OK ) + { + CtxtHandle theContextHandle; + SecBufferDesc theOutBufferDesc; + SecBuffer theOutBuffer[ 3 ]; + ULONG theAttrs; + + theOutBuffer[ 1 ].cbBuffer = + theOutBuffer[ 2 ].cbBuffer = 0; + theOutBufferDesc.ulVersion = SECBUFFER_VERSION; + theOutBufferDesc.cBuffers = 1; + theOutBufferDesc.pBuffers = &theOutBuffer[ 0 ]; + theOutBuffer[ 0 ].BufferType = SECBUFFER_TOKEN; + theOutBuffer[ 0 ].cbBuffer = sMaxTokenSize; + theOutBuffer[ 0 ].pvBuffer = + ( PBYTE )malloc( sMaxTokenSize ); + + theStatus = + ( theSecurityInterface->InitializeSecurityContext ) + ( + &theCredHandle, + NULL, + ( SEC_CHAR * )inServiceName, + ISC_REQ_DELEGATE, + 0, + SECURITY_NATIVE_DREP, + NULL, + 0, + &theContextHandle, + &theOutBufferDesc, + &theAttrs, + &theCredLifetime + ); + if ( theStatus == SEC_E_OK || + theStatus == SEC_I_CONTINUE_NEEDED || + theStatus == SEC_I_COMPLETE_NEEDED || + theStatus == SEC_I_COMPLETE_AND_CONTINUE ) + { + writeGSSAPIAuthId( theSecurityInterface, + &theCredHandle, + &theContextHandle, + &theOutBuffer[ 2 ], + outStatus ); + if ( *outStatus == PAPISuccess ) + { + encodeGSSAPITokens( theOutBuffer, + 3, + &theCredentials ); + } + FreeContextBuffer( &theContextHandle ); + } + FreeCredentialsHandle( &theCredHandle ); + } + } + } + return theCredentials; +} + +const char * getUserName( void ) +{ + DWORD theBufferSize = UNLEN + 1; + LPTSTR theBuffer = ( LPTSTR )malloc( ( size_t )theBufferSize ); + + GetUserName( theBuffer, &theBufferSize ); + return theBuffer; +} + +int isDaemonEnabled( void ) +{ + return isNewerThanWindows98() == 1 ? + isServiceEnabled() : isRegistryEnabled(); +} + +int lockMutex( PAPIMutex * inMutex ) +{ + int theRC = -1; + if ( inMutex != 0 ) + { + EnterCriticalSection( inMutex ); + theRC = 0; + } + return theRC; +} + +int socketPoll( PAPISocket inSocket, int inMillis ) +{ + fd_set theReadSet; + + FD_ZERO( &theReadSet ); + FD_SET( inSocket, &theReadSet ); + if ( inMillis != -1 ) + { + struct timeval theTimeout; + theTimeout.tv_sec = 0; + theTimeout.tv_usec = inMillis * 1000; + return select( 1, &theReadSet, 0, 0, &theTimeout ); + } + else + { + return select( 1, &theReadSet, 0, 0, 0 ); + } +} + +int startDaemon( void ) +{ + int theRC = 1; + static const char * theFormat = "%s%sbin%sapocd start"; + static char * theCommand = 0; + + if ( isNewerThanWindows98() == 0 && isDaemonEnabled() == 1 ) + { + if ( theCommand == 0 ) + { + const char * theDaemonInstallDir = getDaemonInstallDir(); + char * theCP = ( char * )theDaemonInstallDir + + strlen( theDaemonInstallDir ) - 1; + while ( theCP-- != theDaemonInstallDir ) + { + if ( *theCP == '\\' ) + { + *theCP = 0; + break; + } + } + theCommand = + ( char * )malloc( strlen( theDaemonInstallDir ) + + ( strlen( FILESEP ) * 2 ) + + strlen( theFormat ) + 1 ); + if ( theCommand != 0 ) + { + sprintf( theCommand, + theFormat, + theDaemonInstallDir, + FILESEP, + FILESEP ); + } + } + if ( theCommand != 0 ) + { + STARTUPINFO theStartupInfo; + PROCESS_INFORMATION theProcessInfo; + + ZeroMemory( &theStartupInfo, sizeof( theStartupInfo ) ); + theStartupInfo.dwFlags = STARTF_USESHOWWINDOW; + theStartupInfo.wShowWindow = SW_HIDE; + theStartupInfo.cb = sizeof( theStartupInfo ); + ZeroMemory( &theProcessInfo, sizeof( theProcessInfo ) ); + if ( CreateProcess( 0, + theCommand, + 0, + 0, + FALSE, + DETACHED_PROCESS, + 0, + 0, + &theStartupInfo, + &theProcessInfo ) != 0 ) + { + theRC = 0; + CloseHandle( theProcessInfo.hProcess ); + CloseHandle( theProcessInfo.hThread ); + } + } + } + return theRC; +} + +int unlockMutex( PAPIMutex * inMutex ) +{ + int theRC = -1; + if ( inMutex != 0 ) + { + LeaveCriticalSection( inMutex ); + theRC = 0; + } + return theRC; +} + +void encodeGSSAPITokens( SecBuffer * inBuffers, + int inBufferCount, + char ** outB64Buffer ) +{ + void * theBuffer; + char * theTmpPtr; + int theBufferSize = 0; + int theIndex; + + for ( theIndex = 0; theIndex < inBufferCount; ++ theIndex ) + { + theBufferSize += inBuffers[ theIndex ].cbBuffer + 5; + } + + theBuffer = malloc( theBufferSize ); + theTmpPtr = ( char *)theBuffer; + for ( theIndex = 0; theIndex < inBufferCount; ++ theIndex ) + { + /* Write the token size */ + snprintf( theTmpPtr, 6, "%05d", inBuffers[ theIndex ].cbBuffer ); + theTmpPtr[ 5 ] = 0; + theTmpPtr += 5; + + /* Write the token */ + memcpy( ( void *)theTmpPtr, + inBuffers[ theIndex ].pvBuffer, + inBuffers[ theIndex ].cbBuffer ); + theTmpPtr += inBuffers[ theIndex ].cbBuffer; + } + base64_encode( theBuffer, theBufferSize, outB64Buffer ); + free( ( void * )theBuffer ); +} + +PSecurityFunctionTable getSecurityInterface( int * outMaxTokenSize ) +{ + static PSecurityFunctionTable theSecurityInterface = 0; + static int isInitialised = 0; + + if ( isInitialised == 0 ) + { + isInitialised = 1; + theSecurityInterface = InitSecurityInterface(); + if ( theSecurityInterface != 0 ) + { + PSecPkgInfo thePkgInfo; + if ( ( theSecurityInterface->QuerySecurityPackageInfo ) + ( + "Kerberos", + &thePkgInfo + ) != SEC_E_OK ) + { + theSecurityInterface = 0; + } + *outMaxTokenSize = thePkgInfo->cbMaxToken; + } + } + return theSecurityInterface; +} + +int isRegistryEnabled( void ) +{ + int theRC = 0; + HKEY theKey; + if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, + APOCENABLEDKEY, + 0, + KEY_QUERY_VALUE, + &theKey ) == ERROR_SUCCESS ) + { + RegCloseKey( theKey ); + theRC = 1; + } + return theRC; +} + +int isServiceEnabled( void ) +{ + int theRC = 0; + HMODULE theModule = GetModuleHandle( "advapi32" ); + + if ( theModule != 0 ) + { + OpenSCManagerFunc fOpenSCManager = + ( OpenSCManagerFunc )GetProcAddress( theModule, "OpenSCManagerA" ); + EnumServicesStatusFunc fEnumServicesStatus = + ( EnumServicesStatusFunc )GetProcAddress( theModule, + "EnumServicesStatusA" ); + if ( fOpenSCManager != 0 && fEnumServicesStatus != 0 ) + { + SC_HANDLE theSCManager = + fOpenSCManager( 0, 0, SC_MANAGER_ENUMERATE_SERVICE ); + if ( theSCManager != 0 ) + { + DWORD theBytes; + DWORD theCount; + DWORD theHandle = 0; + + if ( fEnumServicesStatus( + theSCManager, + SERVICE_WIN32, + SERVICE_STATE_ALL, + 0, + 0, + &theBytes, + &theCount, + &theHandle ) == 0 && + GetLastError() == ERROR_MORE_DATA && + theBytes > 0 ) + { + ENUM_SERVICE_STATUS * theServices = + ( ENUM_SERVICE_STATUS * )malloc( theBytes ); + if ( theServices != 0 ) + { + DWORD theIndex; + + fEnumServicesStatus( + theSCManager, + SERVICE_WIN32, + SERVICE_STATE_ALL, + theServices, + theBytes, + &theBytes, + &theCount, + &theHandle ); + for ( theIndex = 0; theIndex < theCount; ++ theIndex ) + { + if ( strcmp( theServices[ theIndex ].lpServiceName, + APOCSERVICENAME ) == 0 ) + { + theRC = 1; + break; + } + } + } + } + CloseServiceHandle( theSCManager ); + } + } + } + return theRC; +} + +void writeGSSAPIAuthId( PSecurityFunctionTable inSecurityInterface, + CredHandle * inCredentials, + CtxtHandle * inContext, + SecBuffer * outBuffer, + PAPIStatus * outStatus ) +{ + SecPkgContext_Sizes theContextSizes; + SecPkgContext_Names theSourceName; + SECURITY_STATUS theStatus = + ( inSecurityInterface->QueryCredentialsAttributes ) + ( + inCredentials, + SECPKG_CRED_ATTR_NAMES, + ( PVOID )&theSourceName + ); + *outStatus = PAPIAuthenticationFailure; + if ( theStatus == SEC_E_OK ) + { + theStatus = ( inSecurityInterface->QueryContextAttributes ) + ( + inContext, + SECPKG_ATTR_SIZES, + ( PVOID )&theContextSizes + ); + if ( theStatus == SEC_E_OK ) + { + SecBufferDesc theBufferDesc; + SecBuffer theBuffers[ 3 ]; + int theSourceNameSize = strlen(theSourceName.sUserName); + char * theCP; + BYTE * theOutput = + ( PBYTE )malloc( theContextSizes.cbSecurityTrailer + + theSourceNameSize + + 4 + + sizeof( DWORD ) ); + + theBufferDesc.ulVersion = SECBUFFER_VERSION; + theBufferDesc.cBuffers = 3; + theBufferDesc.pBuffers = theBuffers; + + theBuffers[ 0 ].cbBuffer = theContextSizes.cbSecurityTrailer; + theBuffers[ 0 ].BufferType = SECBUFFER_TOKEN; + theBuffers[ 0 ].pvBuffer = theOutput + sizeof( DWORD ); + + + theBuffers[ 1 ].cbBuffer = theSourceNameSize + 4; + theBuffers[ 1 ].BufferType = SECBUFFER_DATA; + theBuffers[ 1 ].pvBuffer = malloc( theBuffers[ 1 ].cbBuffer ); + theCP = ( char * )theBuffers[ 1 ].pvBuffer; + theCP[ 0 ] = 1; + theCP[ 1 ] = theCP[ 2 ] = theCP[ 3 ] = ( char )0; + memcpy( theCP + 4, + theSourceName.sUserName, + theSourceNameSize ); + + theBuffers[ 2 ].cbBuffer = theContextSizes.cbBlockSize; + theBuffers[ 2 ].BufferType = SECBUFFER_PADDING; + theBuffers[ 2 ].pvBuffer = malloc( theBuffers[ 2 ].cbBuffer ); + + theStatus = inSecurityInterface->EncryptMessage( inContext, + KERB_WRAP_NO_ENCRYPT, + &theBufferDesc, + 0 ); + if ( theStatus == SEC_E_OK ) + { + outBuffer->cbBuffer = theBuffers[ 0 ].cbBuffer + + theBuffers[ 1 ].cbBuffer + + theBuffers[ 2 ].cbBuffer; + outBuffer->pvBuffer = malloc( outBuffer->cbBuffer ); + if ( outBuffer->pvBuffer != 0 ) + { + theCP = ( char * )outBuffer->pvBuffer; + memcpy( theCP, + theBuffers[ 0 ].pvBuffer, + theBuffers[ 0 ].cbBuffer ); + memcpy( theCP + theBuffers[ 0 ].cbBuffer, + theBuffers[ 1 ].pvBuffer, + theBuffers[ 1 ].cbBuffer ); + memcpy( theCP + + theBuffers[ 0 ].cbBuffer + + theBuffers[ 1 ].cbBuffer, + theBuffers[ 2 ].pvBuffer, + theBuffers[ 2 ].cbBuffer ); + *outStatus = PAPISuccess; + } + else + { + *outStatus = PAPIOutOfMemoryFailure; + } + } + } + } + else + { + *outStatus = PAPIAuthenticationFailure; + } +} diff --git a/libfileaccess/FileAccess.c b/libfileaccess/FileAccess.c new file mode 100644 index 0000000..35dfca7 --- /dev/null +++ b/libfileaccess/FileAccess.c @@ -0,0 +1,493 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +#include "FileAccess.h" + +#ifndef WNT + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> + +#else + +#include <windows.h> +#include <aclapi.h> + +static BOOL addACE( PACL inACL, + DWORD inMask, + PSID inSid ); + +static int chmod( const char * inFile, + int inMode ); + +static int chown( const char * inFile, + const char * inUser ); + +static BOOL initSid( PSID_IDENTIFIER_AUTHORITY inAuthority, + DWORD inSubAuthority, + PSID * outSid ); + +static BOOL getSID( const char * inOwner, + PSID * outSID ); + +static void modeToAccessMask( int inMode, + DWORD * outOwnerMask, + DWORD * outGroupMask, + DWORD * outOthersMask ); + + +static BOOL setOwner( PSID inSID, + const char * inFile ); + +static BOOL setPrivelege( LPCTSTR inPrivelege ); + +static BOOL setPriveleges( LPCTSTR * inPriveleges, + int inCount ); + +static BOOL setSecurity( const char * inFileName, + PACL inDACL ); + +int S_IRWXU=0700; +int S_IRUSR=0400; +int S_IWUSR=0200; +int S_IXUSR=0100; +int S_IRWXG=0070; +int S_IRGRP=0040; +int S_IWGRP=0020; +int S_IXGRP=0010; +int S_IRWXO=0007; +int S_IROTH=0004; +int S_IWOTH=0002; +int S_IXOTH=0001; + +#endif + +JNIEXPORT int JNICALL +Java_com_sun_apoc_daemon_misc_FileAccess_chmod + ( JNIEnv * inEnv, + jclass inClass, + jstring inFileName, + jint inMode ) +{ + int theResult; + const char * theFileName = + ( *inEnv )->GetStringUTFChars( inEnv, inFileName, 0); + +#ifndef WNT + + theResult = chmod( theFileName, ( mode_t )inMode ); + +#else + + theResult = chmod( theFileName, inMode ); + +#endif + + ( *inEnv )->ReleaseStringUTFChars( inEnv, inFileName, theFileName ); + return theResult; +} + +JNIEXPORT int JNICALL +Java_com_sun_apoc_daemon_misc_FileAccess_chown + ( JNIEnv * inEnv, + jclass inClass, + jstring inFileName, + jstring inUserName ) +{ + int theResult; + const char * theFileName = + ( *inEnv )->GetStringUTFChars( inEnv, inFileName, 0 ); + const char * theUserName = + ( *inEnv )->GetStringUTFChars( inEnv, inUserName, 0 ); +#ifndef WNT + + struct passwd * thePasswd = getpwnam( theUserName ); + if ( thePasswd != 0 ) + { + theResult = chown( theFileName, + thePasswd->pw_uid, + thePasswd->pw_gid ); + } + else + { + theResult = 1; + } + +#else + theResult = chown( theFileName, theUserName ); + +#endif + ( *inEnv )->ReleaseStringUTFChars( inEnv, inFileName, theFileName ); + ( *inEnv )->ReleaseStringUTFChars( inEnv, inUserName, theUserName ); + return theResult; +} + +#ifdef WNT + +BOOL addACE( PACL inACL, DWORD inMask, PSID inSid ) +{ + return inMask != 0 ? + AddAccessAllowedAce( inACL, ACL_REVISION, inMask, inSid ) : + AddAccessDeniedAce( inACL, ACL_REVISION, GENERIC_ALL, inSid ); +} + +int chmod( const char * inFileName, int inMode ) +{ + #define sizeofACE( inACE ) \ + sizeof( ACCESS_ALLOWED_ACE ) - sizeof( DWORD ) + GetLengthSid( inACE ) + SID_IDENTIFIER_AUTHORITY theCreator = SECURITY_CREATOR_SID_AUTHORITY; + PSID theOwner = 0; + PSID theGroup = 0; + PSID theOthers = 0; + PSID theAdmin = 0; + DWORD theOwnerMask; + DWORD theGroupMask; + DWORD theOthersMask; + DWORD theDACLSize; + PACL theDACL = 0; + int theResult = 1; + + if ( GetVersion() < 0x80000000 ) + { + getSID( "Administrators", &theAdmin ); + modeToAccessMask( inMode, &theOwnerMask, &theGroupMask, &theOthersMask); + if ( initSid( &theCreator, SECURITY_CREATOR_OWNER_RID, &theOwner )!=0 && + initSid( &theCreator, SECURITY_CREATOR_GROUP_RID, &theGroup )!=0 ) + { + getSID( "Users", &theOthers ); + theDACLSize = sizeof( ACL ) + + sizeofACE( theOwner ) + + sizeofACE( theGroup ) + + sizeofACE( theOthers ) + + sizeofACE( theAdmin ); + theDACL = ( PACL ) malloc( theDACLSize ); + if ( theDACL != 0 ) + { + InitializeAcl( theDACL, theDACLSize, ACL_REVISION ); + if ( addACE( theDACL, GENERIC_ALL, theAdmin ) != 0 && + addACE( theDACL, GENERIC_ALL, theOwner ) != 0 && + addACE( theDACL, theGroupMask, theGroup ) != 0 && + addACE( theDACL, theOthersMask, theOthers ) != 0 ) + { + theResult = setSecurity( inFileName, theDACL ) != 0 ? 0 : 1; + } + free( ( void *)theDACL ); + } + } + if ( theOwner != 0 ) { FreeSid( theOwner ); } + if ( theGroup != 0 ) { FreeSid( theGroup ); } + } + else + { + theResult = _chmod( inFileName, inMode ); + } + return theResult; +} + +int chown( const char * inFileName, const char * inUserName ) +{ + int theResult = 1; + PSID theSID; + LPCTSTR thePriveleges[ 4 ] = + { + SE_TAKE_OWNERSHIP_NAME, + SE_RESTORE_NAME, + SE_BACKUP_NAME, + SE_CHANGE_NOTIFY_NAME + }; + + if ( GetVersion() < 0x80000000 ) + { + if ( setPriveleges( thePriveleges, 4 ) ) + { + if ( getSID( inUserName, &theSID ) ) + { + theResult = setOwner( theSID, inFileName ) ? 0 : 1; + } + } + } + else + { + theResult = 0; + } + return theResult; +} + +BOOL initSid( PSID_IDENTIFIER_AUTHORITY inAuthority, + DWORD inSubAuthority, + PSID * outSid ) +{ + return AllocateAndInitializeSid( + inAuthority, + 1, + inSubAuthority, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + outSid ); +} + +BOOL getSID( const char * inOwner, PSID * outSID ) +{ + BOOL theRC = FALSE; + DWORD theSIDSize = 128; + LPTSTR theDomain = NULL; + DWORD theDomainSize = 16; + SID_NAME_USE theUse; + + *outSID = ( PSID )HeapAlloc( GetProcessHeap(), 0, theSIDSize ); + theDomain = + ( LPTSTR )HeapAlloc(GetProcessHeap(), 0, theDomainSize *sizeof( TCHAR)); + if ( *outSID != 0 ) + { + while ( TRUE ) + { + if ( ! LookupAccountName( NULL, + inOwner, + *outSID, + &theSIDSize, + theDomain, + &theDomainSize, + &theUse ) ) + { + DWORD theError = GetLastError(); + if ( theError == ERROR_INSUFFICIENT_BUFFER ) + { + *outSID = ( PSID )HeapReAlloc( + GetProcessHeap(), + 0, + *outSID, + theSIDSize ); + + if ( *outSID == 0 ) + { + break; + } + + theDomain = ( LPTSTR )HeapReAlloc( + GetProcessHeap(), + 0, + theDomain, + theDomainSize *sizeof( TCHAR) ); + if ( theDomain == 0 ) + { + break; + } + } + else + { + break; + } + } + else + { + theRC = TRUE; + break; + } + } + if ( theDomain != 0 ) + { + HeapFree( GetProcessHeap(), 0, theDomain ); + } + if ( theRC == FALSE && *outSID != 0 ) + { + HeapFree( GetProcessHeap(), 0, *outSID ); + } + } + return theRC; +} + +void modeToAccessMask( int inMode, + DWORD * outOwnerMask, + DWORD * outGroupMask, + DWORD * outOthersMask ) +{ + *outOwnerMask = *outGroupMask = *outOthersMask = 0; + + if ( ( inMode & S_IRUSR ) == S_IRUSR ) + { + *outOwnerMask |= GENERIC_READ; + } + if ( ( inMode & S_IWUSR ) == S_IWUSR ) + { + *outOwnerMask |= GENERIC_WRITE; + } + if ( ( inMode & S_IXUSR ) == S_IXUSR ) + { + *outOwnerMask |= GENERIC_EXECUTE; + } + + if ( ( inMode & S_IRGRP ) == S_IRGRP ) + { + *outGroupMask |= GENERIC_READ; + } + if ( ( inMode & S_IWGRP ) == S_IWGRP ) + { + *outGroupMask |= GENERIC_WRITE; + } + if ( ( inMode & S_IXGRP ) == S_IXGRP ) + { + *outGroupMask |= GENERIC_EXECUTE; + } + + if ( ( inMode & S_IROTH ) == S_IROTH ) + { + *outOthersMask |= GENERIC_READ; + } + if ( ( inMode & S_IWOTH ) == S_IWOTH ) + { + *outOthersMask |= GENERIC_WRITE; + } + if ( ( inMode & S_IXOTH ) == S_IXOTH ) + { + *outOthersMask |= GENERIC_EXECUTE; + } +} + +BOOL setOwner( PSID * inSID, const char * inFileName ) +{ + BOOL theRC = FALSE; + SECURITY_DESCRIPTOR theDescriptor; + + if ( InitializeSecurityDescriptor( &theDescriptor, + SECURITY_DESCRIPTOR_REVISION ) ) + { + if ( SetSecurityDescriptorOwner( &theDescriptor, + inSID, + FALSE ) ) + { + if ( SetFileSecurity( + inFileName, + ( SECURITY_INFORMATION )( OWNER_SECURITY_INFORMATION ), + &theDescriptor ) ) + { + theRC = TRUE; + } + } + } + return theRC; +} + +BOOL setPrivelege( LPCTSTR inPrivelege ) +{ + BOOL theRC = FALSE; + HANDLE theToken; + LUID theLUID; + TOKEN_PRIVILEGES theTP; + TOKEN_PRIVILEGES thePreviousTP; + DWORD thePreviousTPSize = sizeof( TOKEN_PRIVILEGES ); + + if ( OpenProcessToken( + GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &theToken ) ) + { + if ( LookupPrivilegeValue( NULL, inPrivelege, &theLUID ) ) + { + theTP.PrivilegeCount = 1; + theTP.Privileges[0].Luid = theLUID; + theTP.Privileges[0].Attributes = 0; + + AdjustTokenPrivileges( theToken, + FALSE, + &theTP, + sizeof( TOKEN_PRIVILEGES ), + &thePreviousTP, + &thePreviousTPSize ); + + thePreviousTP.PrivilegeCount = 1; + thePreviousTP.Privileges[0].Luid = theLUID; + thePreviousTP.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED; + + AdjustTokenPrivileges( theToken, + FALSE, + &thePreviousTP, + thePreviousTPSize, + NULL, + NULL ); + CloseHandle( theToken ); + theRC = TRUE; + } + } + return theRC; +} + +BOOL setPriveleges( LPCTSTR * inPriveleges, int inCount ) +{ + BOOL theRC; + int theIndex; + for ( theIndex = 0 ; theIndex < inCount; theIndex ++ ) + { + if ( ( theRC = setPrivelege( inPriveleges[ theIndex ] ) ) == FALSE ) + { + break; + } + } + return theRC; +} + +BOOL setSecurity( const char * inFileName, PACL inDACL ) +{ + BOOL theRC = 0; + SECURITY_DESCRIPTOR theDescriptor; + + if ( InitializeSecurityDescriptor( &theDescriptor, + SECURITY_DESCRIPTOR_REVISION ) != 0 ) + { + if ( SetSecurityDescriptorDacl( &theDescriptor, + TRUE, + inDACL, + FALSE ) != 0 ) + { + + theRC = SetNamedSecurityInfo( ( char *)inFileName, + SE_FILE_OBJECT, + ( SECURITY_INFORMATION )( DACL_SECURITY_INFORMATION ), + NULL, + NULL, + inDACL, + NULL ) == ERROR_SUCCESS ? 1 : 0; + } + } + return theRC; +} +#endif diff --git a/libfileaccess/FileAccess.h b/libfileaccess/FileAccess.h new file mode 100644 index 0000000..148cc00 --- /dev/null +++ b/libfileaccess/FileAccess.h @@ -0,0 +1,63 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class com_sun_apoc_daemon_misc_FileAccess */ + +#ifndef _Included_com_sun_apoc_daemon_misc_FileAccess +#define _Included_com_sun_apoc_daemon_misc_FileAccess +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sun_apoc_daemon_misc_FileAccess + * Method: chmod + * Signature: (Ljava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_com_sun_apoc_daemon_misc_FileAccess_chmod + (JNIEnv *, jclass, jstring, jint); + +/* + * Class: com_sun_apoc_daemon_misc_FileAccess + * Method: chown + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_com_sun_apoc_daemon_misc_FileAccess_chown + (JNIEnv *, jclass, jstring, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/libfileaccess/Makefile.am b/libfileaccess/Makefile.am new file mode 100644 index 0000000..a3a01be --- /dev/null +++ b/libfileaccess/Makefile.am @@ -0,0 +1,7 @@ +lib_LTLIBRARIES = libFileAccess.la + +libFileAccessdir = $(includedir)/apoc/papi + +libFileAccess_la_SOURCES = \ + FileAccess.c \ + FileAccess.h diff --git a/m4/ac_check_class.m4 b/m4/ac_check_class.m4 new file mode 100644 index 0000000..b12e7f0 --- /dev/null +++ b/m4/ac_check_class.m4 @@ -0,0 +1,107 @@ +dnl @synopsis AC_CHECK_CLASS +dnl +dnl AC_CHECK_CLASS tests the existence of a given Java class, either in +dnl a jar or in a '.class' file. +dnl +dnl *Warning*: its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_check_class.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_CHECK_CLASS],[ +AC_REQUIRE([AC_PROG_JAVA]) +ac_var_name=`echo $1 | sed 's/\./_/g'` +dnl Normaly I'd use a AC_CACHE_CHECK here but since the variable name is +dnl dynamic I need an extra level of extraction +AC_MSG_CHECKING([for $1 class]) +AC_CACHE_VAL(ac_cv_class_$ac_var_name, [ +if test x$ac_cv_prog_uudecode_base64 = xyes; then +dnl /** +dnl * Test.java: used to test dynamicaly if a class exists. +dnl */ +dnl public class Test +dnl { +dnl +dnl public static void +dnl main( String[] argv ) +dnl { +dnl Class lib; +dnl if (argv.length < 1) +dnl { +dnl System.err.println ("Missing argument"); +dnl System.exit (77); +dnl } +dnl try +dnl { +dnl lib = Class.forName (argv[0]); +dnl } +dnl catch (ClassNotFoundException e) +dnl { +dnl System.exit (1); +dnl } +dnl lib = null; +dnl System.exit (0); +dnl } +dnl +dnl } +cat << \EOF > Test.uue +begin-base64 644 Test.class +yv66vgADAC0AKQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE +bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 +bWJlclRhYmxlDAAKAAsBAANlcnIBABVMamF2YS9pby9QcmludFN0cmVhbTsJ +AA0ACQcADgEAEGphdmEvbGFuZy9TeXN0ZW0IABABABBNaXNzaW5nIGFyZ3Vt +ZW50DAASABMBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgAV +ABEHABYBABNqYXZhL2lvL1ByaW50U3RyZWFtDAAYABkBAARleGl0AQAEKEkp +VgoADQAXDAAcAB0BAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylM +amF2YS9sYW5nL0NsYXNzOwoAHwAbBwAgAQAPamF2YS9sYW5nL0NsYXNzBwAi +AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BAAY8aW5pdD4B +AAMoKVYMACMAJAoAAwAlAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQAhAAEA +AwAAAAAAAgAJAAUABgABAAcAAABtAAMAAwAAACkqvgSiABCyAAwSD7YAFBBN +uAAaKgMyuAAeTKcACE0EuAAaAUwDuAAasQABABMAGgAdACEAAQAIAAAAKgAK +AAAACgAAAAsABgANAA4ADgATABAAEwASAB4AFgAiABgAJAAZACgAGgABACMA +JAABAAcAAAAhAAEAAQAAAAUqtwAmsQAAAAEACAAAAAoAAgAAAAQABAAEAAEA +JwAAAAIAKA== +==== +EOF + if uudecode$EXEEXT Test.uue; then + : + else + echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC + echo "configure: failed file was:" >&AC_FD_CC + cat Test.uue >&AC_FD_CC + ac_cv_prog_uudecode_base64=no + fi + rm -f Test.uue + if AC_TRY_COMMAND($JAVA $JAVAFLAGS Test $1) >/dev/null 2>&1; then + eval "ac_cv_class_$ac_var_name=yes" + else + eval "ac_cv_class_$ac_var_name=no" + fi + rm -f Test.class +else + AC_TRY_COMPILE_JAVA([$1], , [eval "ac_cv_class_$ac_var_name=yes"], + [eval "ac_cv_class_$ac_var_name=no"]) +fi +eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`" +eval "HAVE_$ac_var_name=$`echo ac_cv_class_$ac_var_val`" +HAVE_LAST_CLASS=$ac_var_val +if test x$ac_var_val = xyes; then + ifelse([$2], , :, [$2]) +else + ifelse([$3], , :, [$3]) +fi +]) +dnl for some reason the above statment didn't fall though here? +dnl do scripts have variable scoping? +eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`" +AC_MSG_RESULT($ac_var_val) +]) diff --git a/m4/ac_check_classpath.m4 b/m4/ac_check_classpath.m4 new file mode 100644 index 0000000..b18d479 --- /dev/null +++ b/m4/ac_check_classpath.m4 @@ -0,0 +1,23 @@ +dnl @synopsis AC_CHECK_CLASSPATH +dnl +dnl AC_CHECK_CLASSPATH just displays the CLASSPATH, for the edification +dnl of the user. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_check_classpath.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_CHECK_CLASSPATH],[ +if test "x$CLASSPATH" = x; then + echo "You have no CLASSPATH, I hope it is good" +else + echo "You have CLASSPATH $CLASSPATH, hope it is correct" +fi +]) diff --git a/m4/ac_check_junit.m4 b/m4/ac_check_junit.m4 new file mode 100644 index 0000000..cc02e32 --- /dev/null +++ b/m4/ac_check_junit.m4 @@ -0,0 +1,54 @@ +dnl @synopsis AC_CHECK_JUNIT +dnl +dnl AC_CHECK_JUNIT tests the availability of the Junit testing +dnl framework, and set some variables for conditional compilation +dnl of the test suite by automake. +dnl +dnl If available, JUNIT is set to a command launching the text +dnl based user interface of Junit, @JAVA_JUNIT@ is set to $JAVA_JUNIT +dnl and @TESTS_JUNIT@ is set to $TESTS_JUNIT, otherwise they are set +dnl to empty values. +dnl +dnl You can use these variables in your Makefile.am file like this : +dnl +dnl # Some of the following classes are built only if junit is available +dnl JAVA_JUNIT = Class1Test.java Class2Test.java AllJunitTests.java +dnl +dnl noinst_JAVA = Example1.java Example2.java @JAVA_JUNIT@ +dnl +dnl EXTRA_JAVA = $(JAVA_JUNIT) +dnl +dnl TESTS_JUNIT = AllJunitTests +dnl +dnl TESTS = StandaloneTest1 StandaloneTest2 @TESTS_JUNIT@ +dnl +dnl EXTRA_TESTS = $(TESTS_JUNIT) +dnl +dnl AllJunitTests : +dnl echo "#! /bin/sh" > $@ +dnl echo "exec @JUNIT@ my.package.name.AllJunitTests" >> $@ +dnl chmod +x $@ +dnl +dnl @author Luc Maisonobe +dnl @version $Id: ac_check_junit.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_CHECK_JUNIT],[ +AC_CACHE_VAL(ac_cv_prog_JUNIT,[ +AC_CHECK_CLASS(junit.textui.TestRunner) +if test x"`eval 'echo $ac_cv_class_junit_textui_TestRunner'`" != xno ; then + ac_cv_prog_JUNIT='$(CLASSPATH_ENV) $(JAVA) $(JAVAFLAGS) junit.textui.TestRunner' +fi]) +AC_MSG_CHECKING([for junit]) +if test x"`eval 'echo $ac_cv_prog_JUNIT'`" != x ; then + JUNIT="$ac_cv_prog_JUNIT" + JAVA_JUNIT='$(JAVA_JUNIT)' + TESTS_JUNIT='$(TESTS_JUNIT)' +else + JUNIT= + JAVA_JUNIT= + TESTS_JUNIT= +fi +AC_MSG_RESULT($JAVA_JUNIT) +AC_SUBST(JUNIT) +AC_SUBST(JAVA_JUNIT) +AC_SUBST(TESTS_JUNIT)]) diff --git a/m4/ac_check_rqrd_class.m4 b/m4/ac_check_rqrd_class.m4 new file mode 100644 index 0000000..c7c26b8 --- /dev/null +++ b/m4/ac_check_rqrd_class.m4 @@ -0,0 +1,26 @@ +dnl @synopsis AC_CHECK_RQRD_CLASS +dnl +dnl AC_CHECK_RQRD_CLASS tests the existence of a given Java class, either in +dnl a jar or in a '.class' file and fails if it doesn't exist. +dnl Its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_check_rqrd_class.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl + +AC_DEFUN([AC_CHECK_RQRD_CLASS],[ +CLASS=`echo $1|sed 's/\./_/g'` +AC_CHECK_CLASS($1) +if test "$HAVE_LAST_CLASS" = "no"; then + AC_MSG_ERROR([Required class $1 missing, exiting.]) +fi +]) diff --git a/m4/ac_expand.m4 b/m4/ac_expand.m4 new file mode 100644 index 0000000..ae8188a --- /dev/null +++ b/m4/ac_expand.m4 @@ -0,0 +1,8 @@ +AC_DEFUN([AC_EXPAND], [ + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + ac_expand=[$]$1 + test "x$ac_expand" = xNONE && ac_expand="[$]$2" + ac_expand=`eval echo [$]ac_expand` + $3=`eval echo [$]ac_expand` +]) diff --git a/m4/ac_java_options.m4 b/m4/ac_java_options.m4 new file mode 100644 index 0000000..e71adfe --- /dev/null +++ b/m4/ac_java_options.m4 @@ -0,0 +1,32 @@ +dnl @synopsis AC_JAVA_OPTIONS +dnl +dnl AC_JAVA_OPTIONS adds configure command line options used for Java m4 +dnl macros. This Macro is optional. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Devin Weaver <ktohg@tritarget.com> +dnl @version $Id: ac_java_options.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_JAVA_OPTIONS],[ +AC_ARG_WITH(java-prefix, + [ --with-java-prefix=PFX prefix where Java runtime is installed (optional)]) +AC_ARG_WITH(javac-flags, + [ --with-javac-flags=FLAGS flags to pass to the Java compiler (optional)]) +AC_ARG_WITH(java-flags, + [ --with-java-flags=FLAGS flags to pass to the Java VM (optional)]) +JAVAPREFIX=$with_java_prefix +JAVACFLAGS=$with_javac_flags +JAVAFLAGS=$with_java_flags +AC_SUBST(JAVAPREFIX)dnl +AC_SUBST(JAVACFLAGS)dnl +AC_SUBST(JAVAFLAGS)dnl +AC_SUBST(JAVA)dnl +AC_SUBST(JAVAC)dnl +]) diff --git a/m4/ac_jni_include_dirs.m4 b/m4/ac_jni_include_dirs.m4 new file mode 100644 index 0000000..35cdda3 --- /dev/null +++ b/m4/ac_jni_include_dirs.m4 @@ -0,0 +1,114 @@ +dnl @synopsis AC_JNI_INCLUDE_DIR +dnl +dnl AC_JNI_INCLUDE_DIR finds include directories needed +dnl for compiling programs using the JNI interface. +dnl +dnl JNI include directories are usually in the java distribution +dnl This is deduced from the value of JAVAC. When this macro +dnl completes, a list of directories is left in the variable +dnl JNI_INCLUDE_DIRS. +dnl +dnl Example usage follows: +dnl +dnl AC_JNI_INCLUDE_DIR +dnl +dnl for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +dnl do +dnl CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +dnl done +dnl +dnl If you want to force a specific compiler: +dnl +dnl - at the configure.in level, set JAVAC=yourcompiler before calling +dnl AC_JNI_INCLUDE_DIR +dnl +dnl - at the configure level, setenv JAVAC +dnl +dnl Note: This macro can work with the autoconf M4 macros for Java programs. +dnl This particular macro is not part of the original set of macros. +dnl +dnl @author Don Anderson <dda@sleepycat.com> +dnl @version $Id: ac_jni_include_dirs.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN(AC_JNI_INCLUDE_DIR,[ + +JNI_INCLUDE_DIRS="" + +test "x$JAVAC" = x && AC_MSG_ERROR(['$JAVAC' undefined]) +AC_PATH_PROG(_ACJNI_JAVAC, $JAVAC, $JAVAC) +test ! -x "$_ACJNI_JAVAC" && AC_MSG_ERROR([$JAVAC could not be found in path]) +AC_MSG_CHECKING(absolute path of $JAVAC) +case "$_ACJNI_JAVAC" in +/*) AC_MSG_RESULT($_ACJNI_JAVAC);; +*) AC_MSG_ERROR([$_ACJNI_JAVAC is not an absolute path name]);; +esac + +_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") +_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +case "$host_os" in + darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + _JINC="$_JTOPDIR/Headers";; + *) _JINC="$_JTOPDIR/include";; +esac + +# If we find jni.h in /usr/include, then it's not a java-only tree, so +# don't add /usr/include or subdirectories to the list of includes. +# An extra -I/usr/include can foul things up with newer gcc's. +# +# If we don't find jni.h, just keep going. Hopefully javac knows where +# to find its include files, even if we can't. +if test -r "$_JINC/jni.h"; then + if test "$_JINC" != "/usr/include"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC" + fi +else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -r "$_JTOPDIR/include/jni.h"; then + if test "$_JTOPDIR" != "/usr"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include" + fi + fi +fi + +# get the likely subdirectories for system specific java includes +if test "$_JTOPDIR" != "/usr"; then + case "$host_os" in + aix*) _JNI_INC_SUBDIRS="aix";; + bsdi*) _JNI_INC_SUBDIRS="bsdos";; + freebsd*) _JNI_INC_SUBDIRS="freebsd";; + hp*) _JNI_INC_SUBDIRS="hp-ux";; + linux*) _JNI_INC_SUBDIRS="linux genunix";; + osf*) _JNI_INC_SUBDIRS="alpha";; + solaris*) _JNI_INC_SUBDIRS="solaris";; + *) _JNI_INC_SUBDIRS="genunix";; + esac +fi + +# add any subdirectories that are present +for _JINCSUBDIR in $_JNI_INC_SUBDIRS +do + if test -d "$_JTOPDIR/include/$_JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$_JINCSUBDIR" + fi +done +]) + +# _ACJNI_FOLLOW_SYMLINKS <path> +# Follows symbolic links on <path>, +# finally setting variable _ACJNI_FOLLOWED +# -------------------- +AC_DEFUN(_ACJNI_FOLLOW_SYMLINKS,[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING(symlink for $_cur) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT($_cur) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/m4/ac_prog_jar.m4 b/m4/ac_prog_jar.m4 new file mode 100644 index 0000000..c60a79a --- /dev/null +++ b/m4/ac_prog_jar.m4 @@ -0,0 +1,36 @@ +dnl @synopsis AC_PROG_JAR +dnl +dnl AC_PROG_JAR tests for an existing jar program. It uses the environment +dnl variable JAR then tests in sequence various common jar programs. +dnl +dnl If you want to force a specific compiler: +dnl +dnl - at the configure.in level, set JAR=yourcompiler before calling +dnl AC_PROG_JAR +dnl +dnl - at the configure level, setenv JAR +dnl +dnl You can use the JAR variable in your Makefile.in, with @JAR@. +dnl +dnl Note: This macro depends on the autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download that whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl +dnl The general documentation of those macros, as well as the sample +dnl configure.in, is included in the AC_PROG_JAVA macro. +dnl +dnl @author Egon Willighagen <egonw@sci.kun.nl> +dnl @version $Id: ac_prog_jar.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAR],[ +AC_REQUIRE([AC_EXEEXT])dnl +if test "x$JAVAPREFIX" = x; then + test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar$EXEEXT) +else + test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar, $JAVAPREFIX) +fi +test "x$JAR" = x && AC_MSG_ERROR([no acceptable jar program found in \$PATH]) +AC_PROVIDE([$0])dnl +]) diff --git a/m4/ac_prog_java.m4 b/m4/ac_prog_java.m4 new file mode 100644 index 0000000..05c65e7 --- /dev/null +++ b/m4/ac_prog_java.m4 @@ -0,0 +1,79 @@ +dnl @synopsis AC_PROG_JAVA +dnl +dnl Here is a summary of the main macros: +dnl +dnl AC_PROG_JAVAC: finds a Java compiler. +dnl +dnl AC_PROG_JAVA: finds a Java virtual machine. +dnl +dnl AC_CHECK_CLASS: finds if we have the given class (beware of CLASSPATH!). +dnl +dnl AC_CHECK_RQRD_CLASS: finds if we have the given class and stops otherwise. +dnl +dnl AC_TRY_COMPILE_JAVA: attempt to compile user given source. +dnl +dnl AC_TRY_RUN_JAVA: attempt to compile and run user given source. +dnl +dnl AC_JAVA_OPTIONS: adds Java configure options. +dnl +dnl AC_PROG_JAVA tests an existing Java virtual machine. It uses the +dnl environment variable JAVA then tests in sequence various common Java +dnl virtual machines. For political reasons, it starts with the free ones. +dnl You *must* call [AC_PROG_JAVAC] before. +dnl +dnl If you want to force a specific VM: +dnl +dnl - at the configure.in level, set JAVA=yourvm before calling AC_PROG_JAVA +dnl (but after AC_INIT) +dnl +dnl - at the configure level, setenv JAVA +dnl +dnl You can use the JAVA variable in your Makefile.in, with @JAVA@. +dnl +dnl *Warning*: its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl TODO: allow to exclude virtual machines (rationale: most Java programs +dnl cannot run with some VM like kaffe). +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl +dnl A Web page, with a link to the latest CVS snapshot is at +dnl <http://www.internatif.org/bortzmeyer/autoconf-Java/>. +dnl +dnl This is a sample configure.in +dnl Process this file with autoconf to produce a configure script. +dnl +dnl AC_INIT(UnTag.java) +dnl +dnl dnl Checks for programs. +dnl AC_CHECK_CLASSPATH +dnl AC_PROG_JAVAC +dnl AC_PROG_JAVA +dnl +dnl dnl Checks for classes +dnl AC_CHECK_RQRD_CLASS(org.xml.sax.Parser) +dnl AC_CHECK_RQRD_CLASS(com.jclark.xml.sax.Driver) +dnl +dnl AC_OUTPUT(Makefile) +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_prog_java.ac,v 12.1 2006/08/24 14:45:36 bostic Exp $ +dnl +dnl Note: Modified to prefer java over kaffe. [#8059] +dnl +AC_DEFUN([AC_PROG_JAVA],[ +AC_REQUIRE([AC_EXEEXT])dnl +if test x$JAVAPREFIX = x; then + test x$JAVA = x && AC_CHECK_PROGS(JAVA, java$EXEEXT kaffe$EXEEXT) +else + test x$JAVA = x && AC_CHECK_PROGS(JAVA, java$EXEEXT kaffe$EXEEXT, $JAVAPREFIX) +fi +test x$JAVA = x && AC_MSG_ERROR([no acceptable Java virtual machine found in \$PATH]) +AC_PROG_JAVA_WORKS +AC_PROVIDE([$0])dnl +]) diff --git a/m4/ac_prog_java_works.m4 b/m4/ac_prog_java_works.m4 new file mode 100644 index 0000000..f0ff8c5 --- /dev/null +++ b/m4/ac_prog_java_works.m4 @@ -0,0 +1,97 @@ +dnl @synopsis AC_PROG_JAVA_WORKS +dnl +dnl Internal use ONLY. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_prog_java_works.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAVA_WORKS], [ +AC_CHECK_PROG(uudecode, uudecode$EXEEXT, yes) +if test x$uudecode = xyes; then +AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [ +dnl /** +dnl * Test.java: used to test if java compiler works. +dnl */ +dnl public class Test +dnl { +dnl +dnl public static void +dnl main( String[] argv ) +dnl { +dnl System.exit (0); +dnl } +dnl +dnl } +cat << \EOF > Test.uue +begin-base64 644 Test.class +yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE +bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 +bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s +YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG +aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB +AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB +AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ= +==== +EOF +if uudecode$EXEEXT Test.uue; then + ac_cv_prog_uudecode_base64=yes +else + echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC + echo "configure: failed file was:" >&AC_FD_CC + cat Test.uue >&AC_FD_CC + ac_cv_prog_uudecode_base64=no +fi +rm -f Test.uue]) +fi +if test x$ac_cv_prog_uudecode_base64 != xyes; then + rm -f Test.class + AC_MSG_WARN([I have to compile Test.class from scratch]) + if test x$ac_cv_prog_javac_works = xno; then + AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly]) + fi + if test x$ac_cv_prog_javac_works = x; then + AC_PROG_JAVAC + fi +fi +AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [ +JAVA_TEST=Test.java +CLASS_TEST=Test.class +TEST=Test +changequote(, )dnl +cat << \EOF > $JAVA_TEST +/* [#]line __oline__ "configure" */ +public class Test { +public static void main (String args[]) { + System.exit (0); +} } +EOF +changequote([, ])dnl +if test x$ac_cv_prog_uudecode_base64 != xyes; then + if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then + : + else + echo "configure: failed program was:" >&AC_FD_CC + cat $JAVA_TEST >&AC_FD_CC + AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)) + fi +fi +if AC_TRY_COMMAND($JAVA $JAVAFLAGS $TEST) >/dev/null 2>&1; then + ac_cv_prog_java_works=yes +else + echo "configure: failed program was:" >&AC_FD_CC + cat $JAVA_TEST >&AC_FD_CC + AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?)) +fi +rm -fr $JAVA_TEST $CLASS_TEST Test.uue +]) +AC_PROVIDE([$0])dnl +] +) diff --git a/m4/ac_prog_javac.m4 b/m4/ac_prog_javac.m4 new file mode 100644 index 0000000..b3607dc --- /dev/null +++ b/m4/ac_prog_javac.m4 @@ -0,0 +1,43 @@ +dnl @synopsis AC_PROG_JAVAC +dnl +dnl AC_PROG_JAVAC tests an existing Java compiler. It uses the environment +dnl variable JAVAC then tests in sequence various common Java compilers. For +dnl political reasons, it starts with the free ones. +dnl +dnl If you want to force a specific compiler: +dnl +dnl - at the configure.in level, set JAVAC=yourcompiler before calling +dnl AC_PROG_JAVAC +dnl +dnl - at the configure level, setenv JAVAC +dnl +dnl You can use the JAVAC variable in your Makefile.in, with @JAVAC@. +dnl +dnl *Warning*: its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl TODO: allow to exclude compilers (rationale: most Java programs cannot compile +dnl with some compilers like guavac). +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_prog_javac.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAVAC],[ +AC_REQUIRE([AC_EXEEXT])dnl +if test "x$JAVAPREFIX" = x; then + test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT) +else + test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT, $JAVAPREFIX) +fi +test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) +AC_PROG_JAVAC_WORKS +AC_PROVIDE([$0])dnl +]) diff --git a/m4/ac_prog_javac_works.m4 b/m4/ac_prog_javac_works.m4 new file mode 100644 index 0000000..0cfd1f2 --- /dev/null +++ b/m4/ac_prog_javac_works.m4 @@ -0,0 +1,35 @@ +dnl @synopsis AC_PROG_JAVAC_WORKS +dnl +dnl Internal use ONLY. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr> +dnl @version $Id: ac_prog_javac_works.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAVAC_WORKS],[ +AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [ +JAVA_TEST=Test.java +CLASS_TEST=Test.class +cat << \EOF > $JAVA_TEST +/* [#]line __oline__ "configure" */ +public class Test { +} +EOF +if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then + ac_cv_prog_javac_works=yes +else + AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)]) + echo "configure: failed program was:" >&AC_FD_CC + cat $JAVA_TEST >&AC_FD_CC +fi +rm -f $JAVA_TEST $CLASS_TEST +]) +AC_PROVIDE([$0])dnl +]) diff --git a/m4/ac_prog_javadoc.m4 b/m4/ac_prog_javadoc.m4 new file mode 100644 index 0000000..36b95bd --- /dev/null +++ b/m4/ac_prog_javadoc.m4 @@ -0,0 +1,37 @@ +dnl @synopsis AC_PROG_JAVADOC +dnl +dnl AC_PROG_JAVADOC tests for an existing javadoc generator. It uses the environment +dnl variable JAVADOC then tests in sequence various common javadoc generator. +dnl +dnl If you want to force a specific compiler: +dnl +dnl - at the configure.in level, set JAVADOC=yourgenerator before calling +dnl AC_PROG_JAVADOC +dnl +dnl - at the configure level, setenv JAVADOC +dnl +dnl You can use the JAVADOC variable in your Makefile.in, with @JAVADOC@. +dnl +dnl Note: This macro depends on the autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download that whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl +dnl The general documentation of those macros, as well as the sample +dnl configure.in, is included in the AC_PROG_JAVA macro. +dnl +dnl @author Egon Willighagen <egonw@sci.kun.nl> +dnl @version $Id: ac_prog_javadoc.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAVADOC],[ +AC_REQUIRE([AC_EXEEXT])dnl +if test "x$JAVAPREFIX" = x; then + test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc$EXEEXT) +else + test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc, $JAVAPREFIX) +fi +test "x$JAVADOC" = x && AC_MSG_ERROR([no acceptable javadoc generator found in \$PATH]) +AC_PROVIDE([$0])dnl +]) + diff --git a/m4/ac_prog_javah.m4 b/m4/ac_prog_javah.m4 new file mode 100644 index 0000000..7563036 --- /dev/null +++ b/m4/ac_prog_javah.m4 @@ -0,0 +1,26 @@ +dnl @synopsis AC_PROG_JAVAH +dnl +dnl AC_PROG_JAVAH tests the availability of the javah header generator +dnl and looks for the jni.h header file. If available, JAVAH is set to +dnl the full path of javah and CPPFLAGS is updated accordingly. +dnl +dnl @author Luc Maisonobe +dnl @version $Id: ac_prog_javah.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_PROG_JAVAH],[ +AC_REQUIRE([AC_CANONICAL_SYSTEM])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_PATH_PROG(JAVAH,javah) +if test x"`eval 'echo $ac_cv_path_JAVAH'`" != x ; then + AC_TRY_CPP([#include <jni.h>],,[ + ac_save_CPPFLAGS="$CPPFLAGS" +changequote(, )dnl + ac_dir=`echo $ac_cv_path_JAVAH | sed 's,\(.*\)/[^/]*/[^/]*$,\1/include,'` + ac_machdep=`echo $build_os | sed 's,[-0-9].*,,'` +changequote([, ])dnl + CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" + AC_TRY_CPP([#include <jni.h>], + ac_save_CPPFLAGS="$CPPFLAGS", + AC_MSG_WARN([unable to include <jni.h>])) + CPPFLAGS="$ac_save_CPPFLAGS"]) +fi]) diff --git a/m4/ac_try_compile_java.m4 b/m4/ac_try_compile_java.m4 new file mode 100644 index 0000000..d22aeab --- /dev/null +++ b/m4/ac_try_compile_java.m4 @@ -0,0 +1,39 @@ +dnl @synopsis AC_TRY_COMPILE_JAVA +dnl +dnl AC_TRY_COMPILE_JAVA attempt to compile user given source. +dnl +dnl *Warning*: its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Devin Weaver <ktohg@tritarget.com> +dnl @version $Id: ac_try_compile_java.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_TRY_COMPILE_JAVA],[ +AC_REQUIRE([AC_PROG_JAVAC])dnl +cat << \EOF > Test.java +/* [#]line __oline__ "configure" */ +ifelse([$1], , , [import $1;]) +public class Test { +[$2] +} +EOF +if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class +then +dnl Don't remove the temporary files here, so they can be examined. + ifelse([$3], , :, [$3]) +else + echo "configure: failed program was:" >&AC_FD_CC + cat Test.java >&AC_FD_CC +ifelse([$4], , , [ rm -fr Test* + $4 +])dnl +fi +rm -fr Test*]) diff --git a/m4/ac_try_run_javac.m4 b/m4/ac_try_run_javac.m4 new file mode 100644 index 0000000..0124935 --- /dev/null +++ b/m4/ac_try_run_javac.m4 @@ -0,0 +1,40 @@ +dnl @synopsis AC_TRY_RUN_JAVA +dnl +dnl AC_TRY_RUN_JAVA attempt to compile and run user given source. +dnl +dnl *Warning*: its success or failure can depend on a proper setting of the +dnl CLASSPATH env. variable. +dnl +dnl Note: This is part of the set of autoconf M4 macros for Java programs. +dnl It is VERY IMPORTANT that you download the whole set, some +dnl macros depend on other. Unfortunately, the autoconf archive does not +dnl support the concept of set of macros, so I had to break it for +dnl submission. +dnl The general documentation, as well as the sample configure.in, is +dnl included in the AC_PROG_JAVA macro. +dnl +dnl @author Devin Weaver <ktohg@tritarget.com> +dnl @version $Id: ac_try_run_javac.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $ +dnl +AC_DEFUN([AC_TRY_RUN_JAVA],[ +AC_REQUIRE([AC_PROG_JAVAC])dnl +AC_REQUIRE([AC_PROG_JAVA])dnl +cat << \EOF > Test.java +/* [#]line __oline__ "configure" */ +ifelse([$1], , , [include $1;]) +public class Test { +[$2] +} +EOF +if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class && ($JAVA $JAVAFLAGS Test; exit) 2>/dev/null +then +dnl Don't remove the temporary files here, so they can be examined. + ifelse([$3], , :, [$3]) +else + echo "configure: failed program was:" >&AC_FD_CC + cat Test.java >&AC_FD_CC +ifelse([$4], , , [ rm -fr Test* + $4 +])dnl +fi +rm -fr Test*]) diff --git a/smf/apocd.xml.in b/smf/apocd.xml.in new file mode 100755 index 0000000..452634e --- /dev/null +++ b/smf/apocd.xml.in @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + Copyright 2004 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + ident "@(#)x11-server.xml.cpp 1.2 04/11/17 SMI" +--> + +<service_bundle type='manifest' name='SUNWapoc:apocd'> + +<service + name='network/apocd/udp' + type='service' + version='1'> + + <dependency + type='service' + name='fs-local' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/local'/> + </dependency> + + <dependency + type='service' + name='name-services' + grouping='require_all' + restart_on='refresh'> + <service_fmri value='svc:/milestone/name-services'/> + </dependency> + + <exec_method + type='method' + name='start' + exec='@APOCD_DIR@/apocd svcStart' + timeout_seconds='30'> + <method_context> + <method_credential user='root' group='root'/> + </method_context> + </exec_method> + + <exec_method + type='method' + name='stop' + exec='@APOCD_DIR@/apocd svcStop' + timeout_seconds='20'> + <method_context> + <method_credential user='root' group='root'/> + </method_context> + </exec_method> + + <exec_method + type='method' + name='refresh' + exec='@APOCD_DIR@/apocd reload' + timeout_seconds='5'> + <method_context> + <method_credential user='root' group='root'/> + </method_context> + </exec_method> + + <instance name='default' enabled='false'/> + + <stability value='External'/> + + <template> + <common_name> + <loctext xml:lang='C'>Configuration Agent</loctext> + </common_name> + </template> + +</service> + +</service_bundle> diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..05023f1 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = com/ diff --git a/src/com/Makefile.am b/src/com/Makefile.am new file mode 100644 index 0000000..1d06788 --- /dev/null +++ b/src/com/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = sun diff --git a/src/com/sun/Makefile.am b/src/com/sun/Makefile.am new file mode 100644 index 0000000..b5d5f2c --- /dev/null +++ b/src/com/sun/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = apoc diff --git a/src/com/sun/apoc/Makefile.am b/src/com/sun/apoc/Makefile.am new file mode 100644 index 0000000..75ad827 --- /dev/null +++ b/src/com/sun/apoc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = daemon diff --git a/src/com/sun/apoc/daemon/Makefile.am b/src/com/sun/apoc/daemon/Makefile.am new file mode 100644 index 0000000..f76f046 --- /dev/null +++ b/src/com/sun/apoc/daemon/Makefile.am @@ -0,0 +1,5 @@ +all: + $(ANT) + +clean-local: + $(ANT) -q clean diff --git a/src/com/sun/apoc/daemon/admin/AdminManager.java b/src/com/sun/apoc/daemon/admin/AdminManager.java new file mode 100644 index 0000000..3dfcf68 --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/AdminManager.java @@ -0,0 +1,286 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; + +public class AdminManager extends Thread +{ + private static final byte[] sSuccess = { 0 }; + private static final byte[] sFailure = { 1 }; + private static final byte sOpChangeDetect = ( byte )1; + private static final byte sOpReload = ( byte )6; + private static final byte sOpStatus = ( byte )9; + private static final byte sOpStop = ( byte )10; + + private static final byte[] sAcceptByte = { 1 }; + private static final ByteBuffer sAccept = + ( ByteBuffer )ByteBuffer.wrap( sAcceptByte ); + + private Selector mSelector; + private ServerSocketChannel mChannel; + private AdminOpHandler mAdminOpHandler; + private final Object mTerminateLock = new Object(); + private boolean mTerminate = false; + + public AdminManager( final AdminOpHandler inAdminOpHandler ) + throws APOCException + { + setName( "AdminManager" ); + mAdminOpHandler = inAdminOpHandler; + initChannel(); + } + + public void run() + { + APOCLogger.fine( "Admr001" ); + while ( ! shouldTerminate() ) + { + try + { + final ClientChannel theChannel = acceptClientChannel(); + if ( theChannel != null ) + { + if ( authenticate( theChannel ) ) + { + try + { + handleRequest( theChannel ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "AdminManager", + "run", + theException ); + } + } + theChannel.close(); + } + } + catch ( IOException theException ) + { + APOCLogger.throwing( "AdminManager", "run", theException ); + break; + } + } + closeServerChannel(); + APOCLogger.fine( "Admr002" ); + } + + public void terminate() + { + synchronized( mTerminateLock ) + { + mTerminate = true; + } + } + + private ClientChannel acceptClientChannel() + throws IOException + { + ClientChannel theChannel = null; + if ( mSelector.select() > 0 ) + { + final Iterator theIterator = mSelector.selectedKeys().iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = ( SelectionKey )theIterator.next(); + theIterator.remove(); + if ( theKey.isAcceptable() ) + { + SocketChannel theSocketChannel = null; + try + { + theSocketChannel = + (( ServerSocketChannel )theKey.channel() ).accept(); + if ( theSocketChannel. + socket(). + getInetAddress(). + isLoopbackAddress() ) + { + theChannel = + new ClientChannel( theSocketChannel, null); + theChannel.write( sAccept ); + sAccept.flip(); + break; + } + } + catch( IOException theException ) + { + if ( theSocketChannel != null ) + { + try + { + theSocketChannel.close(); + } + catch( IOException ignore ){} + } + APOCLogger.throwing( "AdminManager", + "acceptClientChannel", + theException ); + } + } + } + } + return theChannel; + } + + private boolean authenticate( final ClientChannel inChannel ) + { + boolean isAuthenticated; + APOCAuthenticator theAuthenticator = null; + try + { + theAuthenticator = new APOCAuthenticator( null ); + byte[] theChallenge = theAuthenticator.getChallenge(); + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( theChallenge.length + 1 ) + .put( theChallenge ) + .put( ( byte )0 ) + .flip() ); + ByteBuffer theAuthBuffer = + ByteBuffer.wrap( + new byte[ APOCAuthenticator.getAuthBufferSize() ] ); + while ( inChannel.read( theAuthBuffer ) == 0 ){} + theAuthenticator.processResponse( theAuthBuffer.array() ); + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sSuccess ).flip() ); + isAuthenticated = true; + } + catch( Exception theException ) + { + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sFailure ).flip() ); + isAuthenticated = false; + } + finally + { + if ( theAuthenticator != null ) + { + theAuthenticator.cleanup(); + } + } + return isAuthenticated; + } + + private void closeServerChannel() + { + try + { + mSelector.close(); + mChannel.close(); + } + catch( IOException theException ) + { + APOCLogger.throwing( "AdminManager", + "closeServerChannel", + theException ); + } + } + + private void handleRequest( final ClientChannel inChannel ) + throws Exception + { + int theRC; + ByteBuffer theBuffer = ByteBuffer.wrap( new byte[ 1 ] ); + while ( inChannel.read( theBuffer ) != 1 ){} + switch( theBuffer.array()[ 0 ] ) + { + case sOpStop: + theRC = mAdminOpHandler.onStop(); + terminate(); + break; + + case sOpStatus: + theRC = mAdminOpHandler.onStatus(); + break; + + case sOpReload: + theRC = mAdminOpHandler.onReload(); + break; + + case sOpChangeDetect: + theRC = mAdminOpHandler.onChangeDetect(); + break; + + default: + theRC = -1; + break; + } + theBuffer = ByteBuffer.wrap( theRC == 0 ? sSuccess : sFailure ); + inChannel.write( theBuffer ); + } + + private void initChannel() + throws APOCException + { + try + { + mSelector = Selector.open(); + mChannel = ServerSocketChannel.open(); + mChannel.configureBlocking( false ); + mChannel.socket().bind( null ); + mChannel.register( mSelector, SelectionKey.OP_ACCEPT ); + /* + * 6417539 - Need to use IANA registered port + * Use a PortMapper instance to let admin. clients + * know which port the agent is using. + */ + new PortMapper( + ( ( InetSocketAddress )mChannel.socket().getLocalSocketAddress() ) + .getPort() ).start(); + } + catch( IOException theException ) + { + throw new APOCException( theException ); + } + } + + private boolean shouldTerminate() + { + synchronized( mTerminateLock ) + { + return mTerminate; + } + } +} diff --git a/src/com/sun/apoc/daemon/admin/AdminOpHandler.java b/src/com/sun/apoc/daemon/admin/AdminOpHandler.java new file mode 100644 index 0000000..edc357c --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/AdminOpHandler.java @@ -0,0 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +public interface AdminOpHandler +{ + int onStop(); + int onStatus(); + int onReload(); + int onChangeDetect(); +} diff --git a/src/com/sun/apoc/daemon/admin/PortMapper.java b/src/com/sun/apoc/daemon/admin/PortMapper.java new file mode 100644 index 0000000..04c3b5f --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/PortMapper.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.net.*; + +/* + * Not really a port mapper but .... + * + * This class is used to inform admin. clients which port is currently being + * used for admin. access. It simply accepts a udp connection and reponds + * with the relevant port number. This is repeated indefinitely. + */ +public class PortMapper extends Thread +{ + private static int sPort = + DaemonConfig.getIntProperty( DaemonConfig.sDaemonPort ); + private ByteBuffer mAdminPort; + private DatagramChannel mChannel; + + public PortMapper( int inAdminPort ) + throws APOCException + { + try + { + setName( "PortMapper" ); + setDaemon( true ); + mAdminPort = + ( ByteBuffer )ByteBuffer.allocate( 6 ) + .put( String.valueOf( inAdminPort ).getBytes() ) + .put( ( byte )0 ); + mChannel = DatagramChannel.open(); + mChannel.socket().bind( new InetSocketAddress( sPort ) ); + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + public void run() + { + ByteBuffer theBuffer = ByteBuffer.allocate( 1 ); + while ( true ) + { + try + { + InetSocketAddress theClient = + ( InetSocketAddress )mChannel.receive( + ( ByteBuffer )theBuffer.position( 0 ) ); + if ( theClient != null && + theClient.getAddress().isLoopbackAddress() ) + { + mChannel.send( ( ByteBuffer )mAdminPort.position( 0 ), + theClient ); + } + } + catch( Exception theIgnore ) + {} + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Cache.java b/src/com/sun/apoc/daemon/apocd/Cache.java new file mode 100755 index 0000000..515ce09 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Cache.java @@ -0,0 +1,927 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.policies.*; + +import java.util.*; +import javax.security.auth.callback.*; + + +public class Cache implements ConfigEventListener +{ + private String mUserName; + private String mEntityType; + private String mEntityId; + private CallbackHandler mHandler; + private DataSource mDataSources[] = null; + private final HashSet mSessions = new HashSet(); + private int mRefCount = 0; + private boolean mIsLocalPolicyEnabled = + DaemonConfig.getBooleanProperty( DaemonConfig.sApplyLocalPolicy ); + private static final String[] sStringModel = new String[ 0 ]; + + public Cache( final String inUserName, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler ) + { + mUserName = inUserName; + mEntityType = inEntityType; + mEntityId = inEntityId; + mHandler = inHandler; + createDataSources(); + inHandler.setReconnectMode(); + DaemonConfig.addConfigEventListener( this ); + } + + public synchronized int acquire( final Session inSession ) + { + mSessions.add( inSession ); + return ++ mRefCount; + } + public synchronized int release( final Session inSession ) + { + mSessions.remove( inSession ); + return -- mRefCount; + } + public synchronized Session [] getSessions() + { + return (Session []) mSessions.toArray(new Session [0]); + } + public synchronized ArrayList changeDetect() + { + for ( int theIndex = 0 ; theIndex < mDataSources.length ; ++ theIndex ) + { + mDataSources[ theIndex ].open(mHandler); + } + ArrayList theResults = new ArrayList(); + HashSet theOriginalList = null; + int theOnlineDataSourceCount = 0; + + for ( int theIndex = 0 ; theIndex < mDataSources.length ; ++ theIndex ) + { + if ( mDataSources[ theIndex ].isOnline()) + { + ++ theOnlineDataSourceCount; + } + } + if ( theOnlineDataSourceCount > 1 ) + { + theOriginalList = list(); + } + for ( int theIndex = 0 ; theIndex < mDataSources.length ; theIndex ++ ) + { + final ArrayList theResult = + changeDetect( mDataSources[ theIndex ] ); + if ( theResult != null ) + { + theResults.addAll( theResult ); + } + } + if ( theOnlineDataSourceCount > 1 ) + { + theResults = mergeUpdateResults( theResults, theOriginalList ); + } + return theResults; + } + + public synchronized void close() + { + for ( int theIndex = 0; theIndex < mDataSources.length ; theIndex ++ ) + { + mDataSources[ theIndex ].close(); + } + } + + public String getEntityType() { return mEntityType; } + + public String getEntityId() { return mEntityId; } + + public boolean isOutOfDate() + { + long lastChangeDetect = Timestamp.getMillis(getLastChangeDetect()) ; + + if (lastChangeDetect == 0) { return true ; } + return lastChangeDetect + + (long) (DaemonConfig.getFloatProperty( + DaemonConfig.sChangeDetectionInterval) * 60000) < + Timestamp.getMillis(Timestamp.getTimestamp()) ; + } + + public synchronized String getLastChangeDetect() + { + String theResult = null; + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final LocalDatabase theDatabase = + mDataSources[ theIndex ].getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + final String theTimestamp=theDatabase.getLastChangeDetect(); + if ( theTimestamp.compareTo( Timestamp.sEpoch ) == 0 ) + { + break; + } + else if ( theResult == null ) + { + theResult = theTimestamp; + } + else if ( Timestamp.isNewer( theResult, theTimestamp ) ) + { + theResult = theTimestamp; + } + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "getLastChangeDetect", + theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "getLastChangeDetect", + theException ); + } + } + } + } + return theResult != null ? theResult : Timestamp.sEpoch; + } + + public String getUserId() { return mUserName; } + + public synchronized boolean hasDatabase( final Database inDatabase ) + { + boolean haveLocalDatabase = false; + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + if ( mDataSources[ theIndex ].getLocalDatabase() == inDatabase ) + { + haveLocalDatabase = true; + break; + } + } + return haveLocalDatabase; + } + + public synchronized HashSet list() + { + HashSet theComponents = new HashSet(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final HashSet theSet = list ( mDataSources[ theIndex ] ); + if ( theSet != null ) + { + theComponents.addAll( theSet ); + } + } + return theComponents; + } + + public synchronized void onConfigEvent() + { + boolean isLocalPolicyEnabled = + DaemonConfig.getBooleanProperty( DaemonConfig.sApplyLocalPolicy ); + if ( isLocalPolicyEnabled != mIsLocalPolicyEnabled ) + { + mIsLocalPolicyEnabled = isLocalPolicyEnabled; + if ( mIsLocalPolicyEnabled ) + { + enableLocalPolicy(); + } + else + { + disableLocalPolicy(); + } + } + } + + public synchronized ArrayList read( final String inComponentName ) + { + final ArrayList theResults = new ArrayList(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final ArrayList theResult = + read( mDataSources[ theIndex ], inComponentName ); + if ( theResult != null ) + { + theResults.addAll( theResult ); + } + } + return theResults; + } + + public synchronized String toString() + { + final StringBuffer theBuffer = new StringBuffer(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + theBuffer.append( " dataSource" + ( theIndex + 1 ) ) + .append( "\n " ) + .append( mDataSources[ theIndex ].toString() ) + .append( "\n" ); + } + return theBuffer.toString(); + } + + private ArrayList changeDetect( final DataSource inDataSource ) + { + ArrayList theResult = null; + if ( inDataSource.isOnline() ) + { + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + try + { + theDatabase.beginTransaction(); + switch( inDataSource.getState() ) + { + case DataSource.sStateEnabled: + theResult = updateLocalDatabase( inDataSource ); + break; + + case DataSource.sStateDisabling: + theResult = new ArrayList(); + addRemovalItems( theResult, + theDatabase.getLocalComponentList() ); + break; + case DataSource.sStateEnabling: + theResult = new ArrayList(); + addAdditionItems( theResult, + inDataSource, + theDatabase.getLocalComponentList() ); + inDataSource.setState( DataSource.sStateEnabled ); + break; + + default: + break; + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "Cache", "changeDetect", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "changeDetect", + theException ); + } + } + if ( inDataSource.mState == DataSource.sStateDisabling ) + { + inDataSource.close(); + } + } + return theResult; + } + + private void createDataSources() + { + mDataSources = new DataSource [2]; + mDataSources[ 0 ] = new DataSource( mUserName, + mEntityType, + mEntityId, + true ); + mDataSources[ 1 ] = new DataSource( mUserName, + mEntityType, + mEntityId, + false ); + if ( mIsLocalPolicyEnabled ) + { + mDataSources[ 0 ].open( mHandler ); + } + mDataSources[ 1 ].open( mHandler ); + } + + private void disableLocalPolicy() + { + mDataSources[ 0 ].setState( DataSource.sStateDisabling ); + } + + private void enableLocalPolicy() + { + mDataSources[ 0 ].setState( DataSource.sStateEnabling ); + } + + private HashSet list( final DataSource inDataSource ) + { + HashSet theSet = null; + if ( inDataSource.getState() == DataSource.sStateEnabled ) + { + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + theSet = theDatabase.getRemoteComponentList(); + } + catch ( APOCException theException ) + { + APOCLogger.throwing( "Cache", "list", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", "list", theException ); + } + } + } + } + return theSet; + } + + private ArrayList mergeUpdateResults( final ArrayList inResults, + final HashSet inOriginalList ) + { + ArrayList theResult = inResults; + if ( inResults.size() > 0 && + inOriginalList != null && + inOriginalList.size() > 0 ) + { + final HashSet theNewList = list(); + final HashSet theUpdatedComponents = new HashSet(); + final Iterator theIterator = inResults.iterator(); + theResult = new ArrayList(); + while ( theIterator.hasNext() ) + { + final UpdateItem theItem = ( UpdateItem )theIterator.next(); + final String theName = theItem.getComponentName(); + if ( theUpdatedComponents.add( theName ) ) + { + if ( ( theItem.getUpdateType() == UpdateItem.ADD && + inOriginalList.contains( theName ) ) || + ( theItem.getUpdateType() == UpdateItem.REMOVE ) && + theNewList.contains( theName ) ) + { + theItem.setUpdateType( UpdateItem.MODIFY ); + } + theResult.add( theItem ); + } + } + } + return theResult; + } + + private ArrayList read( final DataSource inDataSource, + final String inComponentName ) + { + final ArrayList theResult = new ArrayList(); + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + boolean haveComponent = + theDatabase.hasComponent( inComponentName ); + if ( ! haveComponent && inDataSource.isOnline() ) + { + final HashSet theSet = theDatabase.getRemoteComponentList(); + if ( theSet != null && theSet.contains( inComponentName ) ) + { + final Policy[] thePolicies = + inDataSource. + getPolicyBackend(). + getLayeredPolicies( + inComponentName, + false ); + if ( thePolicies != null ) + { + theDatabase. + update( + new UpdateItem( + UpdateItem.ADD, + inComponentName, + thePolicies ), + Timestamp.getTimestamp() ); + haveComponent = true; + } + } + } + if ( haveComponent ) + { + final Vector theLayerIds = + theDatabase.getLayerIds( inComponentName ); + for ( int theIndex = 0; + theIndex < theLayerIds.size(); + ++ theIndex ) + { + final String theLayerId = + ( String )theLayerIds.elementAt( theIndex ); + theResult.add( + new CacheReadResult( + theDatabase. + getLastModified( theLayerId, + inComponentName ), + theDatabase. + getLayer( inComponentName, theLayerId ) ) ); + } + } + } + catch ( APOCException theException ) + { + APOCLogger.throwing( "Cache", "read", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", "read", theException ); + } + } + } + return theResult; + } + + private void addDownloadItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inAddComponents, + final HashSet inModifyComponents ) + throws APOCException + { + if ( inAddComponents != null && inModifyComponents != null ) + { + final HashSet theSet = ( HashSet)inAddComponents.clone(); + int theAddCount = theSet.size(); + theSet.addAll( inModifyComponents ); + final Policy[][] thePolicies = + ( Policy[][] )inDataSource.getPolicyBackend(). + getLayeredPolicies( theSet, false ); + final Iterator theIterator = theSet.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + final String theComponent = ( String )theIterator.next(); + outResult.add( + new UpdateItem( inAddComponents.contains( theComponent ) ? + UpdateItem.ADD : UpdateItem.MODIFY, + theComponent, + thePolicies[ theIndex ++ ] ) ); + } + + } + else + if ( inAddComponents != null ) + { + addAdditionItems( outResult, inDataSource, inAddComponents ); + } + else if ( inModifyComponents != null ) + { + addModificationItems( outResult, inDataSource, inModifyComponents ); + } + + } + + private void addAdditionItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Policy[][] thePolicies = + ( Policy[][] )inDataSource. + getPolicyBackend(). + getLayeredPolicies( inComponents, false ); + final Iterator theIterator = inComponents.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.ADD, + ( String )theIterator.next(), + thePolicies[ theIndex ++ ] ) ); + } + } + } + + private void addModificationItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Policy[][] thePolicies = + ( Policy[][] )inDataSource. + getPolicyBackend(). + getLayeredPolicies( inComponents, false ); + final Iterator theIterator = inComponents.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.MODIFY, + ( String )theIterator.next(), + thePolicies[ theIndex ++ ] ) ); + } + } + } + + private void addRemovalItems( final ArrayList outResult, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Iterator theIterator = inComponents.iterator(); + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.REMOVE, + ( String )theIterator.next(), + null ) ); + } + } + } + + private int compareLayers( final DataSource inDataSource, + final String inComponentName, + final PolicyInfo[] inPolicies ) + throws APOCException + { + int theRC = 0; + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + final Vector theLayerIds = + theDatabase.getLayerIds( inComponentName ); + if ( theLayerIds.size() != inPolicies.length ) + { + theRC = 1; + } + else + { + final String theComponentName = inPolicies[ 0 ].getId(); + for ( int theIndex = 0 ; theIndex < inPolicies.length; ++ theIndex) + { + final String theLayerId = + ( String )theLayerIds.elementAt( theIndex ); + + + if ( theLayerId.compareTo( + String.valueOf( + inPolicies[ theIndex ].getProfileId().hashCode() ) ) + != 0 + || + Timestamp.getTimestamp( + inPolicies[ theIndex ].getLastModified() ).compareTo( + theDatabase. + getLastModified( theLayerId, theComponentName )) + != 0 ) + { + theRC = 1; + break; + } + } + } + return theRC; + } + + private void createUpdateItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inRemoteComponents ) + throws APOCException + { + final HashSet theLocalComponents = + inDataSource.getLocalDatabase().getLocalComponentList(); + final HashSet theAdditions = + diff( inRemoteComponents, theLocalComponents ); + final HashSet theRemovals = + diff( theLocalComponents, inRemoteComponents ); + final HashSet theModifications = + getModifications( inDataSource, + diff( theLocalComponents, theRemovals ) ); + addDownloadItems( outResult, + inDataSource, + theAdditions, + theModifications ); + addRemovalItems( outResult, theRemovals ); + } + + private HashSet diff( final HashSet inSet1, final HashSet inSet2 ) + { + HashSet theResult = null; + if ( inSet2 == null ) + { + theResult = inSet1; + } + else + if ( inSet1 != null ) + { + theResult = ( HashSet )inSet1.clone(); + theResult.removeAll( inSet2 ); + if ( theResult.size() == 0 ) + { + theResult = null; + } + } + return theResult; + } + + private HashSet getModifications( final DataSource inDataSource, + final HashSet inSet ) + throws APOCException + { + HashSet theModifications = null; + if ( inSet != null ) + { + final PolicyInfo[][] thePolicies = + inDataSource. + getPolicyBackend(). + getLayeredPolicies( inSet, true ); + final String[] theComponents = + ( String[] )inSet.toArray( sStringModel ); + theModifications = new HashSet(); + for ( int theIndex = 0 ; theIndex < thePolicies.length; ++ theIndex) + { + if ( isUpdated( inDataSource, + theComponents[ theIndex ], + thePolicies[ theIndex ] ) ) + { + theModifications.add( theComponents[ theIndex ] ); + } + } + if ( theModifications.size() == 0 ) + { + theModifications = null; + } + } + return theModifications; + } + + private boolean isUpdated( final DataSource inDataSource, + final String inComponent, + final PolicyInfo[] inPolicies ) + throws APOCException + { + boolean isUpdated = false; + if ( inPolicies == null ) + { + isUpdated = true; + } + else + { + isUpdated = compareLayers( inDataSource, inComponent, inPolicies ) + == 0 ? false : true; + } + return isUpdated; + } + + private ArrayList updateLocalDatabase( final DataSource inDataSource ) + throws APOCException + { + final ArrayList theResult = new ArrayList(); + try + { + final PolicyBackend theBackend = inDataSource.getPolicyBackend(); + theBackend.refreshProfiles(); + final HashSet theRemoteComponents = theBackend.getComponentList(); + createUpdateItems( theResult, inDataSource, theRemoteComponents ); + theResult.trimToSize(); + final String theTimestamp= Timestamp.getTimestamp(); + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + theDatabase.update( theResult, theTimestamp ); + theDatabase.putLastChangeDetect( theTimestamp ); + theDatabase.putRemoteComponentList( + theRemoteComponents != null ? + theRemoteComponents : new HashSet() ); + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + return theResult; + } + + private static class DataSource + { + protected LocalDatabase mLocalDatabase; + protected PolicyBackend mPolicyBackend; + protected Name mName; + protected int mState = sStateDisabled; + protected boolean mInitialised = false; + + static final int sStateEnabled = 0; + static final int sStateDisabled = 1; + static final int sStateEnabling = 2; + static final int sStateDisabling = 3; + + DataSource( final String inUserName, + final String inEntityType, + final String inEntityId, + final boolean inIsLocal ) + { + mName = new Name( inUserName, inEntityType, inEntityId, inIsLocal ); + } + + void close() + { + closePolicyBackend(); + closeLocalDatabase(); + } + + synchronized LocalDatabase getLocalDatabase() { return mLocalDatabase; } + + synchronized PolicyBackend getPolicyBackend() { return mPolicyBackend; } + + synchronized int getState() { return mState; } + + synchronized boolean isOnline() { + return mPolicyBackend != null && mLocalDatabase != null; } + + synchronized void open( final CallbackHandler inHandler ) + { + boolean isLocal = mName.isLocal(); + if ( ! isLocal || + DaemonConfig.getBooleanProperty( + DaemonConfig.sApplyLocalPolicy ) ) + { + if ( mLocalDatabase == null ) + { + mLocalDatabase = openLocalDatabase(); + } + try + { + if ( mLocalDatabase != null && mPolicyBackend == null && + ( mInitialised || + mLocalDatabase.getLastChangeDetect().compareTo( + Timestamp.sEpoch ) == 0 ) ) + { + mPolicyBackend = openPolicyBackend( inHandler ); + if ( ! mInitialised && mPolicyBackend != null ) + { + initialiseDatabase(); + } + } + } + catch( APOCException theException ) + { + APOCLogger.throwing( "DataSource", "open", theException ); + } + mInitialised = true; + if ( ! isLocal || mState != sStateEnabling ) + { + mState = sStateEnabled; + } + } + } + + synchronized void setState( int inState ) { mState = inState; } + + public String toString() + { + return new StringBuffer( " Name: " ) + .append( mName.toString() ) + .append( "\n Cache: " ) + .append( mLocalDatabase ) + .append( "\n Backend: " ) + .append( mPolicyBackend ) + .toString(); + } + + protected void initialiseDatabase() + { + try + { + final HashSet theSet = mPolicyBackend.getComponentList(); + if ( theSet != null ) + { + mLocalDatabase.beginTransaction(); + mLocalDatabase.putRemoteComponentList( theSet ); + mLocalDatabase.endTransaction(); + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "DataSource", + "initialiseDatabase", + theException); + } + } + + protected void closeLocalDatabase() + { + if ( mLocalDatabase != null ) + { + try + { + LocalDatabaseFactory.getInstance().closeLocalDatabase( + mLocalDatabase ); + } + catch( Exception theException ){} + finally { mLocalDatabase = null; } + } + } + + protected void closePolicyBackend() + { + if ( mPolicyBackend != null ) + { + PolicyBackendFactory.getInstance().closePolicyBackend( + mPolicyBackend ); + mPolicyBackend = null; + } + } + + protected LocalDatabase openLocalDatabase() + { + LocalDatabase theLocalDatabase = null; + try + { + theLocalDatabase = + LocalDatabaseFactory.getInstance(). + openLocalDatabase( mName ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "DataSource", + "openLocalDatabase", + theException ); + } + return theLocalDatabase; + } + + protected PolicyBackend openPolicyBackend( + final CallbackHandler inHandler ) + { + PolicyBackend theBackend = null; + try + { + theBackend = + PolicyBackendFactory + .getInstance() + .openPolicyBackend( mName, inHandler ); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "PolicyBackend", + "openPolicyBackend", + theException ); + } + return theBackend; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/CacheFactory.java b/src/com/sun/apoc/daemon/apocd/CacheFactory.java new file mode 100755 index 0000000..65d5f39 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/CacheFactory.java @@ -0,0 +1,151 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.misc.*; + +import java.util.*; +import javax.security.auth.callback.*; + +public class CacheFactory +{ + private final HashMap mCaches = new HashMap(); + private static final CacheFactory sInstance = new CacheFactory(); + private static final Cache[] sCacheModel = new Cache[ 0 ]; + + private synchronized void closeCache( final Cache inCache, + final Session inSession ) + { + if ( inCache.release( inSession ) == 0 ) + { + final Cache theCache = + ( Cache )mCaches.remove( + makeKey( inCache.getUserId(), + inCache.getEntityType(), + inCache.getEntityId() ) ); + if ( theCache != null ) + { + theCache.close(); + } + } + } + + public void closeCaches( final Cache[] inCaches, final Session inSession ) + { + for ( int theIndex = 0 ; theIndex < inCaches.length ; ++ theIndex ) + { + closeCache( inCaches[ theIndex ], inSession ); + } + } + + public synchronized Cache[] getCaches() + { + Cache[] theCaches = null; + if ( mCaches.size() > 0 ) + { + theCaches = ( Cache[] )mCaches.values().toArray( sCacheModel ); + } + return theCaches; + } + + public static CacheFactory getInstance() { return sInstance; } + + public synchronized Cache [] openCaches( + final String inUserId, + final Hashtable inEntities, + final Session inSession, + final SaslAuthCallbackHandler inHandler ) + throws APOCException + { + String [] theSources = PolicyBackendFactory.getInstance().getSources(); + ArrayList theCaches = new ArrayList(); + + for ( int theIndex = 0 ; theIndex < theSources.length ; ++ theIndex ) + { + String theEntity = + (String) inEntities.get( theSources[ theIndex ] ); + Cache theCache = getCache( inUserId, theSources[ theIndex ], + theEntity, inHandler ); + + theCache.acquire( inSession ); + theCaches.add( theCache ); + } + return (Cache []) theCaches.toArray( sCacheModel ); + } + + private CacheFactory(){} + + private Cache getCache(final String inUserId, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler) + throws APOCException + { + Cache retCode = getExistingCache(inUserId, inEntityType, inEntityId) ; + + if (retCode == null) + { + retCode = createNewCache(inUserId, inEntityType, + inEntityId, inHandler) ; + } + return retCode ; + } + private Cache createNewCache( final String inUserId, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler ) + throws APOCException + { + Cache theCache = new Cache( inUserId, inEntityType, + inEntityId, inHandler ); + mCaches.put( makeKey( inUserId, inEntityType, inEntityId ), theCache ); + return theCache; + } + + private Cache getExistingCache( final String inUserId, + final String inEntityType, + final String inEntityId ) + { + return ( Cache )mCaches.get( makeKey( inUserId, inEntityType, + inEntityId ) ); + } + + private String makeKey( final String inUserId, final String inEntityType, + final String inEntityId ) + { + return inUserId + "/" + inEntityType + "/" + + ( inEntityId != null ? inEntityId : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/CacheReadResult.java b/src/com/sun/apoc/daemon/apocd/CacheReadResult.java new file mode 100755 index 0000000..e7e9a75 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/CacheReadResult.java @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +public class CacheReadResult +{ + public String mTimestamp; + public String mData; + + public CacheReadResult( final String inTimestamp, final String inData ) + { + mTimestamp = inTimestamp; + mData = inData; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java b/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java new file mode 100644 index 0000000..0ee5bb6 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java @@ -0,0 +1,93 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.transaction.*; + +class ChangeDetectEventHandler implements EventHandler +{ + private final ChangeDetectTransaction mTransaction; + private long sTimeout = 100; + private final Object mCompleteLock = new Object(); + private boolean mComplete = false; + + ChangeDetectEventHandler( final ClientManager inManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + mTransaction = TransactionFactory + .getInstance() + .createChangeDetectTransaction( inManager, + inCache, + inAggregator ); + } + + public void handleEvent( final Messenger inMessenger ) + { + mTransaction.execute(); + setComplete(); + } + + public synchronized void waitForCompletion() + { + while ( ! isComplete() ) + { + try + { + wait( sTimeout ); + } + catch( InterruptedException theException ) + {} + } + } + + private boolean isComplete() + { + synchronized( mCompleteLock ) + { + return mComplete; + } + } + + private void setComplete() + { + synchronized( mCompleteLock ) + { + mComplete = true; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Client.java b/src/com/sun/apoc/daemon/apocd/Client.java new file mode 100644 index 0000000..ff67959 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Client.java @@ -0,0 +1,148 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; +import java.util.*; + +public class Client +{ + private final ClientChannel mChannel; + private final HashMap mSessions = new HashMap( 1 ); // norm is 1 session + private final HashSet mSessionListeners = new HashSet( 1 ); + + public Client( final ClientChannel inChannel ) + { + mChannel = inChannel; + } + + public ClientChannel getClientChannel() { return mChannel; } + + // Changing this from a simple accessor because when change detection + // and session closure occur around the same time, the toArray() call + // below ( originally located in ClientManager ) can get confused. + public Object[] getSessions() + { + synchronized( mSessions ) + { + return mSessions.values().toArray(); + } + } + + public Session getSession( final String inSessionId ) + { + synchronized( mSessions ) + { + return inSessionId != null ? + ( Session )mSessions.get( inSessionId ): + null; + } + } + + public void addSession( final Session inSession ) + { + synchronized( mSessions ) + { + mSessions.put( inSession.getSessionId(), inSession ); + } + notifySessionCreated( inSession ); + } + + public void addSessionListener( final SessionListener inSessionListener ) + { + synchronized( mSessionListeners ) + { + mSessionListeners.add( inSessionListener ); + } + } + + public void closeSession( final Session inSession ) + { + synchronized( mSessions ) + { + mSessions.remove( inSession.getSessionId() ); + } + inSession.close(); + notifySessionDestroyed( inSession ); + } + + synchronized public void close() + { + final Iterator theIterator = mSessions.keySet().iterator(); + while ( theIterator.hasNext() ) + { + final Session theSession = + ( Session )mSessions.get( theIterator.next() ); + theSession.close(); + notifySessionDestroyed( theSession ); + } + mSessions.clear(); + } + + public void removeSessionListener( final SessionListener inSessionListener ) + { + synchronized( mSessionListeners ) + { + mSessionListeners.remove( inSessionListener ); + } + } + + private void notifySessionCreated( final Session inSession ) + { + synchronized( mSessionListeners ) + { + final Iterator theIterator = mSessionListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( SessionListener )theIterator.next() ) + .onSessionCreate( inSession ); + } + } + } + + private void notifySessionDestroyed( final Session inSession ) + { + synchronized( mSessionListeners ) + { + final Iterator theIterator = mSessionListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( SessionListener )theIterator.next() ) + .onSessionDestroy( inSession ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java b/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java new file mode 100644 index 0000000..9df1cba --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; + +class ClientEventHandler implements EventHandler +{ + private final Client mClient; + + ClientEventHandler( final Client inClient) + { + mClient = inClient; + } + + public void handleEvent( final Messenger inMessenger ) + { + try + { + inMessenger.setClientChannel( mClient.getClientChannel() ); + final Transaction theTransaction = + TransactionFactory + .getInstance() + .createTransaction( + mClient, + inMessenger.receiveRequest() ); + inMessenger.sendResponse( theTransaction.execute() ); + } + catch( APOCException theException ) + { + final Throwable theThrowable = theException.getCause(); + if ( theThrowable == null || !(theThrowable instanceof IOException)) + { + APOCLogger.throwing( "ClientEventHandler", + "handleEvent", + theException ); + inMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespInvalidRequest, null, null ) ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ClientManager.java b/src/com/sun/apoc/daemon/apocd/ClientManager.java new file mode 100644 index 0000000..061e184 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ClientManager.java @@ -0,0 +1,311 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; +import com.sun.apoc.daemon.transport.*; + +import java.util.*; + +public class ClientManager implements ClientChannelEventListener, + ConfigEventListener, + SessionListener +{ + private final HashMap mClients = + new HashMap( DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ) ); + private final EventQueue mPendingEvents = + new EventQueue(); + private final EventWorkerThreadPool mThreadPool = + new EventWorkerThreadPool( + mPendingEvents, + DaemonConfig.getIntProperty( DaemonConfig.sMaxClientThreads ) ); + private final DaemonTimerTask mChangeDetector = + new DaemonTimerTask( new ChangeDetector( this ) ); + private int mSessionCount = 0; + + public ClientManager( final ChannelManager inChannelManager ) + throws APOCException + { + inChannelManager.addClientChannelEventListener( this ); + DaemonConfig.addConfigEventListener( this ); + APOCLogger.fine( "Clmr001" ); + } + + public void changeDetect() + { + new ChangeDetector( this ).run(); + } + + public void onPending( final ClientChannel inClientChannel ) + { + putEventHandler( + new ClientEventHandler( getClient( inClientChannel)) ); + } + + public void onClosed( final ClientChannel inClientChannel ) + { + synchronized( mClients ) + { + final Client theClient = + ( Client )mClients.remove( inClientChannel ); + if ( theClient != null ) + { + theClient.close(); + APOCLogger.finer( "Clmr002" ); + } + } + } + + public void onConfigEvent() + { + startChangeDetectionTimer(); + + mThreadPool.resizePool( + DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientThreads ) ); + } + + /* Warning: putting this here because we need access to the EventQueue. + * This Queue should be separated from this class in future. + */ + public void onGarbageCollect() + { + try + { + Object[] theDatabases = + LocalDatabaseFactory.getInstance().getDatabases(); + if ( theDatabases != null ) + { + for ( int theIndex = 0; + theIndex < theDatabases.length; + ++ theIndex ) + { + putEventHandler( + new GarbageCollectEventHandler( + ( Database )theDatabases[ theIndex ] ) ); + } + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "ClientManager", + "onGarbageCollect", + theException ); + } + } + + synchronized public void onSessionCreate( final Session inSession ) + { + mSessionCount ++; + doInitialChangeDetect( inSession ); + } + + synchronized public void onSessionDestroy( final Session inSession ) + { + mSessionCount --; + stopChangeDetectionTimer(); + } + + public void terminate() + { + mThreadPool.terminate(); + APOCLogger.fine( "Clmr007" ); + } + + private void doInitialChangeDetect( final Session inSession ) + { + try + { + Cache [] theCaches = inSession.getCaches() ; + ArrayList theOutOfDateCaches = new ArrayList() ; + + for (int i = 0 ; i < theCaches.length ; ++ i) + { + if (theCaches [i].isOutOfDate()) + { + theOutOfDateCaches.add(theCaches [i]) ; + } + } + final DaemonTimerTask theTask = + new DaemonTimerTask( + new ChangeDetector( + this, + (Cache []) theOutOfDateCaches.toArray( + new Cache [0])), + true) ; + + theTask.setPeriod( + DaemonConfig.getIntProperty( + DaemonConfig.sInitialChangeDetectionDelay) * + 1000) ; + startChangeDetectionTimer() ; + } + catch( Exception theException ) + {} + } + + private Client getClient( final ClientChannel inClientChannel ) + { + synchronized( mClients ) + { + Client theClient = ( Client )mClients.get( inClientChannel ); + if ( theClient == null ) + { + theClient = new Client( inClientChannel ); + theClient.addSessionListener( this ); + mClients.put( inClientChannel, theClient ); + APOCLogger.finer( "Clmr005" ); + } + return theClient; + } + } + + private boolean putEventHandler( final EventHandler inEventHandler ) + { + boolean theRC = true; + mPendingEvents.put( inEventHandler ); + try + { + mThreadPool.ensureThread(); + } + catch( APOCException theException ) + { + theRC = false; + APOCLogger.throwing( "ChangeDetector", "run", theException ); + } + return theRC; + } + + private void startChangeDetectionTimer() + { + if ( mSessionCount > 0 ) + { + final float theMinuteDelay = + DaemonConfig.getFloatProperty( + DaemonConfig.sChangeDetectionInterval ); + if ( mChangeDetector.setPeriod( ( long )(60000 * theMinuteDelay) ) ) + { + if ( mChangeDetector.getPeriod() > 0 ) + { + APOCLogger.fine( "Clmr004", + String.valueOf( theMinuteDelay ) ); + } + else + { + APOCLogger.fine( "Clmr006" ); + } + } + } + } + + private void stopChangeDetectionTimer() + { + if ( mSessionCount < 1 ) + { + mChangeDetector.cancel(); + } + } + + static class ChangeDetector implements Runnable + { + private ClientManager mManager; + private Cache [] mCaches = null; + boolean mCheckCaches = false ; + + public ChangeDetector( final ClientManager inManager, + final Cache [] inCaches ) + { + mManager = inManager; + mCaches = inCaches ; + mCheckCaches = true ; + } + + public ChangeDetector( final ClientManager inManager ) + { + mManager = inManager; + } + + public void run() + { + Cache [] theCaches = mCaches ; + + if ( theCaches == null ) + { + synchronized( mManager.mClients ) + { + if ( ! mManager.mClients.isEmpty() ) + { + theCaches = CacheFactory.getInstance().getCaches(); + } + } + } + if ( theCaches != null ) + { + final ArrayList theHandlers = new ArrayList(); + final UpdateAggregator theAggregator = new UpdateAggregator() ; + + for ( int theIndex = 0; + theIndex < theCaches.length; + ++ theIndex ) + { + if (!mCheckCaches || theCaches [theIndex].isOutOfDate()) { + final ChangeDetectEventHandler theHandler = + new ChangeDetectEventHandler( + mManager, theCaches[ theIndex ], + theAggregator ); + if ( mManager.putEventHandler( theHandler ) ) + { + theHandlers.add( theHandler ); + } + } + } + int theHandlerCount = theHandlers.size(); + for ( int theIndex = 0; + theIndex < theHandlerCount; + ++ theIndex ) + { + ( ( ChangeDetectEventHandler )theHandlers + .get( theIndex ) ).waitForCompletion(); + } + theAggregator.sendNotifications() ; + mManager.startChangeDetectionTimer(); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Daemon.java b/src/com/sun/apoc/daemon/apocd/Daemon.java new file mode 100644 index 0000000..8eddcaa --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Daemon.java @@ -0,0 +1,209 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.admin.*; +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.util.*; + +public class Daemon implements ConfigEventListener, AdminOpHandler +{ + private ChannelManager mChannelManager; + private ClientManager mClientManager; + private AdminManager mAdminManager; + private final DaemonTimerTask mGarbageCollector = + new DaemonTimerTask( new GarbageCollector() ); + + public static void main( final String[] inArgs ) + { + try + { + new Daemon( inArgs ).run(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "Daemon", "main", theException ); + } + } + + public Daemon( final String[] inArgs ) + throws APOCException, IOException, InterruptedException + { + if ( inArgs.length != 2 ) + { + usage(); + System.exit( 1 ); + } + init( inArgs ); + } + + public void onConfigEvent() + { + startGarbageCollectionTimer(); + DaemonConfig.log(); + } + + public int onStop() + { + mChannelManager.terminate(); + return 0; + } + + public int onStatus() + { + return 0; + } + + public int onReload() + { + int theRC; + try + { + DaemonConfig.reload(); + DaemonConfig.log(); + theRC = 0; + } + catch( Exception theException ) + { + APOCLogger.throwing( "Daemon", "onReload", theException ); + theRC = 1; + } + return theRC; + } + + public int onChangeDetect() + { + mClientManager.changeDetect(); + return 0; + } + + public void run() + throws APOCException, InterruptedException + { + APOCLogger.info( "Dmon001" ); + + startGarbageCollectionTimer(); + mChannelManager = new ChannelManager(); + mClientManager = new ClientManager( mChannelManager ); + verifyConfig(); + mChannelManager.start(); + DaemonConfig.addConfigEventListener( this ); + mAdminManager = new AdminManager( this ); + mAdminManager.start(); + mChannelManager.join(); + + mClientManager.terminate(); + mChannelManager.closeChannels(); + APOCLogger.info( "Dmon002" ); + } + + private void usage() + { + System.err.println( "Usage: apocd <daemon installation directory>" ); + } + + private void init( final String[] inArgs ) + throws IOException, APOCException + { + System.loadLibrary( "FileAccess" ); + initConfig( inArgs ); + initAuthDir(); + } + + private void initAuthDir() + throws APOCException + { + if ( ! APOCAuthenticator.sAuthDir.exists() ) + { + if ( ! APOCAuthenticator.sAuthDir.mkdirs() ) + { + throw new APOCException(); + } + } + else + { + if ( ! APOCAuthenticator.sAuthDir.isDirectory() ) + { + throw new APOCException(); + } + } + FileAccess.chmod( APOCAuthenticator.sAuthDir.getAbsolutePath(), 0755 ); + FileAccess.chmod( APOCAuthenticator.sAuthDir.getParent(), 0755 ); + } + + private void initConfig( final String[] inArgs ) + throws IOException, APOCException + { + DaemonConfig.init( inArgs ); + DaemonConfig.log(); + } + + private void startGarbageCollectionTimer() + { + final long theMinuteDelay = + DaemonConfig.getIntProperty( + DaemonConfig.sGarbageCollectionInterval ); + if ( mGarbageCollector.setPeriod( 60000 * theMinuteDelay ) ) + { + if ( mGarbageCollector.getPeriod() > 0 ) + { + APOCLogger.fine( "Dmon003", String.valueOf( theMinuteDelay ) ); + } + else + { + APOCLogger.fine( "Dmon004" ); + } + } + } + + private void verifyConfig() + throws APOCException + { + LocalDatabaseFactory.getInstance(); + } + + class GarbageCollector implements Runnable + { + public void run() + { + mClientManager.onGarbageCollect(); + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventHandler.java b/src/com/sun/apoc/daemon/apocd/EventHandler.java new file mode 100644 index 0000000..a1550a4 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventHandler.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; + +interface EventHandler +{ + public void handleEvent( final Messenger inMessenger ); +} diff --git a/src/com/sun/apoc/daemon/apocd/EventQueue.java b/src/com/sun/apoc/daemon/apocd/EventQueue.java new file mode 100644 index 0000000..b913754 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventQueue.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import java.util.*; + +class EventQueue +{ + private final List mList = new ArrayList(); + static private final long sTimeout = 100; + + public void put( final EventHandler inEventHandler ) + { + add( inEventHandler ); + synchronized( mList ) + { + mList.notify(); + } + } + + public EventHandler get() + { + EventHandler theEventHandler = remove(); + if ( theEventHandler == null ) + { + try + { + synchronized( mList ) + { + mList.wait( sTimeout ); + } + } + catch ( InterruptedException theException ) + {} + theEventHandler = remove(); + } + return theEventHandler; + } + + public void releaseWaitingThreads() + { + synchronized( mList ) + { + mList.notifyAll(); + } + } + + private void add( final EventHandler inEventHandler ) + { + synchronized( mList ) + { + mList.add( inEventHandler ); + } + } + + private EventHandler remove() + { + EventHandler theEventHandler = null; + synchronized( mList ) + { + if ( ! mList.isEmpty() ) + { + theEventHandler = ( EventHandler )mList.remove( 0 ); + } + } + return theEventHandler; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java b/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java new file mode 100644 index 0000000..bfef9f7 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java @@ -0,0 +1,122 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; +import java.util.*; + +class EventWorkerThread extends Thread +{ + private final EventQueue mQueue; + private final Messenger mMessenger = new Messenger(); + private final Object mStateLock = new Object(); + private long mTimestamp = System.currentTimeMillis(); + private int mState = sStateIdle; + + private static int sStateIdle = 0; + private static int sStateBusy = 1; + private static int sStateTerminating = 2; + private static long sIdleTimeout = + ( long )DaemonConfig. + getIntProperty( DaemonConfig.sThreadTimeToLive ) * 60000; + + public EventWorkerThread( final EventQueue inQueue ) + throws APOCException + { + setName( "EventWorker" ); + setDaemon( true ); + mQueue = inQueue; + } + + public boolean isAvailable() + { + return privgetState() == sStateIdle; + } + + public void run() + { + while ( ! ( privgetState() == sStateTerminating ) ) + { + final EventHandler theEventHandler = mQueue.get(); + if ( theEventHandler != null ) + { + setState( sStateBusy ); + theEventHandler.handleEvent( mMessenger ); + setState( sStateIdle ); + } + } + } + + public boolean terminate( boolean inIfIdle ) + { + boolean isTerminated = true; + if ( ! inIfIdle ) + { + setState( sStateTerminating ); + } + else + { + long theIdleTime = + privgetState() == sStateIdle ? + System.currentTimeMillis() - mTimestamp : 0; + if ( theIdleTime > sIdleTimeout ) + { + setState( sStateTerminating ); + } + else + { + isTerminated = false; + } + } + return isTerminated; + } + + private synchronized int privgetState() { return mState; } + + private synchronized void setState( int inState ) + { + if ( mState != sStateTerminating ) + { + mTimestamp = inState == sStateTerminating ? + 0 : System.currentTimeMillis(); + mState = inState; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java b/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java new file mode 100644 index 0000000..191015b --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java @@ -0,0 +1,191 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; +import java.util.*; + +class EventWorkerThreadPool +{ + private final EventQueue mQueue; + private final ArrayList mPool = new ArrayList(); + private int mMaxPoolSize; + private int mPoolSize = 0; + private final DaemonTimerTask mIdleDetector = + new DaemonTimerTask( new IdleDetector() ); + + private static long sIdleDetectorPeriod = + ( long )DaemonConfig. + getIntProperty( DaemonConfig.sIdleThreadDetectionInterval ) * 60000; + + public EventWorkerThreadPool( final EventQueue inQueue, + final int inPoolSize ) + throws APOCException + { + mQueue = inQueue; + mMaxPoolSize = inPoolSize; + mIdleDetector.setPeriod( sIdleDetectorPeriod ); + } + + synchronized public void ensureThread() + throws APOCException + { + if ( mPoolSize < mMaxPoolSize && ! haveIdleThread() ) + { + final EventWorkerThread theThread = new EventWorkerThread( mQueue ); + mPool.add( theThread ); + mPoolSize ++; + theThread.start(); + } + } + + synchronized public void resizePool( int inPoolSize ) + { + inPoolSize = inPoolSize > 0 ? inPoolSize : 1; + if ( inPoolSize != mMaxPoolSize ) + { + if ( inPoolSize > mMaxPoolSize ) + { + mMaxPoolSize = inPoolSize; + } + else if ( inPoolSize < mMaxPoolSize ) + { + shrinkPool( inPoolSize ); + } + } + } + + public synchronized void terminate() + { + terminateThreads(); + waitForLiveThreads(); + } + + private boolean haveIdleThread() + { + boolean haveIdleThread = false; + for ( int theIndex = 0; theIndex < mPoolSize; theIndex ++ ) + { + if ( ( ( EventWorkerThread )mPool.get( theIndex ) ).isAvailable() ) + { + haveIdleThread = true; + break; + } + } + return haveIdleThread; + } + + private boolean haveLiveThread() + { + boolean haveLiveThread = false; + for ( int theIndex = 0; theIndex < mPoolSize; theIndex ++ ) + { + if ( ( ( EventWorkerThread )mPool.get( theIndex ) ).isAlive() ) + { + haveLiveThread = true; + break; + } + } + return haveLiveThread; + } + + private void shrinkPool( int inPoolSize ) + { + for ( int theIndex = mPoolSize; theIndex > inPoolSize; theIndex -- ) + { + ( ( EventWorkerThread )( mPool.remove( 0 ) ) ).terminate( false ); + } + mPool.trimToSize(); + mMaxPoolSize = inPoolSize; + } + + private void terminateThreads() + { + terminateThreads( false ); + } + + private synchronized void terminateThreads( boolean inIdleOnly ) + { + int theTerminatedCount = 0; + for ( int theIndex = mPoolSize - 1; theIndex >= 0; theIndex -- ) + { + EventWorkerThread theThread = + ( EventWorkerThread )mPool.get( theIndex ); + if ( theThread.terminate( inIdleOnly ) ) + { + mPool.remove( theIndex ); + theTerminatedCount ++; + } + } + if ( theTerminatedCount > 0 ) + { + mQueue.releaseWaitingThreads(); + mPoolSize -= theTerminatedCount; + } + } + + private void waitForLiveThreads() + { + for ( int theIndex = 0; theIndex < 5; theIndex ++ ) + { + if ( haveLiveThread() ) + { + try + { + wait( 1000 ); + } + catch( Exception theException ){} + } + else + { + break; + } + } + } + + class IdleDetector implements Runnable + { + public void run() + { + terminateThreads( true ); + } + } +} + diff --git a/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java b/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java new file mode 100644 index 0000000..8c09ba5 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.transaction.*; + +class GarbageCollectEventHandler implements EventHandler +{ + private final GarbageCollectTransaction mTransaction; + + GarbageCollectEventHandler( final Database inDatabase ) + { + mTransaction = TransactionFactory + .getInstance() + .createGarbageCollectTransaction( inDatabase ); + } + + public void handleEvent( final Messenger inMessenger ) + { + mTransaction.execute(); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/PolicyBackend.java b/src/com/sun/apoc/daemon/apocd/PolicyBackend.java new file mode 100644 index 0000000..66e8401 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/PolicyBackend.java @@ -0,0 +1,366 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.policies.*; +import com.sun.apoc.spi.profiles.*; + +import java.io.*; +import java.net.*; +import java.util.*; +import javax.security.auth.callback.*; + +public class PolicyBackend +{ + protected static final PolicyInfo[] sPolicyInfoModel= new PolicyInfo[ 0 ]; + protected static final Policy[] sPolicyModel = new Policy[ 0 ]; + protected static final Profile[] sProfileModel = new Profile[ 0 ]; + + protected Name mName; + protected PolicyManager mPolicyMgr; + protected Entity mEntity; + protected Profile[] mProfiles; + private int mRefCount = 0; + private Object mLock = new Object(); + private boolean mProfilesInitialised = false; + + public synchronized int acquire() { return ++ mRefCount; } + public synchronized int release() { return -- mRefCount; } + + public PolicyBackend( final Name inName, + final Properties inProperties ) + throws APOCException + { + mName = inName; + try + { + mPolicyMgr = + PolicyBackendFactory + .getInstance() + .openPolicyMgr( inProperties, mName ); + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + public void close() + { + PolicyBackendFactory.getInstance().closePolicyMgr( mPolicyMgr ); + } + + public String toString() { return mName.toString() ; } + + public synchronized HashSet getComponentList() + throws APOCException + { + try + { + initProfiles(); + HashSet theComponentList = null; + if ( mProfiles != null && mProfiles.length > 0 ) + { + theComponentList = new HashSet(); + for ( int theIndex = 0; + theIndex < mProfiles.length; + theIndex ++ ) + { + Iterator theIterator = mProfiles[ theIndex ].getPolicies(); + if ( theIterator != null ) + { + while ( theIterator.hasNext() ) + { + Policy policy = (Policy) theIterator.next() ; + + theComponentList.add(policy.getId()) ; + } + } + } + } + return theComponentList; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public synchronized PolicyInfo[][] getLayeredPolicies( + final Set inComponentList, + boolean inTimeStampOnly ) + throws APOCException + { + try + { + initProfiles(); + PolicyInfo[][] thePolicies = null; + + if ( inComponentList != null && + mProfiles != null && + mProfiles.length > 0 ) + { + int theIndex; + int theComponentCount = inComponentList.size(); + if ( theComponentCount > 0 ) + { + final Hashtable theTable = + new Hashtable( theComponentCount ); + final ArrayList theComponentList = + new ArrayList( inComponentList ); + for ( theIndex = 0; + theIndex < theComponentCount; + ++ theIndex ) + { + theTable.put( theComponentList.get( theIndex ), + new ArrayList() ); + } + for ( theIndex = 0; + theIndex < mProfiles.length; + ++ theIndex ) + { + final Iterator theIterator = + inTimeStampOnly ? + mProfiles[ theIndex ].getPolicyInfos( + inComponentList.iterator() ) : + mProfiles[ theIndex ].getPolicies( + inComponentList.iterator() ); + while ( theIterator.hasNext() ) + { + final PolicyInfo thePolicy = + ( PolicyInfo )theIterator.next(); + ( ( ArrayList )theTable.get( thePolicy.getId() ) ) + .add( thePolicy ); + } + } + thePolicies = inTimeStampOnly ? + new PolicyInfo[ theComponentCount ][] : + new Policy[ theComponentCount ][]; + for ( theIndex = 0; + theIndex < theComponentCount; + ++ theIndex ) + { + ArrayList theList = + ( ArrayList )theTable.get( + theComponentList.get( theIndex ) ); + theList.trimToSize(); + if ( theList.size() > 0 ) + { + thePolicies[ theIndex ] = + inTimeStampOnly ? + ( PolicyInfo[] )theList. + toArray( sPolicyInfoModel ) : + ( Policy[] )theList.toArray( sPolicyModel ); + } + else + { + thePolicies[ theIndex ] = null; + } + } + } + } + return thePolicies; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public synchronized Policy[] getLayeredPolicies( + final String inComponentName, + boolean inTimeStampOnly ) + throws APOCException + { + try + { + Policy[] thePolicies = null; + + if ( inComponentName != null ) + { + if ( mProfiles != null && mProfiles.length > 0 ) + { + ArrayList theList = new ArrayList(); + for ( int theIndex = 0; + theIndex < mProfiles.length; + ++ theIndex ) + { + Policy thePolicy = mProfiles[ theIndex ]. + getPolicy( inComponentName ); + if ( thePolicy != null ) + { + theList.add( thePolicy ); + } + } + theList.trimToSize(); + if ( theList.size() > 0 ) + { + thePolicies = + ( Policy[] )theList.toArray( sPolicyModel ); + } + } + } + return thePolicies; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public Name getName() { return mName; } + + public synchronized void refreshProfiles() + throws SPIException + { + if ( mName.isLocal() ) + { + refreshLocalProfiles(); + } + else + { + refreshGlobalProfiles(); + } + } + + private Entity findEntity() + { + Entity theEntity = null; + + try + { + final Node theRoot = + ( Node ) mPolicyMgr.getRootEntity( mName.getEntityType() ); + final Iterator theIterator = + theRoot.findEntities( mName.getEntityName(), true ); + if ( theIterator != null && theIterator.hasNext() ) + { + theEntity = ( Entity ) theIterator.next(); + } + } + catch ( Exception theException ){} + return theEntity; + } + + private void initProfiles() + throws SPIException + { + // There are two special cases to handle here + // 1. Creation of a first ever session for a user. + // In this case, we need to write the remote component list to bdb + // and we need profiles to figure out the list + // 2. Reading a component for the first time + // If a component isn't yet in bdb, we'll need the profiles to + // get the appropriate layers + synchronized( mLock ) + { + if ( ! mProfilesInitialised ) + { + refreshProfiles(); + mProfilesInitialised = true; + } + } + } + + private void refreshGlobalProfiles() + throws SPIException + { + mProfiles = null; + if ( mEntity == null ) + { + mEntity = findEntity(); + } + if ( mEntity != null ) + { + final Iterator theIterator = mEntity.getLayeredProfiles(); + if ( theIterator != null ) + { + final ArrayList theProfiles = new ArrayList(); + while ( theIterator.hasNext() ) + { + theProfiles.add( theIterator.next() ); + } + if ( mEntity instanceof User ) + { + final Profile theProfile = + ( ( User ) mEntity ).getUserProfile(); + if ( theProfile != null ) + { + theProfiles.add( theProfile ); + } + } + if ( theProfiles.size() > 0 ) + { + mProfiles = + ( Profile[] )theProfiles.toArray( sProfileModel ); + } + } + } + } + + private void refreshLocalProfiles() + throws SPIException + { + mProfiles = null; + final ProfileProvider theProvider = + mPolicyMgr.getProfileProvider( mName.getEntityType() ); + final Iterator theIterator = theProvider.getAllProfiles(); + + if ( theIterator != null ) + { + final ArrayList theProfiles = new ArrayList(); + while ( theIterator.hasNext() ) + { + final Profile theProfile = ( Profile )theIterator.next(); + final Applicability theApp = theProfile.getApplicability(); + if ( theApp.equals( Applicability.ALL ) || + theApp.equals( mName.getEntityType() ) ) + { + theProfiles.add( theProfile ); + } + } + if ( theProfiles.size() > 0 ) + { + mProfiles = + ( Profile[] )theProfiles.toArray( sProfileModel ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java b/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java new file mode 100644 index 0000000..35dddf9 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java @@ -0,0 +1,235 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.profiles.*; + +import java.io.*; +import java.util.*; +import javax.security.auth.callback.*; + +public class PolicyBackendFactory +{ + public static int sTypeHost = 0; + public static int sTypeUser = 1; + public static final String sLocalHostName = "localHost"; + public static final String sLocalUserName = "localUsers"; + public static final Properties sLocalProperties= new Properties(); + + private HashMap mPolicyBackends = new HashMap(); + private HashMap mPolicyMgrs = new HashMap(); + private static PolicyBackendFactory sInstance; + private static final String sLocalPolicyDir = + new StringBuffer( "file://" ) + .append( DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( "/" ) + .append( "Policies/" ) + .toString(); + + static + { + sLocalProperties.setProperty( + EnvironmentConstants.URL_KEY, sLocalPolicyDir ); + String sourcesList = + (String) ((Properties) DaemonConfig.getLocalConfig()).get( + EnvironmentConstants.SOURCES_KEY) ; + + if (sourcesList != null) { + sLocalProperties.setProperty(EnvironmentConstants.SOURCES_KEY, + sourcesList); + } + try + { + new File ( + new java.net.URI( sLocalPolicyDir + "/assignments" ) ).mkdirs(); + new File ( + new java.net.URI( sLocalPolicyDir + "/profiles" ) ).mkdirs(); + new File ( + new java.net.URI( + sLocalPolicyDir + "/entities.txt" ) ).createNewFile(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "PolicyBackendFactory", "init", theException ); + } + } + + public void closePolicyBackend( final PolicyBackend inPolicyBackend ) + { + synchronized( mPolicyBackends ) + { + if ( inPolicyBackend.release() == 0 ) + { + inPolicyBackend.close(); + mPolicyBackends.remove( + createPolicyBackendKey( inPolicyBackend.getName() ) ); + } + } + } + + public void closePolicyMgr( final PolicyManager inPolicyMgr ) + { + synchronized( mPolicyMgrs ) + { + final RefCountedPolicyMgr thePolicyMgr = + ( RefCountedPolicyMgr )inPolicyMgr; + if ( thePolicyMgr.release() == 0 ) + { + try + { + thePolicyMgr.close(); + } + catch( SPIException theException ){} + mPolicyMgrs.remove( + createPolicyMgrKey( thePolicyMgr.mName ) ); + } + } + } + + public static PolicyBackendFactory getInstance() + { + if ( sInstance == null ) + { + sInstance = new PolicyBackendFactory(); + } + return sInstance; + } + + public PolicyBackend openPolicyBackend( + final Name inName, + final CallbackHandler inHandler ) + throws APOCException + { + final String theKey = createPolicyBackendKey( inName ); + PolicyBackend theBackend = null; + synchronized( mPolicyBackends ) + { + theBackend = ( PolicyBackend )mPolicyBackends.get( theKey ); + if ( theBackend == null ) + { + final Properties theProperties = inName.isLocal() ? + sLocalProperties : + ( Properties )( + ( Properties )DaemonConfig.getLocalConfig() ).clone(); + if ( inHandler != null ) + { + theProperties.put( EnvironmentConstants.LDAP_AUTH_CBH, + inHandler ); + } + theBackend = new PolicyBackend( inName, theProperties ); + mPolicyBackends.put( theKey, theBackend ); + } + if ( theBackend != null ) + { + theBackend.acquire(); + } + } + return theBackend; + } + + public static String [] getSources() + { + return EnvironmentMgr.getSources( DaemonConfig.getLocalConfig() ); + } + + public PolicyManager openPolicyMgr( final Properties inProperties, + final Name inName ) + throws APOCException + { + final String theKey = createPolicyMgrKey( inName ); + RefCountedPolicyMgr thePolicyMgr = null; + synchronized( mPolicyMgrs ) + { + try + { + thePolicyMgr = + ( RefCountedPolicyMgr )mPolicyMgrs.get( theKey ); + if ( thePolicyMgr == null ) + { + thePolicyMgr = + new RefCountedPolicyMgr( + inName, + inProperties ); + mPolicyMgrs.put( theKey, thePolicyMgr ); + } + if ( thePolicyMgr != null ) + { + thePolicyMgr.acquire(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + return thePolicyMgr; + } + + private PolicyBackendFactory() + { + } + + private String createPolicyBackendKey( final Name inName ) + { + return inName.toString(); + } + + private String createPolicyMgrKey( final Name inName ) + { + return inName.getUserName() + Name.sSep + inName.getLocation(); + } + + class RefCountedPolicyMgr extends PolicyManager + { + private int mRefCount = 0; + private Name mName; + + RefCountedPolicyMgr( final Name inName, + final Hashtable inProperties ) throws SPIException + { + super( inProperties ); + mName = inName; + } + + int acquire() { return ++ mRefCount; } + int release() { return -- mRefCount; } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java b/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java new file mode 100644 index 0000000..f594b25 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java @@ -0,0 +1,221 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import com.sun.apoc.spi.ldap.authentication.*; + +import java.io.IOException; +import java.nio.*; +import javax.security.auth.callback.*; + +class SaslAuthCallbackHandler implements CallbackHandler +{ + private Messenger mMessenger = new Messenger(); + private ClientChannel mChannel; + private ByteBuffer mBuffer; + private boolean mReconnectMode = false; + + SaslAuthCallbackHandler( final Client inClient ) + throws APOCException + { + mChannel = inClient.getClientChannel(); + mMessenger.setClientChannel( mChannel ); + } + + public void handle( Callback[] inCallbacks ) + throws IOException, UnsupportedCallbackException + { + final LdapSaslGSSAPICallback theCallback = + ( LdapSaslGSSAPICallback )inCallbacks[ 0 ]; + if ( mBuffer == null ) + { + createTokens( theCallback ); + } + theCallback.setResponse( getToken() ); + } + + public void setReconnectMode() { mReconnectMode = true; } + + private void createTokens( final LdapSaslGSSAPICallback inCallback ) + { + try + { + if ( mReconnectMode ) + { + mChannel.registerForSelection( false ); + } + mMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccessContinueSASLAuth, + null, + new StringBuffer( inCallback.getServiceName() ) + .append( "/" ) + .append( inCallback.getHostname() ) + .toString() ), + false ); + final CredentialsProviderMessage theMessage = + ( CredentialsProviderMessage )mMessenger.receiveRequest( + ! mReconnectMode ); + + if ( theMessage != null ) + { + final String theCreds = theMessage.getCredentials(); + if ( theCreds != null ) + { + mBuffer = + ByteBuffer.wrap( + base64ToByteArray( theCreds.toCharArray() ) ); + } + } + if ( mReconnectMode ) + { + mMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccess, null, null ), + true ); + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "SaslAuthCallbackHandler", + "createTokens", + theException ); + } + } + + private byte[] getToken() + { + byte[] theToken = null; + if ( mBuffer != null && mBuffer.hasRemaining() ) + { + int theTokenSize = nextTokenSize(); + if ( theTokenSize > 0 ) + { + theToken = new byte[ theTokenSize ]; + mBuffer = mBuffer.get( theToken ); + } + if ( ! mBuffer.hasRemaining() ) + { + mBuffer = null; + } + } + return theToken; + } + + private int nextTokenSize() + { + int theTokenSize = 0; + try + { + if ( mBuffer.hasRemaining() ) + { + final byte[] theTokenSizeBytes = new byte[ 5 ]; + mBuffer = mBuffer.get( theTokenSizeBytes ); + theTokenSize = + Integer.parseInt( new String( theTokenSizeBytes ) ); + } + } + catch( Exception theException ) + {} + return theTokenSize; + } + + // Code borrowed from java.util.prefs.Base64 + private static final byte base64ToInt[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + + private byte[] base64ToByteArray(char[] encoded) { + byte[] alphaToInt = base64ToInt; + int encodedLen = encoded.length; + int numGroups = encodedLen/4; + if (4*numGroups != encodedLen) + throw new IllegalArgumentException( + "String length must be a multiple of four."); + int missingBytesInLastGroup = 0; + int numFullGroups = numGroups; + if (encodedLen != 0) { + if (encoded[encodedLen-1] == '=') { + missingBytesInLastGroup++; + numFullGroups--; + } + if (encoded[encodedLen-2] == '=') + missingBytesInLastGroup++; + } + byte[] result = new byte[3*numGroups - missingBytesInLastGroup]; + + // Translate all full groups from base64 to byte array elements + int inCursor = 0, outCursor = 0; + for (int i=0; i<numFullGroups; i++) { + int ch0 = base64toInt(encoded[inCursor++], alphaToInt); + int ch1 = base64toInt(encoded[inCursor++], alphaToInt); + int ch2 = base64toInt(encoded[inCursor++], alphaToInt); + int ch3 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); + result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); + result[outCursor++] = (byte) ((ch2 << 6) | ch3); + } + + // Translate partial group, if present + if (missingBytesInLastGroup != 0) { + int ch0 = base64toInt(encoded[inCursor++], alphaToInt); + int ch1 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); + + if (missingBytesInLastGroup == 1) { + int ch2 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); + } + } + return result; + } + + private int base64toInt(char c, byte[] alphaToInt) { + int result = alphaToInt[c]; + if (result < 0) + throw new IllegalArgumentException("Illegal character " + c); + return result; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Session.java b/src/com/sun/apoc/daemon/apocd/Session.java new file mode 100644 index 0000000..44d2416 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Session.java @@ -0,0 +1,335 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.DaemonConfig; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; + +import java.io.*; +import java.nio.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; + + +public class Session +{ + private Client mClient; + private String mSessionId; + private HashMap mListeners = new HashMap(); + private Cache[] mCaches; + private Object mLock = new Object(); + private Hashtable mEntities = null ; + + private static final String sSep = "."; + private static final Random sRandom = new Random(); + private static int sAuthBufferSize = 20; + private static int sCantLock = 0; + private static int sUnlocked = 1; + private static int sLocked = 2; + private int mState = sUnlocked; + + Session() {} + + public Session( final Client inClient, + final String inUserId, + String inEntityName ) + throws APOCException + { + Hashtable theEntities = new Hashtable(); + + if (inEntityName == null) { inEntityName = inUserId ; } + theEntities.put( EnvironmentConstants.USER_SOURCE, inEntityName ); + initialise( inClient, inUserId, theEntities ); + } + public Session( final Client inClient, + final String inUserId, + final Hashtable inEntities) + throws APOCException + { + initialise( inClient, inUserId, inEntities ); + } + private void initialise( final Client inClient, + final String inUserId, + Hashtable inoutEntities) throws APOCException { + APOCLogger.finer( "Sess001" ); + try + { + authenticate( inClient, inUserId ); + mClient = inClient; + mSessionId = String.valueOf ( sRandom.nextLong() ); + if (!inoutEntities.containsKey(EnvironmentConstants.HOST_SOURCE)) { + String hostName = DaemonConfig.getHostIdentifier() ; + + if (hostName != null) { + inoutEntities.put(EnvironmentConstants.HOST_SOURCE, + hostName) ; + } + } + mEntities = inoutEntities ; + mCaches = CacheFactory + .getInstance() + .openCaches( + inUserId, + mEntities, + this, + new SaslAuthCallbackHandler( mClient ) ); + } + catch( APOCException theException ) + { + close(); + throw theException; + } + APOCLogger.finer( "Sess002", toString( inUserId ) ); + } + + public Cache[] getCaches() { return mCaches; } + public Client getClient() { return mClient; } + public String getSessionId() { return mSessionId; } + + public void addListeners( final Vector inComponentNames, + final String inClientData ) + { + synchronized( mListeners ) + { + for ( int theIndex = 0; + theIndex < inComponentNames.size(); + ++theIndex ) + { + mListeners.put( inComponentNames.elementAt( theIndex ), + inClientData ); + } + } + } + + public void removeListeners( final Vector inComponentNames ) + { + synchronized( mListeners ) + { + for ( int theIndex = 0; + theIndex < inComponentNames.size(); + ++ theIndex ) + { + mListeners.remove( inComponentNames.elementAt( theIndex ) ); + } + } + } + + public void close() + { + synchronized( mLock ) + { + if ( mState == sLocked ) + { + try + { + mLock.wait(); + } + catch( Exception e ) + {} + } + mState = sCantLock; + mLock.notify(); + } + if ( mCaches != null ) + { + CacheFactory.getInstance().closeCaches( mCaches, this ); + mCaches = null; + } + if ( mSessionId != null ) + { + APOCLogger.finer( "Sess003", mSessionId ); + } + } + + public String getListenerClientData( final String inComponentName ) + { + return ( String )mListeners.get( inComponentName ); + } + + public String getListenerComponentName( final String inComponentName ) + { + synchronized( mListeners ) + { + String theComponentName = + mListeners.containsKey( inComponentName ) ? inComponentName : + null; + if ( theComponentName == null ) + { + final StringTokenizer theTokenizer = + new StringTokenizer( inComponentName, sSep ); + final StringBuffer theBuffer = new StringBuffer(); + int theCount = theTokenizer.countTokens(); + for ( int theIndex = 0; theIndex < theCount - 1 ; theIndex ++ ) + { + final String theContainerName = + theBuffer.append( theTokenizer.nextToken() ) + .append( sSep ) + .toString(); + if ( mListeners.containsKey( theContainerName ) ) + { + theComponentName = theContainerName; + break; + } + } + } + return theComponentName; + } + } + + // + // lock() & unlock() are provided to support the case where a + // change detection transaction and a destroy session transaction are + // happening at the same time. lock() will allow a change detection to + // continue using the session until it's complete without fear of the + // session being closed. Once complete, the change detection transaction + // will unlock the session, allowing it to be destroyed. + // + public boolean lock() + { + boolean isLocked = false; + synchronized( mLock ) + { + if ( mState == sUnlocked ) + { + mState = sLocked; + isLocked = true; + } + } + return isLocked; + } + + public void unlock() + { + synchronized( mLock ) + { + mState = sUnlocked; + mLock.notify(); + } + } + + public void sendNotification(UpdateItem aUpdate) { + String component = aUpdate.getComponentName() ; + String listenerComponent = getListenerComponentName(component) ; + + if (listenerComponent == null) { return ; } + int notificationType = -1 ; + StringBuffer logMessage = new StringBuffer(" sessionId = ") + .append(mSessionId).append("\n") + .append(" component name = ") + .append(component).append("\n") + .append(" type = ") ; + + switch (aUpdate.getUpdateType()) { + case UpdateItem.ADD: + notificationType = APOCSymbols.sSymAddNotification ; + logMessage.append("Add") ; + break ; + case UpdateItem.REMOVE: + notificationType = APOCSymbols.sSymRemoveNotification ; + logMessage.append("Remove") ; + break ; + case UpdateItem.MODIFY: + notificationType = APOCSymbols.sSymModifyNotification ; + logMessage.append("Modify") ; + break ; + default: + notificationType = -1 ; + logMessage.append("Unknown") ; + break ; + } + APOCLogger.finer("Cdtn003", logMessage.toString()) ; + final Notification notification = + (Notification) MessageFactory.createNotification(mSessionId, + notificationType) ; + + notification.setComponentName(component) ; + notification.setClientData(getListenerClientData(listenerComponent)) ; + mClient.getClientChannel().write(notification.serialise()) ; + } + + private void authenticate( final Client inClient, + final String inUserId ) + throws APOCException + { + APOCAuthenticator theAuthenticator = null; + try + { + theAuthenticator = new APOCAuthenticator( inUserId ); + final Messenger theMessenger = new Messenger(); + theMessenger.setClientChannel( inClient.getClientChannel() ); + theMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccessContinueLocalAuth, + null, + new String( theAuthenticator.getChallenge() ) ), + false ); + final CredentialsProviderMessage theMessage = + ( CredentialsProviderMessage )theMessenger.receiveRequest(); + theAuthenticator.processResponse( + theMessage.getCredentials().getBytes() ); + } + finally + { + if ( theAuthenticator != null ) + { + theAuthenticator.cleanup(); + } + } + } + + private String toString( final String inUserId ) + { + StringBuffer theMessage = new StringBuffer() + .append( " userId = " ) + .append( inUserId ) + .append( "\n" ) + + .append( " sessionId = ") + .append( mSessionId ) + .append( "\n" ); + for ( int theIndex = 0 ; theIndex < mCaches.length ; ++ theIndex ) + { + theMessage.append( mCaches[ theIndex ].toString() ).append( "\n "); + } + return theMessage.toString(); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/SessionListener.java b/src/com/sun/apoc/daemon/apocd/SessionListener.java new file mode 100644 index 0000000..3648b92 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/SessionListener.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +public interface SessionListener +{ + void onSessionCreate( final Session inSession ); + + void onSessionDestroy( final Session inSession ); +} diff --git a/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java b/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java new file mode 100644 index 0000000..a51b058 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd ; + +import com.sun.apoc.daemon.localdatabase.UpdateItem ; + +import java.util.ArrayList ; +import java.util.HashMap ; +import java.util.Iterator ; +import java.util.Map ; + +public class UpdateAggregator { + // Key = session, value = updates + private Map mUpdates = new HashMap() ; + + public synchronized void addUpdate(Session [] aSessions, + UpdateItem aUpdate) { + for (int i = 0 ; i < aSessions.length ; ++ i) { + Session session = aSessions [i] ; + + if (!mUpdates.containsKey(session)) { + ArrayList updateList = new ArrayList() ; + + updateList.add(aUpdate) ; + mUpdates.put(session, updateList) ; + } + else { + ArrayList updateList = (ArrayList) mUpdates.get(session) ; + + for (int j = 0 ; j < updateList.size() ; ++ j) { + UpdateItem update = (UpdateItem) updateList.get(j) ; + + if (update.getComponentName().equals( + aUpdate.getComponentName())) { + if (update.getUpdateType() != aUpdate.getUpdateType()) { + update.setUpdateType(UpdateItem.MODIFY) ; + } + return ; + } + } + updateList.add(aUpdate) ; + } + } + } + public void sendNotifications() { + Iterator updates = mUpdates.entrySet().iterator() ; + + while (updates.hasNext()) { + Map.Entry update = (Map.Entry) updates.next(); + Session session = (Session) update.getKey() ; + ArrayList updateList = (ArrayList) update.getValue() ; + int nbUpdates = updateList.size() ; + + for (int i = 0 ; i < nbUpdates ; ++ i) { + session.sendNotification((UpdateItem) updateList.get(i)) ; + } + } + } +} + diff --git a/src/com/sun/apoc/daemon/build.xml.in b/src/com/sun/apoc/daemon/build.xml.in new file mode 100644 index 0000000..0ddc898 --- /dev/null +++ b/src/com/sun/apoc/daemon/build.xml.in @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +#************************************************************************* +#* +#* $RCSfile: build.xml,v $ +#* +#* Creation date cas 12 February, 2002 +#* last change $Author: cm122549 $ $Date: 2006/11/27 15:42:26 $ +#* $Revision: 1.4 $ +#* +#* Copyright 2003, Sun Microsystems, Inc. All Rights Reserved. +#* +#************************************************************************* +--> +<project name="ap_policy" default="main" basedir="../../../../../"> + + <property name="jarname" value="apocd.jar"/> + <property name="package" value="com/sun/apoc/daemon"/> + <property name="build.dir" value="build"/> + <property name="build.class" value="build/class"/> + <property name="build.inc" value="build/inc"/> + + <target name="info"> + <echo message="-------------------------------"/> + <echo message="| APOC Daemon |"/> + <echo message="-------------------------------"/> + </target> + + <path id="classpath"> + <pathelement location="@SPIJDK@"/> + <pathelement location="@BDBJDK@"/> + </path> + + <target name="prepare"> + <mkdir dir="${build.dir}"/> + <mkdir dir="${build.class}"/> + </target> + + <target name="compile" depends="prepare"> + <javac srcdir="src" + destdir="${build.class}" + optimize="${optimize}" + debug="${debug}" + classpathref="classpath"> + <include name="${package}/**/*.java"/> + </javac> + </target> + + <target name="jar" depends="compile"> + <condition property="dataDir" value="@APOC_DATADIR@"> + <os name="SunOS"/> + </condition> + <condition property="dataDir" value="@APOC_DATADIR@"> + <os name="Linux"/> + </condition> + <condition property="dataDir" value="\\Documents and Settings\\All Users\\Application Data\\apoc"> + <os family="Windows"/> + </condition> + + <copy file="src/${package}/properties/defaults.properties" + tofile="${build.class}/${package}/defaults.properties"/> + <copy file="src/${package}/properties/os.properties" filtering="true" + tofile="${build.class}/${package}/os.properties"> + <filterset> + <filter token="DataDir" value="${dataDir}"/> + </filterset> + </copy> + <copy file="src/${package}/properties/daemon.properties" + tofile="${build.class}/com/sun/apoc/daemon.properties"/> + + <jar jarfile="${build.class}/${jarname}" + basedir="${build.class}" + includes="${package}/** ${package}/defaults.properties ${package}/os.properties com/sun/apoc/daemon.properties"> + <manifest> + <attribute name="Class-Path" value="@SPIJDK@ @BDBJDK@"/> + </manifest> + </jar> + </target> + + <target name="main" depends="info, jar"/> + + <target name="clean" depends="info"> + <delete file="${build.class}/${jarname}"/> + <delete dir="${build.class}/${package}"/> + </target> + +</project> diff --git a/src/com/sun/apoc/daemon/config/ConfigEventListener.java b/src/com/sun/apoc/daemon/config/ConfigEventListener.java new file mode 100644 index 0000000..52e31fb --- /dev/null +++ b/src/com/sun/apoc/daemon/config/ConfigEventListener.java @@ -0,0 +1,40 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +public interface ConfigEventListener +{ + public void onConfigEvent(); +} diff --git a/src/com/sun/apoc/daemon/config/DaemonConfig.java b/src/com/sun/apoc/daemon/config/DaemonConfig.java new file mode 100644 index 0000000..639d712 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/DaemonConfig.java @@ -0,0 +1,418 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.spi.*; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; +import java.util.zip.*; + +public class DaemonConfig implements ConfigEventListener +{ + // Public bootstrap properties + public static final String sDaemonPort = "DaemonPort"; + public static final String sDataDir = "DataDir"; + + // Non bootstrap + public static final String sMaxClientThreads = + "MaxClientThreads"; + public static final String sMaxClientConnections = + "MaxClientConnections"; + public static final String sMaxRequestSize = + "MaxRequestSize"; + public static final String sConfigCDInterval = + "DaemonChangeDetectionInterval"; + public static final String sChangeDetectionInterval = + "ChangeDetectionInterval"; + public static final String sGarbageCollectionInterval = + "GarbageCollectionInterval"; + public static final String sTimeToLive = + "TimeToLive"; + public static final String sLogLevel = + "LogLevel"; + public static final String sIdleThreadDetectionInterval = + "IdleThreadDetectionInterval"; + public static final String sThreadTimeToLive = + "ThreadTimeToLive"; + public static final String sConnectionReadTimeout = + "ConnectionReadTimeout"; + public static final String sInitialChangeDetectionDelay = + "InitialChangeDetectionDelay"; + public static final String sApplyLocalPolicy = + "ApplyLocalPolicy"; + public static final String sMaxDbLocks = + "MaxDatabaseLocks"; + private static DaemonConfig sInstance; + + private static final String sAPOCJarFile = "apocd.jar"; + private static final String sDefaultsPropertiesFile = "defaults.properties"; + public static final String sOSPropertiesFile = "os.properties"; + public static final String sApocPropertiesFile = "apocd.properties"; + public static final String sJProxyPropertiesFile = "policymgr.properties"; + private static final String[] sLocalPropertiesFiles = + { sOSPropertiesFile, sApocPropertiesFile, sJProxyPropertiesFile }; + private static String sDaemonInstallDir; + private static String sDaemonPropertiesDir; + + private Properties mDefaultProperties; + private RemoteConfig mRemoteConfig; + private LocalConfig mLocalConfig; + private final HashSet mConfigEventListeners = new HashSet(); + private String mHostIdentifier; + private final DaemonTimerTask mConfigLoader = + new DaemonTimerTask( new ConfigLoader() ); + + public static void addConfigEventListener( + final ConfigEventListener inConfigListener ) + { + synchronized( sInstance.mConfigEventListeners ) + { + sInstance.mConfigEventListeners.add( inConfigListener ); + } + } + + static public String getHostIdentifier() + { + return sInstance.mHostIdentifier; + } + + public static DaemonConfig getInstance() + { + return sInstance; + } + + public static boolean getBooleanProperty( final String inPropertyName ) + { + return getBooleanProperty( inPropertyName, null ); + } + + public static boolean getBooleanProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Boolean.valueOf( + getStringProperty( inPropertyName, inDefaultValue ).trim() ). + booleanValue(); + } + + public static float getFloatProperty( final String inPropertyName ) + { + return getFloatProperty( inPropertyName, null ); + } + + public static float getFloatProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Float.parseFloat( + getStringProperty( inPropertyName, inDefaultValue ).trim() ); + } + + public static int getIntProperty( final String inPropertyName ) + { + return getIntProperty( inPropertyName, null ); + } + + public static int getIntProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Integer.parseInt( + getStringProperty( inPropertyName, inDefaultValue ).trim() ); + } + + public static LocalConfig getLocalConfig() + { + return sInstance.mLocalConfig; + } + + public static String getStringProperty( final String inPropertyName ) + { + return getStringProperty( inPropertyName, null ); + } + + public static String getStringProperty( final String inPropertyName, + final String inDefaultValue ) + { + return sInstance.mLocalConfig.getProperty( inPropertyName, + inDefaultValue ); + } + + public static void init( final String[] inArgs ) + throws IOException, APOCException + { + sInstance = new DaemonConfig( inArgs ); + reload(); + addConfigEventListener( sInstance ); + sInstance.pollForChanges(); + } + + public static void log() + { + if ( APOCLogger.isLoggable( Level.CONFIG ) && + sInstance != null && + sInstance.mLocalConfig != null ) + { + final StringBuffer theBuffer = new StringBuffer( "" ); + final Enumeration theEnumeration = + sInstance.mLocalConfig.propertyNames(); + while ( theEnumeration.hasMoreElements() ) + { + final String theName = ( String )theEnumeration.nextElement(); + theBuffer.append( " " ) + .append( theName ) + .append( " = " ) + .append( + theName.compareTo( "Password" ) == 0 ? + obscure( + DaemonConfig.getStringProperty( theName ) ): + DaemonConfig.getStringProperty( theName ) ) + .append( "\n" ); + } + APOCLogger.config( "Dcfg001", theBuffer.toString() ); + } + } + + public void onConfigEvent() + { + pollForChanges(); + } + + public static void reload() + throws IOException + { + reload( false ); + } + + public static void reload( boolean inRemoteOnly ) + throws IOException + { + final Set theOriginalValues = sInstance.getAllValues(); + if ( ! inRemoteOnly ) + { + sInstance.mLocalConfig.load( sLocalPropertiesFiles ); + sInstance.setHostIdentifier(); + } + sInstance.mRemoteConfig.load(); + if ( ! sInstance.getAllValues().equals( theOriginalValues ) ) + { + sInstance.configLoaded(); + } + } + + public static void removeConfigEventListener( + final ConfigEventListener inConfigListener) + { + synchronized( sInstance.mConfigEventListeners ) + { + sInstance.mConfigEventListeners.remove( inConfigListener ); + } + } + + private DaemonConfig( final String[] inArgs ) + throws IOException + { + sDaemonInstallDir = inArgs[ 0 ]; + sDaemonPropertiesDir = inArgs[ 1 ]; + createDefaults(); + mLocalConfig = new LocalConfig( sDaemonPropertiesDir ); + mRemoteConfig = new RemoteConfig(); + mLocalConfig.setDefaults( mRemoteConfig ); + mRemoteConfig.setDefaults( mDefaultProperties ); + } + + private void configLoaded() + { + Object[] theConfigEventListeners; + synchronized( mConfigEventListeners ) + { + theConfigEventListeners = mConfigEventListeners.toArray(); + } + if ( theConfigEventListeners != null ) + { + for ( int theIndex = 0; + theIndex < theConfigEventListeners.length; + ++ theIndex ) + { + ( ( ConfigEventListener )theConfigEventListeners[ theIndex ] ) + .onConfigEvent(); + } + } + } + + private void createDefaults() + throws IOException + { + ZipFile theZipFile = + new ZipFile( + new StringBuffer( sDaemonInstallDir ) + .append( File.separatorChar ) + .append( sAPOCJarFile ) + .toString() ); + + String thePath = new String( "com/sun/apoc/daemon/" ); + + mDefaultProperties = new Properties(); + mDefaultProperties.load( + theZipFile.getInputStream( + theZipFile.getEntry( + new StringBuffer( thePath ) + .append( sDefaultsPropertiesFile ) + .toString() ) ) ); + + mDefaultProperties.load( + theZipFile.getInputStream( + theZipFile.getEntry( + new StringBuffer( thePath ) + .append( sOSPropertiesFile ) + .toString() ) ) ); + } + + private Set getAllValues() + { + final HashSet theSet = new HashSet(); + if ( mLocalConfig != null ) + { + final Enumeration theEnumeration = mLocalConfig.propertyNames(); + while ( theEnumeration.hasMoreElements() ) + { + theSet.add( + mLocalConfig.getProperty( + ( String )theEnumeration.nextElement() ) ); + } + } + return theSet; + } + + /** + * Check if the address can be used to identify the machine from + * an external point of view. For the moment limited to checking + * that it's not the loopback address. + */ + private static boolean isAcceptableAddress(InetAddress inAddress) { + return !inAddress.isLoopbackAddress() ; + } + + private String guessHostIdentifer() + { + String theHostIdentifier = null; + try + { + Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces(); + if ( theInterfaces != null ) + { + while ( theInterfaces.hasMoreElements() ) + { + NetworkInterface theInterface = + ( NetworkInterface )theInterfaces.nextElement(); + Enumeration theInetAddresses= + theInterface.getInetAddresses(); + if ( theInetAddresses != null ) + { + while ( theInetAddresses.hasMoreElements() ) + { + InetAddress theAddress = + ( InetAddress )theInetAddresses.nextElement(); + if (isAcceptableAddress(theAddress)) + { + theHostIdentifier = theAddress.getHostAddress(); + break; + } + } + } + } + } + } + catch( Exception theException ){} + return theHostIdentifier; + } + + private static String obscure( final String inString ) + { + String theString = null; + if ( inString != null ) + { + theString = inString.replaceAll( "\\p{Alnum}", "*" ); + } + return theString; + } + + private void pollForChanges() + { + mConfigLoader.setPeriod( 60000 * getIntProperty( sConfigCDInterval ) ); + } + + private void setHostIdentifier() + { + try + { + if ( mLocalConfig.getProperty( "HostIdentifierType", "Hostname" ) + .compareTo( "IPAddress" ) == 0 ) + { + InetAddress theLocalHost = InetAddress.getLocalHost() ; + if (isAcceptableAddress(theLocalHost)) + { + mHostIdentifier = theLocalHost.getHostAddress() ; + } + else + { + mHostIdentifier = guessHostIdentifer(); + } + } + else + { + mHostIdentifier = InetAddress.getLocalHost().getHostName(); + } + } + catch( UnknownHostException theException ) + { + mHostIdentifier = null; + } + } + + class ConfigLoader implements Runnable + { + public void run() + { + try + { + sInstance.reload( true ); + } + catch( IOException theException ) + {} + } + } +} diff --git a/src/com/sun/apoc/daemon/config/LocalConfig.java b/src/com/sun/apoc/daemon/config/LocalConfig.java new file mode 100644 index 0000000..26c8e65 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/LocalConfig.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import java.io.*; +import java.util.*; + +class LocalConfig extends Properties +{ + private String mPropertiesDir; + + public LocalConfig( final String inPropertiesDir ) + { + super(); + mPropertiesDir = + new StringBuffer( inPropertiesDir ) + .append( File.separatorChar ) + .toString(); + } + + public void load ( final String[] inFileNames ) + { + clear(); + for ( int theIndex = 0; theIndex < inFileNames.length; theIndex ++ ) + { + load( inFileNames[ theIndex ] ); + } + } + + public void setDefaults( final Properties inDefaults ) + { + defaults = inDefaults; + } + + private void load( final String inFileName ) + { + try + { + load( + new FileInputStream( + new StringBuffer( mPropertiesDir ) + .append( inFileName ) + .toString() ) ); + } + catch( IOException theException ) {} + } +} diff --git a/src/com/sun/apoc/daemon/config/RemoteConfig.java b/src/com/sun/apoc/daemon/config/RemoteConfig.java new file mode 100644 index 0000000..b3935f9 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/RemoteConfig.java @@ -0,0 +1,198 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.cfgtree.*; +import com.sun.apoc.spi.cfgtree.property.*; +import com.sun.apoc.spi.cfgtree.policynode.*; +import com.sun.apoc.spi.cfgtree.readwrite.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.policies.*; +import com.sun.apoc.spi.profiles.*; + +import java.util.*; + +class RemoteConfig extends Properties +{ + private static final String sParentNodeName = "com.sun.apoc.apocd"; + + public void load() + { + clear(); + PolicyManager thePolicyMgr = null; + try + { + final Properties theProperties = + ( Properties )DaemonConfig.getLocalConfig().clone(); + theProperties.put( EnvironmentConstants.LDAP_AUTH_TYPE_KEY, + EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS ); + thePolicyMgr = new PolicyManager( theProperties ); + load( thePolicyMgr ); + } + catch ( Exception theException ) + {} + finally + { + if ( thePolicyMgr != null ) + { + try + { + thePolicyMgr.close(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "RemoteConfig", "load", theException ); + } + } + } + } + + public void setDefaults( final Properties inProperties ) + { + defaults = inProperties; + } + + private String getPropertyValue( final PolicyNode inParentNode, + final String inPropertyName ) + { + String theValue = null; + if ( inParentNode != null ) + { + final Property theProperty = + inParentNode.getProperty( inPropertyName ); + if ( theProperty != null ) + { + try + { + theValue = theProperty.getValue(); + } + catch( SPIException theException ){} + } + } + return theValue; + } + + private void load( final PolicyManager inPolicyMgr ) + throws SPIException + { + final Entity theDomain = + inPolicyMgr.getRootEntity( EnvironmentConstants.HOST_SOURCE ); + final Iterator theIterator = ((Domain) theDomain).findEntities( + DaemonConfig.getHostIdentifier(), + true ); + if ( theIterator != null && theIterator.hasNext() ) + { + final Entity theEntity = ( Entity )theIterator.next(); + final Iterator theProfiles = theEntity.getLayeredProfiles(); + if ( theProfiles != null ) + { + final ArrayList thePolicies = new ArrayList(); + while ( theProfiles.hasNext() ) + { + final Profile theProfile = ( Profile )theProfiles.next(); + final Policy thePolicy = + theProfile.getPolicy( sParentNodeName); + if ( thePolicy != null ) + { + thePolicies.add( thePolicy ); + } + } + if ( thePolicies.size() > 0 ) + { + final PolicyTree theTree = + new ReadWritePolicyTreeFactoryImpl() + .getPolicyTree( thePolicies.iterator() ); + if ( theTree != null ) + { + final PolicyNode theParentNode = + theTree.getNode( sParentNodeName ); + if ( theParentNode != null ) + { + setProp( DaemonConfig.sMaxClientThreads, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxClientThreads ) ); + setProp( DaemonConfig.sMaxClientConnections, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxClientConnections ) ); + setProp( DaemonConfig.sMaxRequestSize, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxRequestSize ) ); + setProp( DaemonConfig.sConfigCDInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sConfigCDInterval ) ); + setProp( DaemonConfig.sChangeDetectionInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sChangeDetectionInterval ) ); + setProp( DaemonConfig.sGarbageCollectionInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sGarbageCollectionInterval ) ); + setProp( DaemonConfig.sTimeToLive, + getPropertyValue( + theParentNode, + DaemonConfig.sTimeToLive ) ); + setProp( DaemonConfig.sLogLevel, + getPropertyValue( + theParentNode, + DaemonConfig.sLogLevel ) ); + setProp( DaemonConfig.sApplyLocalPolicy, + getPropertyValue( + theParentNode, + DaemonConfig.sApplyLocalPolicy ) ); + } + } + } + } + } + } + + private void setProp( final String inPropertyName, + final String inPropertyValue ) + { + if ( inPropertyValue != null ) + { + setProperty( inPropertyName, inPropertyValue ); + } + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/Database.java b/src/com/sun/apoc/daemon/localdatabase/Database.java new file mode 100644 index 0000000..6470c6c --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/Database.java @@ -0,0 +1,365 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.util.*; + +public class Database extends Db +{ + protected final Name mName; + private Dbc mDbc; + + private static final int sDbType = Db.DB_BTREE; + private static final int sDbFlags = Db.DB_CREATE; + private static final int sDbMode = 0600; + private static final String sValueEpoch = "19700101000000Z"; + + public static final String sKeyLastChangeDetect = "lastChangeDetect"; + public static final String sKeyLastModified = "lastModified/"; + public static final String sKeyLastRead = "lastRead"; + public static final String sKeyLayerIds = "layerIds/"; + public static final String sKeyDBs = "dbs"; + public static final String sKeyRemoteComponentList = + "remoteComponentList"; + public static final String sKeyLocalComponentList = + "localComponentList"; + + public Database( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + super( LocalDatabaseFactory.getInstance(), 0 ); + mName = inName; + openDatabase( LocalDatabaseFactory.getLocalDatabaseFileName(mName), + getDatabaseName(mName)); + } + + public Database(final Name inName, final String inFileName) + throws APOCException, DbException, FileNotFoundException + { + super(LocalDatabaseFactory.getInstance(), 0) ; + mName = inName ; + openDatabase(inFileName, getDatabaseName(mName)) ; + } + private void openDatabase(final String inFileName, + final String inDatabaseName) + throws APOCException, DbException, FileNotFoundException + { + open(null, inFileName, inDatabaseName, sDbType, sDbFlags, sDbMode) ; + } + + public Name getName() { return mName; } + + public static String getDatabaseName(Name aName) + { + return new StringBuffer(aName.getEntityType()).append(Name.sSep) + .append(aName.getEntityName()).append(Name.sSep) + .append(aName.getLocation()).toString() ; + } + + public static Database createDatabase(String aName) + throws APOCException, DbException, FileNotFoundException + { + String [] components = aName.split(Name.sSep) ; + + if (components != null && components.length > 2) + { + return new Database(new Name(null, + components [0], + components [1], + components [2])) ; + } + throw new APOCException() ; + } + + public String toString() { return getDatabaseName(mName) ; } + + public void beginTransaction() + throws APOCException + { + try + { + final Dbc theCursor = cursor( null, Db.DB_WRITECURSOR ); + mDbc = theCursor; + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public void endTransaction() + throws APOCException + { + if ( mDbc != null ) + { + try + { + final Dbc theCursor = mDbc; + mDbc = null; + theCursor.close(); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + } + + public int get( String inKey, final Dbt outValue ) + throws APOCException + { + return get( new StringDbt( inKey ), outValue ); + } + + public int get( final Dbt inKey, final Dbt outValue ) + throws APOCException + { + try + { + return get( null, inKey, outValue, 0 ); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public HashSet getDBList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyDBs, theSetDbt ); + return theSetDbt.getApocData(); + } + + public String getLastChangeDetect() + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( sKeyLastChangeDetect, theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLastModified( final String inLayerId, + final String inComponentName ) + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( new StringBuffer( sKeyLastModified ) + .append( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(), + theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLastRead() + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( sKeyLastRead, theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLayer( final String inComponentName, + final String inLayerId ) + throws APOCException + { + final String theKey = new StringBuffer( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(); + StringDbt theValue = new StringDbt(); + get( theKey, theValue ); + return theValue.getApocData(); + } + + public Vector getLayerIds( final String inComponentName ) + throws APOCException + { + final VectorStringDbt theVectorDbt = new VectorStringDbt(); + get( new StringBuffer( sKeyLayerIds ) + .append( inComponentName ) + .toString(), + theVectorDbt ); + return theVectorDbt.retrieveData(); + } + + public HashSet getLocalComponentList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyLocalComponentList, theSetDbt ); + return theSetDbt.getApocData(); + } + + public HashSet getRemoteComponentList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyRemoteComponentList, theSetDbt ); + return theSetDbt.getApocData(); + } + + public int put( final Dbt inKey, final String inData ) + throws APOCException + { + return put( inKey, new StringDbt( inData ) ); + } + + public int put( final String inKey, final HashSet inData ) + throws APOCException + { + return put( new StringDbt( inKey ), new SetDbt( inData ) ); + } + + public int put( final Dbt inKey, final HashSet inData ) + throws APOCException + { + return put( inKey, new SetDbt( inData ) ); + } + + public int put(final String inKey, final Vector inData) + throws APOCException + { + return put(new StringDbt(inKey), new VectorStringDbt(inData)) ; + } + + public int put( final String inKey, final String inData ) + throws APOCException + { + return put( new StringDbt( inKey ), new StringDbt( inData ) ); + } + + public int put( final String inKey, final Dbt inData ) + throws APOCException + { + return put( new StringDbt( inKey ), inData ); + } + + public int put( final Dbt inKey, final Dbt inData ) + throws APOCException + { + try + { + return mDbc.put( inKey, inData, Db.DB_KEYFIRST ); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public void putDBList( final HashSet inDBList ) + throws APOCException + { + put( sKeyDBs, inDBList ); + } + + public void putLastChangeDetect( final String inTimestamp ) + throws APOCException + { + put( sKeyLastChangeDetect, inTimestamp ); + } + + public void putLastModified( final String inLayerId, + final String inComponentName, + final String inTimestamp ) + throws APOCException + { + put( new StringBuffer( sKeyLastModified ) + .append( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(), + inTimestamp ); + } + + public void putLayerIds( final String inComponentName, + final Vector inLayerIds ) + throws APOCException + { + put ( new StringBuffer( sKeyLayerIds ) + .append( inComponentName ) + .toString(), + inLayerIds ); + } + + public void putRemoteComponentList( final HashSet inRemoteComponentList ) + throws APOCException + { + put( sKeyRemoteComponentList, inRemoteComponentList ); + } + + public void putLocalComponentList( final HashSet inComponentNames ) + throws APOCException + { + put( sKeyLocalComponentList, inComponentNames ); + } + + protected void putLastRead() + throws APOCException + { + put( sKeyLastRead, Timestamp.getTimestamp() ); + } + +} diff --git a/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java b/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java new file mode 100644 index 0000000..6154dff --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java @@ -0,0 +1,200 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.policies.*; + +import java.io.*; +import java.nio.*; +import java.util.*; + +public class LocalDatabase extends Database +{ + private HashSet mLocalComponentList; + private int mRefCount = 0; + + public LocalDatabase( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + super( inName ); + initLocalComponentList(); + } + + synchronized public int acquire() { return ++mRefCount; } + synchronized public int release() + { + if ( --mRefCount == 0 ) + { + try + { + beginTransaction(); + putLastRead(); + endTransaction(); + close( 0 ); + } + catch( DbException theException ) + {} + catch( APOCException theException ) + {} + } + return mRefCount; + } + + public boolean hasComponent( final String inComponentName ) + { + return mLocalComponentList.contains( inComponentName ); + } + + public void putLocalComponentList( final HashSet inLocalComponentList ) + throws APOCException + { + mLocalComponentList = inLocalComponentList; + super.putLocalComponentList( mLocalComponentList ); + } + + public void update( final UpdateItem inUpdateItem, final String inTimestamp) + throws APOCException + { + if ( inUpdateItem != null ) + { + updateItem( inUpdateItem, new StringDbt( inTimestamp ) ); + } + } + + public void update( final ArrayList inUpdateItems, final String inTimestamp) + throws APOCException + { + int theSize; + if ( inUpdateItems != null && ( theSize = inUpdateItems.size() ) > 0 ) + { + StringDbt theTimestamp = new StringDbt( inTimestamp ); + for ( int theIndex = 0; theIndex < theSize; ++ theIndex ) + { + updateItem( ( UpdateItem )inUpdateItems.get( theIndex ), + theTimestamp ); + } + } + } + + private void addLocalComponent( final String inComponentName ) + throws APOCException + { + mLocalComponentList.add( inComponentName ); + super.putLocalComponentList( mLocalComponentList ); + } + + private void initLocalComponentList() + throws APOCException + { + if ( ( mLocalComponentList = super.getLocalComponentList() ) == null ) + { + mLocalComponentList = new HashSet(); + } + } + + private void putComponent( final String inComponentName, + final Policy[] inPolicies ) + throws APOCException + { + if ( inPolicies != null && inPolicies.length > 0 ) + { + final Vector theLayerIds = new Vector( inPolicies.length ); + for ( int theIndex = 0; theIndex < inPolicies.length; theIndex ++ ) + { + final String theLayerId = + String.valueOf( + inPolicies[ theIndex].getProfileId().hashCode() ); + + String theKey = new StringBuffer( theLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(); + put( theKey, inPolicies[ theIndex ].getData() ); + + theLayerIds.add( theLayerId ); + + putLastModified( theLayerId, + inComponentName, + Timestamp.getTimestamp( + inPolicies[ theIndex ].getLastModified() )); + } + putLayerIds( inComponentName, theLayerIds ); + } + } + + private void removeLocalComponent( final String inComponentName ) + throws APOCException + { + mLocalComponentList.remove( inComponentName ); + super.putLocalComponentList( mLocalComponentList ); + } + + private void updateItem( final UpdateItem inUpdateItem ) + throws APOCException + { + updateItem( inUpdateItem, new StringDbt( Timestamp.getTimestamp() ) ); + } + + private void updateItem( final UpdateItem inUpdateItem, + final Dbt inTimestamp ) + throws APOCException + { + String theComponentName = inUpdateItem.getComponentName(); + Policy[] thePolicies = inUpdateItem.getPolicies(); + switch ( inUpdateItem.getUpdateType() ) + { + case UpdateItem.ADD: + putComponent( theComponentName, thePolicies ); + addLocalComponent( theComponentName ); + break; + + case UpdateItem.MODIFY: + putComponent( theComponentName, thePolicies ); + break; + + case UpdateItem.REMOVE: + removeLocalComponent( theComponentName ); + break; + + default: + break; + } + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java b/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java new file mode 100644 index 0000000..13ae22b --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java @@ -0,0 +1,460 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.util.*; + +public class LocalDatabaseFactory extends DbEnv +{ + private static LocalDatabaseFactory sInstance; + private static final HashMap sDatabases = + new HashMap( DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ) ); + private static final String sLDBHome = + new StringBuffer( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( File.separatorChar ) + .append( "LocalDB" ) + .toString(); + private static final Name sDbListDbName = + new Name(null, "DbListType", "DbList", true) ; + + + private static final int sDbEnvFlags = Db.DB_CREATE | + Db.DB_INIT_CDB | + Db.DB_INIT_MPOOL | + Db.DB_PRIVATE; + + private static final int sDbEnvMode = 0600; + private static final String s__dbPrefix = "__db."; + + private LocalDatabaseFactory() + throws APOCException, DbException + { + super( 0 ); + createDBHome(); + initLocks(); + openEnv(); + } + + public void deleteDatabase( final Database inDatabase ) + { + final Name theName = inDatabase.getName(); + synchronized ( sDatabases ) + { + if ( ! sDatabases.containsKey( createDatabaseKey( theName ) ) ) + { + try + { + final HashSet theDBs = removeDbFromDbList( theName ); + if ( theDBs == null || theDBs.size() == 0 ) + { + new File(getLocalDatabaseFilePath(theName)).delete() ; + } + } + catch( Exception theException ) + {} + } + } + } + public static LocalDatabaseFactory getInstance() + throws APOCException + { + if ( sInstance == null ) + { + try + { + sInstance = new LocalDatabaseFactory(); + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + try { + Iterator databases = + sDatabases.values().iterator() ; + + while (databases.hasNext()) { + ((Database) databases.next()).close(0) ; + } + sInstance.close(0) ; + } + catch (DbException ignored) {} + } + })) ; + + } + catch ( DbException theException ) + { + throw new APOCException( theException ); + } + } + return sInstance; + } + + public Object[] getDatabases() + { + Object[] theDatabases = null; + final String[] theDBFileNames = new File( sLDBHome ).list(); + if ( theDBFileNames != null ) + { + final ArrayList theDBList = new ArrayList( theDBFileNames.length ); + for ( int theIndex = 0; + theIndex < theDBFileNames.length; + ++ theIndex ) + { + if ( theDBFileNames[ theIndex ].startsWith( s__dbPrefix ) ) + { + continue; + } + String[] theNames = + getDatabaseNames( theDBFileNames[ theIndex ] ); + if ( theNames != null ) + { + for ( int theNamesIndex = 0; + theNamesIndex < theNames.length; + ++ theNamesIndex ) + { + synchronized( sDatabases ) + { + // No need to include LocalDatabase instances + // ( i.e. databases with client connections ) + // in return array + Database theDatabase = + ( Database )sDatabases. + get( theNames[ theNamesIndex ] ); + if ( theDatabase == null ) + { + try + { + theDatabase = + Database.createDatabase( + theNames [ theNamesIndex ] ) ; + theDBList.add( theDatabase ); + } + catch( Exception theException) + {} + } + } + } + } + } + theDatabases = theDBList.toArray(); + } + return theDatabases; + } + + public String[] getDatabaseNames( final String inDBFileName ) + { + String[] theDatabaseNames = null; + try + { + final HashSet theDBNames = getDBList( inDBFileName ); + if ( theDBNames != null && theDBNames.size() > 0 ) + { + theDatabaseNames = + ( String[] )theDBNames.toArray( new String[ 0 ] ); + } + } + catch( Exception theException ) + {} + return theDatabaseNames; + } + + public Object[] openLocalDatabases() + { + Object[] theLocalDatabases = null; + if ( ! sDatabases.isEmpty() ) + { + theLocalDatabases = sDatabases.values().toArray(); + } + return theLocalDatabases; + } + + public LocalDatabase openLocalDatabase( final Name inName ) + throws APOCException + { + final String theKey = createDatabaseKey( inName ); + LocalDatabase theLocalDatabase = null; + synchronized( sDatabases ) + { + theLocalDatabase = ( LocalDatabase )sDatabases.get( theKey ); + if ( theLocalDatabase == null ) + { + theLocalDatabase = createNewLocalDatabase( inName ); + } + if ( theLocalDatabase != null ) + { + theLocalDatabase.acquire(); + } + } + return theLocalDatabase; + } + + public void closeLocalDatabase( final LocalDatabase inLocalDatabase ) + { + synchronized( sDatabases ) + { + if ( inLocalDatabase.release() == 0 ) + { + sDatabases.remove( + createDatabaseKey( + inLocalDatabase.getName() ) ); + } + } + } + + private void addDbToDbList( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = + new Database(sDbListDbName, getLocalDatabaseFileName(inName)) ; + HashSet theDBList = theDatabase.getDBList(); + if ( theDBList == null ) + { + theDBList = new HashSet( 1 ); + } + theDBList.add( createDatabaseKey(inName) ); + theDatabase.beginTransaction(); + theDatabase.putDBList( theDBList ); + theDatabase.endTransaction(); + theDatabase.close( 0 ); + } + + private static String createDatabaseKey( final Name inName ) + { + return Database.getDatabaseName(inName); + } + + private void createDBHome() + throws APOCException + { + final File theFile = new File( sLDBHome ); + if ( ! theFile.exists() ) + { + if ( ! theFile.mkdirs() ) + { + throw new APOCException( APOCSymbols.sSymDBEnvCreateFailed ); + } + } + else + { + if ( ! theFile.isDirectory() ) + { + throw new APOCException( APOCSymbols.sSymDBEnvCreateFailed ); + } + } + FileAccess.chmod( sLDBHome, 0700 ); + FileAccess.chmod( theFile.getParent(), 0755 ); + } + + private LocalDatabase createNewLocalDatabase( final Name inName ) + throws APOCException + { + return createNewLocalDatabase( inName, true ); + } + + private LocalDatabase createNewLocalDatabase( final Name inName, + boolean inDeleteRetry ) + throws APOCException + { + ensureNonZeroLengthDBFile( inName ); + try + { + final LocalDatabase theLocalDatabase = new LocalDatabase( inName ); + addDbToDbList( inName ); + sDatabases.put( createDatabaseKey( inName ), theLocalDatabase ); + return theLocalDatabase; + } + catch ( Exception theException ) + { + if ( inDeleteRetry ) + { + new File( getLocalDatabaseFilePath(inName)).delete(); + return createNewLocalDatabase( inName, false ); + } + else + { + throw new APOCException( theException ); + } + } + } + + private void ensureNonZeroLengthDBFile( final Name inName ) + throws APOCException + { + File theFile = new File( getLocalDatabaseTmpFilePath( inName ) ); + try + { + if ( theFile.exists() ) + { + theFile.delete(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + + theFile = new File ( getLocalDatabaseFilePath( inName ) ); + try + { + if ( theFile.exists() && theFile.length() == 0 ) + { + theFile.delete(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + /* + * 6417522 - default bdb values ( 1000 )for max lockers etc. too small + * Adjusting the max. number of lockers dynamically ( based + * roughly on MaxClientConnections ) would require the ability + * to close & reopen the db environment and all database + * dynamically. That's not terribly easy ... at least for our + * current implementation. + * + * As an alternative and considering that additional locks etc. + * are really quite cheap ( in terms of memory usge ), have + * decided that a practical solution to running out of locks etc. + * is to set the max at a ( most likely ) unreachable value. + * The number of locks required per user connection seems to + * vary dependent on the platform but 12 is a reasonable + * generalisation. + * For the moment, I'm using a default value of 12000 for max. + * locks. This would allow approx. 1000 users to connect. It + * also has no significant impact on memory use. + */ + private void initLocks() + throws DbException + { + int theCount = DaemonConfig.getIntProperty( DaemonConfig.sMaxDbLocks ); + setLockMaxLockers( theCount ); + setLockMaxLocks( theCount ); + setLockMaxObjects( theCount ); + } + + private void openEnv() + throws APOCException + { + try + { + new DbEnv( 0 ).remove( sLDBHome, Db.DB_FORCE ); + open( sLDBHome, sDbEnvFlags, sDbEnvMode ); + } + catch( DbException theException ) + { + APOCLogger.throwing( "LocalDatabaseFactory", + "openEnv", + theException ); + throw new APOCException( theException ); + } + catch( FileNotFoundException theException ) + { + APOCLogger.throwing( "LocalDatabaseFactory", + "openEnv", + theException ); + throw new APOCException( theException ); + } + } + + private HashSet getDBList( final String inDBFileName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = new Database(sDbListDbName, + inDBFileName) ; + final HashSet theList = theDatabase.getDBList(); + theDatabase.close( 0 ); + return theList; + } + + public static String getLocalDatabaseFileName( final Name inName ) + { + return new StringBuffer(inName.getEntityType()) + .append(".") + .append(inName.getEntityName()).toString(); + } + + private static String getLocalDatabaseFilePath( final Name inName ) + { + return new StringBuffer( sLDBHome ) + .append( File.separatorChar ) + .append(getLocalDatabaseFileName(inName) ) + .toString(); + } + + private static String getLocalDatabaseTmpFilePath( final Name inName ) + { + return new StringBuffer( sLDBHome ) + .append( File.separatorChar ) + .append( s__dbPrefix ) + .append( getLocalDatabaseFileName( inName ) ) + .toString(); + } + + private HashSet removeDbFromDbList( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = + new Database( sDbListDbName, getLocalDatabaseFileName( inName ) ); + /* + * 6417504 - ensure Db handle is closed to avoid leak + */ + HashSet theDBList = null; + try + { + theDBList = theDatabase.getDBList(); + if ( theDBList != null ) + { + theDBList.remove( inName.toString() ); + theDatabase.beginTransaction(); + theDatabase.putDBList( theDBList ); + theDatabase.endTransaction(); + } + } + finally + { + theDatabase.close( 0 ); + } + return theDBList; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/SetDbt.java b/src/com/sun/apoc/daemon/localdatabase/SetDbt.java new file mode 100644 index 0000000..e06fe6c --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/SetDbt.java @@ -0,0 +1,96 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import java.nio.*; +import java.util.*; + +class SetDbt extends Dbt +{ + SetDbt() + { + set_flags( Db.DB_DBT_MALLOC ); + } + + SetDbt( final HashSet inValue ) + { + setApocData( inValue ); + set_flags( Db.DB_DBT_MALLOC ); + } + + void setApocData( final HashSet inValue ) + { + int theSize = 0; + Iterator theIterator = inValue.iterator(); + while ( theIterator.hasNext() ) + { + theSize += ( ( String )theIterator.next() ).length() + 1; + } + ByteBuffer theBuffer = ByteBuffer.allocate( theSize ); + theIterator = inValue.iterator(); + while ( theIterator.hasNext() ) + { + theBuffer + .put( ( ( String )theIterator.next() ).getBytes() ) + .put( ( byte )0 ); + } + theBuffer.flip(); + set_data( theBuffer.array() ); + set_size( theSize ); + } + + HashSet getApocData() + { + byte[] theByte = { 0 }; + String theString = new String( theByte ); + HashSet theData = null; + int theSize = get_size(); + if ( theSize > 0 ) + { + final StringTokenizer theTokenizer = + new StringTokenizer( + new String( get_data(), get_offset(), theSize ), + theString ); + theData = new HashSet(); + while ( theTokenizer.hasMoreTokens() ) + { + theData.add( theTokenizer.nextToken() ); + } + } + return theData; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/StringDbt.java b/src/com/sun/apoc/daemon/localdatabase/StringDbt.java new file mode 100644 index 0000000..afd46da --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/StringDbt.java @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +class StringDbt extends Dbt +{ + StringDbt() + { + set_flags( Db.DB_DBT_MALLOC ); + } + + StringDbt( final String inValue ) + { + setApocData( inValue ); + set_flags( Db.DB_DBT_MALLOC ); + } + + void setApocData( final String inValue ) + { + final byte[] theData = inValue.getBytes(); + set_data( theData ); + set_size( theData.length ); + } + + String getApocData() + { + String theData = null; + int theSize = get_size(); + + if ( theSize > 0 ) + { + theData = new String( get_data(), get_offset(), theSize ); + } + return theData; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/Timestamp.java b/src/com/sun/apoc/daemon/localdatabase/Timestamp.java new file mode 100644 index 0000000..7faff34 --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/Timestamp.java @@ -0,0 +1,108 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import java.util.*; + +public class Timestamp +{ + private static final TimeZone sUTC = TimeZone.getTimeZone( "UTC" ); + + public static final String sEpoch = "19700101000000Z"; + public static final long sEpochMillis = 0; + + public static String getTimestamp() + { + StringBuffer theBuffer = new StringBuffer( 15 ); + Calendar theCalendar = Calendar.getInstance( sUTC ); + theBuffer.append( theCalendar.get( Calendar.YEAR ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MONTH ) + 1 ); + padAppend( theBuffer, theCalendar.get( Calendar.DAY_OF_MONTH ) ); + padAppend( theBuffer, theCalendar.get( Calendar.HOUR_OF_DAY ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MINUTE ) ); + padAppend( theBuffer, theCalendar.get( Calendar.SECOND ) ); + theBuffer.append( "Z" ); + return theBuffer.toString(); + } + + public static String getTimestamp( long inMillis ) + { + StringBuffer theBuffer = new StringBuffer( 15 ); + Calendar theCalendar = Calendar.getInstance( sUTC ); + theCalendar.setTimeInMillis( inMillis ); + theBuffer.append( theCalendar.get( Calendar.YEAR ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MONTH ) + 1 ); + padAppend( theBuffer, theCalendar.get( Calendar.DAY_OF_MONTH ) ); + padAppend( theBuffer, theCalendar.get( Calendar.HOUR_OF_DAY ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MINUTE ) ); + padAppend( theBuffer, theCalendar.get( Calendar.SECOND ) ); + theBuffer.append( "Z" ); + return theBuffer.toString(); + } + + public static long getMillis( String inTimestamp ) + { + if ( inTimestamp == null || inTimestamp.compareTo( sEpoch ) == 0 ) + { + return sEpochMillis; + } + Calendar theCalendar = Calendar.getInstance( sUTC ); + theCalendar.set( + Integer.parseInt( inTimestamp.substring( 0, 4 ) ), + Integer.parseInt( inTimestamp.substring( 4, 6 ) ) - 1, + Integer.parseInt( inTimestamp.substring( 6, 8 ) ), + Integer.parseInt( inTimestamp.substring( 8, 10 ) ), + Integer.parseInt( inTimestamp.substring( 10, 12 ) ), + Integer.parseInt( inTimestamp.substring( 12, 14 ) ) ); + return theCalendar.getTimeInMillis(); + } + + public static boolean isNewer( String inTimestamp1, String inTimestamp2 ) + { + String theTimestamp1 = inTimestamp1.substring( 0, 14 ); + String theTimestamp2 = inTimestamp2.substring( 0, 14 ); + return Long.parseLong( theTimestamp1 ) > + Long.parseLong( theTimestamp2 ); + } + + private static void padAppend( StringBuffer inBuffer, int inValue ) + { + if ( inValue < 10 ) + { + inBuffer.append( 0 ); + } + inBuffer.append( inValue ); + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java b/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java new file mode 100755 index 0000000..f3045fd --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sun.apoc.spi.policies.*; + +import java.util.*; + +public class UpdateItem +{ + public static final int NOCHANGE = 0; + public static final int ADD = 1; + public static final int REMOVE = 2; + public static final int MODIFY = 3; + + private int mUpdateType; + private final String mComponentName; + private final Policy[] mPolicies; + + public UpdateItem() + { + mComponentName = null; + mPolicies = null; + } + + public UpdateItem( int inUpdateType, + final String inComponentName, + final Policy[] inPolicies ) + { + mUpdateType = inUpdateType; + mComponentName = inComponentName; + mPolicies = inPolicies; + } + + public int getUpdateType() { return mUpdateType; } + public final String getComponentName() { return mComponentName; } + public final Policy[] getPolicies() { return mPolicies; } + + public void setUpdateType( int inUpdateType ) + { + mUpdateType = inUpdateType; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java b/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java new file mode 100644 index 0000000..5ea9394 --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import java.util.*; + +class VectorStringDbt extends Dbt +{ + VectorStringDbt() + { + super() ; + set_flags(Db.DB_DBT_MALLOC) ; + } + + VectorStringDbt(final Vector inValue) + { + super() ; + fillData(inValue) ; + set_flags(Db.DB_DBT_MALLOC) ; + } + + private void fillData(final Vector inValue) + { + Iterator theIterator = inValue.iterator() ; + int theTotalLength = 0 ; + + while (theIterator.hasNext()) + { + theTotalLength += ((String) theIterator.next()).length() ; + ++ theTotalLength ; // The intermediate 0 + } + byte [] theData = new byte [theTotalLength] ; + int theCurrentIndex = 0 ; + + theIterator = inValue.iterator() ; + while (theIterator.hasNext()) + { + byte [] theSource = ((String) theIterator.next()).getBytes() ; + + for (int i = 0 ; i < theSource.length ; ++ i) + { + theData [theCurrentIndex ++] = theSource [i] ; + } + theData [theCurrentIndex ++] = 0 ; + } + set_data(theData) ; + set_size(theTotalLength) ; + } + + Vector retrieveData() + { + Vector theData = null ; + int theSize = get_size() ; + + if (theSize > 0) + { + int theStart = 0 ; + int theEnd = 0 ; + byte [] theArray = get_data() ; + + theData = new Vector() ; + do + { + while (theEnd < theSize && theArray [theEnd] != 0) + { + ++ theEnd ; + } + theData.add(new String(theArray, theStart, theEnd - theStart)) ; + ++ theEnd ; + theStart = theEnd ; + } while (theEnd < theSize) ; + } + return theData ; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java b/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java new file mode 100644 index 0000000..bfc203e --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java @@ -0,0 +1,133 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class AddListenerMessage extends Message +{ + private Vector mComponentNames; + private String mClientData; + private int[] mExpectedSymbols = { APOCSymbols.sSymParamSessionId, + APOCSymbols.sSymUnknown }; + private boolean mIsValid = false; + + public AddListenerMessage() + { + super( APOCSymbols.sSymReqAddListener ); + } + + public boolean isValid() + { + return mIsValid; + } + + public String getClientData() { return mClientData; } + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamClientData: + addClientData( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbols( APOCSymbols.sSymParamClientData, + APOCSymbols.sSymParamComponentName ); + } + + private void addClientData( final String inClientData ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamClientData ); + mClientData = inClientData; + setCheckSymbols( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbols[ 0 ] == APOCSymbols.sSymUnknown || + ( mExpectedSymbols[ 0 ] != inSymbol && + mExpectedSymbols[ 1 ] != inSymbol ) ) + { + throw new APOCException(); + } + } + + private void setCheckSymbols( final int inSymbol ) + { + setCheckSymbols( inSymbol, APOCSymbols.sSymUnknown ); + } + + private void setCheckSymbols( final int inSymbol1, final int inSymbol2 ) + { + mExpectedSymbols[ 0 ] = inSymbol1; + mExpectedSymbols[ 1 ] = inSymbol2; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java b/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java new file mode 100644 index 0000000..571c337 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.messaging ; + +import java.util.Hashtable ; + +import com.sun.apoc.daemon.apocd.Client ; + +import com.sun.apoc.daemon.misc.APOCException ; +import com.sun.apoc.daemon.misc.APOCSymbols ; + +public class CreateSessionExtMessage extends Message + implements CredentialsProviderMessage { + private String mUserId = null ; + private String mCredentials = null ; + private Hashtable mEntities = new Hashtable() ; + private int mExpectedSymbol = APOCSymbols.sSymParamUserId ; + private String mLastEntityType = null ; + private boolean mIsValid = false ; + + public CreateSessionExtMessage() { + super(APOCSymbols.sSymReqCreateSessionExt) ; + } + public boolean isValid() { return mIsValid ; } + public String getUserId() { return mUserId ; } + public String getCredentials() { return mCredentials ; } + public Hashtable getEntities() { return mEntities ; } + + protected void addParameter(final String aName, + final String aValue) throws APOCException { + switch (APOCSymbols.getProtocolSymbol(aName)) { + case APOCSymbols.sSymParamUserId: + setUserId(aValue) ; + break ; + case APOCSymbols.sSymParamCredentials: + setCredentials(aValue) ; + break ; + case APOCSymbols.sSymParamEntityType: + setEntityType(aValue) ; + break ; + case APOCSymbols.sSymParamEntityId: + setEntityId(aValue) ; + } + } + private void setUserId(final String aUserId) throws APOCException { + checkState(APOCSymbols.sSymParamUserId) ; + mUserId = aUserId ; + mExpectedSymbol = APOCSymbols.sSymParamCredentials ; + } + private void setCredentials( + final String aCredentials) throws APOCException { + checkState(APOCSymbols.sSymParamCredentials) ; + mCredentials = aCredentials ; + mExpectedSymbol = APOCSymbols.sSymParamEntityType ; + } + private void setEntityType(final String aEntityType) throws APOCException { + try { checkState(APOCSymbols.sSymParamEntityType) ; } + catch (APOCException exception) { + // Allow for skipping credentials + if (mExpectedSymbol != APOCSymbols.sSymParamCredentials) { + throw exception ; + } + } + if (mEntities.contains(aEntityType)) { throw new APOCException() ; } + mLastEntityType = aEntityType ; + mExpectedSymbol = APOCSymbols.sSymParamEntityId ; + } + private void setEntityId(final String aEntityId) throws APOCException { + checkState(APOCSymbols.sSymParamEntityId) ; + mEntities.put(mLastEntityType, aEntityId) ; + mIsValid = true ; + mExpectedSymbol = APOCSymbols.sSymParamEntityType ; + } + private void checkState(final int aSymbol) throws APOCException { + if (aSymbol != mExpectedSymbol) { throw new APOCException() ; } + } +} + diff --git a/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java b/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java new file mode 100644 index 0000000..3b85514 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java @@ -0,0 +1,134 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class CreateSessionMessage extends Message + implements CredentialsProviderMessage +{ + private String mUserId; + private String mEntityId; + private String mCredentials; + private int[] mExpectedSymbols= { APOCSymbols.sSymParamUserId, + APOCSymbols.sSymUnknown }; + private boolean mIsValid = false; + + public CreateSessionMessage() + { + super( APOCSymbols.sSymReqCreateSession ); + } + + public boolean isValid() + { + return mIsValid; + } + + public String getUserId() { return mUserId; } + public String getEntityId() { return mEntityId; } + public String getCredentials() { return mCredentials; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamUserId: + addUserId( inValue ); + break; + + case APOCSymbols.sSymParamEntityId: + addEntityId( inValue ); + break; + + case APOCSymbols.sSymParamCredentials: + addCredentials( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addUserId( final String inUserId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamUserId ); + mUserId = inUserId; + setCheckSymbols( APOCSymbols.sSymParamEntityId, + APOCSymbols.sSymParamCredentials ); + mIsValid = true; + } + + private void addEntityId( final String inEntityId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamEntityId ); + mEntityId = inEntityId; + setCheckSymbols( APOCSymbols.sSymParamCredentials ); + } + + private void addCredentials( final String inCredentials ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamCredentials ); + mCredentials = inCredentials; + setCheckSymbols( APOCSymbols.sSymUnknown ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbols[ 0 ] == APOCSymbols.sSymUnknown || + ( mExpectedSymbols[ 0 ] != inSymbol && + mExpectedSymbols[ 1 ] != inSymbol ) ) + { + throw new APOCException(); + } + } + + private void setCheckSymbols( final int inSymbol ) + { + setCheckSymbols( inSymbol, + APOCSymbols.sSymUnknown ); + } + + private void setCheckSymbols( final int inSymbol1, + final int inSymbol2 ) + { + mExpectedSymbols[ 0 ] = inSymbol1; + mExpectedSymbols[ 1 ] = inSymbol2; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java b/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java new file mode 100644 index 0000000..1815090 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java @@ -0,0 +1,41 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.messaging ; + +public interface CredentialsProviderMessage { + public String getCredentials() ; +} + diff --git a/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java b/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java new file mode 100644 index 0000000..f136497 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class DestroySessionMessage extends Message +{ + private boolean mIsValid = false; + + public DestroySessionMessage() + { + super( APOCSymbols.sSymReqDestroySession ); + } + + public boolean isValid() + { + return mIsValid; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + if ( APOCSymbols.getProtocolSymbol( inName ) != + APOCSymbols.sSymParamSessionId || + mSessionId != null ) + { + throw new APOCException(); + } + mSessionId = inValue; + mIsValid = true; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ListMessage.java b/src/com/sun/apoc/daemon/messaging/ListMessage.java new file mode 100644 index 0000000..78e65c8 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ListMessage.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class ListMessage extends Message +{ + private boolean mIsValid = false; + + public ListMessage() + { + super( APOCSymbols.sSymReqList ); + } + + public boolean isValid() + { + return mIsValid; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + if ( APOCSymbols.getProtocolSymbol( inName ) != + APOCSymbols.sSymParamSessionId || + mSessionId != null ) + { + throw new APOCException(); + } + mSessionId = inValue; + mIsValid = true; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Message.java b/src/com/sun/apoc/daemon/messaging/Message.java new file mode 100644 index 0000000..90f1a9e --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Message.java @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +import java.nio.ByteBuffer; + +public abstract class Message +{ + protected int mName; + protected String mSessionId; + + public int getName() { return mName; } + public String getSessionId() { return mSessionId; } + + protected Message( final int inName ) + { + mName = inName; + } + + protected abstract void addParameter( String inName, String inValue ) + throws APOCException; + + public abstract boolean isValid(); + + private static final byte [] sBindingHeader = + APOCSymbols.sContentLength.getBytes() ; + private static final int sBindingHeaderLen = sBindingHeader.length ; + + public ByteBuffer serialise() + { + final byte [] theContent = toString().getBytes() ; + final byte [] theContentLength = + String.valueOf(theContent.length).getBytes() ; + + return (ByteBuffer) ByteBuffer.allocate(sBindingHeaderLen + + theContentLength.length + + 2 + // "\r\n" + theContent.length) + .put(sBindingHeader) + .put(theContentLength) + .put((byte) '\r') + .put((byte) '\n') + .put(theContent) + .flip() ; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/MessageFactory.java b/src/com/sun/apoc/daemon/messaging/MessageFactory.java new file mode 100644 index 0000000..1f99e91 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/MessageFactory.java @@ -0,0 +1,113 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class MessageFactory +{ + public static Message createRequest( final String inMessageName ) + throws APOCException + { + Message theMessage; + switch ( APOCSymbols.getProtocolSymbol( inMessageName ) ) + { + case APOCSymbols.sSymReqRead: + theMessage = new ReadMessage(); + break; + + case APOCSymbols.sSymReqList: + theMessage = new ListMessage(); + break; + + case APOCSymbols.sSymReqAddListener: + theMessage = new AddListenerMessage(); + break; + + case APOCSymbols.sSymReqCreateSession: + theMessage = new CreateSessionMessage(); + break; + + case APOCSymbols.sSymReqCreateSessionExt: + theMessage = new CreateSessionExtMessage(); + break; + + case APOCSymbols.sSymReqDestroySession: + theMessage = new DestroySessionMessage(); + break; + + case APOCSymbols.sSymReqRemoveListener: + theMessage = new RemoveListenerMessage(); + break; + + default: + throw new APOCException(); + } + return theMessage; + } + + public static Message createResponse( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + Message theMessage = null; + switch ( inResponseType ) + { + case APOCSymbols.sSymRespSuccess: + case APOCSymbols.sSymRespInvalidRequest: + case APOCSymbols.sSymRespConnectionFailure: + case APOCSymbols.sSymRespAuthenticationFailure: + case APOCSymbols.sSymRespInvalidSessionId: + case APOCSymbols.sSymRespNoSuchComponent: + case APOCSymbols.sSymRespUnknownFailure: + case APOCSymbols.sSymRespSuccessContinueLocalAuth: + case APOCSymbols.sSymRespSuccessContinueSASLAuth: + theMessage = new Response( inResponseType, + inSessionId, + inResponseMessage ); + break; + + default: + break; + } + return theMessage; + } + + public static Message createNotification( final String inSessionId, + int inType ) + { + return new Notification( inSessionId, inType ); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Messenger.java b/src/com/sun/apoc/daemon/messaging/Messenger.java new file mode 100644 index 0000000..874f0bf --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Messenger.java @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; + +public class Messenger +{ + private ClientChannel mClientChannel; + private RequestReceiver mRequestReceiver = new RequestReceiver(); + + public Messenger() + throws APOCException + { + } + + public void setClientChannel( final ClientChannel inClientChannel ) + { + mClientChannel = inClientChannel; + } + + public Message receiveRequest() + throws APOCException + { + return receiveRequest( true ); + } + + public Message receiveRequest( boolean inSetBusy ) + throws APOCException + { + return mRequestReceiver.receiveRequest( mClientChannel ); + } + + public void sendResponse( final Message inResponse ) + { + sendResponse( inResponse, true ); + } + + public void sendResponse( final Message inResponse, boolean inSetIdle ) + { + try + { + if ( inSetIdle ) + { + mClientChannel.registerForSelection( true ); + } + mClientChannel.write( inResponse.serialise() ); + } + catch( Exception theException ) + { + APOCLogger.finest( "Msgr001" ); + APOCLogger.throwing( "Messenger", "sendResponse", theException ); + } + } + +} diff --git a/src/com/sun/apoc/daemon/messaging/Notification.java b/src/com/sun/apoc/daemon/messaging/Notification.java new file mode 100644 index 0000000..3518041 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Notification.java @@ -0,0 +1,119 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class Notification extends Message +{ + private String mComponentName; + private String mClientData; + + public Notification( final String inSessionId, + int inType ) + { + super( inType ); + mSessionId = inSessionId; + } + + public boolean isValid() + { + return true; + } + + public void setComponentName( final String inComponentName ) + { + mComponentName = inComponentName; + } + + public void setClientData( final String inClientData ) + { + mClientData = inClientData; + } + + public String toString() + { + StringBuffer theBuffer = + new StringBuffer() + .append( "<" ) + .append( APOCSymbols.getProtocolString( mName ) ) + .append( ">" ) + + .append( "<" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">" ) + + .append( mSessionId ) + + .append( "</" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">"); + + if ( mClientData != null ) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamClientData ) + .append( ">" ) + + .append( mClientData ) + + .append( "</" ) + .append( APOCSymbols.sParamClientData ) + .append( ">" ); + } + + theBuffer.append( "<" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + + .append( mComponentName ) + + .append( "</" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + + .append( "</" ) + .append( APOCSymbols.getProtocolString( mName ) ) + .append( ">" ); + return theBuffer.toString(); + } + + protected void addParameter( String inName, String inValue ) + throws APOCException + { + throw new APOCException(); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java b/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java new file mode 100644 index 0000000..607e1ef --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java @@ -0,0 +1,72 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.nio.charset.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; +import javax.xml.parsers.*; + +class ProtocolDeserialiser +{ + private InputStream mInputStream; + private final XMLReader mXMLReader; + private final ProtocolHandler mHandler = + new ProtocolHandler(); + private static final SAXParserFactory sSAXParserFactory = + SAXParserFactory.newInstance(); + + public ProtocolDeserialiser() + throws SAXException, ParserConfigurationException + { + mXMLReader = sSAXParserFactory.newSAXParser().getXMLReader(); + mXMLReader.setContentHandler( mHandler ); + } + + public void setInputStream( final InputStream inInputStream ) + { + mInputStream = inInputStream; + } + + public Message deserialise() + throws IOException, SAXException + { + mXMLReader.parse( new InputSource( mInputStream ) ); + return mHandler.getMessage(); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java b/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java new file mode 100644 index 0000000..20d77e2 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java @@ -0,0 +1,103 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +class ProtocolHandler extends DefaultHandler +{ + private Message mMessage; + private String mCurrentParamName; + + public Message getMessage() + { + return mMessage; + } + + public void characters( final char[] inCharArray, final int inStart, final int inLength ) + throws SAXException + { + if ( mMessage == null ) + { + throw new SAXException( new APOCException() ); + } + + try + { + mMessage.addParameter( mCurrentParamName, + new String( inCharArray, inStart, inLength ) ); + } + catch ( APOCException theException ) + { + throw new SAXException( theException ); + } + } + + public void startDocument() + { + init(); + } + + public void startElement( final String inURI, + final String inName, + final String inQName, + final Attributes inAttributes ) + throws SAXException + { + if ( mMessage == null ) + { + try + { + mMessage = MessageFactory.createRequest( inQName ); + } + catch( APOCException theException ) + { + throw new SAXException( theException ); + } + } + else + { + mCurrentParamName = inQName; + } + } + + private void init() + { + mMessage = null; + mCurrentParamName = null; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java b/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java new file mode 100644 index 0000000..36eb9f6 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java @@ -0,0 +1,206 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.nio.*; + +class ProtocolUnbinder extends InputStream implements ConfigEventListener +{ + private ClientChannel mClientChannel; + private final ByteBuffer mInputBuffer = ByteBuffer.allocate( 1024 ); + private int mContentLength; + private final StringBuffer mContentLengthBuffer = + new StringBuffer( sContentLengthValueSize ); + private long mAvailableByteCount; + + private static int sMaxRequestLengthMinimum= 4096; + private static Integer sMaxRequestLength = + new Integer( sMaxRequestLengthMinimum ); + private static final byte[] sContentLengthHeader = + APOCSymbols.sContentLength.getBytes(); + private static final int sContentLengthValueSize = 5; + + static + { + setMaxRequestLength(); + } + + public ProtocolUnbinder() + { + DaemonConfig.addConfigEventListener( this ); + } + + public void setClientChannel( final ClientChannel inClientChannel ) + { + mClientChannel = inClientChannel; + mAvailableByteCount = 0; + } + + public void onConfigEvent() + { + setMaxRequestLength(); + } + + public int read() + throws IOException + { + int theByte = -1; + if ( mContentLength-- > 0 ) + { + theByte = ( int )getByte(); + } + return theByte; + } + + public int read( final byte[] outBytes, final int inOffset, final int inByteCount ) + throws IOException + { + int theByteCount = 0; + while ( mContentLength > 0 && theByteCount < inByteCount ) + { + outBytes[ inOffset + theByteCount++ ] = getByte(); + mContentLength--; + } + return theByteCount > 0 ? theByteCount : -1; + } + + public InputStream unbind() + throws APOCException, IOException + { + mContentLength = getContentLength(); + if ( mContentLength == 0 || mContentLength > getMaxRequestLength() ) + { + throw new APOCException( APOCSymbols.sSymRespInvalidRequest ); + } + return this; + } + + private byte getByte() + throws IOException + { + if ( mAvailableByteCount == 0 ) + { + mInputBuffer.clear(); + mAvailableByteCount = mClientChannel.read( mInputBuffer ); + mInputBuffer.flip(); + } + mAvailableByteCount--; + return mInputBuffer.get(); + } + + private int getContentLength() + throws IOException + { + return hasContentHeader() ? readContentLength() : 0; + } + + private int getMaxRequestLength() + { + synchronized( sMaxRequestLength ) + { + return sMaxRequestLength.intValue(); + } + } + + private boolean hasContentHeader() + throws IOException + { + boolean hasContentHeader = true; + for ( int theIndex = 0; + theIndex < sContentLengthHeader.length; + theIndex ++ ) + { + if ( getByte() != sContentLengthHeader[ theIndex ] ) + { + hasContentHeader = false; + break; + } + } + return hasContentHeader; + } + + private int readContentLength() + throws IOException + { + + mContentLengthBuffer.delete( 0, sContentLengthValueSize ); + byte theByte = 0; + for ( int theIndex = 0 ; + theIndex < sContentLengthValueSize ; + theIndex ++ ) + { + if ( ( theByte = getByte() ) == '\r' ) + { + break; + } + else + { + mContentLengthBuffer.append( ( char )theByte ); + } + } + if ( theByte != '\r' ) + { + getByte(); // skip '\r' + } + getByte(); // skip '\n' + return Integer.parseInt( mContentLengthBuffer.toString() ); + } + + private static void setMaxRequestLength() + { + synchronized( sMaxRequestLength ) + { + int theMaxRequestLength = + DaemonConfig.getIntProperty( DaemonConfig.sMaxRequestSize ); + if ( theMaxRequestLength < sMaxRequestLengthMinimum ) + { + String theRequestSizes[] = + { + String.valueOf( theMaxRequestLength ), + String.valueOf( sMaxRequestLengthMinimum ), + String.valueOf( sMaxRequestLengthMinimum ) + }; + APOCLogger.warning( "Punb001", theRequestSizes ); + theMaxRequestLength = sMaxRequestLengthMinimum; + } + sMaxRequestLength = new Integer( theMaxRequestLength ); + } + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ReadMessage.java b/src/com/sun/apoc/daemon/messaging/ReadMessage.java new file mode 100644 index 0000000..e7399f2 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ReadMessage.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class ReadMessage extends Message +{ + private Vector mComponentNames; + private int mExpectedSymbol = APOCSymbols.sSymParamSessionId; + private boolean mIsValid = false; + + public ReadMessage() + { + super( APOCSymbols.sSymReqRead ); + } + + public boolean isValid() + { + return mIsValid; + } + + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbol( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbol != inSymbol ) + { + throw new APOCException(); + } + } + + private void setCheckSymbol( final int inSymbol ) + { + mExpectedSymbol = inSymbol; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java b/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java new file mode 100644 index 0000000..d50fd0c --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class RemoveListenerMessage extends Message +{ + private Vector mComponentNames; + private int mExpectedSymbol = APOCSymbols.sSymParamSessionId; + private boolean mIsValid = false; + + public RemoveListenerMessage() + { + super( APOCSymbols.sSymReqRemoveListener ); + } + + public boolean isValid() + { + return mIsValid; + } + + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbol( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbol != inSymbol ) + { + throw new APOCException(); + } + } + + private void setCheckSymbol( final int inSymbol ) + { + mExpectedSymbol = inSymbol; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/RequestReceiver.java b/src/com/sun/apoc/daemon/messaging/RequestReceiver.java new file mode 100644 index 0000000..0781793 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/RequestReceiver.java @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; + +class RequestReceiver +{ + private ProtocolUnbinder mUnbinder; + private ProtocolDeserialiser mDeserialiser; + + public RequestReceiver() + throws APOCException + { + try + { + mUnbinder = new ProtocolUnbinder(); + mDeserialiser = new ProtocolDeserialiser(); + } + catch ( org.xml.sax.SAXException theException ) + { + throw new APOCException( theException ); + } + catch ( javax.xml.parsers.ParserConfigurationException theException ) + { + throw new APOCException( theException ); + } + } + + public Message receiveRequest( final ClientChannel inClientChannel ) + throws APOCException + { + Message theMessage; + try + { + mUnbinder.setClientChannel( inClientChannel ); + mDeserialiser.setInputStream( mUnbinder.unbind() ); + theMessage = mDeserialiser.deserialise(); + if ( ! theMessage.isValid() ) + { + throw new APOCException( APOCSymbols.sSymRespInvalidRequest ); + } + } + catch ( org.xml.sax.SAXException theException ) + { + APOCLogger.throwing( "RequestReceiver", + "receiveRequest", + theException ); + throw new APOCException( theException ); + } + catch ( IOException theException ) + { + throw new APOCException( theException ); + } + return theMessage; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Response.java b/src/com/sun/apoc/daemon/messaging/Response.java new file mode 100644 index 0000000..3c8f2de --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Response.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class Response extends Message +{ + private String mBody; + + public Response( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + super( inResponseType ); + setBody( inResponseType, inSessionId, inResponseMessage ); + } + + public boolean isValid() + { + return true; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + throw new APOCException(); + } + + public String toString() + { + return mBody; + } + + private void setBody( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + final String theResponseType = + APOCSymbols.getProtocolString( inResponseType ); + + final StringBuffer theBuffer = new StringBuffer() + .append( "<" ) + .append( theResponseType ) + .append( ">" ) + + .append( "<" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">" ) + + .append( inSessionId ) + + .append( "</" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">"); + + if ( inResponseMessage != null ) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamMessage ) + .append( ">") + + .append( inResponseMessage ) + + .append( "</" ) + .append( APOCSymbols.sParamMessage ) + .append( ">"); + } + + theBuffer.append( "</" ) + .append( theResponseType ) + .append( ">" ); + + mBody = theBuffer.toString(); + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java b/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java new file mode 100644 index 0000000..b275830 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java @@ -0,0 +1,169 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.io.*; +import java.util.*; + +public class APOCAuthenticator +{ + public static final File sAuthDir = + new File( + new StringBuffer( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( File.separatorChar ) + .append( ".auth" ) + .toString() ); + + private File mFile; + private String mFileName; + private byte[] mResponse; + + private static final Random sRandom = new Random(); + private static int sAuthBufferSize = 20; + + public APOCAuthenticator( final String inUserId ) + throws APOCException + { + final String theUserId = + inUserId != null ? inUserId : "<Daemon administrator>"; + APOCLogger.finest( "Auth001", theUserId ); + try + { + createAuthFile( inUserId ); + createAuthToken(); + } + catch( Exception theException ) + { + cleanup(); + APOCLogger.finest( "Auth003" ); + throw new APOCException( theException ); + } + } + + public void cleanup() + { + try + { + if ( mFile != null ) + { + mFile.delete(); + mFile = null; + } + } + catch( Exception theException ) + {} + } + + public static int getAuthBufferSize() { return sAuthBufferSize; } + + public byte[] getChallenge() + { + return mFileName.getBytes(); + } + + public void processResponse( final byte[] inResponse ) + throws APOCException + { + try + { + if ( inResponse == null || inResponse.length != sAuthBufferSize ) + { + APOCLogger.finest( "Auth003" ); + throw new APOCException(); + } + for ( int theIndex = 0; theIndex < sAuthBufferSize; theIndex ++ ) + { + if ( mResponse[ theIndex ] != inResponse[ theIndex ] ) + { + APOCLogger.finest( "Auth003" ); + throw new APOCException(); + } + } + APOCLogger.finest( "Auth002" ); + } + finally + { + cleanup(); + } + } + + private void createAuthFile( final String inUserId ) + throws Exception + { + long thePrefix = sRandom.nextLong(); + thePrefix = thePrefix < 0 ? -thePrefix : thePrefix; + mFile = + File.createTempFile( String.valueOf( thePrefix ), null, sAuthDir ); + mFile.deleteOnExit(); + mFileName = mFile.getAbsolutePath(); + if ( inUserId != null ) + { + FileAccess.chown( mFileName, inUserId ); + } + FileAccess.chmod( mFileName, 0600 ); + } + + private void createAuthToken() + throws Exception + { + final FileOutputStream theOutputStream = + new FileOutputStream( mFileName ); + long theValue = sRandom.nextLong(); + theValue = theValue < 0 ? -theValue : theValue; + final StringBuffer theStringBuffer = + new StringBuffer().append( theValue ); + int theLength = theStringBuffer.length(); + if ( theLength > sAuthBufferSize ) + { + theStringBuffer.delete( sAuthBufferSize + 1, theLength ); + } + else + if ( theLength < sAuthBufferSize ) + { + int theExtraCharacters = sAuthBufferSize - theLength; + for ( int theIndex = 0; theIndex < theExtraCharacters; theIndex ++ ) + { + theStringBuffer.append( ( int )0 ); + } + } + mResponse = theStringBuffer.toString().getBytes(); + theOutputStream.write( mResponse ); + theOutputStream.close(); + } + +} diff --git a/src/com/sun/apoc/daemon/misc/APOCException.java b/src/com/sun/apoc/daemon/misc/APOCException.java new file mode 100644 index 0000000..b84033a --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCException.java @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.spi.*; + +public class APOCException extends Exception +{ + private int mCode = APOCSymbols.sSymRespUnknownFailure; + + public APOCException(){} + + public APOCException( final int inCode ) + { + this( inCode, null ); + } + + public APOCException( final Throwable inThrowable ) + { + this( APOCSymbols.sSymRespUnknownFailure, inThrowable ); + mCode = getCode( inThrowable ); + } + + public APOCException( final int inCode, final Throwable inThrowable ) + { + super( inThrowable ); + mCode = inCode; + } + + public int getCode() { return mCode; } + + private int getCode( final Throwable inThrowable ) + { + int theCode = APOCSymbols.sSymRespUnknownFailure; + if ( inThrowable != null ) + { + if ( inThrowable instanceof SPIException ) + { + theCode = getCode( ( SPIException )inThrowable ); + } + } + return theCode; + } + + private int getCode( final SPIException inException ) + { + int theCode = APOCSymbols.sSymRespUnknownFailure; + final String theStringCode = + inException.getLocalizedErrorMessageCode(); + if ( theStringCode != null ) + { + if ( theStringCode.compareTo( + SPIException.ERROR_OPEN_CONNECTION ) == 0 ) + { + theCode = APOCSymbols.sSymRespConnectionFailure; + } + else + if ( theStringCode.compareTo( + SPIException.ERROR_USER_INVALID ) == 0 ) + { + theCode = APOCSymbols.sSymRespAuthenticationFailure; + } + } + return theCode; + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCLogger.java b/src/com/sun/apoc/daemon/misc/APOCLogger.java new file mode 100644 index 0000000..cab6c00 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCLogger.java @@ -0,0 +1,227 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.io.*; +import java.util.*; +import java.util.logging.*; + +public class APOCLogger +{ + private static final String sLoggerName = "com.sun.apoc.daemon"; + private static final String sLogDir = "/Logs"; + private static final String sLogFile = "/apocd.log"; + private static final Logger sLogger = + ConfigurableLogger.getLogger( sLoggerName, sLoggerName ); + private static final int sLimit = 1000000; + private static final int sCount = 5; + + static + { + try + { + final Handler theHandler = + createHandler( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ); + final Level theLevel = + Level.parse( + DaemonConfig.getStringProperty( DaemonConfig.sLogLevel ) ); + theHandler.setLevel( theLevel ); + theHandler.setFormatter( new SimpleFormatter() ); + + sLogger.addHandler( theHandler ); + sLogger.setLevel( theLevel ); + } + catch( Exception theException ) + { + theException.printStackTrace(); + } + } + + public static void config( final String inKey ) + { + sLogger.log( Level.CONFIG, inKey ); + } + + public static void config( final String inKey, final Object inParam ) + { + sLogger.log( Level.CONFIG, inKey, inParam ); + } + + public static void fine( final String inKey ) + { + sLogger.log( Level.FINE, inKey ); + } + + public static void fine( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINE, inKey, inParam ); + } + + public static void finer( final String inKey ) + { + sLogger.log( Level.FINER, inKey ); + } + + public static void finer( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINER, inKey, inParam ); + } + + public static void finest( final String inKey ) + { + sLogger.log( Level.FINEST, inKey ); + } + + public static void finest( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINEST, inKey, inParam ); + } + + public static boolean isLoggable( final Level inLevel ) + { + return sLogger.isLoggable( inLevel ); + } + + public static void info( final String inKey ) + { + sLogger.log( Level.INFO, inKey ); + } + + public static void info( final String inKey, final Object inParam ) + { + sLogger.log( Level.INFO, inKey, inParam ); + } + + public static void severe( final String inKey ) + { + sLogger.log( Level.SEVERE, inKey ); + } + + public static void severe( final String inKey, final Object inParam ) + { + sLogger.log( Level.SEVERE, inKey, inParam ); + } + + public static void throwing( final String inClass, + final String inMethod, + final Throwable inThrowable ) + { + sLogger.throwing( inClass, inMethod, inThrowable ); + } + + public static void warning( final String inKey ) + { + sLogger.log( Level.WARNING, inKey ); + } + + public static void warning( final String inKey, final Object inParam ) + { + sLogger.log( Level.WARNING, inKey, inParam ); + } + + public static void warning( final String inKey, final Object[] inParams ) + { + sLogger.log( Level.WARNING, inKey, inParams ); + } + + private static Handler createHandler( final String inDataDir ) + { + Handler theHandler; + if ( needFileHandler() && inDataDir != null ) + { + final String theLogDir = + new StringBuffer( inDataDir ).append( sLogDir ).toString(); + createLogDir( theLogDir ); + try + { + theHandler = + new FileHandler( + new StringBuffer( theLogDir ) + .append( sLogFile ) + .toString(), + sLimit, + sCount, + true ); + } + catch( Exception theException ) + { + System.err.println("Warning:Failed to create log file handler"); + theHandler = new ConsoleHandler(); + } + } + else + { + theHandler = new ConsoleHandler(); + } + return theHandler; + } + + private static void createLogDir( final String inLogDir ) + { + final File theFile = new File( inLogDir ); + if ( ! theFile.exists() ) + { + if ( ! theFile.mkdirs() ) + { + System.err.println( "Warning: Cannot create Log directory '" + + inLogDir + "'" ); + } + } + else + { + if ( ! theFile.isDirectory() ) + { + System.err.println( "Warning: Log directory '" + + inLogDir + + "' is actually a file" ); + } + } + } + + private static boolean needFileHandler() + { + boolean needsFileHandler = false; + final String theHandler = DaemonConfig.getStringProperty( "handlers" ); + if ( theHandler == null || + theHandler.compareTo( "java.util.logging.FileHandler" ) == 0 ) + { + needsFileHandler = true; + } + return needsFileHandler; + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCSymbols.java b/src/com/sun/apoc/daemon/misc/APOCSymbols.java new file mode 100644 index 0000000..8e09528 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCSymbols.java @@ -0,0 +1,246 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import java.util.*; + +public class APOCSymbols +{ + public static final int sSymUnknown = 0; + + + // Protocol Stuff + // Binding + public static final String sContentLength = "CONTENT-LENGTH:"; + + public static final int sSymContentLength = 1; + + // Message Names - Requests + public static final String sReqAddListener = "addListener"; + public static final String sReqCreateSession = "createSession"; + public static final String sReqDestroySession = "destroySession"; + public static final String sReqList = "list"; + public static final String sReqRead = "read"; + public static final String sReqRemoveListener = "removeListener"; + public static final String sReqCreateSessionExt = "createSessionExt"; + + public static final int sSymReqAddListener = 11; + public static final int sSymReqCreateSession = 12; + public static final int sSymReqDestroySession = 13; + public static final int sSymReqList = 14; + public static final int sSymReqRead = 15; + public static final int sSymReqRemoveListener = 16; + public static final int sSymReqCreateSessionExt = 17; + + // Message Names - Responses + public static final String sRespSuccess = "success"; + public static final String sRespInvalidRequest = + "invalidRequest"; + public static final String sRespConnectionFailure = + "connectionFailure"; + public static final String sRespAuthenticationFailure = + "authenticationFailure"; + public static final String sRespInvalidSessionId = + "invalidSessionId"; + public static final String sRespNoSuchComponent = + "noSuchComponent"; + public static final String sRespUnknownFailure = + "unknownFailure"; + public static final String sRespSuccessContinueLocalAuth = + "successContinueLocalAuth"; + public static final String sRespSuccessContinueSASLAuth = + "successContinueSASLAuth"; + + public static final int sSymRespSuccess = 20; + public static final int sSymRespInvalidRequest = 21; + public static final int sSymRespConnectionFailure = 22; + public static final int sSymRespAuthenticationFailure = 23; + public static final int sSymRespInvalidSessionId = 24; + public static final int sSymRespNoSuchComponent = 25; + public static final int sSymRespUnknownFailure = 26; + public static final int sSymRespSuccessContinueLocalAuth= 27; + public static final int sSymRespSuccessContinueSASLAuth = 28; + + // Message Names - Notification + public static final String sAddNotification = "addNotification"; + public static final String sRemoveNotification = "removeNotification"; + public static final String sModifyNotification = "modifyNotification"; + + public static final int sSymAddNotification = 30; + public static final int sSymRemoveNotification = 31; + public static final int sSymModifyNotification = 32; + + // Message Parameters + public static final String sParamUserId = "userId"; + public static final String sParamEntityId = "entityId"; + public static final String sParamCredentials = "credentials"; + public static final String sParamSessionId = "sessionId"; + public static final String sParamComponentName = "componentName"; + public static final String sParamClientData = "clientData"; + public static final String sParamMessage = "message"; + public static final String sParamVersion = "version"; + public static final String sParamServer = "server"; + public static final String sParamAuthType = "authType"; + public static final String sParamLayer = "layer"; + public static final String sParamEntityType = "entityType"; + + public static final int sSymParamUserId = 40; + public static final int sSymParamEntityId = 41; + public static final int sSymParamCredentials = 42; + public static final int sSymParamSessionId = 43; + public static final int sSymParamComponentName = 44; + public static final int sSymParamClientData = 45; + public static final int sSymParamMessage = 46; + public static final int sSymParamVersion = 47; + public static final int sSymParamServer = 48; + public static final int sSymParamAuthType = 49; + public static final int sSymParamLayer = 50; + public static final int sSymParamEntityType = 51; + + // Misc + public static final String sDBCreateFailed = + "Failed to create a db handle"; + public static final String sDBEnvCreateFailed = + "Failed to create a db environment handle"; + public static final String sCreateServerChannelFailed = + "Failed to create a server channel"; + + public static final int sSymDBCreateFailed = 60; + public static final int sSymDBEnvCreateFailed = 61; + public static final int sSymCreateServerChannelFailed = 62; + + private static final Hashtable sProtocolSyms = new Hashtable(); + private static final Hashtable sProtocolStrs = new Hashtable(); + + static + { + addEntries( sContentLength, + new Integer( sSymContentLength ) ); + addEntries( sReqAddListener, + new Integer( sSymReqAddListener ) ); + addEntries( sReqCreateSession, + new Integer( sSymReqCreateSession ) ); + addEntries( sReqDestroySession, + new Integer( sSymReqDestroySession ) ); + addEntries( sReqList, + new Integer( sSymReqList ) ); + addEntries( sReqRead, + new Integer( sSymReqRead ) ); + addEntries( sReqRemoveListener, + new Integer( sSymReqRemoveListener ) ); + addEntries( sReqCreateSessionExt, + new Integer( sSymReqCreateSessionExt ) ); + addEntries( sRespSuccess, + new Integer( sSymRespSuccess ) ); + addEntries( sRespInvalidRequest, + new Integer( sSymRespInvalidRequest ) ); + addEntries( sRespConnectionFailure, + new Integer( sSymRespConnectionFailure ) ); + addEntries( sRespAuthenticationFailure, + new Integer( sSymRespAuthenticationFailure ) ); + addEntries( sRespInvalidSessionId, + new Integer( sSymRespInvalidSessionId ) ); + addEntries( sRespNoSuchComponent, + new Integer( sSymRespNoSuchComponent ) ); + addEntries( sRespUnknownFailure, + new Integer( sSymRespUnknownFailure ) ); + addEntries( sRespSuccessContinueLocalAuth, + new Integer( sSymRespSuccessContinueLocalAuth ) ); + addEntries( sRespSuccessContinueSASLAuth, + new Integer( sSymRespSuccessContinueSASLAuth ) ); + addEntries( sAddNotification, + new Integer( sSymAddNotification ) ); + addEntries( sRemoveNotification, + new Integer( sSymRemoveNotification ) ); + addEntries( sModifyNotification, + new Integer( sSymModifyNotification ) ); + addEntries( sParamUserId, + new Integer( sSymParamUserId ) ); + addEntries( sParamEntityId, + new Integer( sSymParamEntityId ) ); + addEntries( sParamCredentials, + new Integer( sSymParamCredentials ) ); + addEntries( sParamSessionId, + new Integer( sSymParamSessionId ) ); + addEntries( sParamComponentName, + new Integer( sSymParamComponentName ) ); + addEntries( sParamClientData, + new Integer( sSymParamClientData ) ); + addEntries( sParamMessage, + new Integer( sSymParamMessage ) ); + addEntries( sParamVersion, + new Integer( sSymParamVersion ) ); + addEntries( sParamServer, + new Integer( sSymParamServer ) ); + addEntries( sParamAuthType, + new Integer( sSymParamAuthType ) ); + addEntries( sParamLayer, + new Integer( sSymParamLayer ) ); + addEntries( sParamEntityType, + new Integer( sSymParamEntityType ) ); + addEntries( sDBCreateFailed, + new Integer( sSymDBCreateFailed ) ); + addEntries( sDBEnvCreateFailed, + new Integer( sSymDBEnvCreateFailed ) ); + addEntries( sCreateServerChannelFailed, + new Integer( sSymCreateServerChannelFailed ) ); + } + + private static void addEntries( final String inProtocolString, + final Integer inProtocolSymbol ) + { + sProtocolSyms.put( inProtocolString, inProtocolSymbol ); + sProtocolStrs.put( inProtocolSymbol, inProtocolString ); + } + + public static int getProtocolSymbol( final String inString ) + { + int theSym = sSymUnknown; + if ( inString != null ) + { + final Integer theValue = ( Integer )sProtocolSyms.get( inString ); + if ( theValue != null ) + { + theSym = theValue.intValue(); + } + } + return theSym; + } + + public static String getProtocolString( final int inSymbol ) + { + return ( String )sProtocolStrs.get( new Integer( inSymbol ) ); + } +} diff --git a/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java b/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java new file mode 100644 index 0000000..8753741 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java @@ -0,0 +1,72 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.util.logging.*; + +public class ConfigurableLogger extends Logger + implements ConfigEventListener +{ + protected ConfigurableLogger( String inLoggerName, + String inResourceBundleName ) + { + super( inLoggerName, inResourceBundleName ); + DaemonConfig.addConfigEventListener( this ); + } + + public static Logger getLogger( String inLoggerName, + String inResourceBundleName ) + { + return new ConfigurableLogger( inLoggerName, inResourceBundleName); + } + + public void onConfigEvent() + { + final Level theLevel = + Level.parse( + DaemonConfig.getStringProperty( DaemonConfig.sLogLevel ) ); + setLevel( theLevel ); + final Handler[] theHandlers = getHandlers(); + if ( theHandlers != null ) + { + for ( int theIndex = 0; theIndex < theHandlers.length; ++ theIndex ) + { + theHandlers[ theIndex ].setLevel( theLevel ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java b/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java new file mode 100644 index 0000000..312bfa5 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java @@ -0,0 +1,110 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import java.util.*; + +public class DaemonTimerTask +{ + private Runnable mRunnable; + private long mPeriod = 0; + private TimerTask mTimerTask = null; + private boolean mIsOneTime = false; + private static final Timer sTimer = new Timer( true ); + + public DaemonTimerTask( final Runnable inRunnable ) + { + mRunnable = inRunnable; + } + + public DaemonTimerTask( final Runnable inRunnable, boolean inIsOneTime ) + { + this( inRunnable ); + mIsOneTime = inIsOneTime; + } + + public void cancel() + { + setPeriod( -1 ); + } + + public long getPeriod() + { + return mPeriod; + } + + public boolean setPeriod( long inPeriod ) + { + boolean isChanged = false; + if ( inPeriod != mPeriod ) + { + mPeriod = inPeriod; + schedule(); + isChanged = true; + } + return isChanged; + } + + private void schedule() + { + if ( mPeriod > 0 ) + { + if ( mTimerTask != null ) + { + mTimerTask.cancel(); + } + mTimerTask = new Task(); + sTimer.schedule( mTimerTask, mPeriod, mPeriod ); + } + else + if ( mTimerTask != null ) + { + mTimerTask.cancel(); + mTimerTask = null; + } + } + + class Task extends TimerTask + { + public void run() + { + mRunnable.run(); + if ( mIsOneTime ) + { + cancel(); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/misc/FileAccess.java b/src/com/sun/apoc/daemon/misc/FileAccess.java new file mode 100644 index 0000000..f3b3b02 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/FileAccess.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +public class FileAccess +{ + public static native int chmod( final String inFileName, int inMode ); + public static native int chown( final String inFileName, + final String inUserName ); +} diff --git a/src/com/sun/apoc/daemon/misc/Name.java b/src/com/sun/apoc/daemon/misc/Name.java new file mode 100644 index 0000000..cc5f9be --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/Name.java @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +public class Name +{ + // Location + private static int sLocationLocal = 0; + private static int sLocationGlobal = 1; + + // Applicability + private static int sApplicabilityHost = 2; + private static int sApplicabilityUser = 3; + + // Entities + private static int sEntityLocalHost = 4; + private static int sEntityLocalUser = 5; + + private static int sUndefined = 6; + + private static final String sLocationLocalStr = "local"; + private static final String sLocationGlobalStr = "global"; + private static final String sApplicabilityHostStr = "host"; + private static final String sApplicabilityUserStr = "user"; + public static final String sEntityLocalHostStr = "localHost"; + public static final String sEntityLocalUserStr = "localUser"; + + public static final String sSep = "/"; + + public static final String sNames[] = + { + sLocationLocalStr, + sLocationGlobalStr, + sApplicabilityHostStr, + sApplicabilityUserStr, + sEntityLocalHostStr, + sEntityLocalUserStr + }; + + private String mUserName; + private String mEntityType; + private String mEntityName; + private boolean mIsLocal; + + public Name( final String inUserName, + final String inEntityType, + final String inEntityName, + boolean inIsLocal ) + { + mUserName = inUserName; + mEntityType = inEntityType; + mEntityName = inEntityName; + mIsLocal = inIsLocal; + } + public Name( final String inUserName, + final String inEntityType, + final String inEntityName, + final String inIsLocal ) + { + mUserName = inUserName ; + mEntityType = inEntityType ; + mEntityName = inEntityName ; + mIsLocal = inIsLocal.compareTo(sLocationLocalStr) == 0 ; + } + + public String getUserName() { return mUserName; } + + public String getEntityType() { return mEntityType; } + + public String getEntityName() { return mEntityName; } + + public String getLocation() + { + return sNames[ getLocationAsInt() ]; + } + + public int getLocationAsInt() + { + return mIsLocal ? sLocationLocal : sLocationGlobal; + } + + public boolean isLocal() { return mIsLocal; } + public boolean isGlobal() { return ! isLocal(); } + + public String toString() + { + return new StringBuffer(mUserName) + .append(sSep) + .append(mEntityType) + .append(sSep) + .append(mEntityName) + .append(sSep) + .append(getLocation()) + .toString() ; + } +} diff --git a/src/com/sun/apoc/daemon/properties/apocd.properties b/src/com/sun/apoc/daemon/properties/apocd.properties new file mode 100644 index 0000000..bdb350f --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/apocd.properties @@ -0,0 +1,66 @@ +# +# The port used by the APOC daemon for client requests +# +#DaemonPort=3809 + +# +# The maximum number of client threads dictates the number of client requests +# which may be executed simultaneously. +# +#MaxClientThreads=5 + +# +# The maximum number of client connections allowed +# +#MaxClientConnections=50 + +# +# The maximum size of requests issued by clients +# +#MaxRequestSize=4096 + +# +# The interval ( in minutes ) between change detections for daemon config. +# data +# +#DaemonChangeDetectionInterval=10 + +# +# The interval ( in minutes ) between change detection for the local database +# +#ChangeDetectionInterval=60 + +# +# The delay ( in seconds ) between a user session creation and an initial +# change detection for that user ( if one is due ) +# +#InitialChangeDetectionDelay=10 + +# +# The local database garbage collection interval ( in minutes ) +# +#GarbageCollectionInterval=10080 + +# +# The length of time ( in minutes ) since last read, which non offline +# components will remain in the local database +# +#TimeToLive=10080 + +# +# Daemon Log level +# +#LogLevel=INFO + +# +# Whether or not local policy should be applied ( if available ) +#ApplyLocalPolicy=true + +# +# The number of seconds after which an uncompleted transaction will be +# cancelled. A minimum value of 1 second is imposed. +#TransactionTimeout=15 + +# +# The maximum number of Berkeley DB locks available +#MaxDatabaseLocks=12000 diff --git a/src/com/sun/apoc/daemon/properties/daemon.properties b/src/com/sun/apoc/daemon/properties/daemon.properties new file mode 100644 index 0000000..2d54129 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/daemon.properties @@ -0,0 +1,82 @@ +#com.sun.apoc.daemon.admin.AdminManager +Admr001=Admin manager started +Admr002=Admin manager stopped + +#com.sun.apoc.daemon.apocd.ClientManager +Clmr001=Client manager started +Clmr002=Client removed +Clmr003=Failed to resize thread pool +Clmr004=Change detection scheduled ( interval = {0} minutes ) +Clmr005=New client added +Clmr006=Change detection switched off +Clmr007=Client manager stopped + +#com.sun.apoc.daemon.apocd.Daemon +Dmon001=Daemon starting +Dmon002=Daemon finishing +Dmon003=Garbage collection scheduled ( interval = {0} minutes ) +Dmon004=Garbage collection switched off + +#com.sun.apoc.daemon.apocd.Session +Sess001=Creating new client session +Sess002=New client session created:\n{0}\n +Sess003=Client session ( sessionId = {0} ) closed + +#com.sun.apoc.daemon.config.DaemonConfig +Dcfg001=Daemon configuration:\n{0}\n + +#com.sun.apoc.daemon.messaging.Messenger +Msgr001=Failed to send response + +#com.sun.apoc.daemon.messaging.ProtocolUnbinder +Punb001=Configured value of MaxRequestSize, {0}, is less than the minimum allowed value ( {1} ). Adjusting MaxRequestsize to {1}. + +#com.sun.apoc.daemon.misc.APOCAuthenticator +Auth001=Authenticating user {0} +Auth002=Authentication successful +Auth003=Authentication failed + +#com.sun.apoc.daemon.transaction.AddListenerTransaction +Altn001=AddListener transaction started +Altn002=AddListener transaction completed + +#com.sun.apoc.daemon.transaction.ChangeDetectTransaction +Cdtn001=ChangeDetect transaction started +Cdtn002=ChangeDetect transaction completed +Cdtn003=Notification sent:\n{0}\n + +#com.sun.apoc.daemon.transaction.CreateSessionTransaction +Cstn001=CreateSession transaction started +Cstn002=CreateSession transaction completed + +#com.sun.apoc.daemon.transaction.DestroySessionTransaction +Dstn001=DestroySession transaction started +Dstn002=DestroySession transaction completed + +#com.sun.apoc.daemon.transaction.GarbageCollectTransaction +Gctn001=GarbageCollect transaction started +Gctn002=GarbageCollect transaction completed + +#com.sun.apoc.daemon.transaction.ListTransaction +Lstn001=List transaction started +Lstn002=List transaction completed + +#com.sun.apoc.daemon.transaction.ReadTransaction +Rdtn001=Read transaction started +Rdtn002=Read transaction completed + +#com.sun.apoc.daemon.transaction.RemoveListenerTransaction +Rltn001=RemoveListener transaction started +Rltn002=RemoveListener transaction completed + +#com.sun.apoc.daemon.transport.ChannelManager +Chmr001=Channel manager started +Chmr002=The maximum number of client connections ( {0} ) has been reached. No new client connections can be established at this time. +Chmr003=Channel manager stopped + +#com.sun.apoc.daemon.transport.ClientChannel +Clch001=Error while changing channel state ... closing channel +Clch002=Unexpected EOF while reading client channel + +#com.sun.apoc.daemon.transport.ServerChannel +Svch001=Error while accepting new client channel diff --git a/src/com/sun/apoc/daemon/properties/defaults.properties b/src/com/sun/apoc/daemon/properties/defaults.properties new file mode 100644 index 0000000..ae78be6 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/defaults.properties @@ -0,0 +1,83 @@ +# +# The port used by the APOC daemon for client requests +# +DaemonPort=3809 + +# +# The maximum number of client threads dictates the number of client requests +# which may be executed simultaneously. +# +MaxClientThreads=5 + +# +# The maximum number of client connections allowed +# +MaxClientConnections=50 + +# +# The maximum size of requests issued by clients +# +MaxRequestSize=4096 + +# +# The interval ( in minutes ) between change detections for daemon config. +# data +# +DaemonChangeDetectionInterval=10 + +# +# The interval ( in minutes ) between change detection for the local database +# +ChangeDetectionInterval=60 + +# +# The delay ( in seconds ) between a user session creation and an initial +# change detection for that user ( if one is due ) +# +InitialChangeDetectionDelay=10 + +# +# The local database garbage collection interval ( in minutes ) +# +GarbageCollectionInterval=10080 + +# +# The length of time ( in minutes ) since last read, which non offline +# components will remain in the local database +# +TimeToLive=10080 + +# +# The interval ( in minutes ) between detection and removal of idle threads +# +IdleThreadDetectionInterval=15 + +# +# The length of time ( in minutes ) a thread may remain idle before being +# removed +# +ThreadTimeToLive=5 + +# +# The length of time ( in milliseconds ) to wait before timing out a read on +# client connections +# +ConnectionReadTimeout=5000 + +# +# Daemon Log level +# +LogLevel=INFO + +# +# Whether or not local policy should be applied ( if available ) +ApplyLocalPolicy=true + +# +# The number of seconds after which an uncompleted transaction will be +# cancelled. A minimum value of 1 second is imposed. +TransactionTimeout=15 + +# +# The maximum number of Berkeley DB locks available +MaxDatabaseLocks=12000 diff --git a/src/com/sun/apoc/daemon/properties/os.properties.in b/src/com/sun/apoc/daemon/properties/os.properties.in new file mode 100644 index 0000000..b7e1485 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/os.properties.in @@ -0,0 +1,4 @@ +# +# The daemon data directory ... where databases, logs etc. are kept +# +DataDir=@APOC_DATADIR@ diff --git a/src/com/sun/apoc/daemon/properties/policymgr.properties b/src/com/sun/apoc/daemon/properties/policymgr.properties new file mode 100644 index 0000000..baeee3b --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/policymgr.properties @@ -0,0 +1,9 @@ +#-----------------------------# +# Basic Configuration Example # +#-----------------------------# + +#PROVIDER_URL = ldap://server1.freedesktop.org:389/o=mySuffixDn +#AuthType=Anonymous +#AuthDn= +#Password= +#ConnectTimeout=1 diff --git a/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java b/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java new file mode 100644 index 0000000..e4a2522 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class AddListenerTransaction extends Transaction +{ + public AddListenerTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Altn001" ); + mSession.addListeners( + ( ( AddListenerMessage )mRequest ).getComponentNames(), + ( ( AddListenerMessage )mRequest ).getClientData() ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Altn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java b/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java new file mode 100644 index 0000000..0c545bf --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; +import java.nio.*; + +public class ChangeDetectTransaction extends Transaction +{ + private ClientManager mClientManager; + private Cache mCache; + private UpdateAggregator mAggregator ; + private static final String[] sStringModel = new String[ 0 ]; + + public ChangeDetectTransaction( final ClientManager inClientManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + super( null, null); + mClientManager = inClientManager; + mCache = inCache; + mAggregator = inAggregator ; + } + + protected void executeTransaction() + { + Session theSession = null; + try + { + APOCLogger.finer( "Cdtn001" ); + // + // getLockedSession will try to lock 1 of the Session instances + // associated with database to be refreshed. If successful, + // the returned Session instance should be safe to use ( i.e. it + // wont be closed by someone else ) for the duration of the + // transaction. If unsuccessful, all relevant Session objects + // are already closed or closing so we can skip the change + // detection + // + theSession = getLockedSession(); + if ( theSession != null ) + { + final ArrayList theResults = mCache.changeDetect(); + Session [] theSessions = mCache.getSessions(); + int nbResults = theResults.size() ; + + if ( nbResults > 0 ) + { + for (int theIndex = 0 ; theIndex < nbResults ; ++ theIndex) + { + mAggregator.addUpdate( + theSessions, + (UpdateItem) theResults.get(theIndex)) ; + } + } + } + APOCLogger.finer( "Cdtn002" ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "ChangeDetectTransaction", + "execute", + theException ); + } + if ( theSession != null ) + { + theSession.unlock(); + } + } + + protected boolean needSession() { return false; } + + private Session getLockedSession() + { + Session theSession = null; + Session[] theSessions = mCache.getSessions(); + if ( theSessions != null ) + { + for ( int theIndex = 0; theIndex < theSessions.length; ++ theIndex ) + { + if ( theSessions[ theIndex ].lock() ) + { + theSession = theSessions[ theIndex ]; + break; + } + } + } + return theSession; + } + +} diff --git a/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java b/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java new file mode 100644 index 0000000..312bf52 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.transaction ; + +import com.sun.apoc.daemon.apocd.Client ; +import com.sun.apoc.daemon.apocd.Session ; +import com.sun.apoc.daemon.messaging.CreateSessionExtMessage ; +import com.sun.apoc.daemon.messaging.Message ; +import com.sun.apoc.daemon.misc.APOCException ; +import com.sun.apoc.daemon.misc.APOCLogger ; +import com.sun.apoc.daemon.misc.APOCSymbols ; + +class CreateSessionExtTransaction extends Transaction { + public CreateSessionExtTransaction(final Client aClient, + final Message aMessage) { + super(aClient, aMessage) ; + } + protected boolean needSession() { return false ; } + protected void executeTransaction() { + try { + APOCLogger.finer("Cstn001") ; + CreateSessionExtMessage message = + (CreateSessionExtMessage) mRequest ; + + mSession = new Session(mClient, message.getUserId(), + message.getEntities()) ; + mClient.addSession(mSession) ; + setResponse(APOCSymbols.sSymRespSuccess, mSession.getSessionId()) ; + APOCLogger.finer("Cstn002") ; + } + catch (APOCException exception) { + setResponse(exception.getCode()) ; + APOCLogger.throwing("CreateSessionExtTransaction", + "executeTransaction", exception) ; + } + catch (Exception exception) { + setResponse(APOCSymbols.sSymRespUnknownFailure) ; + APOCLogger.throwing("CreateSessionExtTransaction", + "executeTransaction", exception) ; + } + } +} + diff --git a/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java b/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java new file mode 100644 index 0000000..e759397 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class CreateSessionTransaction extends Transaction +{ + public CreateSessionTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected boolean needSession() { return false; } + + protected void executeTransaction() + { + try + { + APOCLogger.finer( "Cstn001" ); + final CreateSessionMessage theMessage = + ( CreateSessionMessage )mRequest; + mSession = new Session( mClient, + theMessage.getUserId(), + theMessage.getEntityId() ); + mClient.addSession( mSession ); + setResponse( APOCSymbols.sSymRespSuccess, + mSession.getSessionId() ); + APOCLogger.finer( "Cstn002" ); + } + catch ( APOCException theException ) + { + setResponse( theException.getCode() ); + APOCLogger.throwing( "CreateSessionTransaction", + "executeTransaction", + theException ); + } + catch ( Exception theException ) + { + setResponse( APOCSymbols.sSymRespUnknownFailure ); + APOCLogger.throwing( "CreateSessionTransaction", + "executeTransaction", + theException ); + } + } +} diff --git a/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java b/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java new file mode 100644 index 0000000..4167cea --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class DestroySessionTransaction extends Transaction +{ + public DestroySessionTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Dstn001" ); + mClient.closeSession( mSession ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Dstn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java b/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java new file mode 100644 index 0000000..4cf92a9 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; + +public class GarbageCollectTransaction extends Transaction +{ + private final Database mDatabase; + + public GarbageCollectTransaction( final Database inDatabase ) + { + super( null, null ); + mDatabase = inDatabase; + } + + protected void executeTransaction() + { + try + { + APOCLogger.finer( "Gctn001" ); + mDatabase.beginTransaction(); + boolean shouldCollect = + Timestamp.getMillis( mDatabase.getLastRead() ) <= + ( Timestamp.getMillis( Timestamp.getTimestamp() ) - + ( DaemonConfig.getIntProperty( DaemonConfig.sTimeToLive ) * + 60000 ) ); + mDatabase.endTransaction(); + mDatabase.close( 0 ); + if ( shouldCollect ) + { + LocalDatabaseFactory.getInstance().deleteDatabase( mDatabase ); + } + APOCLogger.finer( "Gctn002" ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "GarbageCollectTransaction", + "execute", + theException ); + } + } + + protected boolean needSession() { return false; } +} diff --git a/src/com/sun/apoc/daemon/transaction/ListTransaction.java b/src/com/sun/apoc/daemon/transaction/ListTransaction.java new file mode 100644 index 0000000..404f0ae --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ListTransaction.java @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +class ListTransaction extends Transaction +{ + public ListTransaction( final Client inClient, final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected void executeTransaction() + { + APOCLogger.finer( "Lstn001" ); + StringBuffer theBuffer = null; + final Cache [] theCaches = mSession.getCaches(); + final HashSet theSet = new HashSet(); + + for (int theIndex = 0 ; theIndex < theCaches.length ; ++ theIndex) + { + theSet.addAll(theCaches [theIndex].list()); + } + if ( theSet != null && theSet.size() > 0 ) + { + final String[] theNames = + ( String[] )theSet.toArray( new String[ 0 ] ); + theBuffer = new StringBuffer(); + for ( int theIndex = 0; theIndex < theNames.length; theIndex ++) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + .append( theNames[ theIndex ] ) + .append( "</" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ); + } + } + APOCLogger.finer( "Lstn002" ); + setResponse( APOCSymbols.sSymRespSuccess, + mRequest.getSessionId(), + theBuffer != null ? theBuffer.toString() : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/ReadTransaction.java b/src/com/sun/apoc/daemon/transaction/ReadTransaction.java new file mode 100644 index 0000000..44d0d07 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ReadTransaction.java @@ -0,0 +1,86 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +class ReadTransaction extends Transaction +{ + public ReadTransaction( final Client inClient, final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected void executeTransaction() + { + APOCLogger.finer( "Rdtn001" ); + StringBuffer theBuffer = null; + final String theComponentName = + ( String )( ( ReadMessage )mRequest ) + .getComponentNames().elementAt( 0 ); + final Cache [] theCaches = mSession.getCaches(); + final ArrayList theResults = new ArrayList(); + + for (int theIndex = 0 ; theIndex < theCaches.length ; ++ theIndex) + { + theResults.addAll(theCaches [theIndex].read(theComponentName)); + } + if ( theResults.size() > 0 ) + { + theBuffer = new StringBuffer(); + final Iterator theIterator = theResults.iterator(); + while ( theIterator.hasNext() ) + { + CacheReadResult theResult = (CacheReadResult)theIterator.next(); + theBuffer.append( "<" ) + .append( APOCSymbols.sParamLayer ) + .append( "><![CDATA[" ) + .append( theResult.mTimestamp ) + .append( theResult.mData ) + .append( "]]></" ) + .append( APOCSymbols.sParamLayer ) + .append( ">" ); + } + } + APOCLogger.finer( "Rdtn002" ); + setResponse( APOCSymbols.sSymRespSuccess, + mRequest.getSessionId(), + theBuffer != null ? theBuffer.toString() : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java b/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java new file mode 100644 index 0000000..2d346c4 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java @@ -0,0 +1,57 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class RemoveListenerTransaction extends Transaction +{ + public RemoveListenerTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Rltn001" ); + mSession.removeListeners( + ( ( RemoveListenerMessage )mRequest ).getComponentNames() ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Rltn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/Transaction.java b/src/com/sun/apoc/daemon/transaction/Transaction.java new file mode 100644 index 0000000..59fee20 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/Transaction.java @@ -0,0 +1,148 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +public abstract class Transaction +{ + protected final Client mClient; + protected Session mSession; + protected final Message mRequest; + protected Message mResponse; + private Thread mThread; + private Object mThreadLock = new Object(); + private long mStartTime; + + public Transaction( final Client inClient, final Message inRequest ) + { + mClient = inClient; + mRequest = inRequest; + if ( inClient != null && inRequest != null ) + { + mSession = inClient.getSession( mRequest.getSessionId() ); + } + } + + public Message execute() + { + if ( ! needSession() || mSession != null ) + { + try + { + beginTransaction(); + executeTransaction(); + endTransaction(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "Transaction", "execute", theException ); + setResponse( APOCSymbols.sSymRespUnknownFailure ); + } + } + else + { + setResponse( APOCSymbols.sSymRespInvalidSessionId ); + } + return mResponse; + } + + public long getDuration() + { + return System.currentTimeMillis() - mStartTime; + } + + public void interrupt() + { + synchronized( mThreadLock ) + { + if ( mThread != null ) + { + mThread.interrupt(); + mThread = null; + } + } + } + + protected boolean needSession() + { + return true; + } + + protected void beginTransaction() + { + mStartTime = System.currentTimeMillis(); + setThread( Thread.currentThread() ); + TransactionFactory.getInstance().addTransaction( this ); + } + protected abstract void executeTransaction(); + protected void endTransaction() + { + setThread( null ); + TransactionFactory.getInstance().removeTransaction( this ); + } + + protected void setResponse( final int inResponseType ) + { + setResponse( inResponseType, mRequest.getSessionId(), null ); + } + + protected void setResponse( final int inResponseType, + final String inSessionId ) + { + setResponse( inResponseType, inSessionId, null ); + } + + protected void setResponse( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + mResponse = MessageFactory.createResponse( inResponseType, + inSessionId, + inResponseMessage ); + } + + private void setThread( final Thread inThread ) + { + synchronized( mThreadLock ) + { + mThread = inThread; + } + } +} diff --git a/src/com/sun/apoc/daemon/transaction/TransactionFactory.java b/src/com/sun/apoc/daemon/transaction/TransactionFactory.java new file mode 100644 index 0000000..3418d7b --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/TransactionFactory.java @@ -0,0 +1,181 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +public class TransactionFactory +{ + + private static TransactionFactory sInstance; + private static final Transaction[] sTransactionModel = + new Transaction[ 0 ]; + //private static long sTransactionTimeout = 30000; + private static long sTransactionTimeout = 10000; + private final HashSet mTransactions = new HashSet(); + private final DaemonTimerTask mTransactionInterrupter = + new DaemonTimerTask( new TransactionInterrupter() ); + + public void addTransaction( final Transaction inTransaction ) + { + synchronized( mTransactions ) + { + if ( mTransactions.size() == 0 ) + { + mTransactionInterrupter.setPeriod( sTransactionTimeout ); + } + mTransactions.add( inTransaction ); + } + } + + public ChangeDetectTransaction createChangeDetectTransaction( + final ClientManager inClientManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + return new ChangeDetectTransaction( inClientManager, + inCache, inAggregator ); + } + + public GarbageCollectTransaction createGarbageCollectTransaction( + final Database inDatabase ) + { + return new GarbageCollectTransaction( inDatabase ); + } + + public Transaction createTransaction( final Client inClient, + final Message inMessage ) + { + Transaction theTransaction = null; + switch ( inMessage.getName() ) + { + case APOCSymbols.sSymReqRead: + theTransaction = new ReadTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqAddListener: + theTransaction = + new AddListenerTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqCreateSession: + theTransaction = + new CreateSessionTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqCreateSessionExt: + theTransaction = + new CreateSessionExtTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqDestroySession: + theTransaction = + new DestroySessionTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqRemoveListener: + theTransaction = + new RemoveListenerTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqList: + theTransaction = + new ListTransaction( inClient, inMessage ); + break; + + default: + break; + } + return theTransaction; + } + + public static TransactionFactory getInstance() + { + if ( sInstance == null ) + { + sInstance = new TransactionFactory(); + } + return sInstance; + } + + public void removeTransaction( final Transaction inTransaction ) + { + synchronized( mTransactions ) + { + if ( mTransactions.size() == 1 ) + { + mTransactionInterrupter.cancel(); + } + mTransactions.remove( inTransaction ); + } + } + + private TransactionFactory(){} + + class TransactionInterrupter implements Runnable + { + public void run() + { + synchronized( mTransactions ) + { + Transaction[] theTransactions = null; + if ( mTransactions.size() > 0 ) + { + theTransactions = + ( Transaction[] )mTransactions.toArray( sTransactionModel); + } + if ( theTransactions != null && theTransactions.length > 0 ) + { + for ( int theIndex = 0; + theIndex < theTransactions.length; + ++ theIndex ) + { + if ( theTransactions[ theIndex ].getDuration() > + sTransactionTimeout ) + { + theTransactions[ theIndex ].interrupt(); + removeTransaction( theTransactions[ theIndex ] ); + } + } + } + } + } + } +} diff --git a/src/com/sun/apoc/daemon/transport/ChannelManager.java b/src/com/sun/apoc/daemon/transport/ChannelManager.java new file mode 100644 index 0000000..f550350 --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ChannelManager.java @@ -0,0 +1,414 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.util.logging.*; + +public class ChannelManager extends Thread implements ConfigEventListener +{ + private Selector mSelector; + private ServerSocketChannel mChannel; + private final HashSet mRegisteringChannels = + new HashSet(); + private final HashSet mDeRegisteringChannels = + new HashSet(); + private final Object mLock = new Object(); + private int mMaxClientChannels = + DaemonConfig.getIntProperty( DaemonConfig.sMaxClientConnections ); + private final HashSet mClientChannelEventListeners = new HashSet(); + private int mChannelCount = 0; + private boolean mTerminate = false; + private static final byte sReject = 0; + private static final byte[] sAcceptByte = { 1 }; + private static final ByteBuffer sAccept = + ( ByteBuffer )ByteBuffer.wrap( sAcceptByte ); + + public ChannelManager() + throws APOCException + { + try + { + initThread(); + initChannel(); + DaemonConfig.addConfigEventListener( this ); + } + catch( IOException theException ) + { + throw new APOCException( + APOCSymbols.sSymCreateServerChannelFailed, + theException ); + } + } + + public void addClientChannelEventListener( + final ClientChannelEventListener inListener ) + { + if ( inListener != null ) + { + synchronized( mClientChannelEventListeners ) + { + mClientChannelEventListeners.add( inListener ); + } + } + } + + public void closeClientChannels() + { + final Set theKeys = mSelector.keys(); + if ( theKeys != null ) + { + final Iterator theIterator = theKeys.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + if ( theKey.isValid() ) + { + try + { + theKey.channel().close(); + } + catch( IOException theException ) + {} + } + } + } + } + + public void closeChannels() + { + closeClientChannels(); + closeServerChannel(); + } + + public void onConfigEvent() + { + setMaxClientChannels(); + } + + public void removeClientChannelEventListener( + final ClientChannelEventListener inListener ) + { + if ( inListener != null ) + { + synchronized( mClientChannelEventListeners ) + { + mClientChannelEventListeners.remove( inListener ); + } + } + } + + public void run() + { + APOCLogger.fine( "Chmr001" ); + while ( ! shouldTerminate() ) + { + try + { + selectChannels(); + registerChannels(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "ChannelManager", "run", theException ); + break; + } + } + APOCLogger.fine( "Chmr003" ); + } + + public void terminate() + { + synchronized( mLock ) + { + mTerminate = true; + } + mSelector.wakeup(); + } + + void closeClientChannel( final ClientChannel inChannel ) + { + inChannel.close(); + notifyClosed( inChannel ); + synchronized( mLock ) + { + -- mChannelCount; + } + } + + void registerForSelection( final ClientChannel inChannel,boolean inRegister) + { + final HashSet theSet = inRegister ? + mRegisteringChannels : mDeRegisteringChannels; + synchronized( theSet ) + { + theSet. add( inChannel.getSocketChannel().keyFor( mSelector ) ); + mSelector.wakeup(); + try + { + theSet.wait(); + } + catch( Exception theException ) + {} + } + } + + private void acceptableKey( final SelectionKey inKey ) + { + SocketChannel theSocketChannel = null; + try + { + theSocketChannel = + ( ( ServerSocketChannel )inKey.channel() ).accept(); + if ( ! testMaxChannels() && theSocketChannel != null ) + { + try + { + theSocketChannel.socket() + .getOutputStream().write( sReject ); + theSocketChannel.close(); + } + catch( Exception theException ){} + return; + } + if ( theSocketChannel. + socket(). + getInetAddress(). + isLoopbackAddress() ) + { + theSocketChannel.configureBlocking( false ); + final SelectionKey theClientKey = + theSocketChannel.register( + mSelector, + SelectionKey.OP_READ ); + ClientChannel theClientChannel = + new ClientChannel( theSocketChannel, this ); + theClientKey.attach( theClientChannel ); + synchronized( mLock ) + { + ++ mChannelCount; + } + theClientChannel.write( sAccept ); + sAccept.flip(); + } + } + catch( IOException theException ) + { + if ( theSocketChannel != null ) + { + try + { + theSocketChannel.close(); + } + catch( Exception ignore ) + {} + } + APOCLogger.throwing( "ChannelManager", + "acceptableKey", + theException ); + } + } + + private void closeServerChannel() + { + try + { + mSelector.close(); + mChannel.close(); + } + catch( IOException theException ) + { + APOCLogger.throwing( "ClientManager", "close", theException ); + } + } + + private int getMaxClientChannels() + { + synchronized( mLock ) + { + return mMaxClientChannels; + } + } + + private void initChannel() + throws IOException + { + mSelector = Selector.open(); + mChannel = ServerSocketChannel.open(); + mChannel.configureBlocking( false ); + mChannel.socket().bind( + new InetSocketAddress( + DaemonConfig.getIntProperty( DaemonConfig.sDaemonPort ) ) ); + mChannel.register( mSelector, SelectionKey.OP_ACCEPT ); + } + + private void initThread() + { + setName( "ChannelManager" ); + setDaemon( true ); + } + + private void notifyClosed( final ClientChannel inClientChannel ) + { + final Iterator theIterator = mClientChannelEventListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( ClientChannelEventListener )theIterator.next() ).onClosed( + inClientChannel ); + } + } + + private void notifyPending( final ClientChannel inClientChannel ) + { + final Iterator theIterator = mClientChannelEventListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( ClientChannelEventListener )theIterator.next() ).onPending( + inClientChannel ); + } + } + + private void readableKey( final SelectionKey inKey ) + { + inKey.interestOps( + inKey.interestOps() & + ( ~ SelectionKey.OP_READ ) ); + notifyPending( ( ClientChannel )inKey.attachment() ); + } + + private void registerChannels() + { + synchronized( mRegisteringChannels ) + { + if ( mRegisteringChannels.size() > 0 ) + { + final Iterator theIterator = mRegisteringChannels.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + theKey.interestOps( theKey.interestOps() | + SelectionKey.OP_READ ); + } + mRegisteringChannels.clear(); + mRegisteringChannels.notifyAll(); + } + } + synchronized( mDeRegisteringChannels ) + { + if ( mDeRegisteringChannels.size() > 0 ) + { + final Iterator theIterator = mDeRegisteringChannels.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + theKey.interestOps( theKey.interestOps() & + ( ~ SelectionKey.OP_READ ) ); + } + } + mDeRegisteringChannels.clear(); + mDeRegisteringChannels.notifyAll(); + } + } + + private void selectChannels() + throws IOException + { + if ( mSelector.select() > 0 ) + { + final Iterator theIterator = mSelector.selectedKeys().iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = ( SelectionKey )theIterator.next(); + theIterator.remove(); + if ( theKey.isAcceptable() ) + { + acceptableKey( theKey ); + } + if ( theKey.isReadable() ) + { + readableKey( theKey ); + } + } + } + } + + private void setMaxClientChannels() + { + synchronized( mLock ) + { + mMaxClientChannels = + DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ); + } + mSelector.wakeup(); + } + + private boolean shouldTerminate() + { + synchronized( mLock ) + { + return mTerminate; + } + } + + private boolean testMaxChannels() + { + boolean bMoreChannelsAllowed = false; + int theMaxClientChannels = getMaxClientChannels(); + if ( theMaxClientChannels > 0 ) + { + synchronized( mLock ) + { + bMoreChannelsAllowed = theMaxClientChannels > mChannelCount; + } + } + if ( ! bMoreChannelsAllowed ) + { + APOCLogger.warning( "Chmr002", + String.valueOf( theMaxClientChannels ) ); + } + return bMoreChannelsAllowed; + } +} diff --git a/src/com/sun/apoc/daemon/transport/ClientChannel.java b/src/com/sun/apoc/daemon/transport/ClientChannel.java new file mode 100644 index 0000000..87ae738 --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ClientChannel.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; + +public class ClientChannel +{ + private SocketChannel mChannel; + private ChannelManager mManager = null; + + private static int sSoTimeout = + DaemonConfig.getIntProperty( DaemonConfig.sConnectionReadTimeout ); + + public ClientChannel( final SocketChannel inChannel, + final ChannelManager inManager ) + throws IOException + { + this( inChannel ); + mManager = inManager; + } + + public ClientChannel( final SocketChannel inChannel ) + throws IOException + { + initChannel( inChannel ); + } + + public SocketChannel getSocketChannel() { return mChannel; } + + public void registerForSelection( boolean inRegister ) + { + mManager.registerForSelection( this, inRegister ); + } + + public long read( final ByteBuffer outBuffer ) + throws IOException + { + long theByteCount = 0; + while ( theByteCount == 0 ) + { + try + { + theByteCount = mChannel.read( outBuffer ); + if ( theByteCount == 0 ) + { + Thread.currentThread().yield(); + } + } + catch( IOException theException ) + { + theByteCount = -1; + break; + } + } + if ( theByteCount == -1 ) + { + APOCLogger.finest( "Clch002" ); + if ( mManager != null ) + { + mManager.closeClientChannel( this ); + } + throw new IOException(); + } + return theByteCount; + } + + public void write( final ByteBuffer inBuffer ) + { + try + { + while ( inBuffer.hasRemaining() ) + { + mChannel.write( inBuffer ); + } + } + catch( IOException theException ) + { + APOCLogger.throwing( "ClientChannel", "write", theException ); + if ( mManager != null ) + { + mManager.closeClientChannel( this ); + } + } + } + + public void close() + { + try + { + if ( mChannel != null ) + { + mChannel.close(); + mChannel = null; + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "ClientChannel", "close", theException ); + } + } + + private void initChannel( final SocketChannel inChannel ) + throws IOException + { + mChannel = inChannel; + final Socket theSocket = mChannel.socket(); + theSocket.setSoLinger( false, 0 ); + theSocket.setSoTimeout( sSoTimeout ); + } +} diff --git a/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java b/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java new file mode 100644 index 0000000..dfef31c --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java @@ -0,0 +1,41 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +public interface ClientChannelEventListener +{ + public void onPending( ClientChannel inClientChannel ); + public void onClosed( ClientChannel inClientChannel ); +} |